код, который строится быстро вне Manipulate, но медленно строится внутри Manipulate.Помогите выяснить почему - PullRequest
1 голос
/ 06 сентября 2011

Учитывая код, который отображает результат решения ODE с использованием быстрого алгоритма, использующего динамику напрямую, я обнаружил, что он отображает решение очень быстро на экране.

Я интегрировал этот алгоритм в Manipulate [] и заметил, что графическая часть теперь намного медленнее, чем раньше.

Я трачу 4 часа на это и не понимаю, почему это так.Я надеюсь, что кто-то может определить проблему и в чем проблема.

Алгоритм - тот, который только что опубликовал сегодня Леонид в своем ответе на другой мой вопрос здесь (еще раз спасибо Леонид!)

Алгоритм очень быстрый, а такжерендерит сюжет быстро.Но он использует динамику напрямую.Я хотел бы использовать его внутри Манипуляции.

Я интегрировал его в Манипуляции, насколько я знаю, так как, поскольку код усовершенствован для меня, я не уверен, правильно ли я это сделал, норезультат правильный.

Сюжет работает и генерирует правильный график, как и оригинальный алгоритм, но теперь скорость построения графиков теперь значительно ниже.Все параметры одинаковы в обоих случаях (то есть параметры задачи).Это проблема, с которой я долго боролся.Как ускорить fps при использовании Manipulate.

Итак, проблема может заключаться в том, что я интегрировал его для запуска внутри Manipulate, я сделал что-то неэффективное, или это может быть потому, что Manipulate уже использует DynamicModule [] и этоимел побочный эффект в замедлении рендеринга графика или замедлении всего процесса.

Я опубликую свой код Manipulate, в который я интегрировал код Leonid (я пробовал много разных способов, и все они строили медленно, этоодна версия ниже).

