我正在尝试通过Maple中的“ for循环”建立一个递归关系。假设我们有两个序列M[i](x)
和N[i](x)
,其中N[0](x)=x^2
和M[i](x)=N[i-1](x)+1
和N[i](x)=M[i](x)+2
。所以我尝试了这段代码:
N[0] := proc (x) options operator, arrow; x^2 end proc;
for i to 3 do M[i] := proc (x) options operator, arrow; N[i-1](x)+1 end proc; N[i] := proc (x) options operator, arrow; M[i](x)+2 end proc end do;
但是它没有给出正确的答案(例如N[1](x)
必须为x^2+3
)。顺便说一下,由于某些原因,我必须通过映射x
来定义函数。反正有修改此代码吗?
答案 0 :(得分:1)
rsolve
命令可以轻松处理此示例,只是它需要自变量i
的功能。
您所拥有的是包含x
(不涉及递归)功能的方程,其中i
仅作为索引出现。
您可以将方程式重新编写为i
的函数,调用rsolve
,然后重新代入原始函数。
只需手动输入以下内容即可构建下面的替换集S
。但是为了好玩,我以编程方式构造了它。
restart;
R1 := N[0](x) = x^2;
2
R1 := N[0](x) = x
R2 := M[i](x) = N[i-1](x)+1;
R2 := M[i](x) = N[i - 1](x) + 1
R3 := N[i](x) = M[i](x)+2;
R3 := N[i](x) = M[i](x) + 2
S := map( u->u=op([0,0],u)(op([0,1],u)),
indets({R1,R2,R3},
specfunc(anything,{N,M})) );
S := {M[i](x) = M(i), N[0](x) = N(0), N[i](x) = N(i),
N[i - 1](x) = N(i - 1)}
newEqs := eval( {R1,R2,R3}, S );
2
newEqs := { M(i) = N(i - 1) + 1, N(0) = x , N(i) = M(i) + 2 }
newV := eval( {N[i](x),M[i](x)}, S );
newV := {M(i), N(i)}
tempans := rsolve( newEqs, newV );
2 2
tempans := { M(i) = x + 3 i - 2, N(i) = x + 3 i }
ans := eval( tempans, map(rhs=lhs,S) );
2 2
ans := { M[i](x) = x + 3 i - 2, N[i](x) = x + 3 i }
已经为M[i](x)
和N[i](x)
的一般形式构造了方程,您可以在i
的特定校准下评估其中任何一个。您还可以根据这些结果创建过程,然后进行分配。例如,
for k from 1 to 3 do
N[k] := unapply(subs(i=k,eval(N[i](x),ans)), [x]);
end do:
N[3](11);
130
创建所有这些运算符(单独过程)似乎效率低下。为什么不只为N
创建一个,而为M
创建一个,为i
和x
接受两个参数呢?
Nfunc := unapply(eval(N[i](x),ans), [i,x]);
2
Nfunc := (i, x) -> x + 3 i
Nfunc(3,x);
2
x + 9
Nfunc(3, 11);
130
[编辑]我应该告诉你为什么你最初的尝试失败了。
当您尝试原始尝试时,两个过程正文中出现的i
不会简化为循环索引i
的当前值。然后,当您随后尝试并运行任何已构造的过程时,它将只获取全局i
仍然具有的任何值。每当您随后调用N[2]
时,名称i
的索引值与N[2](x)
的分配过程之间就没有链接。
restart;
N[0] := x -> x^2:
for i to 2 do
M[i] := x -> N[i-1](x)+1;
N[i] := x -> M[i](x)+2;
end do;
M[1] := x -> N[i - 1](x) + 1
N[1] := x -> M[i](x) + 2
M[2] := x -> N[i - 1](x) + 1
N[2] := x -> M[i](x) + 2
N[2](11); # why this result, you might asK
M[3](11) + 2
i; # still the value coming out of that do-loop
3
unassign('i');
N[2](11); # no relation between the 2 and the `i`
M[i](11) + 2
您可以通过构造一个递归过程序列来修复原始文件。以下是“作品”。但这在运行时效率极低,因为对N[..]
或M[..]
过程中的任何一个的每次调用都会递归地调用链中的其他过程。整个递归调用集将在每次调用时发生。也就是说,这里的递归发生在每个过程的运行时。
restart;
N[0] := x -> x^2:
for i to 3 do
M[i] := subs(ii=i, x -> N[ii-1](x)+1);
N[i] := subs(ii=i,x -> M[ii](x)+2);
end do;
M[1] := x -> N[0](x) + 1
N[1] := x -> M[1](x) + 2
M[2] := x -> N[1](x) + 1
N[2] := x -> M[2](x) + 2
M[3] := x -> N[2](x) + 1
N[3] := x -> M[3](x) + 2
N[3](11);
130
运行这种方案的整体性能会很差。
更好的方法是利用unapply
命令,使N[i]
和M[i]
(对于明确的i
值)都是一个包含其明确公式的过程。当以以下方式使用unapply
时,我们将递归计算到相应公式的函数调用传递给它。这里,递归仅在每个过程的构建时发生。
restart;
N[0] := x -> x^2:
for i to 3 do
M[i] := unapply( N[i-1](x)+1, x);
N[i] := unapply( M[i](x)+2, x);
end do;
2
M[1] := x -> x + 1
2
N[1] := x -> x + 3
2
M[2] := x -> x + 4
2
N[2] := x -> x + 6
2
M[3] := x -> x + 7
2
N[3] := x -> x + 9
N[3](11);
130
但是正如我在上面的答案中指出的那样,根本不需要构造所有这些过程。通过使用rsolve
命令,我们可以解决通用公式的递归关系(以i
和x
都闭合)。然后,根据该封闭式,我们可以利用unapply
命令为N
构造一个仅由2个参数组成的过程,为M
构造一个由2个参数组成的过程。