制作表格的速度差异

Nas*_*ser 14 wolfram-mathematica

我正在WRI博客上阅读一篇关于提高代码速度的有用帖子,我需要帮助才能理解这一点.

比较这些速度

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

{0.031, Null}
Run Code Online (Sandbox Code Playgroud)

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

{0.422, Null}
Run Code Online (Sandbox Code Playgroud)

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

但我的问题是:上述实际上会如何运作,因为Table必须在某一点上限制必须成为数字?我写不出来

Clear[a]
tbl = Table[i + j, {i, 1, a}, {j, 1, a}]
Run Code Online (Sandbox Code Playgroud)

以上给出了错误.

所以,对我来说,写作a=1000外部Table与内部,应该没有区别,因为没有a数值,Table[]就无能为力.因此,a数字1000 的替换必须由评估者在一个时间点发生,然后Table[]才能做任何有用的事情,不是吗?

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

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

  1. Evaluator a在表的参数中替换1000
  2. Evaluator调用Table结果,现在全部是数字.
  3. 表编译,现在运行得更快.

但似乎发生的事情是别的.(由于HoldAll?)

  1. Table按原样获取其参数.因为它有HoldAll,所以它看到的a不是1000.
  2. 它不会调用Compile,因为它的参数不是所有数字.
  3. 它现在生成一个具有a限制的表,Evaluator的计算结果a为1000
  4. 现在生成表所有限制都是数字,但现在因为代码未编译而变慢.

问题是:上面会发生什么?有人可以解释为解释这种时间差异而发生的步骤吗?

另外,在上面的例子中,如果使用变量作为限制,如何确保在两种情况下Table都被编译?并不总是可以对表限制的数字进行硬编码,但有时必须使用变量.应该明确使用 Compile命令吗?(我不Compile直接使用,因为我认为它是在需要时自动完成的).

编辑(1)

在回答Mike的帖子时,发现在使用呼叫时没有时间差异.

ClearAll[tblFunc];
Timing[a = 1000;
 tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
 Developer`PackedArrayQ[tblFunc[a]]
 ]
Run Code Online (Sandbox Code Playgroud)

{0.031, True}
Run Code Online (Sandbox Code Playgroud)

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

如果我们强制通过引用调用a,那么就不会被评估,那么我们就得到了

ClearAll[tblFunc];
Timing[a = 1000;
 tblFunc[a_] := Table[i + j, {i, 1, a}, {j, 1, a}];
 Developer`PackedArrayQ[tblFunc[Unevaluated@a]]
 ]
Run Code Online (Sandbox Code Playgroud)

现在我们看到了预期的结果,因为现在a仍然是象征性的INSIDE函数,我们又回到了原点,现在它很慢,因为没有打包.由于它没有打包,因此不使用Compile.

{0.437, False}
Run Code Online (Sandbox Code Playgroud)

编辑(2) 感谢大家的答案,我想我从他们那里学到了很多东西.

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

在此输入图像描述

编辑(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. /sf/ask/330482001/
  4. 在Mathematica中使用数组和表函数.哪个是最好的

Tim*_*imo 16

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

Trace[a = 3;
      tbl = Table[i + j, {i, 1, a}, {j, 1, a}];
     ]
Run Code Online (Sandbox Code Playgroud)

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

回答你对速度的跟进; tbl对于数字和符号限制,使函数更快.

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

{0.045171, Null}
Run Code Online (Sandbox Code Playgroud)

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

如果您打算重复使用该tbl结构,您将获得更快的速度.

b=1000;
Timing[tblFunc[b];]
{0.000013, Null}
Run Code Online (Sandbox Code Playgroud)

  • 我认为tblFunc很快,因为定义函数的SetDelayed在评估tblFunc时就像With一样,即.在评估rhs表达式之前,a由其数值替换.因此,我们可以将限制作为一个符号参数,但仍然可以回到数值论证的情况. (3认同)