Quick way to enter validation Symbol in function with held arguments

You can check if the argument is a character without an explicit value using:

func[s_Symbol] = ... 

If the function has the Hold attribute, this pattern will correspond to all characters, and not just those who do not have an explicit value. I could use:

 func[s_] /; Head[s] === Symbol = ... 

but this is due to a greater decrease in performance than we would like. Adding a rule for _Symbol has little effect on performance, and HoldFirst does not have any performance HoldFirst , however, Head[s] === Symbol has significant overhead for a simple function. Tests with ValueQ and MatchQ[s, _Symbol] even slower.

To clarify, I want to have two different definitions for func , one for unassigned characters and one for the other arguments.

Is there a faster way?


Timings:

 f[x_] = 0; f /@ Range@1 *^6; // Timing f[s_Symbol] = 1; f /@ Range@1 *^6; // Timing 
  {0.391, Null} 
  {0.531, Null} 
 Remove[f] SetAttributes[f, HoldFirst] f[x_] = 0; f /@ Range@1 *^6; // Timing f[s_] /; Head[s] === Symbol = 1; f /@ Range@1 *^6; // Timing 
  {0.39, Null} 
  {1.157, Null} 
+7
source share
3 answers

Using the s_Symbol template in code with the HoldFirst attribute will improve performance:

 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} 
+4
source

You can get performance comparable to the fastest set working hours by delegating the arguments of the character being held to the non-fixed helper function g :

 Remove[f, g] SetAttributes[f, HoldFirst] f[_] = 0; f[s_Symbol] := g[s] g[_Symbol] = 1; g[_] = 0; 
+6
source

This can be dealt with faster:

 ClearAll[f]; SetAttributes[f, HoldFirst] f[x_] = 0; f[s_Symbol] /; OwnValues[s] =!= {} = 1; 

To compare, here is the one you used:

 ClearAll[ff]; SetAttributes[ff, HoldFirst] ff[x_] = 0; ff[s_] /; Head[s] === Symbol = 1; 

Now:

 In[30]:= f /@ Range@1 *^6; // Timing Out[30]= {0.719, Null} In[56]:= ff /@ Range@1 *^6; // Timing Out[56]= {1.25, Null} 

This will be more efficient if your arguments are mostly non-characters, and the reason why this happens faster is that you can still use the _Symbol template to filter them. For character lists only, this can be slower:

 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}} 
+4
source

All Articles