Mathematica 中近似相等测试的运算符

发布于 2024-10-02 11:25:30 字数 921 浏览 2 评论 0原文

我经常需要检查是否 expr1==expr2,其中检查符号相等性很困难,但数字检查就足够了

要处理这种情况,使用 TildeTilde 会很方便与 Equal 类似,但不是检查符号相等,而是用数值替换未知数,并在多个点检查数值相等。

未知数是表达式中“看起来像”变量的东西。我能想到的形式有 xx[1,2]Subscript[x,2,3]。欢迎任何提示!

编辑

通常我会做类似下面的事情,但它需要指定变量,有时需要更改斩波容差,并且“10个样本”似乎是任意的。理想的测试器应该是一个像 Equals 一样工作的函数,并保证有意义的 False 答案。 (补充具有有意义的True答案的Equals

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使用了算法用于此类相等性测试

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 values 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

早乙女 2024-10-09 11:25:30

如果您使用 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 解决这些问题/etc.FindMaximum 选项。您还可以重复 FindMaximum 来获取变量的多个起点。

顺便说一句,请注意 TildeTilde(即 ~~)是 StringExpression

哈!

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!

缱倦旧时光 2024-10-09 11:25:30

我真的认为为要替换的符号指定模式和范围是值得的。以下代码是我使用了一段时间的相等测试生成器的改进版本。
我对此的看法是让 numEqual=MakeEqualityTest[...] 生成一个相等测试,然后您可以使用例如 lhs ~numEqual~rhs 或您喜欢的任何内容来应用该测试。你的问题是一个很好的机会来完善我周围的一些代码,最终它太大了,无法放在这里,所以我把它放在 github (链接直接指向可浏览的代码)。

主要特点:

  • 使用 Michael 的深度优先 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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文