是否可以在播种时访问部分列表内容,还是必须等待它收获?

Nas*_*ser 10 wolfram-mathematica

我一直在学习Sow/Reap.它们很酷.但我需要帮助,看看我是否可以使用它们来做我将在下面解释的内容.

我想做的是:绘制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]"}]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

使用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]"}]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

好的,到目前为止一切顺利.但我想要的是访问部分正在构建的列表,因为它累积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]}]
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我正在考虑一种方法来访问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]}]
Run Code Online (Sandbox Code Playgroud)

既然它现在播下一个点,并收获它,所以我只是一次绘制一个点.就像我刚才那样:

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]}]
Run Code Online (Sandbox Code Playgroud)

我的问题是,如何在上面使用Sow/Reap,以避免我在这种情况下使用AppendTo来管理lst.(或者通过使用Table进行预分配,但后来我不知道要分配的大小)因为我认为可能是Sow/Reap会更有效率?

PS.什么是好的,如果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}]
Run Code Online (Sandbox Code Playgroud)

或者,甚至像这样制作一个家庭成长的动画

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}]
Run Code Online (Sandbox Code Playgroud)

小问题:Internal``Bag现在 可以依靠使用吗?由于它是在Internal上下文中,是否有可能在将来删除/更改/等等...破坏一些代码?我似乎记得在某个地方读过这不太可能,但我觉得在InternalContext中使用某些东西感觉不舒服.如果我们可以使用它,为什么它在内部环境中呢?

(在Mathematica中有很多东西可以倾斜,所以很少的时间)

谢谢,

Mr.*_*ard 6

实验表明,Internal`Bag链接列表和链接列表都比使用慢AppendTo.考虑到这一点后,我回想起Sasha告诉我的内容,即列表(数组)创建需要时间.

因此,上述方法既没有,也不是Sow/ Reap,其中结果被收集在每个步骤列表将是更有效的(事实上,小于)AppendTo.

我相信在本机Mathematica结构中只有数组预分配才能更快.

以下老答案供参考:


我相信这是对的地方Internal`Bag,Internal`StuffBagInternal`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]}
]
Run Code Online (Sandbox Code Playgroud)