Search code examples
pythonsympympmath

Convert a sympy poly with imaginary powers to an mpmath mpc


I have a sympy poly that looks like:

Poly(0.764635937801645*I**4 + 7.14650839258644*I**3 - 0.667712176660315*I**2 - 2.81663805543677*I - 0.623299856233272, I, domain='RR')

I'm converting to mpc using the following code:

a = val.subs('I',1.0j)
b = sy.re(a)
c = sy.im(a)
d = mpmath.mpc(b,c)

Two questions.

  1. Assuming my mpc and sympy type have equal precision (of eg 100 dps) is there a precision loss using this conversion from a to d?
  2. Is there a better way to convert?

Aside: sympy seems to treat I just like a symbol here. How do I get sympy to simplify this polynomial?

Edit: Ive also noticed that the following works in place of a above:

a = val.args[0]

Solution

  • Strings and expressions

    Root cause of the issue is seen in val.subs('I', 1.0j) -- you appear to pass strings as arguments to SymPy functions. There are some valid uses for this (such as creation of high-precision floats), but when symbols are concerned, using strings is a recipe for confusion. The string 'I' gets implicitly converted to SymPy expression Symbol('I'), which is different from SymPy expression I. So the answer to

    How do I get sympy to simplify this polynomial?

    is to revisit the process of creation of that polynomial, and fix that. If you really need to create it from a string, then use locals parameter:

    >>> S('3.3*I**2 + 2*I', locals={'I': I})
    -3.3 + 2*I
    

    Polynomials and expressions

    If the Poly structure is not needed, use the method as_expr() of Poly to get an expression from it.

    Conversion to mpmath and precision loss

    is there a precision loss using this conversion from a to d?

    Yes, splitting into real and imaginary and then recombining can lead to precision loss. Pass a SymPy object directly to mpc if you know it's a complex number. Or to mpmathify if you want mpmath to decide what type it should have. An example:

    >>> val = S('1.111111111111111111111111111111111111111111111111')*I**3 - 2 
    >>> val
    -2 - 1.111111111111111111111111111111111111111111111111*I
    >>> import mpmath
    >>> mpmath.mp.dps = 40
    >>> mpmath.mpc(val)
    mpc(real='-2.0', imag='-1.111111111111111111111111111111111111111111')
    >>> mpmath.mpmathify(val)
    mpc(real='-2.0', imag='-1.111111111111111111111111111111111111111111')
    >>> mpmath.mpc(re(val), im(val))
    mpc(real='-2.0', imag='-1.111111111111111111111111111111111111111114')
    

    Observations:

    • When I is actual imaginary unit, I**3 evaluates fo -I, you don't have to do anything for it to happen.
    • A string representation of high-precision decimal is used to create such a float in SymPy. Here S stands for sympify. One can also be more direct and use Float('1.1111111111111111111111111')
    • Direct conversion of a SymPy complex number to an mpmath complex number is preferable to splitting in real/complex and recombining.

    Conclusion

    Most of the above is just talking around an XY problem. Your expression with I was not what you think it was, so you tried to do strange things that were not needed, and my answer is mostly a waste of time.