
Ich suche nach einem Makro, das als Eingabe einen allgemeinen Term einer Sequenz entgegennimmt und die Sequenz ausführlich schreibt.
Was ich meine ist ein Befehl, \GenSeq{general term}{index}{min index}{max index}
so dass zum Beispiel
\GenSeq{f(i)}{i}{1}{n}
produziert
\GenSeq{f(i)}{i}{k}{n}
produziert
\GenSeq{\theta^{(s)}}{s}{s}{T}
Ich frage mich, ob so etwas in Latex programmiert werden kann
Antwort1
\documentclass{article}
\def\GenSeq#1#2#3{%
\def\zz##1{#1}%
\def\zzstart{#2}%
\zz{#2},
\ifx\zzstart\zzzero\zz{1}\else\ifx\zzstart\zzone\zz{2}\else\zz{#2+1}\fi\fi,
\ldots,\zz{#3}}
\def\zzzero{0}
\def\zzone{1}
\begin{document}
\parskip\bigskipamount
$\GenSeq{f(#1)}{1}{n}$
$\GenSeq{f(#1)}{k}{n}$
$\GenSeq{\theta^{(#1)}}{s}{T}$
\end{document}
Antwort2
Eine Implementierung mit expl3
.
Das erste obligatorische Argument \GenSeq
ist ein Template, das #1
für den aktuellen Index in der „Schleife“ steht. Das zweite Argument ist der Startpunkt, das dritte Argument der Endpunkt.
Wenn das zweite Argument eine Ganzzahl ist (erkennbar über einen regulären Ausdruck, null oder ein Bindestrich/Minuszeichen und eine oder mehrere Ziffern), wird der Index für das zweite gedruckte Element berechnet, andernfalls ist es <start point>+1
. Allerdings
- Wenn Start- und Endpunkt zusammenfallen, wird nur ein Element gedruckt.
- Wenn der Startpunkt numerisch ist und der Endpunkt ebenfalls numerisch ist und sich um eins oder zwei unterscheidet, werden nur die relevanten Elemente gedruckt.
- Andernfalls werden das Startelement, das nächste Element, die Punkte und das Endelement gedruckt.
Bei \GenSeq*
werden am Ende Punkte hinzugefügt, um eine unendliche Folge anzuzeigen.
\documentclass{article}
\usepackage{amsmath}
%\usepackage{xparse} % not needed with LaTeX 2020-10-01 or later
\ExplSyntaxOn
\NewDocumentCommand{\GenSeq}{smmm}
{% #1 = optional *
% #2 = template
% #3 = starting point
% #4 = end point
\pinkcollins_genseq:nnn { #2 } { #3 } { #4 }
\IfBooleanT{#1}{,\dotsc}
}
\cs_new_protected:Nn \pinkcollins_genseq:nnn
{
% turn the template into a (temporary) function
\cs_set:Nn \__pinkcollins_genseq_temp:n { #1 }
% do the main work
\tl_if_eq:nnTF { #2 } { #3 }
{% if #2=#3, not much to do
\__pinkcollins_genseq_temp:n { #2 }
}
{% now the hard work
\__pinkcollins_genseq_do:nn { #2 } { #3 }
}
}
\cs_new_protected:Nn \__pinkcollins_genseq_do:nn
{% #1 = start point, #2 = end point
% first check whether #1 is an integer
% \-? = one optional minus sign
% [[:digit:]]+ = one or more digits
% \Z = up to the end of the input
\regex_match:nnTF { \-? [[:digit:]]+ \Z } { #1 }
{
\__pinkcollins_genseq_number:nn { #1 } { #2 }
}
{
\__pinkcollins_genseq_symbolic:nn { #1 } { #2 }
}
}
\cs_new_protected:Nn \__pinkcollins_genseq_number:nn
{% #1 = start point, #2 = end point
\tl_if_eq:enTF { \int_eval:n { #1 + 1 } } { #2 }
{
\__pinkcollins_genseq_temp:n { #1 },\__pinkcollins_genseq_temp:n { #2 }
}
{
\__pinkcollins_genseq_temp:n { #1 },
\__pinkcollins_genseq_temp:n { \int_eval:n { #1+1 } },
\tl_if_eq:enF { \int_eval:n { #1 + 2 } } { #2 } { \dots, }
\__pinkcollins_genseq_temp:n { #2 }
}
}
\prg_generate_conditional_variant:Nnn \tl_if_eq:nn { e } { T, F, TF }
\cs_new_protected:Nn \__pinkcollins_genseq_symbolic:nn
{% #1 = start point, #2 = end point
\__pinkcollins_genseq_temp:n { #1 },
\__pinkcollins_genseq_temp:n { #1+1 },
\dots,
\__pinkcollins_genseq_temp:n { #2 }
}
\ExplSyntaxOff
\begin{document}
$\GenSeq{f(#1)}{1}{n}$
$\GenSeq{f(#1)}{0}{n}$
$\GenSeq{f(#1)}{1}{1}$
$\GenSeq{f(#1)}{1}{2}$
$\GenSeq{f(#1)}{1}{3}$
$\GenSeq{f(#1)}{1}{4}$
$\GenSeq{f(#1)}{-2}{k}$
$\GenSeq{f(#1)}{k}{n}$
$\GenSeq*{\theta^{(#1)}}{s}{T}$
\end{document}
Eine andere Verwendung der *
-Variante könnte darin bestehen, die Sequenz absteigend zu machen:
\documentclass{article}
\usepackage{amsmath}
%\usepackage{xparse} % not needed with LaTeX 2020-10-01 or later
\ExplSyntaxOn
\NewDocumentCommand{\GenSeq}{smmm}
{% #1 = optional * for reverse sequence
% #2 = template
% #3 = starting point
% #4 = end point
\IfBooleanTF{#1}
{
\cs_set:Nn \__pinkcollins_genseq_sign: { - }
}
{
\cs_set:Nn \__pinkcollins_genseq_sign: { + }
}
\pinkcollins_genseq:nnn { #2 } { #3 } { #4 }
}
\cs_new_protected:Nn \pinkcollins_genseq:nnn
{
% turn the template into a (temporary) function
\cs_set:Nn \__pinkcollins_genseq_temp:n { #1 }
% do the main work
\tl_if_eq:nnTF { #2 } { #3 }
{% if #2=#3, not much to do
\__pinkcollins_genseq_temp:n { #2 }
}
{% now the hard work
\__pinkcollins_genseq_do:nn { #2 } { #3 }
}
}
\cs_new_protected:Nn \__pinkcollins_genseq_do:nn
{% #1 = start point, #2 = end point
% first check whether #1 is an integer
% \-? = one optional minus sign
% [[:digit:]]+ = one or more digits
% \Z = up to the end of the input
\regex_match:nnTF { \-? [[:digit:]]+ \Z } { #1 }
{
\__pinkcollins_genseq_number:nn { #1 } { #2 }
}
{
\__pinkcollins_genseq_symbolic:nn { #1 } { #2 }
}
}
\cs_new_protected:Nn \__pinkcollins_genseq_number:nn
{% #1 = start point, #2 = end point
\tl_if_eq:enTF { \int_eval:n { #1 \__pinkcollins_genseq_sign: 1 } } { #2 }
{
\__pinkcollins_genseq_temp:n { #1 },\__pinkcollins_genseq_temp:n { #2 }
}
{
\__pinkcollins_genseq_temp:n { #1 },
\__pinkcollins_genseq_temp:n { \int_eval:n { #1\__pinkcollins_genseq_sign: 1 } },
\tl_if_eq:enF { \int_eval:n { #1 \__pinkcollins_genseq_sign: 2 } } { #2 } { \dots, }
\__pinkcollins_genseq_temp:n { #2 }
}
}
\prg_generate_conditional_variant:Nnn \tl_if_eq:nn { e } { T, F, TF }
\cs_new_protected:Nn \__pinkcollins_genseq_symbolic:nn
{% #1 = start point, #2 = end point
\__pinkcollins_genseq_temp:n { #1 },
\__pinkcollins_genseq_temp:n { #1\__pinkcollins_genseq_sign:1 },
\dots,
\__pinkcollins_genseq_temp:n { #2 }
}
\ExplSyntaxOff
\begin{document}
\textbf{Ascending}
$\GenSeq{f(#1)}{1}{n}$
$\GenSeq{f(#1)}{0}{n}$
$\GenSeq{f(#1)}{1}{1}$
$\GenSeq{f(#1)}{1}{2}$
$\GenSeq{f(#1)}{1}{3}$
$\GenSeq{f(#1)}{1}{4}$
$\GenSeq{f(#1)}{-2}{k}$
$\GenSeq{f(#1)}{k}{n}$
$\GenSeq{\theta^{(#1)}}{s}{T}$
\textbf{Descending}
$\GenSeq*{f(#1)}{n}{1}$
$\GenSeq*{f(#1)}{n}{0}$
$\GenSeq*{f(#1)}{1}{1}$
$\GenSeq*{f(#1)}{2}{1}$
$\GenSeq*{f(#1)}{3}{1}$
$\GenSeq*{f(#1)}{4}{1}$
$\GenSeq*{f(#1)}{k}{-2}$
$\GenSeq*{f(#1)}{k}{n}$
$\GenSeq*{\theta^{(#1)}}{s}{T}$
\end{document}
Antwort3
Aus Spaß am Herumspielen mit expl3 wollte ich es mit expl3 machen.
Aber letztendlich habe ich es mit einer Mischung aus expl3 und meinem eigenen Code gemacht:
- Ich verwende expl3-regex-code um zu prüfen, ob⟨Mindestindex⟩—(!) ohne Erweiterungstoken von⟨Mindestindex⟩ (!)—bildet eine Folge von höchstens einem Vorzeichen und einigen Dezimalstellen und—wenn ja—zum Inkrementieren und Übergeben an die Ersetzungsroutine den (inkrementierten) Wert von⟨Mindestindex⟩.
- Ich verwende meinen eigenen Code zum Ersetzen⟨Index⟩innerhalb⟨allgemeiner Begriff⟩.
⟨Mindestindex⟩wird nicht erweitert, um zu prüfen, ob es (nur) ein gültiges TeX-⟨Nummer⟩-MengeIch lehne die Idee einer solchen Prüfung aus folgendem Grund ab: Es gibt keine Prüfmethode, um zu prüfen, ob sich die⟨Mindestindex⟩ergibt nur eine gültige TeX-⟨Nummer⟩-Menge ist mir bekannt, die nicht in irgendeiner Weise fehlerhaft ist und/oder die keine Einschränkungen für mögliche Benutzereingaben auferlegt. Wenn man versucht, einen Algorithmus für einen solchen Test zu implementieren, dann steht man vor dem Halteproblem: Zum Zeitpunkt der Erweiterung bilden die Token⟨Mindestindex⟩kann einen beliebigen expansionsbasierten Algorithmus bilden. Wenn ein Algorithmus überprüft, ob ein solcher Algorithmus am Ende eine gültige TeX-⟨Nummer⟩-quantity bedeutet, dass ein Algorithmus prüft, ob ein beliebiger anderer Algorithmus überhaupt bzw. ohne Fehlermeldung beendet wird. Dies ist das Halteproblem.Alan Turing bewies 1936dass es nicht möglich ist, einen Algorithmus zu implementieren, der für jeden beliebigen Algorithmus „entscheiden“ kann, ob dieser Algorithmus jemals beendet wird.
Am Anfang hatte ich vor, das Folgende zu ersetzen:⟨Index⟩mittels expl3-Routinen auch:
Teil VII - Das l3tl-Paket - Token-Listen, Abschnitt3 Ändern der Token-ListenvariablenvonSchnittstelle3.pdf(Erschienen am 27.10.2020) heißt es:
\tl_replace_all:Nnn ⟨tl var⟩ {⟨old tokens⟩} {⟨new tokens⟩}
Ersetztalle Vorkommenvon⟨alte Token⟩im⟨tl var⟩mit⟨neue Token⟩.⟨Alte Token⟩
{
darf nicht ,}
oder enthalten#
(genauer gesagt, explizite Zeichentoken mit Kategoriecode 1 (Gruppenanfang) oder 2 (Gruppenende) und Token mit Kategoriecode 6). Da diese Funktion von links nach rechts arbeitet, ist das Muster⟨alte Token⟩können nach dem Austausch verbleiben (siehe\tl_remove_all:Nn
Beispiel).
(Man sagt Ihnen, dass Kategoriecode 1 „Beginngruppe“ und Kategoriecode 2 „Endgruppe“ ist. Ich frage mich, warum man Ihnen nicht sagt, dass Kategoriecode 6 „Parameter“ ist. ;-) )
Ich habe versucht, es mit zu machen \tl_replace_all:Nnn
.
Dies schlug jedoch fehl, da die Aussage nicht stimmt.
(Sie können es selbst testen:
Im folgenden Beispiel werden nicht alle Vorkommen von u
durch ersetzt d
:
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\tl_set:Nn \l_tmpa_tl {uu{uu}uu{uu}}
\tl_replace_all:Nnn \l_tmpa_tl {u} {d}
\tl_show:N \l_tmpa_tl
\stop
⟨alte Token⟩Ist u
.
⟨neue Token⟩ist d
.
Alle Einschränkungen für⟨alte Token⟩Und⟨neue Token⟩werden befolgt.
Die Konsolenausgabe lautet:
\l_tmpa_tl=dd{uu}dd{uu}.
Es scheint, dass nur Vorkommen ersetzt werden, die nicht zwischen einem Paar übereinstimmender expliziter Zeichen-Token mit dem Kategoriecode 1 (Anfangsgruppe) bzw. 2 (Endgruppe) verschachtelt sind.
Daher ist die Aussage, dass alle Vorkommen ersetzt werden, falsch.
Wenn die Anweisung korrekt wäre, würde die Konsolenausgabe lauten:
\l_tmpa_tl=dd{dd}dd{dd}.
)
Daher habe ich beschlossen, meine eigene Ersetzungsroutine \ReplaceAllIndexOcurrences
von Grund auf ohne expl3 zu schreiben.
Als Nebeneffekt \ReplaceAllIndexOcurrences
werden alle expliziten Zeichen-Token der Kategoriecode 1 durch und alle expliziten Zeichen-Token der Kategoriecode 2 durch ersetzt .{1
}2
\documentclass[landscape, a4paper]{article}
%===================[adjust margins/layout for the example]====================
\csname @ifundefined\endcsname{pagewidth}{}{\pagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pdfpagewidth}{}{\pdfpagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pageheight}{}{\pageheight=\paperheight}%
\csname @ifundefined\endcsname{pdfpageheight}{}{\pdfpageheight=\paperheight}%
\textwidth=\paperwidth
\oddsidemargin=1.5cm
\marginparsep=.2\oddsidemargin
\marginparwidth=\oddsidemargin
\advance\marginparwidth-2\marginparsep
\advance\textwidth-2\oddsidemargin
\advance\oddsidemargin-1in
\evensidemargin=\oddsidemargin
\textheight=\paperheight
\topmargin=1.5cm
\footskip=.5\topmargin
{\normalfont\global\advance\footskip.5\ht\strutbox}%
\advance\textheight-2\topmargin
\advance\topmargin-1in
\headheight=0ex
\headsep=0ex
\pagestyle{plain}
\parindent=0ex
\parskip=0ex
\topsep=0ex
\partopsep=0ex
%==================[eof margin-adjustments]====================================
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand\GenSeq{mmmm}{
\group_begin:
% #1 = general term
% #2 = index
% #3 = min index
% #4 = max index
\regex_match:nnTF { ^[\+\-]?\d+$ }{ #3 }{
\int_step_inline:nnnn {#3}{1}{#3+1}{\ReplaceAllIndexOcurrences{#1}{#2}{##1},}
}{
\ReplaceAllIndexOcurrences{#1}{#2}{#3},
\ReplaceAllIndexOcurrences{#1}{#2}{#3+1},
}
\ldots,
\ReplaceAllIndexOcurrences{#1}{#2}{#4}
\group_end:
}
\ExplSyntaxOff
\makeatletter
%%//////////////////// Code of my own replacement-routine: ////////////////////
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo,
%% \UD@PassFirstToSecond, \UD@Exchange, \UD@removespace
%% \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%% \UD@CheckWhetherLeadingTokens, \UD@ExtractFirstArg
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\z@\UD@secondoftwo}%
{\expandafter\z@\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked has leading
%% catcode-1-token>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked has no leading
%% catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
\romannumeral\expandafter\UD@secondoftwo\expandafter{\expandafter{%
\string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\z@\UD@firstoftwo}%
{\expandafter\z@\UD@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's leading tokens form a specific
%% token-sequence that does neither contain explicit character tokens of
%% category code 1 or 2 nor contain tokens of category code 6:
%%.............................................................................
%% \UD@CheckWhetherLeadingTokens{<argument which is to be checked>}%
%% {<a <token sequence> without explicit
%% character tokens of category code
%% 1 or 2 and without tokens of
%% category code 6>}%
%% {<internal token-check-macro>}%
%% {<tokens to be delivered in case
%% <argument which is to be checked> has
%% <token sequence> as leading tokens>}%
%% {<tokens to be delivered in case
%% <argument which is to be checked>
%% does not have <token sequence> as
%% leading tokens>}%
\newcommand\UD@CheckWhetherLeadingTokens[3]{%
\romannumeral\UD@CheckWhetherNull{#1}{\expandafter\z@\UD@secondoftwo}{%
\expandafter\UD@secondoftwo\string{\expandafter
\UD@@CheckWhetherLeadingTokens#3{\relax}#1#2}{}}%
}%
\newcommand\UD@@CheckWhetherLeadingTokens[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
{\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter\z@\expandafter\expandafter
\expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% \UD@internaltokencheckdefiner{<internal token-check-macro>}%
%% {<token sequence>}%
%% Defines <internal token-check-macro> to snap everything
%% until reaching <token sequence>-sequence and spit that out
%% nested in braces.
%%-----------------------------------------------------------------------------
\newcommand\UD@internaltokencheckdefiner[2]{%
\@ifdefinable#1{\long\def#1##1#2{{##1}}}%
}%
\UD@internaltokencheckdefiner{\UD@InternalExplicitSpaceCheckMacro}{ }%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%% \romannumeral\UD@ExtractFirstArgLoop{ABCDE\UD@SelDOm} yields {A}
%%
%% \romannumeral\UD@ExtractFirstArgLoop{{AB}CDE\UD@SelDOm} yields {AB}
%%.............................................................................
\@ifdefinable\UD@RemoveTillUD@SelDOm{%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{\z@#1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%=============================================================================
%% \ReplaceAllIndexOcurrences{<term with <index>>}
%% {<index>}%
%% {<replacement for<index>>}%
%%
%% Replaces all <index> in <term with <index>> by <replacement for<index>>
%%
%% !!! Does also replace all pairs of matching explicit character tokens of
%% catcode 1/2 by matching braces!!!
%% !!! <index> must not contain explicit character tokens of catcode 1 or 2 !!!
%% !!! <index> must not contain tokens of catcode 6 !!!
%% !!! Defines temporary macro \UD@temp, therefore not expandable !!!
%%-----------------------------------------------------------------------------
\newcommand\ReplaceAllIndexOcurrences[2]{%
% #1 - <term with <index>>
% #2 - <index>
\begingroup
\UD@internaltokencheckdefiner{\UD@temp}{#2}%
\expandafter\endgroup
\romannumeral\UD@ReplaceAllIndexOcurrencesLoop{#1}{}{#2}%
}%
\newcommand\UD@ReplaceAllIndexOcurrencesLoop[4]{%
% Do:
% \UD@internaltokencheckdefiner{\UD@temp}{<index>}%
% \romannumeral\UD@ReplaceAllIndexOcurrencesLoop
% {<term with <index>>}%
% {<sequence created so far, initially empty>}%
% {<index>}%
% {<replacement for<index>>}%
%
% #1 - <term with <index>>
% #2 - <sequence created so far, initially empty>
% #3 - <index>
% #4 - <replacement for<index>>
\UD@CheckWhetherNull{#1}{\z@#2}{%
\UD@CheckWhetherLeadingTokens{#1}{#3}{\UD@temp}{%
\expandafter\expandafter\expandafter\UD@ReplaceAllIndexOcurrencesLoop
\expandafter\expandafter\expandafter{%
\expandafter\UD@firstoftwo\expandafter{\expandafter}\UD@temp#1%
}{#2#4}%
}{%
\UD@CheckWhetherLeadingTokens{#1}{ }{\UD@InternalExplicitSpaceCheckMacro}{%
\expandafter\UD@ReplaceAllIndexOcurrencesLoop
\expandafter{\UD@removespace#1}{#2 }%
}{%
\UD@CheckWhetherBrace{#1}{%
\expandafter\expandafter\expandafter\UD@PassFirstToSecond
\expandafter\expandafter\expandafter{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral\expandafter\UD@ReplaceAllIndexOcurrencesLoop
\romannumeral\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{}{#3}{#4}%
}{#2}}%
{\expandafter\UD@ReplaceAllIndexOcurrencesLoop\expandafter{\UD@firstoftwo{}#1}}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral\expandafter\UD@Exchange\romannumeral\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{\z@#2}%
}{\expandafter\UD@ReplaceAllIndexOcurrencesLoop\expandafter{\UD@firstoftwo{}#1}}%
}%
}%
}%
{#3}{#4}%
}%
}%
\makeatother
%%=============================================================================
%%///////////////// End of code of my own replacement-routine. ////////////////
\makeatletter
\newcommand\ParenthesesIfMoreThanOneUndelimitedArgument[1]{%
\begingroup
\protected@edef\UD@temp{#1}%
\expandafter\expandafter\expandafter\UD@CheckWhetherNull
\expandafter\expandafter\expandafter{\expandafter\UD@firstoftwo\UD@temp{}.}{%
\endgroup#1%
}{%
\expandafter\UD@CheckWhetherNull
\expandafter{\romannumeral\expandafter\expandafter
\expandafter \expandafter
\expandafter\expandafter
\expandafter \z@
\expandafter\expandafter
\expandafter \UD@firstoftwo
\expandafter\UD@firstoftwo
\expandafter{%
\expandafter}%
\UD@temp{}.}{%
\endgroup#1%
}{%
\endgroup(#1)%
}%
}%
}%
\makeatother
\begin{document}
Let's use \verb|i| as \textit{$\langle$index$\rangle$}---\verb|$\GenSeq{f(i)}{i}{1}{n}$| yields:
$\GenSeq{f(i)}{i}{1}{n}$
\vfill
Let's use \verb|i| as \textit{$\langle$index$\rangle$}, but \textit{$\langle$min~index$\rangle$} not a digit sequence---\verb|$\GenSeq{f(i)}{i}{k}{n}$| yields:
$\GenSeq{f(i)}{i}{k}{n}$
\vfill
Let's use \verb|s| as \textit{$\langle$index$\rangle$}---\verb|$\GenSeq{\theta^{(s)}}{s}{s}{T}$| yields:
$\GenSeq{\theta^{(s)}}{s}{s}{T}$
\vfill
Let's use \verb|\Weird\Woozles| as \textit{$\langle$index$\rangle$}---\begin{verbatim}
$\GenSeq{%
\sqrt{%
\vphantom{(}%
ParenthesesIfMoreThanOneUndelimitedArgument{\Weird\Woozles}\cdot\ParenthesesIfMoreThanOneUndelimitedArgument{\Weird\Woozles}%
\vphantom{)}%
}%
}%
{\Weird\Woozles}%
{s}%
{T}$
\end{verbatim} yields:
$\GenSeq{%
\sqrt{%
\vphantom{(}%
\ParenthesesIfMoreThanOneUndelimitedArgument{\Weird\Woozles}\cdot\ParenthesesIfMoreThanOneUndelimitedArgument{\Weird\Woozles}%
\vphantom{)}%
}%
}%
{\Weird\Woozles}%
{s}%
{T}$
\vfill
Let's use the explicit space token as \textit{$\langle$index$\rangle$}---\verb|$\GenSeq{f( )}{ }{k}{n}$| yields:
$\GenSeq{f( )}{ }{k}{n}$
\vfill
Let's use the explicit space token as \textit{$\langle$index$\rangle$}---\verb|$\GenSeq{f( )}{ }{-5}{n}$| yields:
$\GenSeq{f( )}{ }{-5}{n}$
\vfill\vfill
\end{document}