Search code examples
sympycomplex-numbers

How to find if expression contains complex number I in it in SymPy?


Given an expression, how do I find (after simplifications if needed) if the expression contains the complex number I which is the square root of −1?

In Maple, this is done using the check has(expression,I); see its help page.

In Mathematica, this is done using the check If[FreeQ[expression, Complex], for example: How to check if expression contains a Complex expression?

But I am not sure how to do similar thing in SymPy.

Using expression.is_complex does not return True even if I in the expression. Also since real is subset of complex, this is not a correct test anyway.

I need to check for an explicit I that shows up in the expression anywhere (after simplification).

Here is an example: I am using SymPy 1.5.

from sympy import *
from sympy.abc import z
ex1=(-(((1 + 3*I) + sqrt(2))*cos(z/2)) + ((1 + I) - I*sqrt(2))*sin(z/2))/(((1 + I) + sqrt(2))*cos(z/2) + I*((-1 -I) + sqrt(2))*sin(z/2))
print(ex1.is_complex)
    #None
print(simplify(ex1).is_complex)
    #None

This is in Maple, for reference:

restart;
result:=(-(((1 + 3*I) + sqrt(2))*cos(z/2)) + ((1 + I) - I*sqrt(2))*sin(z/2))/(((1 + I) + sqrt(2))*cos(z/2) + I*((-1 -I) + sqrt(2))*sin(z/2));
has(simplify(result),I)

Which gives

Mathematica graphics

How to do the above in SymPy?


Solution

  • has checks whether an expression contains some subexpression, such as I:

    ex1.has(I)        # True
    sin(z).has(I)     # False
    (sin(z)+I).has(I) # True
    

    Note that this does not take into account simplifications that might get rid of the I.

    As for checks like is_complex, they consider all possible values of the input variable and return None if there is no clear answer (or if SymPy does not see a relevant simplification). Also, in your case, you want to use is_real (since real numbers are also complex in SymPy’s sense, as you noted). For illustration, consider the following:

    z = Symbol("z")
    (z+1).is_real  # None
    (z+I).is_real  # None
    
    z = Symbol("z", real=True)
    (z+1).is_real  # True
    (z+I).is_real  # False