From 4104bd9b8e9136e4845fbec5d77c8108deabc42a Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Thu, 19 Mar 2026 11:43:42 +0000 Subject: [PATCH 01/13] doc(manual): add pushhide/pophide example --- check/examples.frm | 39 +++++++++++++++++++++++++++ doc/manual/statements.tex | 57 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 93 insertions(+), 3 deletions(-) diff --git a/check/examples.frm b/check/examples.frm index b1ac873a..bc180a2a 100644 --- a/check/examples.frm +++ b/check/examples.frm @@ -805,6 +805,45 @@ assert result("G") =~ expr(" assert succeeded? assert result("F") =~ expr("x^2*acc(-y^3-10*y^2-2*y-5,y^2-1)") *--#] Sta_PolyRatFun_1 : +*--#[ Sta_PushPopHide_1 : +Local F1 = 1; +.sort +PushHide; +Local F2 = 1; +* This statement does not affect F1: +Multiply 2; +.sort +PushHide; +Local F3 = 1; +* This statement does not affect F1,F2: +Multiply 2; +.sort +PopHide; +* This statement does not affect F1: +Multiply 2; +.sort +PopHide; +* This statement affects all expressions: +Multiply 2; +Print; +.end +assert succeeded? +assert result("F1") =~ expr("2") +assert result("F2") =~ expr("8") +assert result("F3") =~ expr("8") +*--#] Sta_PushPopHide_1 : +*--#[ Sta_PushPopHide_2 : +Local F1 = 1; +.sort +PushHide; +Multiply 2; +.sort +PopHide; +.sort +PopHide; +.end +assert compile_error?("PopHide statement without corresponding PushHide statement") +*--#] Sta_PushPopHide_2 : *--#[ Sta_Print_1 : Symbols a,b,c; Local F = 3*a+2*b; diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index e0316ae2..a5e51c10 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -4353,7 +4353,23 @@ \section{pophide} \noindent Undoes\index{pophide} the action of the most recent pushhide\index{pushhide} statement (see \ref{substapushhide}). If there is -no matching pushhide statement an error will result. \vspace{10mm} +no matching pushhide statement an error will result: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_PushPopHide_2) +\begin{verbatim} + Local F1 = 1; + .sort + PushHide; + Multiply 2; + .sort + PopHide; + .sort + PopHide; + .end +pushpophide-2.frm Line 9 --> PopHide statement without corresponding PushHide s +tatement +\end{verbatim} +\vspace{10mm} %--#] pophide : %--#[ print : @@ -4638,9 +4654,44 @@ \section{pushhide} pophide (\ref{substapophide}) \end{tabular} \vspace{4mm} -\noindent Hides\index{hide} all currently\index{pushhide} active +\noindent Hides\index{hide} all currently\index{pushhide}-active expressions (see \ref{substahide}). The pophide\index{pophide} statement -(see \ref{substapophide}) can bring them back to active status again. +(see \ref{substapophide}) can be used to to un-hide the expressions hidden +by the most recent pushhide statement. For example: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_PushPopHide_1) +\begin{verbatim} + Local F1 = 1; + .sort + PushHide; + Local F2 = 1; + * This statement does not affect F1: + Multiply 2; + .sort + PushHide; + Local F3 = 1; + * This statement does not affect F1,F2: + Multiply 2; + .sort + PopHide; + * This statement does not affect F1: + Multiply 2; + .sort + PopHide; + * This statement affects all expressions: + Multiply 2; + Print; + .end + + F1 = + 2; + + F2 = + 8; + + F3 = + 8; +\end{verbatim} \vspace{10mm} %--#] pushhide : From 4ff3b7597f870b8568c439b83cee72d2d98fc5f2 Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Thu, 19 Mar 2026 11:56:44 +0000 Subject: [PATCH 02/13] doc(manual): fix typo and tweak "unhide" description --- doc/manual/statements.tex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index a5e51c10..204804e0 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -6443,19 +6443,19 @@ \section{unhide} \end{tabular} \vspace{4mm} \noindent In its\index{unhide} first variety this statement causes all -statements in the hide\index{hide} file\index{file!hide} to become +expressions in the hide\index{hide} file\index{file!hide} to become active\index{active} expressions again. In its second variety only the specified expressions are taken from the hide system and become active again. An expression that is made active again can be manipulated again in the module in which the unhide statement occurs. For more information one should look at the hide statement in \ref{substahide}. \vspace{4mm} -\noindent Note that if only a number of expressions is taken from the hide +\noindent Note that if only a number of expressions are taken from the hide system, the hide file may be left with `holes', i.e.\ space between the -remaining expressions that contain no relevant information any longer. -{\FORM} contains no mechanism to use the space in these holes. Hence if -space is at a premium and many holes develop one should unhide all -expressions (this causes the hide system to be started from zero size +remaining expressions that no longer contain relevant information. +{\FORM} has no mechanism to use the space in these holes. Hence if +space is at a premium and many holes develop, one should unhide all +expressions (which causes the hide system to be started from zero size again) and then send the relevant expressions back to the hide system. \vspace{10mm} From 4c9d0c7d04ddeed42e5b3a2c0925fd099ee5d25a Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Thu, 19 Mar 2026 12:29:01 +0000 Subject: [PATCH 03/13] doc(manual): add while example --- check/examples.frm | 25 ++++++++++++++++++ doc/manual/statements.tex | 55 +++++++++++++++++++++++++++------------ 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/check/examples.frm b/check/examples.frm index bc180a2a..b8e0d2c6 100644 --- a/check/examples.frm +++ b/check/examples.frm @@ -956,6 +956,31 @@ assert result("F") =~ expr(" assert succeeded? assert result("F") =~ expr("H(907202)") *--#] Sta_Transform_1 : +*--#[ Sta_While_1 : +Symbol x,y,z; +Local Fx = (1+x)^6; +Local Fy = (1+y)^6; +Local Fz = (1+z)^6; + +While (Count(x,1) > 3); + Multiply 1/x; +EndWhile; + +Repeat; + If (Count(y,1) > 3); + Multiply 1/y; + EndIf; +EndRepeat; + +While (Count(z,1) > 3) Multiply 1/z; + +Print; +.end +assert succeeded? +assert result("Fx") =~ expr("1 + 6*x + 15*x^2 + 42*x^3"); +assert result("Fy") =~ expr("1 + 6*y + 15*y^2 + 42*y^3"); +assert result("Fz") =~ expr("1 + 6*z + 15*z^2 + 42*z^3"); +*--#] Sta_While_1 : *--#[ Fun_distrib_1 : Symbols x1,...,x4; CFunctions f,f1,f2; diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index 204804e0..93af6978 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -6510,37 +6510,60 @@ \section{while} if (\ref{substaif}) \end{tabular} \vspace{4mm} -\noindent This statement\index{while} starts the while +\noindent This statement\index{while} starts a while environment\index{environment!while}. It should be paired with an endwhile\index{endwhile} statement (see \ref{substaendwhile}) which terminates the while environment. The statements between the while and the endwhile statements will be executed as long as the condition is met. For -the description of the condition one should consult the if\index{if} +a description of the condition syntax one should consult the if\index{if} statement (see \ref{substaif}). The while/endwhile combination is -equivalent to the construction +equivalent to a nested repeat and if environment. +If only a single statement is inside the environment, one can also use +{\tt while ( condition ) statement;}. For example: + +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_While_1) \begin{verbatim} - repeat; - if ( condition ); + Symbol x,y,z; + Local Fx = (1+x)^6; + Local Fy = (1+y)^6; + Local Fz = (1+z)^6; + While (Count(x,1) > 3); + Multiply 1/x; + EndWhile; - endif; - endrepeat; -\end{verbatim} -If only a single statement is inside the environment one can also use -\begin{verbatim} - while ( condition ) statement; + Repeat; + If (Count(y,1) > 3); + Multiply 1/y; + EndIf; + EndRepeat; + + While (Count(z,1) > 3) Multiply 1/z; + + Print; + .end + + Fx = + 1 + 6*x + 15*x^2 + 42*x^3; + + Fy = + 1 + 6*y + 15*y^2 + 42*y^3; + + Fz = + 1 + 6*z + 15*z^2 + 42*z^3; \end{verbatim} + Of course one should try to avoid infinite\index{infinite loop} loops\index{loops!infinite}. In order to maximize the speed of {\FORM} not all internal stacks are protected and hence the result may be that {\FORM} -may crash. It is also possible that {\FORM} may detect a shortage of buffer +crashes. It is also possible that {\FORM} may detect a shortage of buffer space and quit with an error message. \vspace{4mm} \noindent For each term for which execution reaches the endwhile statement, -control is brought back to the while statement. For each term that reaches -the while statement the condition is checked and if it is met, the -statements inside the environment are executed again on this term. If the -condition is not met, execution continues after the endwhile statement. +control jumps back to the while statement. The condition is checked, and if +it is met the statements within the while environment are executed again on +the term. Otherwise, execution continues after the endwhile statement. \vspace{10mm} %--#] while : From 159ab674a133fec89a055d35f0dd1a1b74c65688 Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Thu, 19 Mar 2026 13:57:46 +0000 Subject: [PATCH 04/13] doc(manual): fix typo and small changes to unfactorize --- doc/manual/statements.tex | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index 93af6978..6a58b55a 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -3634,16 +3634,16 @@ \section{nunfactorize} \end{tabular} \vspace{4mm} \noindent When one uses an UnFactorize (see \ref{substaunfactorize}) -statement without arguments all expressions will be marked for being -unfactorized. If one would like to exclude a few expressions this can be +statement without arguments all expressions will be marked for +unfactorization. If one would like to exclude a few expressions this can be done with the NUnFactorize statement. There should be at least one expression -mentioned as in: +specified, as in: \begin{verbatim} UnFactorize; NUnFactorize expr12,expr29; \end{verbatim} One can also use the UnFactorize statement with a number of expressions after -which the NUnFactorize statement can remove some from the list again as in: +which the NUnFactorize statement can remove some from the list again, as in: \begin{verbatim} UnFactorize expr1,...,expr100; NUnFactorize expr12,expr29; @@ -6416,12 +6416,12 @@ \section{unfactorize} printed, there may be several statistics for this step. \noindent When the statement has arguments, these arguments should be names -of expressions. In that case the unfactorization is applied only to the +of expressions; in this case the unfactorization is applied only to the expressions that are specified. -\noindent If one likes to unfactorized all expressions except for a few -ones, one can use the unfactorize statement without arguments and then -exclude the few expressions that should not be treated with the +\noindent If one wants to unfactorize all expressions except for a few, +one can use the unfactorize statement without arguments and then +exclude specific expressions which should not be treated with the nunfactorize statement (see \ref{substanunfactorize}). \vspace{10mm} From 94fbffe25bb9c3e770c832387ffa41f7099034a9 Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Thu, 19 Mar 2026 14:14:20 +0000 Subject: [PATCH 05/13] doc(manual): add example for tryreplace --- check/examples.frm | 12 ++++++++++++ doc/manual/statements.tex | 29 +++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/check/examples.frm b/check/examples.frm index b8e0d2c6..ff4ff236 100644 --- a/check/examples.frm +++ b/check/examples.frm @@ -956,6 +956,18 @@ assert result("F") =~ expr(" assert succeeded? assert result("F") =~ expr("H(907202)") *--#] Sta_Transform_1 : +*--#[ Sta_TryReplace_1 : +Symbol x,y,z; +Local test = x+z; +* These will replace x by y but not z by y, because z +* comes before y in the default sort ordering: +TryReplace x,y; +TryReplace z,y; +Print; +.end +assert succeeded? +assert result("test") =~ expr("z+y") +*--#] Sta_TryReplace_1 : *--#[ Sta_While_1 : Symbol x,y,z; Local Fx = (1+x)^6; diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index 6a58b55a..822d85e0 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -6382,12 +6382,29 @@ \section{tryreplace} \\ See also & the replace\_ function (\ref{funreplace}) \end{tabular} \vspace{4mm} -\noindent The list\index{tryreplace} of potential replacements should be -similar to the arguments of the replace\_\index{replace\_} -function\index{function!replace\_} (see \ref{funreplace}). {\FORM} will -make a copy of the current term, try the replacement and if the replacement -results in a term which, by the internal ordering of {\FORM}, comes before -the current term, the current term is replaced by the new variety. +The tryreplace\index{tryreplace} statement takes a list of potential +replacements with a syntax similar to the arguments of the +replace\_\index{replace\_} function\index{function!replace\_} (see +\ref{funreplace}). {\FORM} will make a copy of the current term and make the +listed replacements. If the resulting term comes before the current term in +the sort-ordering of {\FORM} (which depends, for example, on the declaration +order of the objects in the term), the current term is replaced by the new +term. Otherwise, the current term is unchanged. For example: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_TryReplace_1) +\begin{verbatim} + Symbol x,y,z; + Local test = x+z; + * These will replace x by y but not z by y, because z + * comes before y in the default sort ordering: + TryReplace x,y; + TryReplace z,y; + Print; + .end + + test = + z + y; +\end{verbatim} \vspace{10mm} %--#] tryreplace : From a5184bffcd6163c5cc78f9f89bdfaac0cf758b58 Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Fri, 20 Mar 2026 10:57:28 +0000 Subject: [PATCH 06/13] doc(manual): add examples for the transform statement --- check/examples.frm | 194 ++++++++++++++++++ doc/manual/statements.tex | 420 +++++++++++++++++++++++++++++--------- 2 files changed, 516 insertions(+), 98 deletions(-) diff --git a/check/examples.frm b/check/examples.frm index ff4ff236..ef88ad25 100644 --- a/check/examples.frm +++ b/check/examples.frm @@ -956,6 +956,200 @@ assert result("F") =~ expr(" assert succeeded? assert result("F") =~ expr("H(907202)") *--#] Sta_Transform_1 : +*--#[ Sta_Transform_2 : +Symbol x,x1,x2; +CF H,H1; +Off Statistics; +L F = H(3,4,2,6,1,1,1,2); +repeat id H(?a,x?!{0,1},?b) = H(?a,0,x-1,?b); +Print; +.sort + +Multiply H1; +repeat id H(x?,?a)*H1(?b) = H(?a)*H1(?b,1-x); +id H1(?a)*H = H(?a); +Print; +.sort + +repeat id H(x1?,x2?,?a) = H(2*x1+x2,?a); +Print; +.end +assert succeeded? +assert result("F") =~ expr("H(907202)") +*--#] Sta_Transform_2 : +*--#[ Sta_Transform_3 : +Symbol a; +Vector p; +CFunction f1,f2; +Local test = f1(0,1) + f2(2,a) + f2(2,p); +Transform f1 replace(1,last)=(0,1,1,0); +* This will not affect f2(2,p) because xarg_ does not match vectors: +Transform f2 replace(1,last)=(xarg_,2*xarg_+1); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f1(1,0) + f2(5,1 + 2*a) + f2(5,p)") +*--#] Sta_Transform_3 : +*--#[ Sta_Transform_4 : +CFunction f2,f3; +Local test = f2(1,1,0,1) + f3(1,1,0,1); +Transform f2 encode(1,last):base=2; +Transform f3 encode(1,last):base=3; +Print; +.end +assert succeeded? +assert result("test") =~ expr("f2(13) + f3(37)") +*--#] Sta_Transform_4 : +*--#[ Sta_Transform_5 : +CFunction f2,f3,F2,F3; +Local test = f2(13) + f2(100) + f3(37) + F2(13) + F3(37); +Transform f2 decode(1,5):base=2; +Transform f3 decode(1,5):base=3; +Transform F2 decode(5,1):base=2; +Transform F3 decode(5,1):base=3; +Print; +.end +assert succeeded? +assert result("test") =~ expr("f2(0,1,1,0,1) + f2(100) + f3(0,1,1,0,1) + F2(1,0,1,1,0) + F3(1,0,1,1,0)") +*--#] Sta_Transform_5 : +*--#[ Sta_Transform_6 : +CFunction f; +Symbol a; +Local test = f(0,0,1,0,a,0,0,0,-1); +Transform f implode(1,last); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(3,2*a,-4)") +*--#] Sta_Transform_6 : +*--#[ Sta_Transform_7 : +CFunction f; +Symbol a; +Local test = f(3,2*a,-4); +Transform f explode(1,last); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(0,0,1,0,a,0,0,0,-1)") +*--#] Sta_Transform_7 : +*--#[ Sta_Transform_8 : +CFunction f,cyc; +Symbol a1,...,a7; +Local test = f(a1,a2,a3,a4,a5,a6,a7)*cyc(2,6); +Identify cyc(?a$cyc) = 1; +Transform f permute(1,3,5)($cyc); +ModuleOption local $cyc; +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(a3,a6,a5,a4,a1,a2,a7)") +*--#] Sta_Transform_8 : +*--#[ Sta_Transform_9 : +CFunction f; +Local test = f(1,...,10); +Transform f reverse(3,7); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(1,2,7,6,5,4,3,8,9,10)") +*--#] Sta_Transform_9 : +*--#[ Sta_Transform_10 : +CFunction f,g; +Function h,i; +Symbol x; +Vector p; +Index mu; +Local test = f(100,g(1),g(2)^2,x,x^2,mu,p,p.p,1/p.p,h*i,i*h); +Identify f(?a) = f(?a,?a); +Transform f dedup(1,last); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(100,g(1),g(2)^2,x,x^2,mu,p,p.p,p.p^-1,h*i,i*h)") +*--#] Sta_Transform_10 : +*--#[ Sta_Transform_11 : +CFunction f,g,h; +Local test = f(1,...,9) + g(1,...,9) + h(1,...,9); +Transform f cycle(3,7)=-1; +Transform g permute(3,...,7); +Transform h cycle(3,7)=+2; +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(1,2,4,5,6,7,3,8,9) + g(1,2,4,5,6,7,3,8,9) + h(1,2,6,7,3,4,5,8,9)") +*--#] Sta_Transform_11 : +*--#[ Sta_Transform_11b : +CFunction h; +Local test = h(1,...,9); +Transform h cycle(3,7)=2; +Print; +.end +assert compile_error?("Cycle in a Transform statement should be followed by =+/-number/$") +*--#] Sta_Transform_11b : +*--#[ Sta_Transform_12 : +CFunction f; +Symbol y,n; +Local test = f(0) + f(1) + f(0,1) + f(0,0,1) + f(0,1,1) + + f(0,0) + f(1,0) + f(1,1) + f(1,0,0) + f(0,1,0) + f(1,0,1); +Transform f islyndon(1,last)=(y,n); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(0)*y + f(0,0)*n + f(0,0,1)*y + f(0,1)*y + f(0,1,0)*n + f(0,1,1)*y + f(1)*y + f(1,0)*n + f(1,0,0)*n + f(1,0,1)*n + f(1,1)*n") +*--#] Sta_Transform_12 : +*--#[ Sta_Transform_13 : +CFunction f; +Symbol y,n; +Local test = f(0) + f(1) + f(0,1) + f(0,0,1) + f(0,1,1) + + f(0,0) + f(1,0) + f(1,1) + f(1,0,0) + f(0,1,0) + f(1,0,1); +Transform f tolyndon(1,last)=(y,n); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(0)*y + f(0,0)*n + 3*f(0,0,1)*y + 2*f(0,1)*y + 2*f(0,1,1)*y + f(1)*y + f(1,1)*n") +*--#] Sta_Transform_13 : +*--#[ Sta_Transform_14 : +CFunction f; +Symbol x; +Local test = f(,...,); +Transform f addargs(1,last); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(x + x^2 + x^3 + x^4 + x^5)") +*--#] Sta_Transform_14 : +*--#[ Sta_Transform_15 : +CFunction f; +Symbol x; +Local test = f(,...,); +Transform f mulargs(1,last); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(x^15)") +*--#] Sta_Transform_15 : +*--#[ Sta_Transform_16 : +CFunction f,g; +Symbol x; +Local test = f(1,...,5) + g(1,...,5); +Transform f dropargs(2,4); +Transform g dropargs(1,last); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(1,5) + g") +*--#] Sta_Transform_16 : +*--#[ Sta_Transform_17 : +CFunction f,g; +Symbol x; +Local test = f(1,...,5) + g(1,...,5); +Transform f selectargs(2,4); +Transform g selectargs(1,last); +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(2,3,4) + g(1,2,3,4,5)") +*--#] Sta_Transform_17 : *--#[ Sta_TryReplace_1 : Symbol x,y,z; Local test = x+z; diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index 822d85e0..64d64748 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -6169,27 +6169,31 @@ \section{transform} Syntax & transform,function(s),{\tt<}one or more transformations{\tt>}; \end{tabular} \vspace{4mm} -\noindent Statement\index{Transform} to manipulation function arguments and -fields of arguments. Allows speedy transformations without the need of +\noindent The transform statement\index{Transform} manipulates function +arguments and +fields of arguments. It allows speedy transformations without the need for multiple statements or repeat loops. -The function(s) is/are indicated as individual, comma or blank space -separated, functions or sets of functions. +The function(s) on which the statement will act are indicated as individual, +comma or blank-space separated functions or sets of functions. If there is more than one transformation, the transformations are separated -by comma's (or blanks, unless the blank space would not induce a comma). +by commas (or blanks, unless the blank space would not induce a comma). Each transformation consists of its keyword, indicating its type, followed -by a range of arguments that is enclosed by parentheses. After that -specific information may follow. The range\index{last}\index{range} is as -in +by a range of arguments that is enclosed by parentheses. After that, +transformation-specific information may follow. +The range\index{range} is specified as two comma-separated +indicators, as in: \begin{verbatim} (1,4) (3,last) (last-6,last-2) \end{verbatim} -hence two indicators, separated by a comma. If the first number is bigger -than the second the arguments will be processed in reverse order whenever +The special keyword \verb:last:\index{last} refers to the last argument of the +function, and \verb:last-1: refers to the next-to-last argument, etc. +If the first number is bigger +than the second, the arguments will be processed in reverse order whenever this is relevant. In the descriptions below we will indicate the range by (r1,r2). The numbers in the above examples may be also dollar variables, provided they evaluate into numbers at the time of execution. Hence @@ -6199,129 +6203,348 @@ \section{transform} (last-$x,last-2) \end{verbatim} are potentially legal ranges. One may not use \verb:$x+2: or other -expressions that still need evaluation. +expression which still needs evaluation. The transformations that are allowed currently are: -\leftvitem{3.2cm}{replace\index{transform!replace}\index{replace}} -\rightvitem{13cm}{replace(r1,r2)=(from1,to1,from2,to2,...,fromn,ton) in -which the from-to pairs are as in the replace\_ function. Here however -there are more options than in the replace\_ function as we can specify -(small) numbers as well as in \\ -replace(1,last)=(0,1,1,0) which would replace arguments that are zero by -one and arguments that are one by zero. Generic arguments are indicated by -the new variables xarg\_, iarg\_, parg\_ and farg\_ as in \\ -replace(1,last)=(xarg\_,2\*xarg\_+1,p) which would replace f(2,a) by f(5, -2\*a+1,p) if a is a symbol and p a vector. To catch p one would need to use -parg\_.} - -\leftvitem{3.2cm}{encode\index{transform!encode}\index{encode}} -\rightvitem{13cm}{encode(r1,r2):base=number will interpret the arguments as -the digits in a base 2 number system, compute the complete number and -replace the arguments by a single argument that is that number. The number -must fit inside a single \FORM{} word and so must each of the original -arguments. They should actually be smaller than the number of the base.} - -\leftvitem{3.2cm}{decode\index{transform!decode}\index{decode}} -\rightvitem{13cm}{decode(r1,r2):base=number will do the opposite of encode. -It will take a single argument (the smallest of the two given) and expand -it into digits in a number system given by the base. It will create the -specified number of digits and replace the original number by the given -number of arguments representing these digits. If r2 is less than r1 the -digits will be in reverse order.} - -\leftvitem{3.2cm}{tosumnotation\index{transform!tosumnotation}\index{tosumnotation} +\leftvitem{3.2cm}{\bf replace\index{transform!replace}\index{replace}} +\rightvitem{13cm}{replace(r1,r2)=(from1,to1,from2,to2,...,fromn,ton), in +which the ``from,to'' pairs are as for the replace\_ function +(see \ref{funreplace}). +Here, however, there is more flexibility than in the replace\_ function: +one may replace (small) numbers, as in {\tt replace(1,last)=(0,1,1,0)}, +which would replace arguments that are zero by one, and arguments that +are one by zero. Some ``generic argument'' objects have been introduced, +given by xarg\_, iarg\_, parg\_ and farg\_, which match symbols, indices, +vectors and functions respectively. +These allow one to use the replaced argument in a non-trivial expression. +For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_3) +\begin{verbatim} + Symbol a; + Vector p; + CFunction f1,f2; + Local test = f1(0,1) + f2(2,a) + f2(2,p); + Transform f1 replace(1,last)=(0,1,1,0); + * This will not affect f2(2,p) because xarg_ does not match vectors: + Transform f2 replace(1,last)=(xarg_,2*xarg_+1); + Print; + .end + + test = + f1(1,0) + f2(5,1 + 2*a) + f2(5,p); +\end{verbatim} + + +\leftvitem{3.2cm}{\bf encode\index{transform!encode}\index{encode}} +\rightvitem{13cm}{encode(r1,r2):base=n will interpret the arguments as +the digits in a base-n number system, and replace the digits with a +single argument containing the number in base 10. The base and resulting +number must fit within a single \FORM{} word, and the input digits +must be less than the specified base. For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_4) +\begin{verbatim} + CFunction f2,f3; + Local test = f2(1,1,0,1) + f3(1,1,0,1); + Transform f2 encode(1,last):base=2; + Transform f3 encode(1,last):base=3; + Print; + .end + + test = + f2(13) + f3(37); +\end{verbatim} + +\leftvitem{3.2cm}{\bf decode\index{transform!decode}\index{decode}} +\rightvitem{13cm}{decode(r1,r2):base=n will do the opposite of encode. +It will take a single argument, the smallest of r1 and r2, and expand +it into digits in a base-n number system. It outputs a number of digits +corresponding to the largest of r1 and r2, which replace the original +argument. If this number is not sufficiently large to convert the +argument, no change is made. If r2 is less than r1, the digits are +produced in reverse order. For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_5) +\begin{verbatim} + CFunction f2,f3,F2,F3; + Local test = f2(13) + f2(100) + f3(37) + F2(13) + F3(37); + Transform f2 decode(1,5):base=2; + Transform f3 decode(1,5):base=3; + Transform F2 decode(5,1):base=2; + Transform F3 decode(5,1):base=3; + Print; + .end + + test = + f2(0,1,1,0,1) + f2(100) + f3(0,1,1,0,1) + F2(1,0,1,1,0) + F3(1,0,1,1,0); +\end{verbatim} + +\leftvitem{3.2cm}{\bf tosumnotation\index{transform!tosumnotation}\index{tosumnotation} \index{transform!implode}\index{implode}} \rightvitem{13cm}{tosumnotation(r1,r2) or implode(r1,r2) realizes an encoding in which zeroes are absorbed as extra values in the first nonzero -argument that is following. This is used when dealing with harmonic sums -and harmonic polylogarithms. An example is that (0,0,1,0,a,0,0,0,-1) (which -is in integral notation) goes into (3,2*a,-4) (which is in sum notation). -Currently only a single symbol is allowed and the numbers should be (small) -integers because otherwise the reverse operation (explode) would generate -too many arguments. Instead of ``tosumnotation'' one may also use the word -``implode'' in accordance with the argimplode statement.} - -\leftvitem{3.2cm}{tointegralnotation\index{transform!tointegralnotation} +argument that follows. This is used when dealing with harmonic sums +and harmonic polylogarithms. This is similar to the {\tt ArgImplode} +statement (see \ref{substaargimplode}), with the difference that here a single +symbol is allowed as an argument which generically represents +/-1. For +example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_6) +\begin{verbatim} + CFunction f; + Symbol a; + Local test = f(0,0,1,0,a,0,0,0,-1); + Transform f implode(1,last); + Print; + .end + + test = + f(3,2*a,-4); +\end{verbatim} + +\leftvitem{3.2cm}{\bf tointegralnotation\index{transform!tointegralnotation} \index{tointegralnotation}\index{transform!explode}\index{explode}} \rightvitem{13cm}{tointegralnotation(r1,r2) or explode(r1,r2) undoes what -implode might have done. Hence each integer with an absolute value $n$ -generates $n-1$ zeroes and leaves something with absolute value one. -Instead of ``tointegralnotation'' one may also use the word -``explode'' in accordance with the argexplode statement.} - -\leftvitem{3.2cm}{permute\index{transform!permute}\index{permute}} -\rightvitem{13cm}{permute(1,3,5)(2,6) will permute the arguments -according to the cycles indicated. The cycles are executed in order and may -overlap. Their number is not restricted. In the above example -f(a1,a2,a3,a4,a5,a6,a7) $\rightarrow$ f(a3,a6,a5,a4,a1,a2,a7). -It is allowed to use \$-variables in the cycles, including \$-variables -that are obtained by matching argument field wildcards.} - -\leftvitem{3.2cm}{reverse\index{transform!reverse}\index{reverse}} +tosumnotation/implode might have done, similar to the {\tt ArgExplode} +statement (see \ref{substaargexplode}). +Hence each integer with an absolute value $n$ +generates $n-1$ zeroes followed by the sign of the original integer. +As for tosumnotation, a single symbol (which generically represents +/-1) +is allowed, possibly multipled by a (small) integral coefficient. +For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_7) +\begin{verbatim} + CFunction f; + Symbol a; + Local test = f(3,2*a,-4); + Transform f explode(1,last); + Print; + .end + + test = + f(0,0,1,0,a,0,0,0,-1); +\end{verbatim} + +\leftvitem{3.2cm}{\bf permute\index{transform!permute}\index{permute}} +\rightvitem{13cm}{permute(n1,...,ni),(m1,...,mj),...~will permute the function +arguments according to the specified cycles. The cycles are executed in the +order in which they are given, and may overlap. There is no restriction on +how many cycles may be provided. Dollar variables may be used to provide the +cycles, including dollar variables containing argument fields obtained from +argument field wildcards. Unlike the other transformations, the keyword +{\tt last} can not be used here. +For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_8) +\begin{verbatim} + CFunction f,cyc; + Symbol a1,...,a7; + Local test = f(a1,a2,a3,a4,a5,a6,a7)*cyc(2,6); + Identify cyc(?a$cyc) = 1; + Transform f permute(1,3,5)($cyc); + ModuleOption local $cyc; + Print; + .end + + test = + f(a3,a6,a5,a4,a1,a2,a7); +\end{verbatim} + +\leftvitem{3.2cm}{\bf reverse\index{transform!reverse}\index{reverse}} \rightvitem{13cm}{reverse(r1,r2) reverses the order of the arguments in -specified range.} +specified range. For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_9) +\begin{verbatim} + CFunction f; + Local test = f(1,...,10); + Transform f reverse(3,7); + Print; + .end -\leftvitem{3.2cm}{dedup\index{transform!dedup}\index{dedup}} -\rightvitem{13cm}{dedup(r1,r2) removes duplicates from the arguments in the range, keeping the first.} + test = + f(1,2,7,6,5,4,3,8,9,10); +\end{verbatim} -\leftvitem{3.2cm}{cycle\index{transform!cycle}\index{cycle}} +\leftvitem{3.2cm}{\bf dedup\index{transform!dedup}\index{dedup}} +\rightvitem{13cm}{dedup(r1,r2) removes duplicates from the arguments in the range, keeping the first. For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_10) +\begin{verbatim} + CFunction f,g; + Function h,i; + Symbol x; + Vector p; + Index mu; + Local test = f(100,g(1),g(2)^2,x,x^2,mu,p,p.p,1/p.p,h*i,i*h); + Identify f(?a) = f(?a,?a); + Transform f dedup(1,last); + Print; + .end + + test = + f(100,g(1),g(2)^2,x,x^2,mu,p,p.p,p.p^-1,h*i,i*h); +\end{verbatim} + +\leftvitem{3.2cm}{\bf cycle\index{transform!cycle}\index{cycle}} \rightvitem{13cm}{cycle(r1,r2)=+/-number will perform a cyclic permutation of the indicated range of arguments. If the number is preceded by a - the cycling is to the left. If there is a plus sign the cycling is to the right. Note that either the plus or the minus sign is mandatory. The number -following the +/- sign is also allowed to be a dollar variable provided it -evaluates to a legal number during execution.} +following the +/- sign is also allowed to be a dollar variable, provided it +evaluates to a legal number during execution. The case cycle(r1,rn)=-1 +is equivalent to permute(r1,...,rn) where r1,...,rn are consecutive integers. +For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_11) +\begin{verbatim} + CFunction f,g,h; + Local test = f(1,...,9) + g(1,...,9) + h(1,...,9); + Transform f cycle(3,7)=-1; + Transform g permute(3,...,7); + Transform h cycle(3,7)=+2; + Print; + .end -\leftvitem{3.2cm}{islyndon\index{transform!islyndon}\index{islyndon}} + test = f(1,2,4,5,6,7,3,8,9) + g(1,2,4,5,6,7,3,8,9) + h(1,2,6,7,3,4,5,8,9); +\end{verbatim} + +\leftvitem{3.2cm}{\bf islyndon\index{transform!islyndon}\index{islyndon}} \rightvitem{13cm}{islyndon(r1,r2)=(yes,no) will test whether the indicated range of arguments forms a Lyndon word\index{Lyndon word} according to the ordering of arguments in \FORM\@. The yes and no arguments are what the main -term will be multiplied by when the range forms a Lyndon word or does not +term will be multiplied by when the range forms a Lyndon word or does not, respectively. Because the definition of a Lyndon word is the unique minimal cyclic permutation of the arguments, and because often we may need the -unique maximal cyclic permutation there are varieties: for the minimum one -may also use islyndon$<$(r1,r2)=(yes,no) or islyndon-(r1,r2)=(yes,no), +unique maximal cyclic permutation, there are varieties: for the minimum one +may also explicitly specify islyndon$<$(r1,r2)=(yes,no) or +islyndon-(r1,r2)=(yes,no), while for the maximum one may use islyndon$>$(r1,r2)=(yes,no) or -islyndon+(r1,r2)=(yes,no).} +islyndon+(r1,r2)=(yes,no). For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_12) +\begin{verbatim} + CFunction f; + Symbol y,n; + Local test = f(0) + f(1) + f(0,1) + f(0,0,1) + f(0,1,1) + + f(0,0) + f(1,0) + f(1,1) + f(1,0,0) + f(0,1,0) + f(1,0,1); + Transform f islyndon(1,last)=(y,n); + Print; + .end -\leftvitem{3.2cm}{tolyndon\index{transform!tolyndon}\index{tolyndon}} + test = + f(0)*y + f(0,0)*n + f(0,0,1)*y + f(0,1)*y + f(0,1,0)*n + f(0,1,1)*y + + f(1)*y + f(1,0)*n + f(1,0,0)*n + f(1,0,1)*n + f(1,1)*n; +\end{verbatim} + +\leftvitem{3.2cm}{\bf tolyndon\index{transform!tolyndon}\index{tolyndon}} \rightvitem{13cm}{tolyndon(r1,r2)=(yes,no) will permute the given range in -a cyclic manner till it is (if possible) a Lyndon word\index{Lyndon word} +a cyclic manner until it is (if possible) a Lyndon word\index{Lyndon word} according to the ordering of arguments in \FORM\@. The yes and no arguments are what the main term will be multiplied by when afterwards the range -forms a Lyndon word or does not respectively. Because the definition of a -Lyndon word is the unique minimal cyclic permutation of the arguments, and -because often we may need the unique maximal cyclic permutation there are -varieties: for the minimum one may also use tolyndon$<$(r1,r2)=(yes,no) or -tolyndon-(r1,r2)=(yes,no), while for the maximum one may use -tolyndon$>$(r1,r2)=(yes,no) or tolyndon+(r1,r2)=(yes,no). If the output is -not a Lyndon word, this will be due to that it is a minimum or maximum that -is not unique.} - -\leftvitem{3.2cm}{addargs\index{transform!addargs}\index{addargs}} +forms a Lyndon word or does not, respectively. As for islyndon, one may +specifically work with minimal or maximal cyclic permutations by specifying +$<$/- or $>$/+ markers, respectively. If the result is not a Lyndon word, +it will be a minimal or maximal cyclic permutation that is not unique. +For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_13) +\begin{verbatim} + CFunction f; + Symbol y,n; + Local test = f(0) + f(1) + f(0,1) + f(0,0,1) + f(0,1,1) + + f(0,0) + f(1,0) + f(1,1) + f(1,0,0) + f(0,1,0) + f(1,0,1); + Transform f tolyndon(1,last)=(y,n); + Print; + .end + + test = + f(0)*y + f(0,0)*n + 3*f(0,0,1)*y + 2*f(0,1)*y + 2*f(0,1,1)*y + f(1)*y + + f(1,1)*n; +\end{verbatim} + +\leftvitem{3.2cm}{\bf addargs\index{transform!addargs}\index{addargs}} \rightvitem{13cm}{addargs(r1,r2) replaces the indicated range of arguments -by their sum. This is effectively the inverse of the SplitArg statement.} +by their sum. This is effectively the inverse of the SplitArg statement +(see \ref{substasplitarg}). For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_14) +\begin{verbatim} + CFunction f; + Symbol x; + Local test = f(,...,); + Transform f addargs(1,last); + Print; + .end -\leftvitem{3.2cm}{mulargs\index{transform!mulargs}\index{mulargs}} + test = + f(x + x^2 + x^3 + x^4 + x^5); +\end{verbatim} + + +\leftvitem{3.2cm}{\bf mulargs\index{transform!mulargs}\index{mulargs}} \rightvitem{13cm}{mulargs(r1,r2) replaces the indicated range of arguments -by their product. This is effectively the inverse of the FactArg statement.} +by their product. This is effectively the inverse of the FactArg statement +(see \ref{substafactarg}). For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_15) +\begin{verbatim} + CFunction f; + Symbol x; + Local test = f(,...,); + Transform f mulargs(1,last); + Print; + .end + + test = + f(x^15); +\end{verbatim} + +\leftvitem{3.2cm}{\bf dropargs\index{transform!dropargs}\index{dropargs}} +\rightvitem{13cm}{dropargs(r1,r2) removes the indicated range of arguments. +For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_16) +\begin{verbatim} + CFunction f,g + Local test = f(1,...,5) + g(1,...,5); + Transform f dropargs(2,4); + Transform g dropargs(1,last); + Print; + .end -\leftvitem{3.2cm}{dropargs\index{transform!dropargs}\index{dropargs}} -\rightvitem{13cm}{dropargs(r1,r2) removes the indicated range of arguments.} + test = + f(1,5) + g; +\end{verbatim} -\leftvitem{3.2cm}{selectargs\index{transform!selectargs}\index{selectargs}} +\leftvitem{3.2cm}{\bf selectargs\index{transform!selectargs}\index{selectargs}} \rightvitem{13cm}{selectargs(r1,r2) removes all arguments with the exception -of the indicated range of arguments.} +of the indicated range of arguments. For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_17) +\begin{verbatim} + CFunction f,g + Local test = f(1,...,5) + g(1,...,5); + Transform f selectargs(2,4); + Transform g selectargs(1,last); + Print; + .end + + test = + f(2,3,4) + g(1,2,3,4); +\end{verbatim} -Some Examples. Assume that we have some Multiple Zeta Values\index{Multiple +As a final example, assume that we have some Multiple Zeta Values\index{Multiple Zeta Value}\index{MZV} (see the papers on harmonic sums\index{harmonic sums}, harmonic polylogarithms\index{harmonic polylogarithm} and the MZV data mine\index{MZV data mine}) in the sum notation, but for calculational -reason we want to use a binary encoding (as used in the MZV programs). We +reasons we would like to use a binary encoding (as used in the MZV programs). We could have % THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS -% WELL! (Sta_Transform_1) +% WELL! (Sta_Transform_2) \begin{verbatim} Symbol x,x1,x2; CF H,H1; @@ -6350,7 +6573,10 @@ \section{transform} F = H(907202); \end{verbatim} -The new version of the same program would be +The same program written using the transform statement is greatly simplified +and runs faster: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Transform_1) \begin{verbatim} Symbol x,x1,x2; CF H,H1; @@ -6365,8 +6591,6 @@ \section{transform} F = H(907202); \end{verbatim} -It should be clear that this is simpler and faster. On a 64-bits computer -it is faster by more than a factor 100. \vspace{10mm} From 03623fe4ff60bfe36040a518b461c3409ac38d3b Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Fri, 20 Mar 2026 11:21:44 +0000 Subject: [PATCH 07/13] doc(manual): add example for tovector, edit totensor --- check/examples.frm | 26 ++++++++++++----- doc/manual/statements.tex | 60 ++++++++++++++++++++++++++------------- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/check/examples.frm b/check/examples.frm index ef88ad25..33149922 100644 --- a/check/examples.frm +++ b/check/examples.frm @@ -930,19 +930,31 @@ assert compile_error?("PopHide statement without corresponding PushHide statemen *--#] Sta_Stuffle_1 : *--#[ Sta_ToTensor_1 : *NOTE: "functions" option is needed. -V p,p1,p2; -F f; -I mu; -T tt,t; -L F = p.p1^2*f(p,p1)*p(mu)*tt(p1,p,p2,p); -totensor functions,p,t; -P; +Vector p,p1,p2; +Function f; +Index mu; +Tensor tt,t; +Local F = p.p1^2*f(p,p1)*p(mu)*tt(p1,p,p2,p); +ToTensor functions, p,t; +Print; .end assert succeeded? assert result("F") =~ expr(" f(N1_?,p1)*tt(p1,N2_?,p2,N3_?)*t(p1,p1,mu,N1_?,N2_?,N3_?) ") *--#] Sta_ToTensor_1 : +*--#[ Sta_ToVector_1 : +Tensor t1,t2; +Vector v1,v2; +Index mu1,mu2,mu3; +Local test = t1(mu1,mu2,mu3) + t2(mu1,mu2,mu3); +ToVector t1,v1; +ToVector v2,t2; +Print; +.end +assert succeeded? +assert result("test") =~ expr("v1(mu1)*v1(mu2)*v1(mu3) + v2(mu1)*v2(mu2)*v2(mu3)") +*--#] Sta_ToVector_1 : *--#[ Sta_Transform_1 : Symbol x,x1,x2; CF H,H1; diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index 64d64748..524d3999 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -6014,44 +6014,49 @@ \section{totensor} \end{tabular} \vspace{4mm} \noindent Looks for multiple\index{totensor} occurrences of the given -vector, either inside dotproducts, contracted with a tensor, as argument of -a function or as a loose vector with an index. In all occurrences in -which the vector has been contracted a dummy index is introduced to make -the contraction apparent. Then all these vectors with their indices are -replaced by the specified tensor with all the indices of these vectors. To -make this clearer: +vector, either inside dotproducts, contracted with a tensor, as an argument of +a function or as a loose vector with an index. In each occurrence in +which the vector has been contracted, a dummy index is introduced to make +the contraction apparent. Then all of these vectors and their indices are +replaced by the specified tensor with all the indices, as in: \begin{eqnarray} p^{\mu_1}p^{\mu_2}p^{\mu_3} & \rightarrow & t^{\mu_1\mu_2\mu_3} \nonumber \end{eqnarray} -and hence +For example: % THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS % WELL! (Sta_ToTensor_1) -% TODO: the functions option needed? \begin{verbatim} - p.p1^2*f(p,p1)*p(mu)*tt(p1,p,p2,p) + Vector p,p1,p2; + Function f; + Index mu; + Tensor tt,t; + Local F = p.p1^2 * f(p,p1) * p(mu) * tt(p1,p,p2,p); + ToTensor functions, p,t; + Print; + .end + + F = + f(N1_?,p1)*tt(p1,N2_?,p2,N3_?)*t(p1,p1,mu,N1_?,N2_?,N3_?); \end{verbatim} -gives after \verb:totensor p,t;: -\begin{verbatim} - f(N1_?,p1)*tt(p1,N2_?,p2,N3_?)*t(p1,p1,mu,N1_?,N2_?,N3_?) -\end{verbatim}\vspace{4mm} +\vspace{4mm} \noindent The options are \leftvitem{3.5cm}{nosquare\index{totensor!nosquare}} -\rightvitem{13cm}{Dotproducts with twice the specified vector (square of -the vector) are not taken into account.} +\rightvitem{13cm}{Dotproducts with twice the specified vector (the square of +the vector) are not considered.} \leftvitem{3.5cm}{functions\index{totensor!functions}} \rightvitem{13cm}{Vectors that are arguments of regular functions will also -be considered. By default this is not done.} +be considered. By default, these are not considered.} \leftvitem{3.5cm}{!vector\index{totensor!"!vector}} \rightvitem{13cm}{Dotproducts involving the specified vector are not -treated.} +considered.} \leftvitem{3.5cm}{!set\index{totensor!"!set}} \rightvitem{13cm}{The set should be a set of vectors. All dotproducts -involving a vector of the set are not treated.}\vspace{10mm} +involving a vector in the set are not considered.}\vspace{10mm} %--#] totensor : %--#[ tovector : @@ -6071,7 +6076,24 @@ \section{tovector} with one of the indices of the tensor as in: \begin{eqnarray} t^{\mu_1\mu_2\mu_3} & \rightarrow & p^{\mu_1}p^{\mu_2}p^{\mu_3} \nonumber -\end{eqnarray}\vspace{10mm} +\end{eqnarray} +For example: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_ToVector_1) +\begin{verbatim} + Tensor t1,t2; + Vector v1,v2; + Index mu1,mu2,mu3; + Local test = t1(mu1,mu2,mu3) + t2(mu1,mu2,mu3); + ToVector t1,v1; + ToVector v2,t2; + Print; + .end + + test = + v1(mu1)*v1(mu2)*v1(mu3) + v2(mu1)*v2(mu2)*v2(mu3); +\end{verbatim} +\vspace{10mm} %--#] tovector : %--#[ trace4 : From 392f7513603a6d5b631cdc724fbf63a2f36e2840 Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Fri, 20 Mar 2026 11:54:58 +0000 Subject: [PATCH 08/13] doc(manual): add simple example of term environment --- check/examples.frm | 12 +++++++++++ doc/manual/statements.tex | 45 ++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/check/examples.frm b/check/examples.frm index 33149922..9bf88ad6 100644 --- a/check/examples.frm +++ b/check/examples.frm @@ -928,6 +928,18 @@ assert compile_error?("PopHide statement without corresponding PushHide statemen EOF ) *--#] Sta_Stuffle_1 : +*--#[ Sta_Term_1 : +CFunction f; +Symbol x; +Local test = f(10); +Term; + Repeat Identify f(x?{>1}) = f(x-1) + f(x-2); +EndTerm; +Print; +.end +assert succeeded? +assert result("test") =~ expr("34*f(0) + 55*f(1)") +*--#] Sta_Term_1 : *--#[ Sta_ToTensor_1 : *NOTE: "functions" option is needed. Vector p,p1,p2; diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index 524d3999..56a1541b 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -5877,18 +5877,39 @@ \section{term} \\ See also & endterm (\ref{substaendterm}), sort (\ref{substasort}) \end{tabular} \vspace{4mm} -\noindent Begins the term\index{term} environment\index{environment!term}. -This environment is terminated with the endterm\index{endterm} statement -(see \ref{substaendterm}). The action is that temporarily the current term -is seen as a little expression by itself. The statements inside the -environment are applied to it and one can even sort the results with the -sort\index{sort} statement (see \ref{substasort}) which should not be -confused with the .sort\index{.sort} instruction that terminates a module. -Inside the term environment one can have only executable statements and -possibly term-wise print statements (see \ref{substaprint}). When the end -of the term environment is reached, the results are sorted (as would be -done with an expression at the end of a module) and execution continues -with the resulting terms. This environment can be nested\index{nested}. +\noindent This statement begins a term\index{term} environment +\index{environment!term}, which is terminated with the endterm\index{endterm} +statement (see \ref{substaendterm}). It causes the current term to be processed +as if it were a small expression; the statements inside the environment are +applied to it and one can sort the results with the sort\index{sort} +statement (see \ref{substasort}) (not to be confused with the .sort +\index{.sort} instruction, which terminates a module). +Inside the term environment, one may only use executable statements or +term-wise print statements (see \ref{substaprint}). When the end of the +term environment is reached, the resulting terms are sorted and then the +module execution proceeds with the resulting terms. This environment can +be nested\index{nested}. For example: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Term_1) +\begin{verbatim} + CFunction f; + Symbol x; + Local test = f(10); + Term; + Repeat Identify f(x?{>1}) = f(x-1) + f(x-2); + EndTerm; + Print; + .end + +Time = 0.00 sec Generated terms = 2 + test Terms in output = 2 + Bytes used = 64 + + test = + 34*f(0) + 55*f(1); +\end{verbatim} +Here, one can see in the sorting statistics that only 2 terms are generated +at the lowest level, rather than the full $34+55=89$. \vspace{10mm} %--#] term : From e71b7a60e2430860a459cd09a95b8dcc6777aa82 Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Fri, 20 Mar 2026 12:08:26 +0000 Subject: [PATCH 09/13] doc(manual): update descriptions of tensors/ctensors/ntensors --- doc/manual/statements.tex | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index 56a1541b..c180048c 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -841,8 +841,11 @@ \section{ctensors} \end{tabular} \vspace{4mm} \noindent This statement declares commuting\index{commuting} -tensors\index{tensor!commuting}. It is equal to the tensor statement (see +tensors\index{tensor!commuting}. It is equivalent to the tensor statement (see \ref{substatensors}) which has the commuting property as its default. + +\noindent The options that exist for properties of tensors are the same as +those for functions (see \ref{substafunctions}). \vspace{10mm} %--#] ctensors : @@ -3613,9 +3616,9 @@ \section{ntensors} \end{tabular} \vspace{4mm} \noindent This statement\index{ntensor} declares -noncommuting\index{noncommuting} tensors\index{tensor!noncommuting}. For -the rest it is equal to the tensor\index{tensor} statement (see -\ref{substatensors}) which has the commuting property as its default. +noncommuting\index{noncommuting} tensors\index{tensor!noncommuting}. +Note that it is not equivalent to the tensors statement (see \ref{substatensors}) +which has the commuting property as its default. \noindent The options that exist for properties of tensors are the same as those for functions (see \ref{substafunctions}). \vspace{10mm} @@ -5861,6 +5864,9 @@ \section{tensors} noncommuting\index{noncommuting}. The tensor statement declares a tensor to be commuting. In order to declare a tensor to be noncommuting one should use the ntensor\index{ntensor} statement (see \ref{substantensors}). +Thus `tensor' is equivalent to `ctensor'; note that this differs from the +convention of functions, where `function' is equivalent to `nfunction' +and not to `cfunction'. \noindent The options that exist for properties of tensors are the same as those for functions (see \ref{substafunctions}). \vspace{10mm} From 1fb85987c3f780f49e2bb9b027f887d586f0040a Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Fri, 20 Mar 2026 14:46:43 +0000 Subject: [PATCH 10/13] doc(manual): add examples of the sum statement --- check/examples.frm | 36 ++++++++++++++++++ doc/manual/statements.tex | 79 +++++++++++++++++++++++++++++++++------ 2 files changed, 103 insertions(+), 12 deletions(-) diff --git a/check/examples.frm b/check/examples.frm index 9bf88ad6..0c60888b 100644 --- a/check/examples.frm +++ b/check/examples.frm @@ -928,6 +928,42 @@ assert compile_error?("PopHide statement without corresponding PushHide statemen EOF ) *--#] Sta_Stuffle_1 : +*--#[ Sta_Sum_1 : +CFunction f; +Index mu,nu; +Local test1 = f(mu,mu); +Local test2 = f(mu,nu); +Local test3 = f(mu,nu)*f(mu,nu); +Sum mu,0,1,2, nu,0,1,2; +Print; +.end +assert succeeded? +assert result("test1") =~ expr("f(0,0) + f(1,1) + f(2,2)") +assert result("test2") =~ expr("f(0,0) + f(0,1) + f(0,2) + f(1,0) + f(1,1) + f(1,2) + f(2,0) + f(2,1) + f(2,2)") +assert result("test3") =~ expr("f(0,0)^2 + f(0,1)^2 + f(0,2)^2 + f(1,0)^2 + f(1,1)^2 + f(1,2)^2 + f(2,0)^2 + f(2,1)^2 + f(2,2)^2") +*--#] Sta_Sum_1 : +*--#[ Sta_Sum_2 : +CFunction f,g; +Index mu,nu; +Local test1 = f(mu,nu)*g(mu,nu); +Local test2 = f(N2_?,N1_?)*g(N2_?,N1_?); +Sum mu,nu; +Print; +.end +assert succeeded? +assert result("test1") =~ expr("f(N1_?,N2_?)*g(N1_?,N2_?)") +assert result("test2") =~ expr("f(N1_?,N2_?)*g(N1_?,N2_?)") +*--#] Sta_Sum_2 : +*--#[ Sta_Sum_3 : +CFunction f,g; +Index mu,nu; +Local test = f(mu,nu)*g(mu,nu); +Sum mu, nu,0,1,2; +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(N1_?,0)*g(N1_?,0) + f(N1_?,1)*g(N1_?,1) + f(N1_?,2)*g(N1_?,2)") +*--#] Sta_Sum_3 : *--#[ Sta_Term_1 : CFunction f; Symbol x; diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index c180048c..a720324d 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -5495,27 +5495,82 @@ \section{sum} \\ See also & renumber (\ref{substarenumber}) \end{tabular}\vspace{4mm} -\noindent The given indices will be summed\index{sum} over. There are two -varieties. In the first the index is followed by a sequence of nonnegative -short integers. In that case the summation means that for each of the -integers a new instance of the term is created in which the index is -replaced by that integer. In the second variety the index is either the -last object in the statement or followed by another index. In that case the +\noindent The specified list of indices will be summed\index{sum} over. There are two +varieties: in the first, an index should be followed by a sequence of non-negative +short integers. In this case, the summation means that for each of the +integers, a new instance of the term is created in which the index is +replaced by that integer. For example: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Sum_1) +\begin{verbatim} + CFunction f; + Index mu,nu; + Local test1 = f(mu,mu); + Local test2 = f(mu,nu); + Local test3 = f(mu,nu)*f(mu,nu); + Sum mu,0,1,2, nu,0,1,2; + Print; + .end + + test1 = + f(0,0) + f(1,1) + f(2,2); + + test2 = + f(0,0) + f(0,1) + f(0,2) + f(1,0) + f(1,1) + f(1,2) + f(2,0) + f(2,1) + + f(2,2); + + test3 = + f(0,0)^2 + f(0,1)^2 + f(0,2)^2 + f(1,0)^2 + f(1,1)^2 + f(1,2)^2 + + f(2,0)^2 + f(2,1)^2 + f(2,2)^2; +\end{verbatim} + +In the second variety the index should be either the +last object in the statement or followed by another index. In this case the index is replaced by an internal dummy\index{dummy} index\index{index!dummy} of the type \verb:N1_?: (or with another number -instead of the 1). Such indices have the current +instead of `1'). Such indices have the current default\index{default dimension} dimension\index{dimension!default} and can -be renamed at will by \FORM\ to bring terms into standard notation. For +be renamed at will by \FORM\ in order to bring terms into standard notation. For example: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Sum_2) \begin{verbatim} - f(N2_?,N1_?)*g(N2_?,N1_?) + CFunction f,g; + Index mu,nu; + Local test1 = f(mu,nu)*g(mu,nu); + Local test2 = f(N2_?,N1_?)*g(N2_?,N1_?); + Sum mu,nu; + Print; + .end + + test1 = + f(N1_?,N2_?)*g(N1_?,N2_?); + + test2 = + f(N1_?,N2_?)*g(N1_?,N2_?); \end{verbatim} -will be changed into +Note that in the `test2' expression here, \FORM\ has re-arranged the dummy +indices into the canonical form. + +The two types of sum statement may be mixed, as in: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Sum_3) \begin{verbatim} - f(N1_?,N2_?)*g(N1_?,N2_?). + CFunction f,g; + Index mu,nu; + Local test = f(mu,nu)*g(mu,nu); + Sum mu, nu,0,1,2; + Print; + .end + + test = + f(N1_?,0)*g(N1_?,0) + f(N1_?,1)*g(N1_?,1) + f(N1_?,2)*g(N1_?,2); \end{verbatim} + The user can use these dummy indices in the left hand side of -id\index{id} statements. +identify\index{id}\index{identify} statements, but should recognise that they +do not represent wildcards for the pattern matcher. Attempting to use them as +wildcards as in `{\tt N1\_??}' is also not valid. \vspace{10mm} %--#] sum : From 5411528786d8d0d6796228ea5b1b31a1c7a80401 Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Fri, 20 Mar 2026 16:24:06 +0000 Subject: [PATCH 11/13] doc(manual): add examples for splitarg, splitfirstarg, splitlastarg --- check/examples.frm | 52 +++++++++++++++ doc/manual/statements.tex | 136 ++++++++++++++++++++++++++------------ 2 files changed, 144 insertions(+), 44 deletions(-) diff --git a/check/examples.frm b/check/examples.frm index 0c60888b..5cc5e699 100644 --- a/check/examples.frm +++ b/check/examples.frm @@ -902,6 +902,58 @@ assert compile_error?("PopHide statement without corresponding PushHide statemen assert result("F1") =~ expr("f(a,b,c,d)+f(a,c,b,d)+f(a,c,d,b)+f(c,a,b,d)+f(c,a,d,b)+f(c,d,a,b)") assert result("F2") =~ expr("g(a,b,c,d)+g(a,c,b,d)+g(a,c,d,b)+g(c,a,b,d)+g(c,a,d,b)+g(c,d,a,b)") *--#] Sta_Shuffle_1 : +*--#[ Sta_Splitarg_1 : +CFunction f; +Symbol a,b,c,d; +Local test = f(a+b-5*c*d); +SplitArg f; +Print; +.end +assert succeeded? +assert result("test") =~ expr("f( - 5*c*d,b,a)") +*--#] Sta_Splitarg_1 : +*--#[ Sta_Splitarg_2 : +CFunction f,g,h; +Symbol x,y; +Local test = f(2 + 3*x + 4*x^2) + g(2 + 3*x + 4*x^2) + h(x + x*y + x^2*y); +SplitArg (x) f; +SplitArg (x^2) g; +SplitArg (x*y) h; +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(2 + 4*x^2,3*x) + g(2 + 3*x,4*x^2) + h(x + x^2*y,x*y)") +*--#] Sta_Splitarg_2 : +*--#[ Sta_Splitarg_3 : +CFunction f; +Symbol x,y; +Local test = f(2 + 3*x + 4*x^2 + 5*x*y + 6*y); +SplitArg ((x)) f; +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(2 + 6*y,3*x,5*x*y,4*x^2)") +*--#] Sta_Splitarg_3 : +*--#[ Sta_Splitfirstarg_1 : +CFunction f; +Symbol x; +Local test = f(1 + x + x^2 + x^3); +SplitFirstArg f; +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(x + x^2 + x^3,1)") +*--#] Sta_Splitfirstarg_1 : +*--#[ Sta_Splitlastarg_1 : +CFunction f; +Symbol x; +Local test = f(1 + x + x^2 + x^3); +SplitLastArg f; +Print; +.end +assert succeeded? +assert result("test") =~ expr("f(1 + x + x^2,x^3)") +*--#] Sta_Splitlastarg_1 : *--#[ Sta_Stuffle_1 : CF S,R; Symbols N,n; diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index a720324d..4575b1f7 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -5300,35 +5300,71 @@ \section{splitarg} factarg (\ref{substafactarg}) \end{tabular}\vspace{4mm} -\noindent Takes\index{splitarg} the indicated argument\index{argument} of a +\noindent Takes\index{splitarg} the indicated arguments\index{argument} of a function and if such an argument is a subexpression that consists on more -than one term, all terms become single arguments of the function as in +than one term, each term becomes a separate argument of the function. For +example: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Splitarg_1) \begin{verbatim} - f(a+b-5*c*d) --> f(a,b,-5*c*d) + CFunction f; + Symbol a,b,c,d; + Local test = f(a + b - 5*c*d); + SplitArg f; + Print; + .end + + test = + f( - 5*c*d,b,a); \end{verbatim} -The way arguments are indicated is rather similar to the way this is done -in the argument\index{argument statement} statement (see -\ref{substaargument}). One can however indicate only a single group of -functions in one statement. Additionally there are other options. All -options are in the order that they should be specified: +The format for the argument specifications is similar to the argument statement +\index{argument} (see \ref{substaargument}), except here only one function or +set of functions may be given. The splitarg action is only applied to the +specified arguments of the given functions. If no (sets of) functions or no +arguments are specified, the action is applied to all functions (including +built-in functions) or all arguments. +\noindent In addition, the following options modify the behaviour of splitarg: + +\vspace{3mm} \leftvitem{5cm}{(term)} \rightvitem{11cm}{Only terms that are a numerical multiple of the given -term are split off. The terms that are split off will trail the remainder.} +term are split off. The terms that are split off will trail the remainder. +For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Splitarg_2) +\begin{verbatim} + CFunction f,g; + Symbol x; + Local test = f(2 + 3*x + 4*x^2) + g(2 + 3*x + 4*x^2) + h(x + x*y + x^2*y); + SplitArg (x) f; + SplitArg (x^2) g; + SplitArg (x*y) h; + Print; + .end + test = + f(2 + 4*x^2,3*x) + g(2 + 3*x,4*x^2) + h(x + x^2*y,x*y); +\end{verbatim} + +\vspace{3mm} \leftvitem{5cm}{((term))} \rightvitem{11cm}{Only terms that contain the given term will be split off. -The terms that are split off will trail the remainder.} +The terms that are split off will trail the remainder. For example:} +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Splitarg_3) +\begin{verbatim} + CFunction f; + Symbol x,y; + Local test = f(2 + 3*x + 4*x^2 + 5*x*y + 6*y); + SplitArg ((x)) f; + Print; + .end -\noindent The statement is terminated with a sequence of functions or -sets\index{set} of functions. The splitting action will apply only to the -specified functions or to members of the set(s). If no functions or sets of -functions are specified all functions will be treated, including the built -in functions. - -\noindent The argument specifications consist of a list of numbers, -indicating the arguments that should be treated. If no arguments are -specified, all arguments will be treated. \vspace{10mm} + test = + f(2 + 6*y,3*x,5*x*y,4*x^2); +\end{verbatim} +\vspace{10mm} %--#] splitarg : %--#[ splitfirstarg : @@ -5344,20 +5380,26 @@ \section{splitfirstarg} splitlastarg (\ref{substasplitlastarg}) \end{tabular}\vspace{4mm} -\noindent A little\index{splitfirstarg} bit like the +\noindent Similar to \index{splitfirstarg} the SplitArg\index{splitarg} statement (see \ref{substasplitarg}). Splits the -given argument(s) into its first term and a remainder. Then replaces the -argument by the remainder\index{remainder}, followed by the first term. - -\noindent The statement is terminated with a sequence of functions or sets -of functions. The splitting action will apply only to the specified -functions or to members of the set(s). If no functions or sets\index{set} -of functions are specified all functions will be treated, including the -built in functions. - -\noindent The argument specifications consist of a list of numbers, -indicating the arguments that should be treated. If no arguments are -specified all arguments will be treated. \vspace{10mm} +given argument(s) into their first term and a remainder. The arguments are +replaced by the remainder\index{remainder}, followed by the first term. The +argument specifications are as for SplitArg. For example: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Splitfirstarg_1) +\begin{verbatim} + CFunction f; + Symbol x; + Local test = f(1 + x + x^2 + x^3); + SplitFirstArg f; + Print; + .end + + test = + f(x + x^2 + x^3,1); +\end{verbatim} + +\vspace{10mm} %--#] splitfirstarg : %--#[ splitlastarg : @@ -5373,20 +5415,26 @@ \section{splitlastarg} splitfirstarg (\ref{substasplitfirstarg}) \end{tabular}\vspace{4mm} -\noindent A little\index{splitlastarg} bit like the +\noindent Similar to \index{splitlastarg} the SplitArg\index{splitarg} statement (see \ref{substasplitarg}). Splits the -given argument(s) into its last term and a remainder. Then replaces the -argument by the remainder, followed by the last term. - -\noindent The statement is terminated with a sequence of functions or sets -of functions. The splitting action will apply only to the specified -functions or to members of the set(s). If no functions or sets\index{set} -of functions are specified all functions will be treated, including the -built in functions. +given argument(s) into their last term and a remainder. The arguments are +replaced by the remainder\index{remainder}, followed by the last term. The +argument specifications are as for SplitArg. For example: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Splitlastarg_1) +\begin{verbatim} + CFunction f; + Symbol x; + Local test = f(1 + x + x^2 + x^3); + SplitLastArg f; + Print; + .end + + test = + f(1 + x + x^2,x^3); +\end{verbatim} -\noindent The argument specifications consist of a list of numbers, -indicating the arguments that should be treated. If no arguments are -specified all arguments will be treated. \vspace{10mm} +\vspace{10mm} %--#] splitlastarg : %--#[ strictrounding : From 2aa4053bb1fc74d88d9b613378099a189d5c4d1a Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Fri, 20 Mar 2026 16:40:38 +0000 Subject: [PATCH 12/13] doc(manual): add example for setexitflag --- check/examples.frm | 21 +++++++++++++++++++++ doc/manual/statements.tex | 28 +++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/check/examples.frm b/check/examples.frm index 5cc5e699..00f6da0b 100644 --- a/check/examples.frm +++ b/check/examples.frm @@ -902,6 +902,27 @@ assert compile_error?("PopHide statement without corresponding PushHide statemen assert result("F1") =~ expr("f(a,b,c,d)+f(a,c,b,d)+f(a,c,d,b)+f(c,a,b,d)+f(c,a,d,b)+f(c,d,a,b)") assert result("F2") =~ expr("g(a,b,c,d)+g(a,c,b,d)+g(a,c,d,b)+g(c,a,b,d)+g(c,a,d,b)+g(c,d,a,b)") *--#] Sta_Shuffle_1 : +*--#[ Sta_Setexitflag_1 : +CFunction f; +Symbol x; +Local test = +...+; +Identify f(x?even_) = x; +If (Match(f(x?))); + Print "Error: unreplaced f: %t"; + SetExitFlag; +EndIf; +.sort +Print; +.end +# For now, this hangs in ParFORM and is not valgrind clean for tform +#pend_if mpi? || ( valgrind? && threaded? ) +assert succeeded? +assert stdout =~ exact_pattern(" +Error: unreplaced f: + f(1) +Error: unreplaced f: + f(3) +Error: unreplaced f: + f(5) +") +*--#] Sta_Setexitflag_1 : *--#[ Sta_Splitarg_1 : CFunction f; Symbol a,b,c,d; diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index 4575b1f7..38e47599 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -5168,7 +5168,33 @@ \section{setexitflag} \noindent Causes\index{setexitflag} termination\index{termination} of the program after execution\index{execution} of the current module has -finished. \vspace{10mm} +finished. For example: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_Setexitflag_1) +\begin{verbatim} + CFunction f; + Symbol x; + Local test = +...+; + Identify f(x?even_) = x; + If (Match(f(x?))); + Print "Error: unreplaced f: %t"; + SetExitFlag; + EndIf; + .sort +Error: unreplaced f: + f(1) +Error: unreplaced f: + f(3) +Error: unreplaced f: + f(5) + Print; + .end +\end{verbatim} +Here, suppose we would like to replace all cfunctions f with some pre-computed +results. It might be useful to terminate the program if any f remains +unreplaced, and print a list of all of them. If the exit statement +(see \ref{substaexit}) were used instead, only the first remaining f is printed +and the program would terminate immediately. The setexitflag statement is more +useful in such a scenario. + +\vspace{10mm} %--#] setexitflag : %--#[ shuffle : From b8d26519ad5b5933ecd5fc961fd631a3685586ce Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Fri, 20 Mar 2026 16:45:33 +0000 Subject: [PATCH 13/13] doc(manual): refer to Sets section for sets --- doc/manual/statements.tex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index 38e47599..c20ff916 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -5127,7 +5127,8 @@ \section{set} \noindent \begin{tabular}{ll} Type & Declaration statement\\ -Syntax & set {\tt<}set to be declared{\tt>}[(option)]:{\tt<}element{\tt>} [{\tt<}more elements{\tt>}]; +Syntax & set {\tt<}set to be declared{\tt>}[(option)]:{\tt<}element{\tt>} [{\tt<}more elements{\tt>}];\\ +See also & Sets (\ref{sect-sets}) \end{tabular} \vspace{4mm} \noindent Declares a single set\index{set} and specifies its