Search code examples
sympyassumption

sympy equality test with complex rational functions gives None (unknown)


When an expression is a ratio with powers that I expect sympy (v1.12) to be able to cancel, I sometimes get results I don't understand. Here's an example. Notice that all of the symbols except d and n are real. (d is sometimes complex, and n is a positive integer.)

from sympy import *

a, b, c, x, y = symbols('a b c x y', real=True)
n = symbols('n', integer=True, positive=True)

I get what I expect for reals:

d = (a * x**n + b * x**(n-1) + c) / x**n
print(d.equals(a + b/x + c/x**n))

prints True.

This complex case gives what I expect:

d = (a * (x + I*y)**n + c)/(x + I*y)**n
print(d.equals(a + c/(x + I*y)**n))

prints True.

Same here:

d = (b * (x + I*y)**(n-1) + c)/(x + I*y)**n
print(d.equals(b/(x + I*y) + c/(x + I*y)**n))

prints True.

But not this case:

d = (a * (x + I*y)**n + b * (x + I*y)**(n-1) + c)/(x + I*y)**n
print(d.equals(a + b/(x + I*y) + c/(x + I*y)**n))

prints None.

The correct (?) answer seems obvious; I'm checking d against what I get when I cancel the x+I*y factors by hand. The None answer means sympy claims the answer is unknown, without further assumptions about the variables. What could make the result unknown, when the previous cases are not unknown?


Solution

  • The None answer means sympy claims the answer is unknown, without further assumptions about the variables.

    According to my experience, it also returns None when SymPy is unable to verify the equality, for whatever reason.

    d = (a * (x + I*y)**n + b * (x + I*y)**(n-1) + c)/(x + I*y)**n
    test = a + b/(x + I*y) + c/(x + I*y)**n
    display(d, test)
    

    enter image description here

    This is a case where you might need to put in extra effort to verify it, by rewriting LHS - RHS (left-hand side, right-hand side) and verifying it is equal to 0.

    d - test
    

    enter image description here

    Now we expand it:

    (d - test).expand()
    

    enter image description here

    Note that the powers have not been simplified. Finally, we simplify it:

    (d - test).expand().simplify()
    # out: 0
    

    What could make the result unknown, when the previous cases are not unknown?

    My guess is that equals is not using powsimp in its code, or something similar in order to simplify powers.