0

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]
Jibbity jobby
  • 1,255
  • 2
  • 12
  • 26

2 Answers2

1

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.

  • Thank you. I did realise that I was not being treated as the imaginary unit, as I think I alluded in my question. However, I don't create my poly from a string as you've indicated. I build an expression using sympy.I and then pass that expression to the sympy.poly function. I'll need to have a closer look at my code with your answer in mind. Thanks again. – Jibbity jobby Mar 10 '18 at 20:32
  • I've tried running your code and get the following exception for both the mpmathify and mpc functions on val: raise TypeError("cannot create mpf from " + repr(x)). Is this a version thing? – Jibbity jobby Mar 10 '18 at 21:20
0

I'm adding my own answer here, as FTP's answer, although relevant and very helpful, did not (directly) resolve my issue (which wasn't that clear from the question tbh). When I ran the code in his example I got the following:

>>> from sympy import *
>>> import mpmath
>>> val = S('1.111111111111111111111111111111111111111111111111')*I**3 - 2
>>> val
-2 - 1.111111111111111111111111111111111111111111111111*I
>>> mpmath.mp.dps = 40
>>> mpmath.mpc(val)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\site-packages\mpmath\ctx_mp_python.py", line 373, in __new__
    real = cls.context.mpf(real)
  File "C:\Python27\lib\site-packages\mpmath\ctx_mp_python.py", line 77, in __new__
    v._mpf_ = mpf_pos(cls.mpf_convert_arg(val, prec, rounding), prec, rounding)
  File "C:\Python27\lib\site-packages\mpmath\ctx_mp_python.py", line 96, in mpf_convert_arg
    raise TypeError("cannot create mpf from " + repr(x))
TypeError: cannot create mpf from -2 - 1.111111111111111111111111111111111111111111111111*I
>>> mpmath.mpmathify(val)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\site-packages\mpmath\ctx_mp_python.py", line 662, in convert
    return ctx._convert_fallback(x, strings)
  File "C:\Python27\lib\site-packages\mpmath\ctx_mp.py", line 614, in _convert_fallback
    raise TypeError("cannot create mpf from " + repr(x))
TypeError: cannot create mpf from -2 - 1.111111111111111111111111111111111111111111111111*I
>>> mpmath.mpc(re(val), im(val))
mpc(real='-2.0', imag='-1.111111111111111111111111111111111111111114')
>>> mpmath.mpmathify(val)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\site-packages\mpmath\ctx_mp_python.py", line 662, in convert
    return ctx._convert_fallback(x, strings)
  File "C:\Python27\lib\site-packages\mpmath\ctx_mp.py", line 614, in _convert_fallback
    raise TypeError("cannot create mpf from " + repr(x))
TypeError: cannot create mpf from -2 - 1.111111111111111111111111111111111111111111111111*I

Updating my sympy (1.0->1.1.1) and mpmath (0.19->1.0.0) fixed the exceptions. I did not test which of these upgrades actually resolved the issue.

Jibbity jobby
  • 1,255
  • 2
  • 12
  • 26
  • I should just add that this bug was why I had such an elaborate conversion. I tried the other ways but all of them gave me the exception. – Jibbity jobby Mar 10 '18 at 21:35