Можно ли получить доступ к содержимому частичного списка во время сеяния или нужно подождать, пока он будет получен? - PullRequest
10 голосов
/ 28 декабря 2011

Я изучаю Соу / Рип. Они классные конструкции. Но мне нужна помощь, чтобы посмотреть, смогу ли я использовать их для выполнения того, что я объясню ниже.

Я хотел бы сделать следующее: подготовить решение для NDSolve, пока оно работает. Я думал, что могу использовать Sow[], чтобы собрать решение (x, y [x]), поскольку NDSolve работает с использованием EvaluationMonitor. Но я не хочу ждать до конца, Reap это и затем готовить решение, но хотел сделать это во время работы.

Я покажу пример базовой настройки

max = 30;
sol1 = y /. 
   First@NDSolve[{y'[x] == y[x] Cos[x + y[x]], y[0] == 1}, 
     y, {x, 0, max}];
Plot[sol1[x], {x, 0, max}, PlotRange -> All, AxesLabel -> {"x", "y[x]"}]

enter image description here

Используя Reap / Sow, можно собрать точки данных и построить решение в конце, как это

sol = Reap[
    First@NDSolve[{y'[x] == y[x] Cos[x + y[x]], y[0] == 1}, 
      y, {x, 0, max}, EvaluationMonitor :> Sow[{x, y[x]}]]][[2, 1]];

ListPlot[sol, AxesLabel -> {"x", "y[x]"}]

enter image description here

Хорошо, пока все хорошо. Но я хочу получить доступ к частично компилируемому списку, так как он накапливается на Sow, и построить решение. Единственная настройка, которую я знаю, как это сделать, это иметь Dynamic ListPlot, который обновляется при изменении данных. Но я не знаю, как использовать Sow для переноса частично построенного решения на эти данные, чтобы ListPlot обновилось.

Я покажу, как я делаю это без Соу, но вы видите, я использую AppenedTo[] в следующем:

ClearAll[x, y, lst];
max = 30;
lst = {{0, 0}};
Dynamic[ListPlot[lst, Joined -> False, PlotRange -> {{0, max}, All}, 
  AxesLabel -> {"x", "y[x]"}]]

NDSolve[{y'[x] == y[x] Cos[x + y[x]], y[0] == 1}, y, {x, 0, max}, 
 EvaluationMonitor :> {AppendTo[lst, {x, y[x]}]; Pause[0.01]}]

enter image description here

Я думал о способе получить доступ к частично скомпилированному списку от Sow и просто использовать его для обновления графика, предполагая, что он может быть более эффективным, чем AppendTo[]

Я не могу просто сделать это:

ClearAll[x, y, lst];
max = 30;
lst = {{0, 0}};
Dynamic[ListPlot[lst, Joined -> False, PlotRange -> All]]

NDSolve[{y'[x] == y[x] Cos[x + y[x]], y[0] == 1}, y, {x, 0, max}, 
 EvaluationMonitor :> {lst = Reap[Sow[{x, y[x]}] ][[2, 1]]; Pause[0.01]}]

Поскольку теперь он сеет одну точку и пожинает ее, я просто строю одну точку за раз. Так же, как если бы я только что сделал:

NDSolve[{y'[x] == y[x] Cos[x + y[x]], y[0] == 1}, y, {x, 0, max}, 
 EvaluationMonitor :> {lst = Sow[{x, y[x]}]; Pause[0.01]}]

Мой вопрос заключается в том, как использовать Sow / Reap в приведенном выше, чтобы я не управлял lst с помощью AppendTo в этом случае. (или путем предварительного распределения с использованием Таблицы, но тогда я бы не знал, какой размер выделить). Поскольку я предполагаю, что может быть Sow / Reap будет более эффективным?

пс. Что было бы хорошо, если бы у Reap была возможность сообщить Reap, что было накоплено Sow, но не удаляйте его из того, что было посеяно до сих пор. Как пассивный Reap вроде. Ну, просто мысль.

спасибо

Обновление: 8:30

Спасибо за ответы и комментарии. Я просто хотел сказать, что главная цель запроса об этом - просто посмотреть, есть ли способ получить доступ к части данных во время сеяния. Мне нужно больше посмотреть на Bag, я раньше этим не пользовался.

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

Следовательно, нет необходимости даже беспокоиться о выделении буфера самостоятельно или использовать AppenedTo. Но возможны и другие случаи, когда доступ к данным будет проще, так как они накапливаются Sow. Этот пример как раз то, что у меня было на данный момент.

Чтобы сделать этот конкретный пример более непосредственным, можно просто использовать Animate[], послесловия, например:

Remove["Global`*"];
max = 30;
sol = Reap[
    First@NDSolve[{y'[x] == y[x] Cos[x + y[x]], y[0] == 1}, 
      y, {x, 0, max}, EvaluationMonitor :> Sow[{x, y[x]}]]][[2, 1]];

Animate[ListPlot[sol[[1 ;; idx]], Joined -> False, 
  PlotRange -> {{0, max}, All}, AxesLabel -> {"x", "y[x]"}], {idx, 1, 
  Length[sol], 1}]

Или даже сделать дом, одушевленный, как этот

Remove["Global`*"];
max = 30;
sol = Reap[
    First@NDSolve[{y'[x] == y[x] Cos[x + y[x]], y[0] == 1}, 
      y, {x, 0, max}, EvaluationMonitor :> Sow[{x, y[x]}]]][[2, 1]];
idx = 1;
Dynamic[idx];
Dynamic[ListPlot[sol[[1 ;; idx]], Joined -> False, 
  PlotRange -> {{0, max}, All}, AxesLabel -> {"x", "y[x]"}]]

Do[++idx; Pause[0.01], {i, 1, Length[sol] - 1}]

Небольшой дополнительный вопрос: Можно ли зависеть от использования Internal``Bag сейчас? Так как он находится в Internal контексте, будет ли вероятность того, что он может быть удален / изменен / и т. Д. ... в будущем, нарушая какой-то код? Кажется, я помню, что где-то читал, что это маловероятно, но я не чувствую себя комфортно, используя что-то в контексте Internal. Если это нормально для нас, то почему же это во Внутреннем контексте?

(так много вещей, на которые можно опираться в Mathematica, так мало времени)

Спасибо

1 Ответ

6 голосов
/ 28 декабря 2011

Эксперимент показывает, что и Internal`Bag, и связанные списки работают медленнее, чем AppendTo. Обдумав это, я вспомнил то, что сказал мне Саша: создание списка (массива) - это то, что требует времени.

Следовательно, ни метод, описанный выше, ни метод Sow / Reap, в котором результат собирается в виде списка на каждом шаге, не будет более эффективным (фактически, менее), чем AppendTo.

Я считаю, что только предварительное выделение массива может быть быстрее среди нативных Mathematica конструкций.

Старый ответ ниже для справки:


Я считаю, что это место для Internal`Bag, Internal`StuffBag и Internal`BagPart.

Мне пришлось прибегнуть к неуклюжему методу двойной переменной, потому что Bag, похоже, не обновляется внутри Dynamic так, как я ожидал.

ClearAll[x, y, lst];
max = 30;
bag = Internal`Bag[];
lst = {{}};

Dynamic@ListPlot[lst, Joined -> False, PlotRange -> All]

NDSolve[{y'[x] == y[x] Cos[x + y[x]], y[0] == 1}, y, {x, 0, max}, 
 EvaluationMonitor :> {Internal`StuffBag[bag, {x, y[x]}];
                       lst = Internal`BagPart[bag, All];
                       Pause[0.01]}
]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...