Convert a sympy poly with imaginary powers to an mpmath mpc - python

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.
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?
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]

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.

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.

Related

Python Numpy Exponential Value from Array of BigFloats

I'm trying to compute the natural log of the exponential plus the median of an array but precision of the floating point numbers has to be at 2000 or the answer will always be 0.
Here is what I have so far:
import bigfloat
x = np.array([-15349.79, -15266.66, -15242.86])
answer = np.median(x) - bigfloat.log(np.mean(bigfloat.exp(x, precision(2000)) + np.median(x)))
This code returns the following error because BigFloat.exp doesn't work on list types.
__main__:1: RuntimeWarning: invalid value encountered in log
array([ nan, nan, nan])
>>> np.median - bigfloat.log(np.mean(bigfloat.exp(x, precision(2000)) + np.median(x)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/bigfloat/core.py", line 1446, in exp
(BigFloat._implicit_convert(x),),
File "/usr/local/lib/python2.7/dist-packages/bigfloat/core.py", line 800, in _implicit_convert
"to BigFloat" % (arg, type(arg)))
TypeError: Unable to convert argument [-15349.79 -15266.66 -15242.86] of type <type 'numpy.ndarray'> to BigFloat
I then tried list comprehension to build exponentials with precision=2000 but the output loses precision.
>>>[bigfloat.exp(num, precision(2000)) + BigFloat(np.median(x), context=precision(2000)) for num in x]
[BigFloat.exact('-15266.660000000000', precision=53), BigFloat.exact('-15266.660000000000', precision=53), BigFloat.exact('-15266.660000000000', precision=53)]
I can get exponential values from x with precision using list comprehension
like this:
>>> y = np.array([bigfloat.exp(num, precision(2000)) for num in x])
array([ BigFloat.exact('4.687104391719151845495683439738733373338442839115295629901427982078731632624437676931490944129698360820181432182432247030174990996132679553420878801399467284014932435857939862423137788809352433385343338286781879066456873472082636971652587852379587642184738259777920214145750081457830886095059600271300801524086458081526778407096875577469007859748418787409261916565428551066536598870494431653463691369520685259389041691328858076222360659135651318185915247243253437425313718584237418827954902711646850362440592578566737383074556346759332830833101196990845567845361685702120838400980658468192376607029699380e-6667', precision=2000),
BigFloat.exact('5.940252515613784074556309936460240719247289162721506036367173706446251980105141516508485353816420203092949808160441872102510858074752258842471232457791645630942356791030979819957875784926363292788234347364203226596687259399429746917920741954706671428927952815041593801046941161417184730521922391569252658359604561007344640221209247257690437938341582528542446104212627600044421405229891732857592357725820529732658234033631318425476205945557122313924830225909708184718714804450362854280687393958953216361511561704836206669636791590655443171684811683402330053964681285971765503804198242627954802184910024902e-6631', precision=2000),
BigFloat.exact('1.288289823457680769007768910906908351089465066737359292851136781233384628626343352992636825492031571595103435334370758196286825224816434202324210124540257467624499933926757723584914581286627071375803686797647455160335628799775858142489656885909172399293492295645703203222218182084249732700966821340431452575815746282651823925677898549539269454644804048695031225101971491985645951419388454738446335860070391719831039721150295437452237572831818257568221336263814212095143032293694959570063677473370798577031762607527221992020661837810811705007892502559603984057933079724597470162879821292957122400421187875e-6620', precision=2000)], dtype=object)
So, how do I add np.median(x) to each item in the exponential array and how do I get the log of the elements in the final array? Is there an easier way to compute the equation given by variable answer in the first code snippet above?
I'm basically trying to convert this R code to Python:
llMed <- stats::median(x)
metric <- as.double(
llMed - log( Rmpfr::mean( exp( -Rmpfr::mpfr(x, prec=2000L) + llMed )))
)
I think I was able to transpose the R code above, using gmpy2 instead of BigFloat but probably could have used either:
import gmpy2 as gp
import numpy as np
with gp.local_context(gp.context(), precision=2000) as ctx:
x = np.array([gp.mpfr(-15349.79), gp.mpfr(-15266.66), gp.mpfr(-15242.86)])
answer = np.median(x) - gp.log(np.mean([gp.exp(gp.add(np.median(x), -gp.mpfr(item))) for item in x]))
Output returns:
mpfr('-15348.69138771133276342351845677418587273364155071266454924792376077085597654860712492594599688058199377288639137666410888137048513058096745776113277020531535761588878042016412651412489608285582998650481415959482636259292554205272401992800167437149224493900214813760731711328834885525224938584036572786202764947113186177391441168267495103157033223800214492991771147327262071249020907408433551462034872024117419365924381891832161483692689444158313503155805562703358104122358438183824459422779020196496507161021965435781332319270106503099589290788685588200038739438059696970511568363022088057740627040541967',2000)

declare a variable as *not* an integer in sage/maxima solve

I am trying to solve symbolically a simple equation for x:
solve(x^K + d == R, x)
I am declaring these variables and assumptions:
var('K, d, R')
assume(K>0)
assume(K, 'real')
assume(R>0)
assume(R<1)
assume(d<R)
assumptions()
︡> [K > 0, K is real, R > 0, R < 1, d < R]
Yet when I run the solve, I obtain the following error:
Error in lines 1-1
Traceback (most recent call last):
File
"/projects/sage/sage-7.3/local/lib/python2.7/site-packages/smc_sagews/sage_server.py",
line 957, in execute
exec compile(block+'\n', '', 'single') in namespace, locals
...
File "/projects/sage/sage-7.3/local/lib/python2.7/site-packages/sage/interfaces/interface.py",
line 671, in init
raise TypeError(x)
TypeError: Computation failed since Maxima requested additional constraints; using the 'assume' command before evaluation may help (example of legal syntax is 'assume(K>0)', see assume? for more details)
Is K an integer?
Apparently, maxima is asking whether K is an integer? But I explicitly declared it 'real'!
How can I spell out to maxima that it should not assume that K is an integer?
I am simply expecting (R-d)^(1/K) or exp(log(R-d)/K) as answer.
The assumption framework in both Sage and Maxima is fairly weak, though in this case it doesn't matter, since integers are real numbers, right?
However, you might want to try assume(K,'noninteger') because apparently Maxima does support this particular assumption (I had not seen it before). I can't try this right now, unfortunately, good luck!

How to detect overflow while arithmetic in python?

I am working on a analysis problem in python in which I have to work on big floating point numbers and was performing some operations on it. My codes seems to break in between; looking carefully I found that sometimes a simple add operation would return inf it must be an overflow.
>>> a = float(2**1022) + float(2**1023)
>>> print a
1.348269851146737e+308
>>> a = float(2**1023) + float(2**1023)
>>> print a
inf
>>>
How do we check for overflow in python while floating point operation since instead of giving a OverflowError it silently gives a value inf.
I can only imagine checking if abs(a)==float('inf'): raise OverflowError()…
Use an arbitrary precision library like GMPY and you won't need to worry.
Disclaimer: I maintain gmpy2.
The gmpy2 library supports both arbitrary precision (to decrease the occurrences of overflow) and the ability to trap on floating point events. Here is an example of modify the context to automatically raise an exception when an overflow occurs.
>>> import gmpy2
>>> from gmpy2 import get_context,set_context, ieee, mpfr
>>> set_context(ieee(64))
>>> get_context()
context(precision=53, real_prec=Default, imag_prec=Default,
round=RoundToNearest, real_round=Default, imag_round=Default,
emax=1024, emin=-1073,
subnormalize=True,
trap_underflow=False, underflow=False,
trap_overflow=False, overflow=False,
trap_inexact=False, inexact=False,
trap_invalid=False, invalid=False,
trap_erange=False, erange=False,
trap_divzero=False, divzero=False,
trap_expbound=False,
allow_complex=False)
>>> get_context().trap_overflow=True
>>> get_context()
context(precision=53, real_prec=Default, imag_prec=Default,
round=RoundToNearest, real_round=Default, imag_round=Default,
emax=1024, emin=-1073,
subnormalize=True,
trap_underflow=False, underflow=False,
trap_overflow=True, overflow=False,
trap_inexact=False, inexact=False,
trap_invalid=False, invalid=False,
trap_erange=False, erange=False,
trap_divzero=False, divzero=False,
trap_expbound=False,
allow_complex=False)
>>> mpfr(2**1023) + mpfr(2**1023)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
gmpy2.OverflowResultError: 'mpfr' overflow in "addition"
>>>

Python : overflow error long int too large to convert to float

I had to compute 2 to the power of 8635. I came across this error when i was computing 2^8635. Any suggestion how to solve this in python. Using Decimal module also didn't help.
math.exp(2**8635)
Traceback (most recent call last):
File "<pyshell#50>", line 1, in <module>
long(math.exp(2**8635))
OverflowError: long int too large to convert to float
You can calculate exp(2**8635) using the mpmath arbitrary precision mathematics module:
>>> from mpmath import mp
>>> mp.exp(2**mp.mpf(8635))
The result is rather large, even in scientific notation, so I did a little bit of string processing on it, by copy & pasting the exponent into a string s and then reformatting it with:
>>> ' '.join([''.join(b) for b in zip(*[iter(s)]*10)])
The result, using a precision of mp.dps=20 is
4.2745087809955028863988E+ 1075961842 0748495519 2355783856 9202899773
5836295555 7242537851 6693465178 9188332936 7912863215 8269919370
9351573282 2091597135 7873818954 8423038425 5471700446 0909815025
4915349824 6380686906 6065142412 7999166978 5222679350 6349971415
2079241766 6069616716 5214806906 8965805654 9049342395 4257087497
9202056938 3115899033 9617474292 7677302965 5753590474 3880492978
3310677063 3380119492 7251778893 3532333942 0392908196 6724211094
8421111629 7159351144 1795137181 2264799291 0856206603 1305457648
0092179442 8275386674 9796135348 4212345607 2596906933 7416259320
1466097812 2578572779 3349115312 8876785712 0147507083 6261226991
0422767260 2197316370 2566751899 4709067324 2810166509 7120800169
7485704027 5902848998 8322436088 0980908767 3758921061 0035161163
7079806523 1330002249 6901129466 0981598858 6254175013 7068344219
8144416569 4188190080 3725722501 2061326523 2288670566 9409102206
8066363145 9074202764 8831634730 7112255017 0796958442 3491574250
3284769002 8003076564 8628481483 0439060173 9895022099 1254178687
3665797407 1814255571 0142720172 8605229862 9458410467 4672777325
9445377886 5938198959 1752282268 4759702578 8305033658 4673474227
0701134707 7350267519 5446056950 6855231007 2274227123 3745529068
2622945712 5542911110 4405852782 0415855498 0153628764 5474618275
7401652756 8947182158 7839446628 2805776521 9227970761 2076840252
6317298197 2928759787 3166056075 4718446805 4085909927 3696546013
4104199677 6666307004 0490874208 2916409726 3519895965 9647475416
4225305349 6334839659 5665063673 3375427908 5570705561 0968733246
7656866381 6185956211 6475910345 4507247539 2187977091 2735607271
0209770526 5707982249 7378999875 8729821041 8908550791 3750558609
2896112135 9430559215 0044675914 5643599469 1254786634 5242493728
3502270440 3874100770 4799209491 3826434565 6967844371 7035989909
7698785578 9911981690 6907193705 6149599295 7385801544 7008446783
4130808551 5517628873 4403074667 6152264003 5246435484 0092524145
7903102870 5636975728 9853241717 1112914752 3204974235 3214176498
6118461362 7598845054 2855525271 2496489615 8680550278 4583386686
7070831392 2705583569 2224816732 3325036729 8106736491 3995562245
2081730125 0118717575 0946706166 8838482200 0110510511 5193674369
7359353196 7070446633 3514990982 6428484539 3692837968 6448096531
0406301917 5207050949 5578924420 0588400753 2802517808 1953501443
3445927237 8496133188 6299359291 6240744112 8041383838 2523556917
1966060664 8100342007 9597089073 1150067540 7733669287 2770028938
5557716323 9545436149 8913712891 0452403558 6380308865 8375826610
3861873050 5349593724 7443661231 6344789431 9248320333 3901279921
2985101147 6464375714 1302826973 5468251818 0411981792 4830271478
1578285904 7739571097 8513979667 0471302144 9500998430 2500602635
1255157768 2597448484 2711867118 3605984621 3175011866 9369283240
7857863664 6903750271 5353454119 0302118673

Infinity generated in python code

I'm looking over some complex Python 2.6 code which is occasionally resulting in an infinity being generated (at least an Infinity being serialized by the json library -- which checks w/ math.isinf).
What is especially baffling is that Python (as far as I can tell) shouldn't be able to ever produce computation results set to infinity. Am I wrong with this assumption? I was aware you can only get infinities from constants:
k = float('inf')
k = 1e900
Somewhere between 1e308 and 1e309 the floats run out of precision, so if you are computing results above that range you will see inf
>>> 1e308
1e+308
>>> 1e309
inf
>>> json.dumps(1e308,allow_nan=False)
'1e+308'
>>> json.dumps(1e309,allow_nan=False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.6/json/__init__.py", line 237, in dumps
**kw).encode(obj)
File "/usr/lib/python2.6/json/encoder.py", line 367, in encode
chunks = list(self.iterencode(o))
File "/usr/lib/python2.6/json/encoder.py", line 304, in _iterencode
yield floatstr(o, self.allow_nan)
File "/usr/lib/python2.6/json/encoder.py", line 47, in floatstr
raise ValueError(msg)
ValueError: Out of range float values are not JSON compliant: inf
>>>
Decimal can handle larger numbers, but obviously there is a performance penalty (and it can't be serialised with json)
>>> from decimal import Decimal
>>> Decimal('1e900')/10
Decimal("1E+899")
Here is an example of an addition that doesn't raise overflow exception
>>> a=1e308
>>> a+a
inf

Categories