Быстрый способ проверки типа Symbol в функции с аргументами - PullRequest
7 голосов
/ 01 мая 2011

Можно проверить, является ли аргумент символом без явного значения, используя:

func[s_Symbol] = ...

Если функция имеет атрибут Hold, этот шаблон будет соответствовать всем символам, а не только тем, у которых нет явного значения,Я мог бы использовать:

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

, но это приводит к большему снижению производительности, чем я хотел бы.Добавление правила для _Symbol оказывает довольно небольшое влияние на производительность, а HoldFirst, похоже, не снижает производительности, однако Head[s] === Symbol имеет значительные издержки на простую функцию.Тесты с ValueQ и MatchQ[s, _Symbol] еще медленнее.

Чтобы уточнить, я хочу иметь два разных определения для func , с одним для неназначенных символов, иодин для других аргументов.

Есть ли более быстрый путь?


Время:

f[x_] = 0;

f /@ Range@1*^6; // Timing

f[s_Symbol] = 1;

f /@ Range@1*^6; // Timing
<b>   {0.391, Null}</b>
<b>   {0.531, Null}</b>
Remove[f]
SetAttributes[f, HoldFirst]

f[x_] = 0;

f /@ Range@1*^6; // Timing

f[s_] /; Head[s] === Symbol = 1;

f /@ Range@1*^6; // Timing
<b>   {0.39, Null}</b>
<b>   {1.157, Null}</b>

Ответы [ 3 ]

6 голосов
/ 01 мая 2011

Вы можете получить производительность, сравнимую с самыми быстрыми выставленными временами выполнения, делегировав аргументы удерживаемого символа несдержанной вспомогательной функции g:

Remove[f, g]
SetAttributes[f, HoldFirst]
f[_] = 0;
f[s_Symbol] := g[s]
g[_Symbol] = 1;
g[_] = 0;
4 голосов
/ 01 мая 2011

Вы можете получить это быстрее с этим:

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}

Это будет более эффективно, когда ваши аргументы в основном не будут символами, и причина того, что они быстрее, заключается в том, что вы все равно можете использовать шаблон _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}}
4 голосов
/ 01 мая 2011

Использование шаблона s_Symbol в коде с атрибутом HoldFirst повысит производительность:

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