gfun[rectoproc] - convert a recurrence into a function

Calling Sequence

rectoproc(eqns,u(n), <remember>, <list>,<params=[a,b,...]>,<options>)

Parameters

eqns - single equation or set of equations

u,n - name and index of recurrence

remember - (optional)

list - (optional)

params = [a,b,...] - (optional) names a,b,... for the arguments

evalfun = fname - (optional) a function applied at each iteration

preargs=[c,d,...] - (optional) first arguments to this function

postargs=[e,f,...] - (optional) last arguments to this function

evalinicond - (optional)

whilecond=boolean_expr - (optional) while condition

errorcond=boolean_expr - (optional) error condition

index - (optional)

rhs=expression - (optional)

copyright=string - (optional) copyright string to be added to the options

extralocal=[g,h,...] - (optional) names for extra local variables

nosymbolsubs - (optional)

plain - (optional)

Description

Examples

Fibonacci numbers

We can create different types of programs to generate Fibonacci numbers that are tailored to certain memory or time requirements.

The most obvious procedure is recursive and "remembers" values that are already computed.

> fiborec:={f(i)=f(i-1)+f(i-2),f(0)=1,f(1)=1};
\[\{f \! \left(0\right) = 1, f \! \left(1\right) = 1, f \! \left(i \right) = f \! \left(i -1\right)+f \! \left(i -2\right)\}\]
> with(gfun):
fib1:=rectoproc(fiborec,f(i),remember);
\[\textbf{proc} (n::nonnegint) \\ \textbf{option} \,remember; \\ \mapleIndent{1} \mathit{\textbf{procname}} (-2 + n::nonnegint) + \mathit{\textbf{procname}} (n::nonnegint + -1)\\ \textbf{end\ proc};\]
> fib1(100);
\[573147844013817084101\]

To create a program which computes and lists the first n terms of the recurrence, we use the list option.

> fib2:=rectoproc(fiborec,f(i),list);
\[\textbf{proc} (n::nonnegint) \\ \textbf{local} \,i1,\,loc; \\ \mapleIndent{1} loc[0]\,\coloneqq \,1;\\ \mapleIndent{1} loc[1]\,\coloneqq \,1;\\ \mapleIndent{1} \textbf{for} \,i1 \,\textbf{to} \,n::nonnegint + -1 \,\textbf{do}\\ \mapleIndent{2} loc[i1 + 1]\,\coloneqq \,loc[i1 + -1] + loc[i1]\\ \mapleIndent{1} \textbf{end\ do};;\\ \mapleIndent{1} [\mathit{seq} (loc[i1],\,i1 \, = \, 0..n::nonnegint)]\\ \textbf{end\ proc};\]
> fib2(10);
\[[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]\]

To create a program that is more space conscious we avoid the remember option. In this case the program exploits the fact that the recurrence has constant coefficients for extra efficiency.

