tel*_*f14 14 wolfram-mathematica package
关于封装设计的性能和可扩展性,最好是:
Mathematica的表现力经常让我感到困惑,就像这样的愚蠢(?)问题.
WRe*_*ach 11
这是一个广泛的问题,但我将借此机会给出一个广泛的答案......
我主张人们应该接受编程语言的主要范式,而不是试图对抗它或编写遵循另一种语言习语的代码.Mathematica是围绕模式匹配的概念构建的,因此,恕我直言,我们应该在尝试表达自己时始终首先考虑模式匹配.遵循这一原则,我赞成定义Switch
.
关于性能问题,在比较Mathematica结构时越来越强调微基准测试,我越来越感到烦恼.虽然了解与构造相关的成本是有价值的,但我们应该注意Knuth(或者是Hoare?):"我们应该忘记效率低,大约97%的时间说:过早的优化是所有邪恶的根源"."邪恶"是程序中可读性的丧失,为了效率,它使用一些模糊或间接的方法来实现效果.这是我的表现清单:
性能是一个问题吗?如果没有,那么跳过清单的其余部分.
性能瓶颈在哪里?分析器在这里有所帮助,但通常可以通过检查或一些打印语句轻松找到瓶颈.然后...
算法效率低下吗?非常频繁:是否存在可以通过索引方案线性化或帮助的双嵌套循环?
好的,算法很好所以我想是时候进行microbenchmark了.
我不知道我对Mathematica的使用是否不够雄心勃勃,但大部分时间我都没有超越第一步.然后#3抓住了剩下的大部分.在Mathematica中,我发现我通常只是喜出望外,我可以用少量代码执行一些雄心勃勃的任务 - 整体表现通常不会进入画面.
哦 - 哦,我最好把肥皂盒拿走.抱歉,那个.
除了非常简单的情况,我更喜欢使用具有多个定义的函数而不是Switch
.原因有三:
编辑
这是一个作为Sjoerd的#2示例创建的示例:
createNColors[fn_, Automatic, n_] := Table[Hue[i/n], {i, n}]
createNColors[fn_, colors_List, n_] := PadRight[colors, n, colors]
createNColors[fn_, color:(Hue | RGBColor | CMYKColor | GrayLevel)[__], n_] :=
Table[color, {n}]
createNColors[fn_, color_, n_] := (
Message[fn::"color", HoldForm[color]];
createNColors[fn, Automatic, n]
)
Run Code Online (Sandbox Code Playgroud)
它可用于为某些选项生成一组n种颜色.
要回答问题的性能部分,请考虑以下两个重载和使用示例 Switch[]
switchFunc[a_] := Switch[a, _String, 5, _Integer, var, _Symbol, "string"]
overloadFunc[a_String] := 5;
overloadFunc[a_Integer] := var;
overloadFunc[a_Symbol] := "string";
Run Code Online (Sandbox Code Playgroud)
这是非常简化的,但足以证明性能的差异
In[1] := Timing@Nest[switchFunc, x, 1000000]
Out[1] := {3.435, "string"}
In[2] := Timing@Nest[overloadFunc, x, 1000000]
Out[2] := {0.754, "string"}
Run Code Online (Sandbox Code Playgroud)
但是,如果您打算基于条件测试重载您的函数,则性能会比Switch[]
以下情况更糟:
switchFunc2[a_] := Switch[a < 5, True, 6, False, 4];
overloadFunc2[a_ /; a < 5] := 6;
overloadFunc2[a_ /; a > 5] := 4;
overloadFunc2[a_] := a;
In[3] := Timing@Nest[switchFunc2, 4, 1000000]
Out[3] := {2.63146, 4}
In[4] := Timing@Nest[overloadFunc2, 6, 1000000]
Out[4] := {4.349, 6}
Run Code Online (Sandbox Code Playgroud)
编辑:这个答案的时间是在OS X 10.7.2上使用Mathematica 8.0.1完成的.有关上述顺序相反的其他结果,请参阅Mr.Wizard的答案.尽管如此,我认为对函数参数进行逻辑模式检查是明智的.
从设计的角度来看,我的个人经历就是这样,Switch[]
而且它很糟糕,因为它们难以阅读和缓慢.但是,我也认为根据参数的类型使相同的函数执行不同通常是糟糕的设计,并使得更难以遵循您的代码(即使它可能更容易阅读).
你写的问题很模糊,对"重载"有不同的解释会改变我的答案.但是,如果您正在讨论关于不同类型(头部)和参数模式的重载您自己的函数,那么无论如何都要利用Mathematica紧密集成的模式匹配.
为了提供一个实际的例子,我将使用我的这个解决方案.以供参考:
f[k_, {}, c__] := If[Plus[c] == k, {{c}}, {}]
f[k_, {x_, r___}, c___] := Join @@ (f[k, {r}, c, #] & /@ Range[0, Min[x, k - Plus[c]]])
Run Code Online (Sandbox Code Playgroud)
如果我在f
没有模式匹配的情况下重写并调用它g
:
g = Function[{k, L, c},
If[L === {},
If[Tr@c == k, {c}, {}],
Join @@ (g[k, Rest@L, Append[c, #]] & /@ Range[0, Min[First@L, k - Tr@c]])
]
];
Run Code Online (Sandbox Code Playgroud)
我觉得这不太清楚,写作肯定不太方便.我不得不使用显式Rest
和First
函数,我不得不介绍,Append
因为我无法容纳可变数量的参数.这也需要使用虚拟的第三个参数:{}
.
Timings表明原始形式也快得多:
f[12, {1, 5, 8, 10, 9, 9, 4, 10, 8}]; // Timing
g[12, {1, 5, 8, 10, 9, 9, 4, 10, 8}, {}]; // Timing
Run Code Online (Sandbox Code Playgroud)
{0.951, Null}
{1.576, Null}
为了回应蒂莫的回答,我认为分享我的时间结果是有价值的,因为它们与他的不同.(我在Windows 7上使用的是Mathematica 7.)此外,我认为他将DownValues版本复杂化,超出了Switch版本的功能.
首先,我的函数编写时间,但使用一系列值:
Array[switchFunc2, 1*^6]; // Timing
Array[overloadFunc2, 1*^6]; // Timing
Run Code Online (Sandbox Code Playgroud)
{1.014, Null}
{0.749, Null}
所以即使写完,DownValues函数对我来说也更快.但不需要第二个条件:
ClearAll[overloadFunc2]
overloadFunc2[a_ /; a < 5] := 6;
overloadFunc2[a_] := 4;
Array[overloadFunc2, 1*^6]; // Timing
Run Code Online (Sandbox Code Playgroud)
{0.546, Null}
当然,在这种简单功能的情况下,也可以使用If
:
ifFunc[a_] := If[a < 5, 6, 4]
Array[ifFunc, 1*^6]; // Timing
Run Code Online (Sandbox Code Playgroud)
{0.593, Null}
如果这是作为Mathematica在Array中编译的纯函数编写的:
ClearAll[ifFunc]
ifFunc = If[# < 5, 6, 4] &;
Array[ifFunc, 1*^6]; // Timing
Run Code Online (Sandbox Code Playgroud)
{0.031, Null}
归档时间: |
|
查看次数: |
2024 次 |
最近记录: |