Определение рекурсивного отношения в Maple с помощью цикла for

Я пытаюсь создать рекурсивное отношение с помощью «цикла for» в Maple. Предположим, у нас есть две последовательности 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. Есть ли способ изменить этот код?


person MEDVIS    schedule 25.10.2018    source источник


Ответы (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 и одной для M.

person acer    schedule 25.10.2018