开发者

operator for approximate equality testing in Mathematica

I often need to check if expr1==expr2, where checking for symbolic equality is hard, but a numeric check suffices

To deal with such cases it would be neat to have TildeTilde work like Equal but instead of checking symbolic equality it would substitute unknowns with numeric val开发者_Go百科ues and check for numeric equality at several points.

Unknowns are things that "look like" variables in the expression. The ones I can think of have form x,x[1,2] and Subscript[x,2,3]. Any tips welcome!

edit

usually I do something like below, but it requires specifying variables, sometimes requires changing Chop tolerance, and "10 samples" seems arbitrary. An ideal tester would be a function that works like Equals and guarantees meaningful False answers. (to complement Equals which has meaningful True answers)

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

As a side-note, apparently Maple uses this algorithm for such equality testing


This is somewhat straightforward if you use FindMaximum as a jumping-off point:

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

Thus:

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

Obviously, in general this is subject to various numerical error issues that you can address with AccuracyGoal / PrecisionGoal / WorkingPrecision / etc. options to FindMaximum. You could also repeat FindMaximum for multiple starting points for the variables.

As an aside, note that TildeTilde, (i.e. ~~), is the infix operator for StringExpression.

HTH!


I really think it is worthwhile specifying patterns and ranges for the symbols you want to replace. The following code is a polished version of an equality test generator I have used for a while.
My take on this is to have numEqual=MakeEqualityTest[...] generate an equality test that you can then apply with e.g. lhs ~numEqual~rhs or whatever you prefer. Your question was a welcome chance to polish up some code I had around, and in the end it got too big to fit here, so i put it out at github (link is directly to browseable code).

Key features:

  • Use Michael's depth first Cases trick for a reasonable auto-pattern
  • Using Norm[#1-#2]& as a distance test to handle vectors, matrices, etc.
  • The number of sampling points depends on the number of independent variables.
  • A flexible system for specifying distributions (e.g. you can replace the symbols with complex numbers or matrices).

Example use:

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}

You can also call directly, via a utility function:

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

And here is an example of special symbols and distributions:

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