制作表格的速度差异

时间:2012-01-03 07:33:04

标签: wolfram-mathematica

我正在阅读a useful post at WRI blog on improving speed of code,我需要帮助才能理解这一点。

比较这些速度

Timing[
 tbl = Table[i + j, {i, 1, 1000}, {j, 1, 1000}];     
]

{0.031, Null}

Timing[
 a = 1000;
 tbl = Table[i + j, {i, 1, a}, {j, 1, a}];
 ]

{0.422, Null}

因此,当将表中的限制的实际值与外部相比时,它会快得多。对此的解释,我确信它是正确的,但我需要帮助理解,如果Table的限制是数字而不是数字,则编译HoldAll,这是因为它的属性是Table

但我的问题是:上述实际上会如何运作,因为Clear[a] tbl = Table[i + j, {i, 1, a}, {j, 1, a}] 的限制必须在某一时刻成为数字?我不能写

a=1000

上面给出了错误。

所以,对我来说,在Table与内部之间写a应该没有区别,因为如果Table[]没有数值,a就不能做任何事情。因此,在Table[]可以做任何有用的事情之前,评估者必须在一个时间点替换Table,不是吗?

换句话说,{i, 1, 1000}, {j, 1, 1000}最终应该看到的是a两种情况。

所以,我认为这种情况会发生的方式是:

  1. Evaluator在表
  2. 的参数中将Table替换为1000
  3. 评估员使用结果调用HoldAll,结果现在全部为数字。
  4. 表格编译,现在运行得更快。
  5. 但似乎发生的事情是别的。 (由于a?)

    1. Table按原样获取其参数。由于它具有HoldAll,因此它会看到a而不是1000。
    2. 它不会调用Compile,因为它的参数不是所有数字。
    3. 现在生成一个a限制的表,Evaluator评估Compile为1000
    4. 现在生成表格所有限制都是数字,但由于代码未编译,因此现在速度较慢。
    5. 问题是:上述情况会发生什么?有人可以解释为解释这种时间差异而发生的步骤吗?

      另外,在上面的例子中,如何确保表格在两种情况下都被编译,即使一个人使用变量作为限制?并不总是可以对表限制的数字进行硬编码,但有时必须使用变量。是否应该明确使用Compile命令? (我不直接使用ClearAll[tblFunc]; Timing[a = 1000; tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}]; Developer`PackedArrayQ[tblFunc[a]] ] ,因为我认为它是在需要时自动完成的。

      修改(1)

      在回答Mike的帖子时,发现使用电话的时间没有差异。

      {0.031, True}
      

      给出

      a

      但这是因为1000现在是函数的a数字,一旦调用它。由于M通过VALUE传递东西。

      如果我们强制通过引用进行调用,以便ClearAll[tblFunc]; Timing[a = 1000; tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}]; Developer`PackedArrayQ[tblFunc[Unevaluated@a]] ] 未被评估,那么我们就会

      a

      现在我们看到了预期的结果,因为现在{0.437, False} 仍然是符号INSIDE函数,我们回到原点,现在它很慢,因为没有打包。由于它没有打包,因此不使用编译。

      {{1}}

      修改(2) 感谢大家的答案,我想我是从他们那里学到的。

      这是一份执行摘要,只是为了确保我把一切都搞定。

      enter image description here

      修改(3)

      以下链接我特别关注用于使Mathematica代码运行得更快的提示。

      1. http://library.wolfram.com/howtos/faster/
      2. http://blog.wolfram.com/2011/12/07/10-tips-for-writing-fast-mathematica-code/
      3. https://stackoverflow.com/questions/4721171/performance-tuning-in-mathematica
      4. Using Array and Table Functions in Mathematica. Which is best when

3 个答案:

答案 0 :(得分:16)

所以这就是我认为正在发生的事情。您在Table上看到数字和符号限制之间的减速的原因是由于您执行双索引。每个子表(例如,遍历所有索引j以获得固定索引i)是单独构造的,当限制是符号时,在构造每个子表之前需要额外的步骤来确定该限制。您可以通过检查,例如,

Trace[a = 3;
      tbl = Table[i + j, {i, 1, a}, {j, 1, a}];
     ]

David给出了一个很好的例子,说明为什么要对每个子列表进行此检查。至于为什么 Mathematica 无法弄清楚何时不需要这项检查,我不知道。如果只有一个索引可以求和,那么符号和数字版本之间的速度没有区别

Timing[tbl = Table[i + j, {j, 1, 1000}];]
{0.0012, Null}

Timing[a = 1000;
       tbl = Table[i + j, {j, 1, a}];
      ]
{0.0013, Null}

回答有关速度的跟进;使tbl函数对数字和符号限制都更快。

Timing[a = 1000;
       tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
       tblFunc[a];
      ]

{0.045171, Null}

VS

Timing[tbl = Table[i + j, {i, 1, 1000}, {j, 1, 1000}];]
{0.066864, Null}

Timing[a = 1000;
       tbl = Table[i + j, {i, 1, a}, {j, 1, a}];
      ]
{0.632128, Null}

如果您打算重复使用tbl构造,可以获得更快的速度。

b=1000;
Timing[tblFunc[b];]
{0.000013, Null}

答案 1 :(得分:3)

正如其他人所提到的,要监控的关键事项是打包和列表长度。我实际上没有看到蒂莫报告的差异:

ClearAll[tblFunc];
Timing[a = 1000;
 tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
 Developer`PackedArrayQ[tblFunc[a]]]

{0.077706, True}

vs

ClearAll[tbl];
Timing[
 tbl = Table[i + j, {i, 1, 1000}, {j, 1, 1000}];
 Developer`PackedArrayQ[tbl]]

{0.076661, True}

ClearAll[tbl];
Timing[a = 1000;
 tbl = Table[i + j, {i, 1, a}, {j, 1, a}];
 Developer`PackedArrayQ[tbl]]

{1.02879, False}

所以对我而言,唯一的区别是列表是否已打包。它是否是一个功能对我的设置时间没有任何影响。正如预期的那样,当您关闭自动编译时,上述所有时间都是相同的,因为没有打包:

SetSystemOptions["CompileOptions" -> {"TableCompileLength" -> Infinity}];

{1.05084, False}

vs

{1.00348, False}

{1.01537, False}

重置表自动编译长度:

SetSystemOptions["CompileOptions" -> {"TableCompileLength" -> 250}]

答案 2 :(得分:2)

这有点OT,但是为了提高速度,您可能希望避免使用在使用Table时隐含的逐项处理。相反,使用外部。这是我在我的系统上看到的内容:

   Timing[Outer[Plus, Range[5000], Range[5000]];]
{0.066763,Null}

   Timing[Table[i + j, {i, 1, 5000}, {j, 1, 5000}];]
{0.555197,Null}

相当显着的差异。