> fib3:=rectoproc(fiborec,f(i));
\[\textbf{proc} (n::nonnegint) \\ \textbf{local} \,i1,\,loc0,\,loc1,\,loc2,\,tmp2,\,tmp1,\,i2; \\ \mapleIndent{1} \textbf{if} \,n::nonnegint&le44 \, \textbf{then} \\ \mapleIndent{2} \textbf{if} \,n::nonnegint \, = \, 0 \, \textbf{then} \\ \mapleIndent{3} 1\\ \mapleIndent{2} \textbf{elif} \,n::nonnegint \, = \, 1 \, \textbf{then} \\ \mapleIndent{3} 1\\ \mapleIndent{2} \textbf{else}\\ \mapleIndent{3} loc0\,\coloneqq \,1;\\ \mapleIndent{3} loc1\,\coloneqq \,1;\\ \mapleIndent{3} \textbf{for} \,i1 \,\textbf{to} \,n::nonnegint + -1 \,\textbf{do}\\ \mapleIndent{4} loc2\,\coloneqq \,loc0 + loc1;\\ \mapleIndent{4} loc0\,\coloneqq \,loc1;\\ \mapleIndent{4} loc1\,\coloneqq \,loc2\\ \mapleIndent{3} \textbf{end\ do};;\\ \mapleIndent{3} loc1\\ \mapleIndent{2} \textbf{end\ if}; \\ \mapleIndent{1} \textbf{else}\\ \mapleIndent{2} tmp2\,\coloneqq \,rtable(1..2,\,1..2,\,{1,\,1 \, = \, 1,\,1,\,2 \, = \, 1,\,2,\,1 \, = \, 1},\,datatype \, = \, anything,\,storage \, = \, rectangular,\,order \, = \, Fortran\_order,\,subtype\, =\, Matrix);\\ \mapleIndent{2} tmp1\,\coloneqq \,rtable(1..2,\,{1 \, = \, 1,\,2 \, = \, 1},\,datatype \, = \, anything,\,storage \, = \, rectangular,\,order \, = \, Fortran\_order,\,subtype\, =\, Vector[column]);\\ \mapleIndent{2} i2\,\coloneqq \,\mathit{convert} (n::nonnegint + -1,\,base,\,2);\\ \mapleIndent{2} \textbf{if} \,i2[1] \, = \, 1 \, \textbf{then} \\ \mapleIndent{3} tmp1\,\coloneqq \,rtable(1..2,\,{1 \, = \, 2,\,2 \, = \, 1},\,datatype \, = \, anything,\,storage \, = \, rectangular,\,order \, = \, Fortran\_order,\,subtype\, =\, Vector[column])\\ \mapleIndent{2} \textbf{end\ if}; ;\\ \mapleIndent{2} \textbf{for} \,i1 \,\textbf{in} \,\mathit{subsop} (1 \, = \, ,\,i2) \,\textbf{do}\\ \mapleIndent{3} tmp2\,\coloneqq \,\mathit{LinearAlgebra:-MatrixMatrixMultiply} (tmp2,\,tmp2);\\ \mapleIndent{3} \textbf{if} \,i1 \, = \, 1 \, \textbf{then} \\ \mapleIndent{4} tmp1\,\coloneqq \,\mathit{LinearAlgebra:-MatrixVectorMultiply} (tmp2,\,tmp1)\\ \mapleIndent{3} \textbf{end\ if}; \\ \mapleIndent{2} \textbf{end\ do};;\\ \mapleIndent{2} tmp1[1]\\ \mapleIndent{1} \textbf{end\ if}; \\ \textbf{end\ proc};\]
> fib3(100);
\[573147844013817084101\]
> fib3(1000);
\[70330367711422815821835254877183549770181269836358732742604905087154537118196933579742249494562611733487750449241765991088186363265450223647106012053374121273867339111198139373125598767690091902245245323403501\]

An example of right-hand side: nested procedures

This example shows how terms of nested recurrences can be computed. The first sequence is first converted into a procedure:

> rec_u:={u(n+2)*(n^2+n+1)+u(n+1)*(n-2)+u(n)*n,u(0)=1,u(1)=2};
\[\{u \! \left(n +2\right) \left(n^{2}+n +1\right)+u \! \left(n +1\right) \left(n -2\right)+u \! \left(n \right) n, u \! \left(0\right) = 1, u \! \left(1\right) = 2\}\]
> u_n := rectoproc(rec_u,u(n),remember);
\[\textbf{proc} (n::nonnegint) \\ \textbf{option} \,remember; \\ \mapleIndent{1} (2 \ast \mathit{\textbf{procname}} (-2 + n::nonnegint) + 4 \ast \mathit{\textbf{procname}} (n::nonnegint + -1)-(\mathit{\textbf{procname}} (-2 + n::nonnegint) + \mathit{\textbf{procname}} (n::nonnegint + -1)) \ast n::nonnegint) \ast 3 + (-3 + n::nonnegint) \ast n::nonnegint\hat{~}{-1}\\ \textbf{end\ proc};\]

The second sequence is defined by

