Mathematica - ограничение x интервала в цикле

Я пытаюсь выполнить такой цикл Do в системе Mathematica, где на каждом шаге g и f пересчитываются с использованием предыдущего значения f:

nend=1000;
f[x_] = Tanh[x];
Do[
   g[x_] = f[x]^3 + f[x] + Laplacian[f[x], {x}];
   f[x_] = f[x] + 0.01 g[x],                     
   {i, 0, nend}
]

Кажется, что это работает для очень малых значений nend (вплоть до nend = 3!), Но ядро ​​останавливается и завершает работу, когда я пытаюсь использовать более высокие значения. Я предполагаю, что это связано с тем, что цикл вычисляется для всех x от -Inf до Inf. Поскольку меня интересует только интервал [-10,10], есть ли способ ограничить цикл этими значениями x?

Меня также интересуют любые другие предложения о том, как сделать то же самое более эффективным способом.

Я работаю с Mathematica 11.0 в Debian 9.

Спасибо!


person pamgur    schedule 02.08.2018    source источник
comment
Это немного проще nend = 4; f[x_]=Tanh[x]; Do[g[x_] = Simplify[f[x]^3+f[x]+ Laplacian[f[x], {x}]]; f[x_] = Simplify[f[x]+0.01 g[x]], {i,0,nend}]; f[x] и показывает, как размер вашего выражения растет по мере роста nend.   -  person Bill    schedule 03.08.2018
comment
Привет, @Bill. Может, я не ясно выразился. Вы предлагаете то же самое, что и я, за исключением использования Simplify. У него та же проблема, что я описал в моем исходном сообщении: и мой пример, и ваш работают для очень малых значений nend (до 3), и я хочу иметь возможность использовать nend = 1000 или больше. Есть ли у вас предложения по ограничению диапазона x в цикле do? В любом случае спасибо за ответ!   -  person pamgur    schedule 06.08.2018
comment
Без моего простого использования Simplify количество символов, необходимое для Mathematica, чтобы найти ваш результат для nend = 1,2,3,4,5,6, составляет 181, 1028, 6290, 40665, 273576, 1895961 и для nend = 1000, что потребовалось бы более 10 ^ 779 символов. С моим простым использованием Simplify числа 127, 300, 840, 3233 ... что займет больше времени, но использует гораздо меньше памяти. Ни один из них не дойдет до nend = 1000. В вашем коде нет вычислений для всех x от -Inf до Inf. Единственное, что нужно сделать, - это точно вычислить производные от вашей растущей башни функций f и g. Вы можете просто объяснить, чего хотите?   -  person Bill    schedule 06.08.2018
comment
Извините, если наткнулся на грубость. Я знаю, что делает Simplify, и согласен с тем, что мой код намного лучше справляется с этим. Простыми словами, я хочу иметь возможность вычислить эту сумму в виде больших значений nend, по крайней мере, для x в [-10,10].   -  person pamgur    schedule 06.08.2018


Ответы (1)


ММА вычисляет большинство вещей точно или почти точно. Он точно вычисляет 181 символ, необходимый для {f [x], g [x]}, когда nend == 1, или 97131923 символов, необходимых для nend == 8, если вы не используете Simplify. Он не собирается отбрасывать миллионы этих терминов, будь то x == 1 или x == 10 ^ 999, если вы не найдете более простой способ сказать это, чтобы приблизить вашу проблему. Таким образом, количество генерируемых терминов и размер результирующего вычисления не зависят от диапазона x.

Возможно, вы сможете посмотреть на результат, решить, действительно ли вам нужен nend == 1000, и попытаться решить, как этого добиться, описывая свою проблему в MMA таким образом, чтобы он мог это сделать на компьютере и в памяти, которая у вас есть.

a[x_] = Tanh[x];
Do[b[x_] = a[x]^3 + a[x] + Laplacian[a[x], {x}];
  a[x_] = a[x] + 0.01 b[x], {i, 0, 1}];
a1[x_] = a[x]; b1[x_] = b[x];
Do[b[x_] = a[x]^3 + a[x] + Laplacian[a[x], {x}];
  a[x_] = a[x] + 0.01 b[x], {i, 2, 2}];
a2[x_] = a[x]; b2[x_] = b[x];
Do[b[x_] = a[x]^3 + a[x] + Laplacian[a[x], {x}];
  a[x_] = a[x] + 0.01 b[x], {i, 3, 3}];
a3[x_] = a[x]; b3[x_] = b[x];
Do[b[x_] = a[x]^3 + a[x] + Laplacian[a[x], {x}];
  a[x_] = a[x] + 0.01 b[x], {i, 4, 4}];
