Отвечая на вопрос физического форума сегодня утром, я столкнулся с очень плохой работой DifferenceRoot
и ] RecurrenceTable
по сравнению с вычислением выражений путем наивного взятия производных экспоненциального производящего функционала. Очень небольшое исследование показало, что DifferenceRoot
и RecurrenceTable
не упрощают выражения по мере их выполнения .
Например, посмотрите следующий вывод RecurrenceTable
и то, как это упрощается, просто Expand
и результат:
In[1]:= RecurrenceTable[f[n] == a f[n - 1] + (a - 1) f[n - 2] &&
f[0] == 0 && f[1] == 1,
f, {n, 6}]
% // Expand
Out[1]= {0, 1, a, -1+a+a^2, -a+a^2+a (-1+a+a^2), 1-a-a^2+a (-1+a+a^2)+a (-a+a^2+a (-1+a+a^2))}
Out[2]= {0, 1, a, -1+a+a^2, -2 a+2 a^2+a^3, 1-2 a-2 a^2+3 a^3+a^4}
Это быстро выходит из-под контроля, поскольку количество листьев на 20-й итерации (вычислено с использованием DifferenceRoot
) показывает :
dr[k_] := DifferenceRoot[Function[{f, n},
{f[n] == a f[n - 1] + (a - 1) f[n - 2], f[0] == 0, f[1] == 1}]][k]
In[2]:= dr20 = dr[20]; // Timing
dr20Exp = Expand[dr20]; // Timing
Out[2]= {0.26, Null}
Out[3]= {2.39, Null}
In[4]:= {LeafCount[dr20], LeafCount[dr20Exp]}
Out[4]= {1188383, 92}
Что можно сравнить с мемоизированной реализацией
In[1]:= mem[n_] := a mem[n-1] + (a-1) mem[n-2] // Expand
mem[0] = 0; mem[1] = 1;
In[3]:= mem20 = mem[20];//Timing
LeafCount[mem20]
Out[3]= {0.48, Null}
Out[4]= 92
Итак, мой вопрос:
Существуют ли какие-либо варианты / приемы, позволяющие получить DifferenceRoot
и RecurrenceTable
для применения (упрощающей) функции по мере их выполнения и, таким образом, сделать их полезными для нечисловой работы?
Изменить: Шорд указал ниже, я по глупости выбрал пример с RSolve
решением в закрытой форме. В этом вопросе меня в первую очередь интересует поведение DifferenceRoot
и RecurrenceTable
. Если это помогает, представьте, что член f [n-2]
умножается на n
, так что не существует простого решения в замкнутой форме.