> rec_v:=v(n+3)*(n+4)+v(n+1)*(n^2+2*n)=u(n+1)-n*u(n);
\[v \! \left(n +3\right) \left(n +4\right)+v \! \left(n +1\right) \left(n^{2}+2 n \right) = u \! \left(n +1\right)-u \! \left(n \right) n\]
> ini_v:={v(0)=1,v(1)=2,v(2)=3};
\[\{v \! \left(0\right) = 1, v \! \left(1\right) = 2, v \! \left(2\right) = 3\}\]

The procedure computing v(n) is now generated

> v_n:=rectoproc({op(1,rec_v)}union ini_v,v(n),rhs=subs(u=u_n,op(2,rec_v)),list);
\[\textbf{proc} (n::nonnegint) \\ \textbf{local} \,i1,\,loc; \\ \mapleIndent{1} loc[0]\,\coloneqq \,1;\\ \mapleIndent{1} loc[1]\,\coloneqq \,2;\\ \mapleIndent{1} loc[2]\,\coloneqq \,3;\\ \mapleIndent{1} \textbf{for} \,i1 \,\textbf{from} \,2 \,\textbf{to} \,n::nonnegint + -1 \,\textbf{do}\\ \mapleIndent{2} loc[i1 + 1]\,\coloneqq \,(\mathit{u\_n} (i1 + -1)-\mathit{u\_n} (i1 + -2) \ast (i1 + -2)-(3 + (i1 + -3) \ast (i1 + 1)) \ast loc[i1 + -1]) \ast i1 + 2\hat{~}{-1}\\ \mapleIndent{1} \textbf{end\ do};;\\ \mapleIndent{1} [\mathit{seq} (loc[i1],\,i1 \, = \, 0..n::nonnegint)]\\ \textbf{end\ proc};\]

Computation of 10 first terms:

> v_n(9);
\[\left[1, 2, 3, {\frac{1}{2}}, -{\frac{7}{5}}, -{\frac{17}{9}}, {\frac{125}{49}}, {\frac{6803}{1092}}, -{\frac{169567}{17199}}, -{\frac{423697}{14105}}\right]\]

Applying a function at each iteration

We illustrate several ways to compute numerical values of the sequence defined by the following recurrence:

> rec := { u(n+2)*(n+1) + u(n)*(n^2+1),u(0)=sin(1),u(1)=cos(1)};
\[\{u \! \left(n +2\right) \left(n +1\right)+u \! \left(n \right) \left(n^{2}+1\right), u \! \left(0\right) = \sin \! \left(1\right), u \! \left(1\right) = \cos \! \left(1\right)\}\]

If hardware floating point numbers give a sufficient accuracy, then it is best to produce the procedure and then call evalhf on it:

> p:=subsop(4=NULL,rectoproc(rec,u(n),'plain'));
\[\textbf{proc} (n::nonnegint) \\ \textbf{local} \,i1,\,loc0,\,loc1,\,loc2; \\ \mapleIndent{1} \textbf{if} \,n::nonnegint \, = \, 0 \, \textbf{then} \\ \mapleIndent{2} \mathit{sin} (1)\\ \mapleIndent{1} \textbf{elif} \,n::nonnegint \, = \, 1 \, \textbf{then} \\ \mapleIndent{2} \mathit{cos} (1)\\ \mapleIndent{1} \textbf{else}\\ \mapleIndent{2} loc0\,\coloneqq \,\mathit{sin} (1);\\ \mapleIndent{2} loc1\,\coloneqq \,\mathit{cos} (1);\\ \mapleIndent{2} \textbf{for} \,i1 \,\textbf{to} \,n::nonnegint + -1 \,\textbf{do}\\ \mapleIndent{3} loc2\,\coloneqq \,-(5 + (i1 + -3) \ast (i1 + 1)) \ast loc0 \ast i1\hat{~}{-1};\\ \mapleIndent{3} loc0\,\coloneqq \,loc1;\\ \mapleIndent{3} loc1\,\coloneqq \,loc2\\ \mapleIndent{2} \textbf{end\ do};;\\ \mapleIndent{2} loc1\\ \mapleIndent{1} \textbf{end\ if}; \\ \textbf{end\ proc};\]
> evalhf(p(100));
\[{ 5.27739153869639746\times 10^{76}}\]

