Wolfram mathematica 在带有保留参数的函数中键入检查符号的快速方法
可以使用以下方法测试参数是否为无显式值的符号:Wolfram mathematica 在带有保留参数的函数中键入检查符号的快速方法,wolfram-mathematica,typechecking,Wolfram Mathematica,Typechecking,可以使用以下方法测试参数是否为无显式值的符号: func[s_Symbol] = ... 但是,如果函数具有Hold属性,则该模式将匹配所有符号,而不仅仅是那些没有显式值的符号。我可以使用: func[s_] /; Head[s] === Symbol = ... 但这带来了比我希望的更大的性能损失。为\u Symbol添加规则对性能的影响相当小,HoldFirst似乎没有任何性能损失,但是Head[s]==Symbol在一个简单函数上有很大的开销。使用ValueQ和MatchQ[s,\u
func[s_Symbol] = ...
但是,如果函数具有Hold属性,则该模式将匹配所有符号,而不仅仅是那些没有显式值的符号。我可以使用:
func[s_] /; Head[s] === Symbol = ...
但这带来了比我希望的更大的性能损失。为\u Symbol
添加规则对性能的影响相当小,HoldFirst
似乎没有任何性能损失,但是Head[s]==Symbol
在一个简单函数上有很大的开销。使用ValueQ
和MatchQ[s,\u Symbol]
的测试更慢
为了澄清,我想对func
有两个不同的定义,一个用于未赋值符号,另一个用于其他参数
有没有更快的方法?
时间: {0.39,Null}
{1.157,Null}在具有
HoldFirst
属性的代码中使用模式s_符号
,将提高性能:
In[121]:= Remove[f]
SetAttributes[f, HoldFirst]
f[s_Symbol] /; Head[s] === Symbol = 1;
f[_] = 0;
In[125]:= f /@ Range@1*^6; // Timing
Out[125]= {1.217, Null}
In[130]:= Remove[f2]
f2[s_Symbol] = 1;
f2[_] = 0;
In[133]:= f2 /@ Range@1*^6; // Timing
Out[133]= {1.123, Null}
通过将保留的符号参数委托给非保留的辅助函数
g
,可以获得与最快运行时间相当的性能:
Remove[f, g]
SetAttributes[f, HoldFirst]
f[_] = 0;
f[s_Symbol] := g[s]
g[_Symbol] = 1;
g[_] = 0;
您可以通过以下方式更快地完成:
ClearAll[f];
SetAttributes[f, HoldFirst]
f[x_] = 0;
f[s_Symbol] /; OwnValues[s] =!= {} = 1;
为了进行比较,这里是您使用的:
ClearAll[ff];
SetAttributes[ff, HoldFirst]
ff[x_] = 0;
ff[s_] /; Head[s] === Symbol = 1;
现在:
当您的参数主要是非符号时,这将更加有效,而且速度更快的原因是您仍然可以使用\u Symbol
模式来过滤它们。仅对于符号列表,实际速度可能较慢:
symbTest = Table[ToExpression["sym" <> ToString[i]], {i, 100000}];
MapIndexed[If[OddQ[First@#2], #1 = First@#2] &, symbTest];
In[54]:= ReleaseHold[Map[f,Hold[symbTest]/.OwnValues[symbTest],{2}]]//Short//Timing
Out[54]= {0.234,{1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,<<99964>>,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0}}
In[58]:= ReleaseHold[Map[ff,Hold[symbTest]/.OwnValues[symbTest],{2}]]//Short//Timing
Out[58]= {0.141,{0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,<<99964>>,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}}
symbTest=Table[ToExpression[“sym”ToString[i],{i,100000}];
MapIndexed[If[OddQ[First@#2],#1=First@#2]&,symbTest];
在[54]中:=ReleaseHold[Map[f,Hold[symbTest]/.OwnValues[symbTest],{2}]///Short//计时
Out[54]={0.234,{1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0}
在[58]:=ReleaseHold[Map[ff,Hold[symbTest]/.OwnValues[symbTest],{2}]///Short//计时
Out[58]={0.141,{0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1}
有趣的factoid。没有意识到类型检查会带来如此大的开销。@Sjoerd我不是说这是一个factoid,这是一个真正的问题。大多数函数都足够复杂,开销相对较小,但在简单的情况下,开销可能相当大。@Sjoerd在这里,让我提一下,在某些情况下,正确使用模式匹配器进行类型检查是至关重要的。考虑:tst=Range[10^6];MatchQ[tst,{{uu Integer}]//定时;和@@Map[Head[#]==Integer&,tst]//计时
。这有点欺骗,因为显著的差异是由于数组的压缩性质造成的,但即使在数组未压缩的情况下,仍然可以得到因子10或其他值。例如,当您需要确定一个函数的输入是一个整数列表时,这一点很重要。@Sjoerd-我从未听说过“Factoid”这个词,但我喜欢它,因为它听起来像“Groupoid”。无论如何,我检查了它的意思:“factoid是一个可疑的或虚假的、未经验证的、不正确的或捏造的陈述,作为一个事实呈现,但没有真实性。”-嗯。@ndroock1有趣;“factoid”与“verbage”类似,因为我听说这两个词都用错了,而不是“fact”和“verbiage”。我认为这会让事情变得更慢,因为它实际上被检查了两次。我应该知道,用Mathematica测试和观察总是最好的+1@Mr.Wizard为什么USENGNECTOS> SyLoad < /C>提高性能是因为它很快拒绝显式的非符号。不像Shasha的方法,在尝试之前我愚蠢地拒绝了,我甚至没有考虑过。像许多伟大的想法一样,事后看起来非常简单。这里有趣地使用了OwnValues
,并对列表内容进行了很好的分析。关于f[s_Symbol]/;头[s]==Symbol
与f[s_Symbol]/;OwnValues[s]=!={}
?@Mr.Wizard我的测试表明,在x=Fold[{1,{2}}&,0,Range[10000]]上,测试Head[s]==Symbol
要快一点代码>。然后Do[TestWithOwnValues[x],{10^6}]//绝对计时
给出2.9秒,而Do[TestWithHead[x],{10^6}]//绝对计时
在2.4秒内完成。@Sasha,@Mr.Wizard,但@Sasha的观察恰恰是我在回答中警告的——重点不在于使用OwnValues
,但在过滤非符号或具有快速值的符号的能力方面。如果有什么不同的话,这告诉我们关于模式匹配器内部的情况:在计算条件下的测试之前,像\u Symbol
这样的显式模式显然会被检查,这对我来说非常有意义。
{1.157, Null}
In[121]:= Remove[f]
SetAttributes[f, HoldFirst]
f[s_Symbol] /; Head[s] === Symbol = 1;
f[_] = 0;
In[125]:= f /@ Range@1*^6; // Timing
Out[125]= {1.217, Null}
In[130]:= Remove[f2]
f2[s_Symbol] = 1;
f2[_] = 0;
In[133]:= f2 /@ Range@1*^6; // Timing
Out[133]= {1.123, Null}
Remove[f, g]
SetAttributes[f, HoldFirst]
f[_] = 0;
f[s_Symbol] := g[s]
g[_Symbol] = 1;
g[_] = 0;
ClearAll[f];
SetAttributes[f, HoldFirst]
f[x_] = 0;
f[s_Symbol] /; OwnValues[s] =!= {} = 1;
ClearAll[ff];
SetAttributes[ff, HoldFirst]
ff[x_] = 0;
ff[s_] /; Head[s] === Symbol = 1;
In[30]:= f /@ Range@1*^6; // Timing
Out[30]= {0.719, Null}
In[56]:= ff /@ Range@1*^6; // Timing
Out[56]= {1.25, Null}
symbTest = Table[ToExpression["sym" <> ToString[i]], {i, 100000}];
MapIndexed[If[OddQ[First@#2], #1 = First@#2] &, symbTest];
In[54]:= ReleaseHold[Map[f,Hold[symbTest]/.OwnValues[symbTest],{2}]]//Short//Timing
Out[54]= {0.234,{1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,<<99964>>,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0}}
In[58]:= ReleaseHold[Map[ff,Hold[symbTest]/.OwnValues[symbTest],{2}]]//Short//Timing
Out[58]= {0.141,{0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,<<99964>>,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}}