Manipulate[

 Module[{ll = emptyList[], sol, plot, t, y, angle, 
   llaux = emptyList[]},
  plot[] := 
   Graphics[{Hue[0.67`, 0.6`, 0.6`], Line[fromLinkedList[ll]]}, 
    AspectRatio -> 1/GoldenRatio, Axes -> True, 
    AxesLabel -> {"time", "angle"}, 
    PlotRange -> {{0, max}, {-Pi/4, Pi/4}}, PlotRangeClipping -> True];

  llaux = ll;
  sol := First@
    NDSolve[{y''[t] + 0.01 y'[t] + Sin[y[t]] == 0, y[0] == Pi/4, 
      y'[0] == 0}, y, {t, time, time + 1}];
  angle := y /. sol;

  ll := With[{res = 
      If[llaux === emptyList[] || pop[llaux][[1]] != time, 
       addToList[llaux, {time, angle[time]}],(*else*)llaux]},
    llaux = res];

  Dynamic[plot[]]
  ]
 ,
 {{time, 0, "run"}, 0, max, Dynamic@delT, AnimationRate -> 1, 
  ControlType -> Trigger}, {{delT, 0.01, "delT"}, 0.01, 1, 0.01, 
  Appearance -> "Labeled"},
 {{y0, Pi/4, "y(0)"}, -Pi, Pi, Pi/100, Appearance -> "Labeled"},
 {{yder0, 0, "y'(0)"}, -1, 1, .1, Appearance -> "Labeled"},
 {{linkedList, {}}, None},

 TrackedSymbols :> {time},
 Initialization :> (
   max = 200;
   toLinkedList[data_List] := Fold[linkedList, linkedList[], data]; 
   fromLinkedList[ll_linkedList] := 
    List @@ Flatten[ll, Infinity, linkedList]; 
   addToList[ll_, value_] := linkedList[ll, value];
   pop[ll_] := Last@ll;
   emptyList[] := linkedList[];
   )
 ]

Вот оригинальный код, точно такой же, как был опубликован Леонидом здесь , но я добавил 2 параметра вверху, поэтому обе версиибудет работать точно такой же параметр, чтобы сравнить скорость легче.Когда вы запустите это, вы заметите, насколько быстро график генерируется на экране по сравнению с приведенным выше.

Я хотел бы помочь выяснить, почему разница в скорости.Теперь я исходил из предположения, что разница в скорости построения графиков обусловлена ​​взаимодействием Dyanmics внутри Manipulate, поскольку я знаю, что алгоритм очень быстрый снаружи.

max = 200; delT = 0.01;

ClearAll[linkedList, toLinkedList, fromLinkedList, addToList, pop, 
  emptyList];

(*SetAttributes[linkedList,HoldAllComplete];*)
toLinkedList[data_List] := Fold[linkedList, linkedList[], data];
fromLinkedList[ll_linkedList] := 
  List @@ Flatten[ll, Infinity, linkedList];
addToList[ll_, value_] := linkedList[ll, value];
pop[ll_] := Last@ll;
emptyList[] := linkedList[];

Clear[getData];
Module[{ll = emptyList[], time = 0, restart, plot, y}, 
 getData[] := fromLinkedList[ll];

 plot[] := 
  Graphics[{Hue[0.67`, 0.6`, 0.6`], Line[fromLinkedList[ll]]}, 
   AspectRatio -> 1/GoldenRatio, Axes -> True, 
   AxesLabel -> {"time", "angle"}, 
   PlotRange -> {{0, max}, {-Pi/4, Pi/4}}, PlotRangeClipping -> True];

 DynamicModule[{sol, angle, llaux}, 
  restart[] := (time = 0; llaux = emptyList[]);
  llaux = ll;
  sol := First@
    NDSolve[{y''[t] + 0.01 y'[t] + Sin[y[t]] == 0, y[0] == Pi/4, 
      y'[0] == 0}, y, {t, time, time + 1}];
  angle := y /. sol;

  ll := With[{res = 
      If[llaux === emptyList[] || pop[llaux][[1]] != time, 
       addToList[llaux, {time, angle[time]}],(*else*)llaux]},
    llaux = res
    ];

  Column[{
    Row[{Dynamic@delT, Slider[Dynamic[delT], {0.01, 1., 0.01}]}],
    Dynamic[time, {None, Automatic, None}], 
    Row[{Trigger[Dynamic[time], {0, max, Dynamic@delT}, 
       AppearanceElements -> {"PlayPauseButton"}],
      Button[Style["Restart", Small], restart[]]}
     ],
    Dynamic[plot[]]}, Frame -> True
   ]
  ]
 ]

enter image description here

Спасибоснова для любых подсказок или вещей, чтобы попробовать.

Обновление

Хорошо, это становится интересным.Я никогда не знал, что можно создать CDF, просто используя Dynamics, я думал, что нужно использовать Manipulate.Но я был неправ.Я только что попробовал один, и это на самом деле работает! Вот на моем сайте , симуляция демпфированного ведомого маятника (который демонстрирует хаотическое движение из-за присутствия движущей силы на суставе), написанная только с использованием Dynamics, без Manipulate.

код для вышеупомянутого следующий:

DynamicModule[{sol, angle, bob, r, time = 0, animationRate = 1},
 (*simulation of damped and driven pendulum, exhibit chaotic motion*)

 Dynamic@Grid[{
    {Trigger[Dynamic[time], {0, Infinity, 0.01}, animationRate, 
      AppearanceElements -> {"PlayPauseButton", "ResetButton"}], 
     Style["time (sec)", 10], Dynamic[time]},
    {
     Dynamic@Show[Graphics[{
         {Dashed, Gray, Thin, Circle[{0, 0}, 1]},
         {Red, Thick, Line[{{0, 0}, bob}]},
         {Blue, PointSize[0.1], Point[bob]}
         }, ImagePadding -> 10], ImageSize -> 300], SpanFromLeft
     }}, Frame -> True, Alignment -> Left],

 Initialization :>
  (
   sol := 
    First@NDSolve[{y''[t] + 0.1 y'[t] + Sin[y[t]] == 1.5 Cos[t], 
       y[0] == Pi/4, y'[0] == 0}, y, {t, time, time + 1}, 
      Sequence@ndsolveOptions];
   bob := {Sin[(y /. sol)[time]], - Cos[(y /. sol)[time]]};

   ndsolveOptions = {MaxSteps -> Infinity, 
     Method -> {"StiffnessSwitching", 
       Method -> {"ExplicitRungeKutta", Automatic}}, 
     AccuracyGoal -> 10, PrecisionGoal -> 10};
   )
 ]

enter image description here

Это мой самый первый CDF, использующий прямую динамику.Если вы хотите увидеть разницу в производительности при обновлении экрана, вот версия выше, с использованием Manipulate.Я не заметил большой разницы в этом случае, но обратите внимание, что это график положения маятника, буферизация не требуется и обработка данных.Просто график точка за точкой позиции боба.

Manipulate[
 (
  sol = First@
    NDSolve[{y''[t] + 0.1 y'[t] + Sin[y[t]] == 1.5 Cos[t], 
      y[0] == Pi/4, y'[0] == 0}, y, {t, time, time + 1}, 
     Sequence@ndsolveOptions];
  bob = {Sin[(y /. sol)[time]], - Cos[(y /. sol)[time]]};

  Show[Graphics[{
     {Dashed, Gray, Thin, Circle[{0, 0}, 1]},
     {Red, Thick, Line[{{0, 0}, bob}]},
     {Blue, PointSize[0.1], Point[bob]}
     }, ImagePadding -> 10], ImageSize -> 300]
  ),

 {{time, 0, "run"}, 0, Infinity, 0.01, AnimationRate -> animationRate,
   AppearanceElements -> {"PlayPauseButton", "ResetButton"}},

 Initialization :>
  (
   animationRate = 1;
   ndsolveOptions = {MaxSteps -> Infinity, 
     Method -> {"StiffnessSwitching", 
       Method -> {"ExplicitRungeKutta", Automatic}}, 
     AccuracyGoal -> 10, PrecisionGoal -> 10};
   )
 ]

Я думаю, что теперь можно сделать CDF из только динамики, это очень интересно.

1 Ответ

4 голосов
/ 06 сентября 2011

Это вопрос AnimationRate.Установка этого значения одинаково в обоих случаях дает идентичные временные интервалы (между прочим, довольно трудно запускаемые по времени триггеры): Оценить:

    Clear[getData];
Module[{ll = emptyList[], time = 0, restart, plot, y, timeinit}, 
 getData[] := fromLinkedList[ll];
 timeinit[n_ /; 0.01 < n < .5] := (init = AbsoluteTime[]);
 plot[] := 
  Graphics[{Hue[0.67`, 0.6`, 0.6`], Line[fromLinkedList[ll]]}, 
   AspectRatio -> 1/GoldenRatio, Axes -> True, 
   AxesLabel -> {"time", "angle"}, 
   PlotRange -> {{0, max}, {-Pi/4, Pi/4}}, PlotRangeClipping -> True, 
   PlotLabel :> 
    Row[{"seconds used: ", (timeinit[time]; 
       If[time < 1, "", Round[AbsoluteTime[] - init]])}]];
 DynamicModule[{sol, angle, llaux}, 
  restart[] := (time = 0; llaux = emptyList[]);
  llaux = ll;
  sol := First@
    NDSolve[{y''[t] + 0.01 y'[t] + Sin[y[t]] == 0, y[0] == Pi/4, 
      y'[0] == 0}, y, {t, time, time + 1}];
  angle := y /. sol;
  ll := With[{res = 
      If[llaux === emptyList[] || pop[llaux][[1]] != time, 
       addToList[llaux, {time, angle[time]}],(*else*)llaux]}, 
    llaux = res];
  Column[{Row[{Dynamic@delT, 
      Slider[Dynamic[delT], {0.01, 1., 0.01}]}], 
    Dynamic[time, {None, Automatic, None}], 
    Row[{Trigger[Dynamic[time], {0, max, Dynamic@delT}, 
       AppearanceElements -> {"PlayPauseButton"}, 
       AnimationRate -> 15], 
      Button[Style["Restart", Small], restart[]]}], Dynamic[plot[]]}, 
   Frame -> True]]]

(* и: *)

    Manipulate[
 Module[{ll = emptyList[], sol, plot, t, y, angle, 
   llaux = emptyList[], timeinit, init},
  timeinit[n_ /; 0.01 < n < .5] := (init = AbsoluteTime[]);
  plot[] := 
   Graphics[{Hue[0.67`, 0.6`, 0.6`], Line[fromLinkedList[ll]]}, 
    AspectRatio -> 1/GoldenRatio, Axes -> True,
    PlotLabel :> 
     Row[{"seconds used: ", (timeinit[time]; 
        If[time < 1, "", Round[AbsoluteTime[] - init]])}],
    AxesLabel -> {"time", "angle"}, 
    PlotRange -> {{0, max}, {-Pi/4, Pi/4}}, PlotRangeClipping -> True];
  llaux = ll;
  sol := First@
    NDSolve[{y''[t] + 0.01 y'[t] + Sin[y[t]] == 0, y[0] == Pi/4, 
      y'[0] == 0}, y, {t, time, time + 1}];
  angle := y /. sol;
  ll := With[{res = 
      If[llaux === emptyList[] || pop[llaux][[1]] != time, 
       addToList[llaux, {time, angle[time]}],(*else*)llaux]}, 
    llaux = res];
  Dynamic[plot[]]], {{time, 0, "run"}, 0, max, Dynamic@delT, 
  AnimationRate -> 15, ControlType -> Trigger}, {{delT, 0.01, "delT"},
   0.01, 1, 0.01, Appearance -> "Labeled"}, {{y0, Pi/4, "y(0)"}, -Pi, 
  Pi, Pi/100, Appearance -> "Labeled"}, {{yder0, 0, "y'(0)"}, -1, 
  1, .1, Appearance -> "Labeled"}, {{linkedList, {}}, None}, 
 TrackedSymbols :> {time}, Initialization :> (max = 200;
   toLinkedList[data_List] := Fold[linkedList, linkedList[], data];
   fromLinkedList[ll_linkedList] := 
    List @@ Flatten[ll, Infinity, linkedList];
   addToList[ll_, value_] := linkedList[ll, value];
   pop[ll_] := Last@ll;
   emptyList[] := linkedList[];)]
...