我正在运行一个 Table 函数,这将花费太多时间才能完成。
我想知道是否有办法检索到目前为止计算的结果。
最佳答案
建议的解决方案
这是Table
的一个版本即 Abort
- 能够并将保留到目前为止收集的中间结果。它是发布的解决方案的修改版本here .
ClearAll[abortableTable];
SetAttributes[abortableTable, HoldAll];
abortableTable[expr_, iter__List] :=
Module[{indices, indexedRes, sowTag},
SetDelayed @@
Prepend[Thread[Map[Take[#, 1] &, List @@ Hold @@@ Hold[iter]],
Hold], indices];
indexedRes =
If[# === {}, #, First@#] &@Last@Reap[
CheckAbort[Do[Sow[{expr, indices}, sowTag], iter], {}], sowTag];
AbortProtect[
Map[First,
SplitBy[indexedRes,
Table[
With[{i = i}, Function[Slot[1][[2, i]]]],
{i, Length[Hold[iter]] - 1}]],
{-3}]]];
它应该能够采用与
Table
相同的迭代器规范。 .工作原理
这是它的工作原理。第一个语句(
SetDelayed @@...
)“解析”迭代器,假设它们都是 {iteratorSymbol_,bounds__}
形式的。 ,并将迭代器变量列表分配给变量 indices
.与Hold
的施工需要防止可能的迭代器变量评估。有很多方法可以做到这一点,我只使用了其中一种。这是它的工作原理:In[44]:=
{i, j, k} = {1, 2, 3};
Prepend[Thread[Map[Take[#, 1] &, List @@ Hold @@@
Hold[{i, 1, 10}, {j, 1, 5}, {k, 1, 3}]], Hold], indices]
Out[45]= Hold[indices, {i, j, k}]
使用
SetDelayed @@ the-above
然后自然会产生形式 indices:={i,j,k}
的延迟定义.我将值分配给索引 i,j,k
证明在使用此构造时不会对它们进行不需要的评估。下一个语句生成一个收集结果的列表,其中每个结果都分组在一个列表中,其中包含用于生成它的索引列表。自
indices
变量由延迟定义定义,它将每次重新评估,以获取新的索引组合。这里使用的另一个重要特征是 Do
循环接受与 Table
相同的迭代器语法(并且还动态本地化迭代器变量),同时是一个顺序(恒定内存)构造。收集中间结果,Reap
和 Sow
被使用。自 expr
可以是任何一段代码,特别是也可以使用 Sow
,只有 Reap
才需要一个具有唯一名称的自定义标签。那些值 Sown
通过我们的函数,而不是它执行的代码。自 Module
自然产生具有唯一名称的(临时)符号,我只是使用了 Module
- 生成的没有值的变量,作为标签。这是一种普遍有用的技术。能够在
Abort[]
的情况下收集结果由用户交互或在代码中发出,我们将 Do
包裹起来。在 CheckAbort
中循环.在 Abort[]
上执行的代码(这里是 {}
)在这种方法中很大程度上是任意的,因为无论如何收集结果都是由 Sow
完成的。和 Reap
,尽管在更复杂的版本中可能有用,该版本将结果保存到用户提供的某个变量中,然后重新发出 Abort[]
(当前未实现的功能)。结果,我们进入了一个变量
indexedRes
表格的平面列表{{expr1, {ind11,ind21,...indn1}},...,{exprk, {ind1k,ind2k,...indnk}}
其中结果与相应的索引组合进行分组。我们需要这些索引组合来从平面列表重建多维结果列表。方法是根据
i
的值对列表进行重复拆分。 -th 索引。函数SplitBy
具有此功能,但我们需要提供用于拆分步骤的函数列表。由于索引i
- 子列表中的第一个迭代器索引 {expr,{ind1,...,indn}}
是 2,i
, 在 i
处进行拆分的函数- 第一步是 #[[2, i]]&
,并且我们需要动态构建此类函数的列表以将其提供给 SplitBy
.下面是一个例子:In[46]:= Table[With[{i = i}, Function[Slot[1][[2, i]]]], {i, 5}]
Out[46]= {#1[[2, 1]] &, #1[[2, 2]] &, #1[[2, 3]] &, #1[[2, 4]] &, #1[[2, 5]] &}
With[{i=i},body]
构造用于注入(inject)i
的特定值纯函数内部。注入(inject)值 i
的替代方案进入 Function
确实存在,例如:In[75]:=
Function[Slot[1][[2, i]]] /. Map[List, Thread[HoldPattern[i] -> Range[5]]]
Out[75]= {#1[[2, 1]] &, #1[[2, 2]] &, #1[[2, 3]] &, #1[[2, 4]] &, #1[[2, 5]] &}
或
In[80]:= Block[{Part}, Function /@ Thread[Slot[1][[2, Range[5]]]]]
Out[80]= {#1[[2, 1]] &, #1[[2, 2]] &, #1[[2, 3]] &, #1[[2, 4]] &, #1[[ 2, 5]] &}
或
In[86]:= Replace[Table[{2, i}, {i, 5}], {inds__} :> (#[[inds]] &), 1]
Out[86]= {#1[[2, 1]] &, #1[[2, 2]] &, #1[[2, 3]] &, #1[[2, 4]] &, #1[[ 2, 5]] &}
但可能更加晦涩(也许除了最后一个)。
生成的嵌套列表具有适当的结构,带有子列表
{expr,{ind1,...,indn}}
处于水平 -3
(从底部算起第三层)。通过使用 Map[First,lst,{-3}]
,我们删除索引组合,因为嵌套列表已经被重建并且不再需要它们。剩下的是我们的结果——结果表达式的嵌套列表,其结构对应于由 Table
生成的类似嵌套列表的结构。 .最后一条语句被包裹在 AbortProtect
中- 以防万一,确保在可能的 Abort[]
之前返回结果火灾。使用示例
这是我按
Alt+.
的示例( Abort[]
) 在评估命令后不久:In[133]:= abortableTable[N[(1+1/i)^i],{i,20000}]//Short
Out[133]//Short= {2.,2.25,2.37037,2.44141,<<6496>>,2.71807,2.71807,2.71807}
它几乎和
Table
一样快:In[132]:= abortableTable[N[(1+1/i)^i,20],{i,10000}]//Short//Timing
Out[132]= {1.515,{2.0000000000000000000,2.2500000000000000000,<<9997>>,2.7181459268252248640}}
In[131]:= Table[N[(1+1/i)^i,20],{i,10000}]//Short//Timing
Out[131]= {1.5,{2.0000000000000000000,2.2500000000000000000,<<9997>>,2.7181459268252248640}}
但它不会自动编译
Table
做:In[134]:= Table[N[(1+1/i)^i],{i,10000}]//Short//Timing
Out[134]= {0.,{2.,2.25,2.37037,2.44141,<<9993>>,2.71815,2.71815,2.71815}}
可以对自动编译进行编码并将其添加到上述解决方案中,我只是没有这样做,因为要做好它需要做很多工作。
编辑
我重新编写了该函数,使某些部分更简洁、更易于理解。还,
在大型列表中,它比第一个版本快约 25%。
ClearAll[abortableTableAlt];
SetAttributes[abortableTableAlt, HoldAll];
abortableTableAlt[expr_, iter : {_Symbol, __} ..] :=
Module[{indices, indexedRes, sowTag, depth = Length[Hold[iter]] - 1},
Hold[iter] /. {sym_Symbol, __} :> sym /. Hold[syms__] :> (indices := {syms});
indexedRes = Replace[#, {x_} :> x] &@ Last@Reap[
CheckAbort[Do[Sow[{expr, indices}, sowTag], iter], Null],sowTag];
AbortProtect[
SplitBy[indexedRes, Array[Function[x, #[[2, x]] &], {depth}]][[##,1]] & @@
Table[All, {depth + 1}]
]];
关于wolfram-mathematica - Mathematica 表函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6470625/