As previously stated, (expr1 - expr2).simplify()
or expr1.equals(expr2)
will sometimes fail to recognize equality for expressions that are complex to simplify. To deal with this, a numerical evaluation of the expressions with random numbers may constitute a relatively safe "brute force" test. I've adapted the excellent solution by @Okapi575 to:
- Test the numerical equality N-times with different random numbers each time for a more confident diagnostic
- Warn the user when a pair of expressions only passes the numeric test but not the symbolic equality test.
For example:

Hope it can prove useful:
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)
EDIT: code updated (1) to compare expressions with differing numbers of free symbols (for example, after symbols got cancelled out during a simplification), and (2) to allow for the specification of a positive or strictly positive random number range.