当前位置 : 主页 > 网络安全 > 测试自动化 >

性能 – Mathematica中两个奇怪的效率问题

来源:互联网 收集:自由互联 发布时间:2021-06-22
第一个问题 我有时间计算以下语句需要多长时间(其中V [x]是一个耗时的函数调用): Alice = Table[V[i],{i,1,300},{1000}];Bob = Table[Table[V[i],{i,1,300}],{1000}]^tr;Chris_pre = Table[V[i],{i,1,300}];Chris = Table
第一个问题

我有时间计算以下语句需要多长时间(其中V [x]是一个耗时的函数调用):

Alice     = Table[V[i],{i,1,300},{1000}];
Bob       = Table[Table[V[i],{i,1,300}],{1000}]^tr;
Chris_pre = Table[V[i],{i,1,300}];
Chris     = Table[Chris_pre,{1000}]^tr;

爱丽丝,鲍勃和克里斯是相同的基质,计算3种略有不同的方式.我发现Chris的计算速度比Alice和Bob快1000倍.

Alice计算速度慢1000倍并不奇怪,因为天真地,函数V必须比计算Chris时多被调用1000次.但令人非常惊讶的是,Bob的速度非常慢,因为除了Chris存储中间步骤Chris_pre之外,他的计算方式与Chris完全相同.

鲍勃为什么评价这么慢?

第二个问题

假设我想在表单的Mathematica中编译一个函数

f(x)=x+y

其中“y”是在编译时固定的常量(但我不希望在代码中直接替换它的数字,因为我希望能够轻松地更改它).如果y的实际值是y = 7.3,我定义

f1=Compile[{x},x+y]
f2=Compile[{x},x+7.3]

然后f1比f2慢50%.当编译f1时,如何使Mathematica将“y”替换为“7.3”,以便f1以f2的速度运行?

编辑:

我找到了第二个问题的一个丑陋的解决方法:

f1=ReleaseHold[Hold[Compile[{x},x+z]]/.{z->y}]

肯定有更好的办法…

您可能应该将这些问题作为单独的问题发布,但不用担心!

问题一

Alice的问题当然是你的期望. Bob的问题是每次外部表的迭代都会评估内部表一次. Trace清晰可见:

Trace[Table[Table[i, {i, 1, 3}], {3}]]

{
Table[Table[i,{i,1,2}],{2}],
{Table[i,{i,1,2}],{i,1},{i,2},{1,2}},{Table[i,{i,1,2}],{i,1},{i,2},{1,2}},
{{1,2},{1,2}}
}

添加了换行符以强调,是的,Trace on Table的输出有点奇怪,但你可以看到它.很明显,Mathematica可以更好地优化它,因为知道外部表没有迭代器,但无论出于何种原因,它都没有考虑到这一点.只有克里斯做你想要的,尽管你可以修改鲍勃:

Transpose[Table[Evaluate[Table[V[i],{i,1,300}]],{1000}]]

这看起来实际上比Chris大约两倍左右,因为它不必存储中间结果.

问题二

使用Evaluate有一个更简单的解决方案,但我希望它不适用于所有可能编译的函数(即真正应该被保存的函数):

f1 = Compile[{x}, Evaluate[x + y]];

您还可以使用With:

With[{y=7.3},
    f1 = Compile[{x}, x + y];
]

或者,如果y在其他地方定义,请使用临时:

y = 7.3;
With[{z = y},
    f1 = Compile[{x}, x + z];
]

我不是Mathematica的范围和评估机制的专家,所以可以很容易地有一个更好的方法,但希望其中一个为你做到!

网友评论