有没有一种方法可以检查两个表达式是否在数学上相等?我期望tg(x)cos(x) == sin(x)
会输出True
,但实际上它输出的是False
。是否有一种使用sympy进行这样比较的方法?另一个例子是(a+b)**2 == a**2 + 2*a*b + b**2
,出乎意料地也输出了False
。
我找到了一些类似的问题,但没有涵盖这个确切的问题。
有没有一种方法可以检查两个表达式是否在数学上相等?我期望tg(x)cos(x) == sin(x)
会输出True
,但实际上它输出的是False
。是否有一种使用sympy进行这样比较的方法?另一个例子是(a+b)**2 == a**2 + 2*a*b + b**2
,出乎意料地也输出了False
。
我找到了一些类似的问题,但没有涵盖这个确切的问题。
来自SymPy文档
==
表示精确的结构相等测试。“精确”在这里意味着只有当两个表达式在结构上完全相等时,它们才会通过==
进行比较相等。在这里,(x + 1)^ 2和x ^ 2 + 2x + 1在符号上并不相同。一个是两个术语相加的幂,另一个是三个术语的相加。事实证明,在使用SymPy作为库时,让
==
测试精确的符号相等性比让它代表符号相等性或测试数学相等性更有用。然而,作为新用户,您可能更关心后两者。我们已经看到了代表符号相等性的替代方法Eq。要测试两个东西是否相等,最好记住以下基本事实:如果a = b,则a-b = 0。因此,检查a = b的最佳方法是取a-b并简化它,看看它是否变为0。我们将在后面学习如何使用名为simplify
的函数来执行此操作。这种方法并非万无一失 - 实际上,可以从理论上证明在一般情况下无法确定两个符号表达式是否完全相等 - 但对于大多数常见的表达式,它运行得很好。
作为您特殊问题的演示,我们可以使用等价表达式的减法并将其与0进行比较,如下所示
>>> from sympy import simplify
>>> from sympy.abc import x,y
>>> vers1 = (x+y)**2
>>> vers2 = x**2 + 2*x*y + y**2
>>> simplify(vers1-vers2) == 0
True
>>> simplify(vers1+vers2) == 0
False
或者您可以使用.equals
方法来比较表达式:
from sympy import *
x = symbols('x')
expr1 = tan(x) * cos(x)
expr2 = sin(x)
expr1.equals(expr2)
True
import numpy as np
import sympy as sp
def check_equal(Expr1,Expr2):
if Expr1==None or Expr2==None:
return(False)
if Expr1.free_symbols!=Expr2.free_symbols:
return(False)
vars = Expr1.free_symbols
your_values=np.random.random(len(vars))
Expr1_num=Expr1
Expr2_num=Expr2
for symbol,number in zip(vars, your_values):
Expr1_num=Expr1_num.subs(symbol, sp.Float(number))
Expr2_num=Expr2_num.subs(symbol, sp.Float(number))
Expr1_num=float(Expr2_num)
Expr2_num=float(Expr2_num)
if not np.allclose(Expr1_num,Expr2_num):
return(False)
if (Expr1.equals(Expr2)):
return(True)
else:
return(False)
Expr1_num=Expr1_num.subs(zip(vars, your_values))
Expr2_num=Expr2_num.subs(zip(vars, your_values))
。Sympy可以一次替换多个元组。 - ProxExpr1_num=float(Expr2_num)
应该是 Expr1_num=float(Expr1_num)
,否则这将始终返回 true。 - undefined(expr1 - expr2).simplify()
或expr1.equals(expr2)
有时无法识别复杂表达式的相等性。为了解决这个问题,使用随机数对表达式进行数值评估可能构成一种相对安全的“暴力”测试。我改编了 @Okapi575 的优秀解决方案来执行以下操作:
import sympy as sp
import numpy as np
def check_equal(Expr1, Expr2, n=10, positive=False, strictly_positive=False):
# Determine over what range to generate random numbers
sample_min = -1
sample_max = 1
if positive:
sample_min = 0
sample_max = 1
if strictly_positive:
sample_min = 1
sample_max = 2
# Regroup all free symbols from both expressions
free_symbols = set(Expr1.free_symbols) | set(Expr2.free_symbols)
# Numeric (brute force) equality testing n-times
for i in range(n):
your_values=np.random.uniform(sample_min, sample_max, len(free_symbols))
Expr1_num=Expr1
Expr2_num=Expr2
for symbol,number in zip(free_symbols, your_values):
Expr1_num=Expr1_num.subs(symbol, sp.Float(number))
Expr2_num=Expr2_num.subs(symbol, sp.Float(number))
Expr1_num=float(Expr2_num)
Expr2_num=float(Expr2_num)
if not np.allclose(Expr1_num, Expr2_num):
print("Fails numerical test")
return(False)
# If all goes well so far, check symbolic equality
if (Expr1.equals(Expr2)):
return(True)
else:
print("Passes the numerical test but not the symbolic test")
# Still returns true though
return(True)
编辑:代码已更新(1)以比较具有不同数量自由符号的表达式(例如,在简化期间符号被消除后),并且(2)允许指定正数或严格正数范围。
a,b,... = sympy.symbols('a b ...',boolean = True)
并且使用sympy.Or
,sympy.Xor
等),那么您可以执行isEquivalent = lambda expr1,expr2:sympy.simplify((expr1&(〜expr2))|((〜expr1)&expr2))== False
。 - Phylliidaf1 = log(x)+log(y)
和f2 = log(x*y)
...(f1+f2).simplify()
得到的结果是log(x)+log(y) - log(x*y)
而不是0
。 - Prokop Hapalax
和y
为正数,那么这个式子的结果实际上是0,否则当x
和y
都是负数时,恒等式不成立。@Prokop - Marco Repetto