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}}