Mathematica 表函数 [英] Mathematica Table function
问题描述
我正在运行一个 Table 函数,它需要很长时间才能完成.
I'm running a Table function which will take too much time to complete.
我想知道是否有办法检索到目前为止计算出的结果.
I wanted to know if there's a way to retrieve the results computed so far.
推荐答案
建议的解决方案
这是 Table
的一个版本,它是 Abort
-able 并且将保留到目前为止收集的中间结果.这是发布的解决方案的修改版本 此处.
The proposed solution
Here is a version of Table
that is Abort
-able and will keep the intermediate results collected so far. It is a modified version of the solution posted 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
相同的迭代器规范.
It should be able to take the same iterator specification as Table
.
这是它的工作原理.第一条语句 (SetDelayed @@...
) 解析"迭代器,假设它们都是 {iteratorSymbol_,bounds__}
形式,并分配变量indices
的迭代器变量.需要使用 Hold
构造以防止可能的迭代器变量求值.有很多方法可以做到这一点,我只使用了其中一种.这是它的工作原理:
Here is how it works. The first statement (SetDelayed @@...
) "parses" the iterators, assuming that they are each of the form {iteratorSymbol_,bounds__}
, and assigns the list of iterator variables to the variable indices
. The construction with Hold
is needed to prevent possible evaluation of iterator variables. There are many ways to do this, I used just one of them. Here is how it works:
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
以证明在使用此构造时不会对它们进行不需要的评估.
Using SetDelayed @@ the-above
will then naturally produce the delayed definition of the form indices:={i,j,k}
. I assigned the values to indices i,j,k
to demonstrate that no unwanted evaluation of them happens when using this construct.
下一个语句生成一个收集结果的列表,其中每个结果都分组在一个列表中,其中包含用于生成它的索引列表.由于 indices
变量是由延迟定义定义的,它每次都会重新评估,以获取新的索引组合.这里使用的另一个关键特性是 Do
循环接受与 Table
相同的迭代器语法(并且还动态本地化迭代器变量),同时是一个顺序(恒定内存)构造.为了收集中间结果,使用了Reap
和Sow
.由于 expr
可以是任何一段代码,特别是也可以使用 Sow
,因此只需要一个具有唯一名称的自定义标签才能Reap
那些由我们的函数Sown
而不是它执行的代码的值.由于 Module
自然地生成具有唯一名称的(临时)符号,我只是使用了一个 Module
- 生成的没有值的变量作为标记.这是一种普遍有用的技术.
The next statement produces a list of collected results, where each result is grouped in a list with the list of indices used to produce it. Since indices
variable is defined by delayed definition, it will evaluate every time afresh, for a new combination of indices. Another crucial feature used here is that the Do
loop accepts the same iterator syntax as Table
(and also dynamically localizes the iterator variables), while being a sequential (constant memory) construct. To collect the intermediate results, Reap
and Sow
were used. Since expr
can be any piece of code, and can in particular also use Sow
, a custom tag with a unique name is needed to only Reap
those values that were Sown
by our function, but not the code it executes. Since Module
naturally produces (temporary) symbols with unique name, I simply used a Module
- generated variable without a value, as a tag. This is a generally useful technique.
为了能够在用户交互式或代码中发出Abort[]
的情况下收集结果,我们将Do
循环包裹在中检查中止
.在Abort[]
(此处为{}
)上执行的代码在这种方法中很大程度上是任意的,因为结果的收集无论如何都是由Sow完成的code> 和
Reap
,虽然在更复杂的版本中可能很有用,它将结果保存到用户提供的某个变量中,然后重新发出 Abort[]
(当前未实现的功能).
To be able to collect the results in the case of Abort[]
issued by the user interactively or in the code, we wrap the Do
loop in CheckAbort
. The code that is executed on Abort[]
({}
here) is largely arbitrary in this approach, since the collection of results is anyway done by Sow
and Reap
, although may be useful in a more elaborate version that would save the result into some variable provided by the user and then re-issue the Abort[]
(the functionality not currently implemented).
结果,我们得到了一个变量 indexedRes
一个形式为
As a result, we get into a variable indexedRes
a flat list of the form
{{expr1, {ind11,ind21,...indn1}},...,{exprk, {ind1k,ind2k,...indnk}}
其中结果与相应的索引组合分组.我们需要这些索引组合来从平面列表重建多维结果列表.这样做的方法是根据 i
-th 个索引的值重复拆分列表.函数 SplitBy
具有此功能,但我们需要提供用于拆分步骤的函数列表.由于子列表{expr,{ind1,...,indn}}
中第i
个迭代器索引的索引为2,i
,在i
-th step进行分裂的函数是#[[2, i]]&
,我们需要动态构造这些函数的列表来将其提供给 SplitBy
.下面是一个例子:
where the results are grouped with the corresponding index combination. We need these index combinations to reconstruct the multi-dimensional resulting list from a flat list. The way to do it is to repeatedly split the list according to the value of i
-th index. The function SplitBy
has this functionality, but we need to provide a list of functions to be used for splitting steps. Since the index of i
-th iterator index in the sublist {expr,{ind1,...,indn}}
is 2,i
, the function to do the splitting at i
-th step is #[[2, i]]&
, and we need to construct the list of such functions dynamically to feed it to SplitBy
. Here is an example:
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]
结构用于在纯函数中注入 i
的特定值.将 i
的值注入 Function
的替代方法确实存在,例如:
The With[{i=i},body]
construct was used to inject the specific values of i
inside pure functions. The alternatives to inject the value of i
into Function
do exist, such as e.g.:
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]] &}
但可能更加晦涩(也许除了最后一个).
but are probably even more obscure (perhaps except the last one).
生成的嵌套列表具有适当的结构,子列表 {expr,{ind1,...,indn}}
位于级别 -3
(从底部).通过使用 Map[First,lst,{-3}]
,我们删除了索引组合,因为嵌套列表已经被重建并且不再需要它们.剩下的是我们的结果 - 结果表达式的嵌套列表,其结构对应于由 Table
生成的类似嵌套列表的结构.最后一条语句包含在 AbortProtect
中 - 以防万一,以确保在可能的 Abort[]
触发之前返回结果.
The resulting nested list has a proper structure, with sublists {expr,{ind1,...,indn}}
being at level -3
(third level from the bottom). By using Map[First,lst,{-3}]
, we remove the index combinations, since the nested list has been reconstructed already and they are no longer needed. What remains is our result - a nested list of resulting expressions, whose structure corresponds to the structure of a similar nested list produced by Table
. The last statement is wrapped in AbortProtect
- just in case, to make sure that the result is returned before the possible Abort[]
fires.
这是我在评估命令后不久按下 Alt+.
(Abort[]
) 的示例:
Here is an example where I pressed Alt+.
(Abort[]
) soon after evaluating the command:
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
会:
But it does not auto-compile while Table
does:
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}}
可以编写自动编译并将其添加到上述解决方案中,我只是没有这样做,因为要正确执行需要很多工作.
One can code the auto-compilation and add it to the above solution, I just did not do it since it will be a lot of work to do it right.
编辑
我重新编写了函数,使某些部分更加简洁和易于理解.还,在大型列表中,它比第一个版本快约 25%.
I rewrote the function to make some parts both more concise and easier to understand. Also, it is about 25 % faster than the first version, on large lists.
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}]
]];
这篇关于Mathematica 表函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!