在 SymPy 中测试 Eq(不是 Expr)的相等性

testing equality of Eq (not Expr) in SymPy

提问人:smichr 提问时间:8/4/2023 最后编辑:smichr 更新时间:8/4/2023 访问量:35

问:

YourHomicidalApe 问了一个本质上是这样的问题:

给定两个字符串表示转换为 SymPy 实例的方程式,您如何判断它们是否表示相同的方程式?(“相同”的意思是,可以对每个方程进行代数运算以获得等价的表达式,也许是某种规范形式。Eq

例如,以下等式应进行比较。可以使用哪些工具来执行此操作?可以理解的是,不能使用 ,因为它测试了结构相等性,并且该方法显然不适用于以下实例,除非它们微不足道地相同:==equalsEq

>>> from sympy.parsing.sympy_parser import T
>>> from sympy.abc import x, y
>>> Eq(y, x).equals(Eq(x, y))
True
>>> Eq(2*y, x).equals(Eq(x/2, y))
False

对于测试如下所示的方程的数学等价性,您有什么建议?

>>> from sympy.parsing import *
>>> a = parse_expr('y=x^2+.5', transformations=T[:])
>>> b = parse_expr('2*y=2x^2+1', transformations=T[:])
>>> a==b
False
>>> a.equals(b)
False
>>> e1, e2 = [i.rewrite(Add) for i in (a, b)]
>>> e1.equals(e2)
False

有没有人处理过这样的表达式,也许是在从初级代数学生那里获得输入的背景下,这些输入将要根据已知答案进行测试?

Python sympy 平等

评论

0赞 jared 8/4/2023
如何定义转换?T[:]
1赞 user2357112 8/4/2023
sympy.parsing.sympy_parser定义了一个对象,但 中没有 。TTsympy.parsing

答:

2赞 Oscar Benjamin 8/4/2023 #1

正如符号计算中经常出现的情况一样,一个看似无辜的问题,如“这个表达式是否等同于那个表达式”,在完全普遍的情况下是无法解决的。由于理查森定理,即使确定两个不同的方程具有相同的左手边和相同的右手边也是无法确定的:

https://en.wikipedia.org/wiki/Richardson%27s_theorem

当然,在很多情况下,这个问题可判定的,但就像符号计算中的通常情况一样,需要对问题空间进行一些限制。特别是,我们需要以下一项或两项:

  • 我们需要定义一些我们希望能够处理的可能的方程或表达式。
  • 我们需要定义允许什么样的操作来将一个方程式转换为另一个方程式。

在您的两个示例中,两个方程都是多项式方程,涉及两个具有有理系数或浮点系数的变量,因此我们可以将其视为允许方程的类别。浮点数是一个潜在的障碍,但我认为在您的用例中将它们转换为最可能的有理数是可以接受的。在这种情况下,我们的方程是多项式方程,涉及多个变量,但具有有理系数。nsimplify

现在允许什么样的操纵?只有对多项式方程的某些操作才必然会给出另一个多项式方程:

  • 从两边加或减多项式。
  • 将两边乘以有理数或多项式。
  • 将两边提高到整数幂。

她出现了一个重要的方程式:

你认为等同于吗?(x - 1)**2 = 0(x - 1) = 0

在某些情况下,区分多项式的因子/根的多重性很重要,但在其他情况下则不然。

另一个考虑因素是你是否希望方程是等效的模,例如,我们可以说,如果说被约束为非负,那么它是等价的。你可以强加许多可能的假设,所以我不会尝试考虑这些假设。(x - 1)**2 = y**2x - 1 = yy

创建方程(通过解析字符串或其他任何内容)并将浮点数转换为有理数:

In [3]: a = Eq(y, x**2 + 0.5)

In [4]: b = Eq(2*y, 2*x**2 + 1)

In [5]: a
Out[5]: 
     2      
y = x  + 0.5

In [6]: b
Out[6]: 
         2    
2⋅y = 2⋅x  + 1

In [7]: a = nsimplify(a) # float to rational

In [8]: a
Out[8]: 
     2   1
y = x  + ─
         2

现在通过减去边转换为表达式:

In [9]: a = a.lhs - a.rhs

In [10]: b = b.lhs - b.rhs

In [11]: a
Out[11]: 
   2       1
- x  + y - ─
           2

In [12]: b
Out[12]: 
     2          
- 2⋅x  + 2⋅y - 1

最后一步假设你不介意两个方程的每一边都说 a,这会被取消。也许你确实在乎这一点,也许你不在乎:这取决于情况。下面是一个示例,说明您可能何时可能关心(如果此等式在您的问题空间中是允许的):+ 1

In [19]: eq = Eq(x + 1/x, 1/x)

In [20]: eq
Out[20]: 
    1   1
x + ─ = ─
    x   x

In [21]: solve(eq)
Out[21]: []

In [22]: eq.lhs - eq.rhs
Out[22]: x

In [23]: solve(eq.lhs - eq.rhs)
Out[23]: [0]

在这个阶段,似乎要使方程等价,您只允许一个方程是另一个方程的倍数,但是我们允许乘以什么?我假设这里唯一允许的差异是一个因子,它是一个显式有理数。在这种情况下,我们可以通过使它们成为一元式来使它们成为规范式:

In [16]: monic(a)
Out[16]: 
 2       1
x  - y + ─
         2

In [17]: monic(b)
Out[17]: 
 2       1
x  - y + ─
         2

In [18]: monic(a) == monic(b)
Out[18]: True

可以定义比这更复杂的等价概念,但对于所给出的例子来说已经足够了。您可以通过概括问题的约束来概括问题,但如果没有一些约束,就不可能有问题的算法答案。