Относительно снижения производительности (так как на ваш первый вопрос уже был дан ответ) - обязательно делайте проверки, но в ваших функциях верхнего уровня (которые получают данные непосредственно от пользователя вашей функциональности. Пользователь также может быть другой независимый модуль, написанный вами или кем-то еще). Не помещайте эти проверки во все ваши промежуточные функции, так как такие проверки будут повторяться и действительно неоправданны.
EDIT
Для решения проблемы ошибок в промежуточных функциях, поднятой @Nasser в комментариях: существует очень простая техника, позволяющая включать и выключать проверки шаблонов «одним щелчком мыши». Вы можете хранить ваши шаблоны в переменных внутри вашего пакета, определенных до определения вашей функции.
Вот пример, где f
- это функция верхнего уровня, а g
и h
- "внутренние функции". Мы определяем два шаблона: для основной функции и для внутренних, например:
Clear[nlPatt,innerNLPatt ];
nlPatt= _?(!VectorQ[#,NumericQ]&);
innerNLPatt = nlPatt;
Теперь мы определим наши функции:
ClearAll[f,g,h];
f[vector:nlPatt]:=g[vector]+h[vector];
g[nv:innerNLPatt ]:=nv^2;
h[nv:innerNLPatt ]:=nv^3;
Обратите внимание, что шаблоны заменяются внутри определений во время определения , а не во время выполнения, так что это в точности эквивалентно кодированию этих шаблонов вручную. После того, как вы протестируете, вам просто нужно изменить одну строку: с
innerNLPatt = nlPatt
до
innerNLPatt = _
и перезагрузите пакет.
И последний вопрос: как быстро найти ошибки? Я ответил, что здесь , в разделах "Вместо возврата $Failed
можно выдать исключение, используя Throw." и "Мета-программирование и автоматизация" .
END EDIT
Я включил краткое обсуждение этого вопроса в мою книгу здесь . В этом примере снижение производительности было на уровне 10% увеличения времени выполнения, что IMO является погранично приемлемым. В данном случае проверка проще, а снижение производительности намного меньше. Как правило, для функции, требующей большого объема вычислений, правильно написанные проверки типа стоят лишь небольшую долю от общего времени выполнения.
Несколько трюков, которые стоит знать:
- Pattern-matcher может быть очень быстрым, если используется синтаксически (в шаблоне нет
Condition
или PatternTest
).
Например:
randomString[]:=FromCharacterCode@RandomInteger[{97,122},5];
rstest = Table[randomString[],{1000000}];
In[102]:= MatchQ[rstest,{__String}]//Timing
Out[102]= {0.047,True}
In[103]:= MatchQ[rstest,{__?StringQ}]//Timing
Out[103]= {0.234,True}
Только из-за того, что в последнем случае использовался PatternTest
, проверка выполняется намного медленнее, потому что вычислитель запускает вычислитель для каждого элемента, тогда как в первом случае все является чисто синтаксическим и все выполняется внутри шаблон-сопоставитель.
- То же самое верно для распакованных числовых списков (разница во времени аналогична). Однако для упакованных числовых списков
MatchQ
и другие функции тестирования шаблонов не распаковывают определенные специальные шаблоны, более того, для некоторых из них проверка мгновенная .
Вот пример:
In[113]:=
test = RandomInteger[100000,1000000];
In[114]:= MatchQ[test,{__?IntegerQ}]//Timing
Out[114]= {0.203,True}
In[115]:= MatchQ[test,{__Integer}]//Timing
Out[115]= {0.,True}
In[116]:= Do[MatchQ[test,{__Integer}],{1000}]//Timing
Out[116]= {0.,Null}
То же самое, по-видимому, справедливо для таких функций, как VectorQ
, MatrixQ
и ArrayQ
с определенными предикатами (NumericQ
) - эти тесты чрезвычайно эффективны.
- Многое зависит от того, как вы пишете свой тест, т. Е. В какой степени вы повторно используете эффективные структуры Mathematica.
Например, мы хотим проверить, что у нас есть настоящая числовая матрица:
In[143]:= rm = RandomInteger[10000,{1500,1500}];
Вот самый простой и медленный путь:
In[144]:= MatrixQ[rm,NumericQ[#]&&Im[#]==0&]//Timing
Out[144]= {4.125,True}
Это лучше, так как мы лучше используем шаблон сопоставления:
In[145]:= MatrixQ[rm,NumericQ]&&FreeQ[rm,Complex]//Timing
Out[145]= {0.204,True}
Однако мы не использовали упакованный характер матрицы. Это еще лучше:
In[146]:= MatrixQ[rm,NumericQ]&&Total[Abs[Flatten[Im[rm]]]]==0//Timing
Out[146]= {0.047,True}
Однако это не конец. Следующий почти мгновенный:
In[147]:= MatrixQ[rm,NumericQ]&&Re[rm]==rm//Timing
Out[147]= {0.,True}