a4[x_] = a[x]; b4[x_] = b[x];
Do[b[x_] = a[x]^3 + a[x] + Laplacian[a[x], {x}];
  a[x_] = a[x] + 0.01 b[x], {i, 5, 5}];
a5[x_] = a[x]; b5[x_] = b[x];
Do[b[x_] = a[x]^3 + a[x] + Laplacian[a[x], {x}];
  a[x_] = a[x] + 0.01 b[x], {i, 6, 6}];
a6[x_] = a[x]; b6[x_] = b[x];
Do[b[x_] = a[x]^3 + a[x] + Laplacian[a[x], {x}];
  a[x_] = a[x] + 0.01 b[x], {i, 7, 7}];
a7[x_] = a[x]; b7[x_] = b[x];
Do[b[x_] = a[x]^3 + a[x] + Laplacian[a[x], {x}];
  a[x_] = a[x] + 0.01 b[x], {i, 8, 8}];
a8[x_] = a[x]; b8[x_] = b[x];
Print[{LeafCount[{a1[x], b1[x]}], LeafCount[{a2[x], b2[x]}], 
       LeafCount[{a3[x], b3[x]}], LeafCount[{a4[x], b4[x]}], 
       LeafCount[{a5[x], b5[x]}], LeafCount[{a6[x], b6[x]}], 
       LeafCount[{a7[x], b7[x]}], LeafCount[{a8[x], b8[x]}]}];
Plot[{a1[x], b1[x], a2[x], b2[x], a3[x], b3[x], a4[x], b4[x], 
      a5[x], b5[x], a6[x], b6[x], a7[x], b7[x], a8[x], b8[x]}, {x, -3, 3}]

который отображает

{181,1028,6290,40665,273576,1895961,13445784,97131923}

а затем графики ваших пар кривых для каждого значения nend.

введите здесь описание изображения

Я выполнил каждую из ваших итераций цикла Do отдельно, чтобы сохранить копии кривых для построения графика для каждого значения nend.

Небольшая разница между нижней оранжевой кривой b1 [x] и верхней оранжевой кривой b4 [x] - это разница между 79 и 18614 членами в ваших расчетах, когда nend == 1 по сравнению с nend == 4.

Ваш график для a немного меняется в зависимости от значения nend, несмотря на то, что a1 [x] имеет 101 член, а a4 [x] имеет 22047 членов. Вот сюжет a1 с наложенным Tanh[x], и большой разницы нет.

введите здесь описание изображения

Ваши графики b меняются немного больше в зависимости от значения nend, и не так очевидно, к какой функции они могут приближаться. Я попытался вычесть a из b, думая, что это может мне что-то показать, но это не помогло.

Количество терминов, которые вы генерируете при повторении снова и снова, будет расти и превысит то, с чем когда-либо сможет справиться любой компьютер.

Если вы хотите рассчитать до nend == 1000, я думаю, вам нужно найти способ приблизить расчет на каждом шаге, чтобы вы не теряли важную информацию, но не увеличивали количество членов в 4 или 8 раз. с каждой итерацией.

Возможно, в конце каждой итерации и после использования Simplify вы могли бы затем вычислить значение каждого члена при x == 10, и если результат был, возможно, меньше 10 ^ -6, вы могли бы затем заменить этот термин нулем. Это может помочь вам бороться с экспоненциальным ростом числа членов, которые вы генерируете с каждой итерацией, сохраняя при этом поведение ваших вычислений.

Если есть какой-то способ сделать это, то почти всегда хорошая идея бросить МНОГО памяти на ММА. 16 ГБ, 32 ГБ или даже 64 ГБ, если есть какой-либо способ получить, это часто помогает. Память не такая дешевая, как несколько лет назад, но если вы можете себе ее позволить и ваша машина может ее использовать, то получение всей доступной памяти было бы хорошим шагом, особенно если вы не хотите тратить много время, пытаясь найти способ оптимизировать вычисление, чтобы завершить его в ограниченной доступной памяти, которая у вас есть.

Пожалуйста, проверьте все это очень внимательно, чтобы убедиться, что не было допущено никаких ошибок.

person Bill    schedule 06.08.2018
comment
Спасибо, Билл! Ваше объяснение было очень ясным, хотя изображения не загружаются - по крайней мере, для меня. Я понимаю, что вы говорите. Тогда мне придется немного подумать над проблемой и посмотреть, как я могу ее уменьшить. - person pamgur; 07.08.2018