Mathematica 表函数 [英] Mathematica Table function

查看:33
本文介绍了Mathematica 表函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在运行一个 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 相同的迭代器语法(并且还动态本地化迭代器变量),同时是一个顺序(恒定内存)构造.为了收集中间结果,使用了ReapSow.由于 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[](此处为{})上执行的代码在这种方法中很大程度上是任意的,因为结果的收集无论如何都是由SowReap,虽然在更复杂的版本中可能很有用,它将结果保存到用户提供的某个变量中,然后重新发出 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