2010-11-17 2 views
3

Я часто нужно проверить, если expr1==expr2, где проверка символического равенства трудно, но цифровая проверка достаточнооператор приближенного тестирования равенства в системе Mathematica

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

Неизвестные вещи, которые являются «похожими» на переменные в выражении. Я могу думать о форме x, x[1,2] и Subscript[x,2,3]. Любые подсказки приветствуются!

редактировать

обычно я делаю что-то вроде ниже, но это требует определения переменных, иногда требует изменения Чоп толерантности, и «10 образцов» кажется произвольным. Идеальным тестером будет функция, которая работает как Equals и гарантирует содержательные ответы False. (В дополнение к Equals, которая имеет значимые True ответы)

 
approxEqual[expr1_, expr2_, vars_] := 
    Chop[(expr1 - expr2 /. Thread[vars -> #]) & /@ 
    RandomReal[{-1, 1}, {10, Length[vars]}]] == Table[0, {10}]; 
expr1 = 1/Sqrt[2] Log[Cosh[q + x/Sqrt[2]] Sech[q - x/Sqrt[2]]]; 
expr2 = Sqrt[2] ArcTanh[Tanh[q] Tanh[x/Sqrt[2]]]; 
approxEqual[expr1, expr2, {q, x}] 

В качестве побочного сведению, по-видимому, Maple использует this алгоритм такого равенства тестирования

+0

числовое тестирование было бы столь же сложно, поскольку числа с плавающей запятой а не действительные числа. –

+2

они есть, если вы достаточно сильно жужжаете –

+0

Я вижу две ключевые проблемы: как вы решаете, что такое переменная (x [1,2] выглядит как вызов функции мне), и как вы определяете область этих переменные? – Janus

ответ

5

Это несколько просто, если вы используете FindMaximum в качестве плацдарма :

In[64]:= FindMaximum[expr1 - expr2, q, x] 

During evaluation of In[64]:= FindMaximum::fmgz: Encountered a gradient that 
is effectively zero. The result returned may not be a maximum; it may be a 
minimum or a saddle point. >> 

Out[64]= {1.11022*10^-16, {q -> 1., x -> 1.}} 

Таким образом:

approxEqual[lhs_, rhs_, tol_: 10^-10] := 
Module[{vars}, 
    vars = DeleteDuplicates[ 
    Cases[{lhs,rhs}, s_Symbol /; Not[ValueQ[s]], Infinity] 
    ]; 
    Chop[ 
    First[ 
    Quiet[FindMaximum[Abs[lhs - rhs], Evaluate[Sequence @@ vars]]] 
    ], 
    tol] == 0 
    ] 

In[65]:= approxEqual[expr1, expr2] 
Out[65]= True 

In[66]:= approxEqual[expr1, expr2, 10^-20] 
Out[66]= False 

Очевидно, что в целом это подвержено различным числовым ошибкам, которые вы можете задать с помощью AccuracyGoal/PrecisionGoal/WorkingPrecision/и т. Д. Опций до FindMaximum. Вы также можете повторить FindMaximum для нескольких стартовых точек для переменных.

В качестве примечания обратите внимание, что TildeTilde, (т.е. ~~), является оператором инфикса для StringExpression.

HTH!

+0

Ничего себе, аккуратная идея, вероятно, более надежная, чем случайные точки выборки. BTW, TildeTilde - «Оператор без встроенного значения» в Mathematica 7 –

+1

Я стою исправлен! Я должен знать об этом. ;-) Я всегда читал '~~' как "тильд-тильда" в моей голове. –

+1

Возможно, необходимо принять абсолютное значение - 'Abs [expr1-expr2]'? –

1

Я действительно думаю, что стоит указать шаблоны и диапазоны для символов, которые вы хотите заменить. Следующий код - это полированная версия генератора тестов равенства, который я использовал некоторое время.
Примите это, чтобы numEqual=MakeEqualityTest[...] сформировал тест равенства, который затем можно применить, например. lhs ~numEqual~rhs или что вы предпочитаете. Ваш вопрос был приятным шансом отполировать некоторый код, который у меня был, и, в конце концов, он стал слишком большим, чтобы поместиться здесь, поэтому я поместил его в github (ссылка прямо на доступный код).

Основные характеристики:

  • Используй Майкл глубины первый Cases трюка для разумного авто-шаблона
  • Использование Norm[#1-#2]& в качестве теста расстояния для обработки векторов, матриц и т.д.
  • числа точек отбора проб зависит от числа независимых переменных.
  • Гибкая система для указания распределений (например, вы можете заменить символы комплексными числами или матрицами).

Пример использования:

numeq=MakeEqualityTester[]; 
(Cos[x]^2+Sin[x]^2)~numeq~1 
Sqrt[x^2]~numeq~x 

Out[5]= True 
During evaluation of In[4]:= EqualityTest::notEqual: The expressions Sqrt[x^2] and x were not equal at the following point: 
Out[6]= {x->-0.352399} 

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

EqualityTest[1,Cos[x]^2+Sin[x]^2] 
Out[7]= True 

А вот пример специальных символов и распределений:

poseq=MakeEqualityTester[{ 
    Subscript[y,_]:>RandomReal[{10,11}], 
    Automatic 
    },Tolerance-> 10^(-5)]; 
x ~poseq~ Sqrt[x^2] 
Subscript[y,1] ~poseq~ Sqrt[Subscript[y,1]^2] 

During evaluation of In[18]:= EqualityTest::notEqual: The expressions x and Sqrt[x^2] were not equal at the following point: 
Out[19]= {x->-0.272029} 
Out[20]= True 
Смежные вопросы