If more precision is required, then evalf can be applied at each iteration using

> p2:=rectoproc(rec,u(n),evalfun='evalf');
\[\textbf{proc} (n::nonnegint) \\ \textbf{local} \,i1,\,loc0,\,loc1,\,loc2; \\ \mapleIndent{1} \textbf{if} \,n::nonnegint \, = \, 0 \, \textbf{then} \\ \mapleIndent{2} \mathit{evalf} (\mathit{sin} (1))\\ \mapleIndent{1} \textbf{elif} \,n::nonnegint \, = \, 1 \, \textbf{then} \\ \mapleIndent{2} \mathit{evalf} (\mathit{cos} (1))\\ \mapleIndent{1} \textbf{else}\\ \mapleIndent{2} loc0\,\coloneqq \,\mathit{evalf} (\mathit{sin} (1));\\ \mapleIndent{2} loc1\,\coloneqq \,\mathit{evalf} (\mathit{cos} (1));\\ \mapleIndent{2} \textbf{for} \,i1 \,\textbf{to} \,n::nonnegint + -1 \,\textbf{do}\\ \mapleIndent{3} loc2\,\coloneqq \,\mathit{evalf} (-(5 + (i1 + -3) \ast (i1 + 1)) \ast loc0 \ast i1\hat{~}{-1});\\ \mapleIndent{3} loc0\,\coloneqq \,loc1;\\ \mapleIndent{3} loc1\,\coloneqq \,loc2\\ \mapleIndent{2} \textbf{end\ do};;\\ \mapleIndent{2} loc1\\ \mapleIndent{1} \textbf{end\ if}; \\ \textbf{end\ proc};\]
> Digits:=30: p2(100);
\[{ 5.27739153869639769206242956896\times 10^{76}}\]

It is also possible to give the precision as an argument:

> p3 := rectoproc(rec,u(n),evalfun='evalf',params=[d],postargs=[d]);
\[\textbf{proc} (n::nonnegintb1) \\ \textbf{local} \,i1,\,loc0,\,loc1,\,loc2; \\ \mapleIndent{1} \textbf{if} \,n::nonnegint \, = \, 0 \, \textbf{then} \\ \mapleIndent{2} \mathit{evalf} (\mathit{sin} (1),\,b1)\\ \mapleIndent{1} \textbf{elif} \,n::nonnegint \, = \, 1 \, \textbf{then} \\ \mapleIndent{2} \mathit{evalf} (\mathit{cos} (1),\,b1)\\ \mapleIndent{1} \textbf{else}\\ \mapleIndent{2} loc0\,\coloneqq \,\mathit{evalf} (\mathit{sin} (1),\,b1);\\ \mapleIndent{2} loc1\,\coloneqq \,\mathit{evalf} (\mathit{cos} (1),\,b1);\\ \mapleIndent{2} \textbf{for} \,i1 \,\textbf{to} \,n::nonnegint + -1 \,\textbf{do}\\ \mapleIndent{3} loc2\,\coloneqq \,\mathit{evalf} (-(5 + (i1 + -3) \ast (i1 + 1)) \ast loc0 \ast i1\hat{~}{-1},\,b1);\\ \mapleIndent{3} loc0\,\coloneqq \,loc1;\\ \mapleIndent{3} loc1\,\coloneqq \,loc2\\ \mapleIndent{2} \textbf{end\ do};;\\ \mapleIndent{2} loc1\\ \mapleIndent{1} \textbf{end\ if}; \\ \textbf{end\ proc};\]
> p3(100,40);
\[{ 5.277391538696397692062429568990170086821\times 10^{76}}\]

Extra local variables

The option extralocal is useful when the values of some parameters are not known until the procedure is executed. In the example below, the recurrence is provided with generic intial conditions. The values of these initial conditions are computed at execution-time.

> rec := { u(n)*n + u(n+2),u(0)=A,u(1)=B}:
p := rectoproc(rec,u(n),params=[p],extralocal=[A='f'(p),B='g'(A,p)]);
Result unavailable; run without --skip-maple.

See Also

gfun, remember, nth_term, diffeqtoproc