numpy: how to set precision printing poly1d - python

I want to set precision (more in general the format) when printing a polynomial. For example:
>>> import numpy as np
>>> beta = np.asarray([-3.61380614191654e-09, 2.489464876955e-05, -0.0836384579176789, 143.213931472633])
>>> p = np.poly1d(beta)
>>> p
poly1d([-3.61380614e-09, 2.48946488e-05, -8.36384579e-02, 1.43213931e+02])
>>> print(p)
3 2
-3.614e-09 x + 2.489e-05 x - 0.08364 x + 143.2
>>> np.set_printoptions(precision=8) # this has no effect
>>> print(p)
3 2
-3.614e-09 x + 2.489e-05 x - 0.08364 x + 143.2
I would like to get, calling print with polynomial, something similar to:
3 2
-3.61380614e-09 x + 2.48946487e-05 x - 0.08363845 x + 143.21393147
[Edit]
I tried using numpy.polynomial as A. Donda suggest but I get a different behaviour:
Python 3.8.6 (default, Jan 27 2021, 15:42:20)
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> beta = np.asarray([-3.61380614191654e-09, 2.489464876955e-05, -0.0836384579176789, 143.213931472633])
>>> p = np.polynomial.Polynomial(np.flip(beta))
>>> p
Polynomial([ 1.4321393147e+02, -8.3638457918e-02, 2.4894648770e-05,
-3.6138061419e-09], domain=[-1, 1], window=[-1, 1])
>>> print(p)
poly([ 1.4321393147e+02 -8.3638457918e-02 2.4894648770e-05 -3.6138061419e-09])
printing the polynomial using print(p) does not give me the expected result
[Edit2]
Ubuntu 20.10 has numpy 1.18.4. Instead, forcing a newer version (1.20.1) using pip3, I get the desired result.

The __str__ method of poly1d uses a custom function to format numbers:
def fmt_float(q):
s = '%.4g' % q
if s.endswith('.0000'):
s = s[:-5]
return s
So, you are right, it is not influenced by NumPy's printoptions.
But the documentation for poly1d says that it is "part of the old polynomial API" and one should better use numpy.polynomial:
>>> p = np.polynomial.Polynomial(np.flip(beta))
>>> p
Polynomial([ 1.432139e+02, -8.363846e-02, 2.489465e-05, -3.613806e-09], domain=[-1, 1], window=[-1, 1])
>>> print(p)
143.213931472633 - 0.0836384579176789·x¹ + 2.489464876955e-05·x² - 3.61380614191654e-09·x³
The np.flip is necessary because other than poly1d, Polynomial expects the coefficients by increasing order.
That seems to solve your concrete problem, getting the coefficients in high precision. However, Polynomial.__str__ still doesn't respect printoptions:
>>> np.set_printoptions(precision=3)
>>> print(p)
143.213931472633 - 0.0836384579176789·x¹ + 2.489464876955e-05·x² - 3.61380614191654e-09·x³
You could file an issue on the NumPy repository.

Related

How to calculate 2x + 4 = 10 using sympy?

How to calculate 2x + 4 = 10 using Sympy? Is it even possible?
It does not run on Sympy gamma but it runs on Wolframalpha and Cymath. Is it normal or is there some built-in library that should be used with this type of equation?
To represent it,
>>> from sympy.abc import x
>>> from sympy import S, Eq, solve
>>> eq = Eq(2*x + 4, 10)
>>> pprint(eq)
2*x + 4 = 10
To solve it:
>>> solve(eq)
[3]
To interpret input:
>>> s = '2*x + 4 = 10'
>>> eq = Eq(*map(S, s.split('=')))

How to convert a number to base 16 with math ( not using strings )?

Say i have
1009732533765201
and i want:
0x1009732533765201 which is
1155581383011619329
You can do this in programming languages with strings like this
int('1009732533765201',16)
but i want the pure math way. To convert 1009732533765201 to it's base16 of 1155581383011619329
I tried: int('1009732533765201',16) but this uses a string, and is slow for large numbers, i'm looking for a math angle only.
Here is a math way i know how to do it:
0x1009732533765201 = 1155581383011619329
Here is a python way to do it:
int('1009732533765201',16)
but i can only do the first math version manually. How can this be accomplished, converting 0x1009732533765201 without using a string to concatenating '0x' to '1009732533765201' and not using eval
Is there any way to take 1009732533765201, and convert it to the same ouput as 0x1009732533765201 to get its integer without using int('1009732533765201',16) my goal is to find a faster approach
ANSWERED BY PARTHIAN SHOT, here is the result of his approach which is exactly what i was looking for, a way to do this without int()
orig = 1009732533765201
num = orig
result = 0
i = 0
while num != 0:
result += (num % 10) * (16 ** i)
num //= 10
i += 1
print(orig, num, result, "%x" % (result))
1009732533765201 0 1155581383011619329 1009732533765201
As I said in my comment, Python knows, out of box, how to deal with base 16 numbers. Just go ahead and assign the base 16 value to a variable.
Here is an example:
Python 3.7.4 (default, Aug 12 2019, 14:45:07)
[GCC 9.1.1 20190605 (Red Hat 9.1.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> i=0x16
>>> i
22
>>> i=0xAA
>>> i
170
>>>
And as I said, that works for other bases, like base 2:
>>> i=0b1010
>>> i
10
>>>
And base 8:
>>> i=0o12
>>> i
10
>>>
The idea here is that we're looking at each digit of the original decimal number one at a time, from right to left, and multiplying it by 16 ** i instead of 10 ** i, then adding it to the new number.
The result is the equivalent of interpreting the original decimal representation of the number as if it were hexadecimal.
#!/usr/bin/env python
orig = 34029235
num = orig
result = 0
i = 0
while num != 0:
result += (num % 10) * (16 ** i)
num //= 10
i += 1
print(orig, num, result, "%x" % (result))
And running that code gets us...
bash$ ./main.py
(34029235, 0, 872583733, '34029235')
bash$

Using Sympy, calculate a limit of sequence whose terms alternate sign

I am trying Sympy to find the limit of this sequence
((-1)**(n))*(2**(-n))
using the PyCharm debugger and the IPython console.
The python module is:
import numpy as np
from plotly.graph_objs import Scatter, Figure
from sympy import Symbol, srepr, limit_seq, oo
from sympy.abc import n
import plotly.plotly as py
py.sign_in('****', '****************')
sym_func = 1 + ((-1)**(n))*(2**(-n))
def rng_func(i):
try:
return 1 + np.power(-1, i)/(np.power(2,i))
except ZeroDivisionError as e:
raise ValueError('Invalid inputs') from e
class Sequence(object):
def __init__(self, i):
self.sum = 0
self.dom = np.arange(1, i + 1, 1)
self.rng = np.array([])
self.is_positive = True
self.is_alternating = True
for i in self.dom:
rng_val = rng_func(i)
self.rng = np.append(self.rng, [rng_val])
self.sum += rng_val
sign_array = np.sign(self.rng)
for i in self.dom:
if self.rng[i - 1] <= 0:
self.is_positive = False
break
for i in self.dom:
if sign_array[0] == -1:
alt_sign = np.power(-1, i)
else:
alt_sign = np.power(-1, i-1)
if alt_sign != sign_array[i-1]:
self.is_alternating = False
break
seq = Sequence(10)
data = [Scatter(x=seq.dom, y=seq.rng)]
fig = Figure(data=data)
py.image.save_as(fig, filename='plots/I3.png')
The IPython Console:
Connected to pydev debugger (build 171.4424.56)
Backend Qt5Agg is interactive backend. Turning interactive mode on.
import sys; print('Python %s on %s' % (sys.version, sys.platform))
Python 3.5.2 |Anaconda custom (64-bit)| (default, Jul 2 2016, 17:53:06)
Type "copyright", "credits" or "license" for more information.
IPython 5.1.0 -- An enhanced Interactive Python.
In[1]: limit_seq(((-1)**(n))*(2**(-n)), n)
In[2]: limit_seq((1**(n))*(2**(-n)), n)
Out[3]:
0
My question is why does Sympy not return a value for the limit for In[1]: but does for In[2]:? The difference is the 1 versus -1 in the numerator.
Is there a different way to create an alternating sign in Sympy?
As of now (SymPy 1.1.1), limit_seq does not support oscillating sequences such as those with (-1)**n. Its documentation says this in a somewhat technical way:
The terms should be built from rational functions, indefinite sums, and indefinite products over an indeterminate n. A term is admissible if the scope of all product quantifiers are asymptotically positive. Every admissible term is asymptotically monotonous.
As a workaround, you can use this:
def mylimit_seq(seq, n):
n_ = Dummy("n", integer=True, positive=True)
L1 = limit_seq(seq.subs(n, 2*n_), n_)
L2 = limit_seq(seq.subs(n, 2*n_ + 1), n_)
if L1 == L2:
return L1
Then mylimit_seq((-1)**n * 2**(-n), n) returns 0.
In a future release, limit_seq will work for such sequences. You can also get this functionality today by cloning SymPy from GitHub.
I separated the series into even terms and odd terms, I reflected the series containing the odd terms about the x axis. This series becomes:
(1)*(2**(-n)), which then is identical to the series containing the even terms.
The function calculating the limit remains the same:
def mylimit_seq(seq, n):
try:
L1 = limit_seq(seq.subs(n, 2*n), n)
L2 = limit_seq(seq.subs(n, 2*n + 1), n)
except:
return np.NaN
if L1 == L2:
return L1
else:
return np.NaN

How to solve multivariate inequalities with python and sympy?

I'm quite new using python and Sympy... And got a problem to solve multivariate inequalities using sympy.
Let's say I have a lot of functions in a file which look like this :
cst**(sqrt(x)/2)/cst
exp(sqrt(cst*x**(1/4)))
log(log(sqrt(cst + exp(x))))
(y**(1/4) + y)**cst
sqrt(y/log(x))/cst
sqrt(cst**log(cst) + x)
(y**2)**(x/4)
sqrt(y*sqrt(cst**y))
log(sqrt(2)*sqrt(cst)*x)
I need to derivate them, set the value of the constant and check if, for each functions f,
df/dx > 0
df/dy < 0
With x in [0, +oo) and y in [0, 1].
To derivate i use :
dx = diff(f, x)
dy = diff(f, y)
Then when i try :
cst = 2 #(for example)
solve(dx > 0)
I got this error :
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/sympy/solvers/solvers.py", line 634, in solve
symbols=symbols)
File "/usr/local/lib/python2.7/dist-packages/sympy/solvers/inequalities.py", line 374, in reduce_inequalities
raise NotImplementedError("only univariate inequalities are supported")
NotImplementedError: only univariate inequalities are supported
But if i try that :
x=Symbol('x', real=True, postive=True, nonzero=True)
y=Symbol('y', real=True, postive=True, nonzero=True)
solve(x**2+y > 0)
I got :
True
Which is good and workable answer.
Is there anyway to solve multivariate inequalities and always get an workable answer?
For example I would like to get :
solve(x**2-y>0)
Or(x>-sqrt(y), x>sqrt(y))
When trying to solve this with SymPy you get a pretty clear error message: NotImplementedError: only univariate inequalities are supported. Be aware that this means that the SymPy team will be very happy if you contribute an algorithm that solves this problem.
Now that it is clear that sympy.solve is not powerful enough you can try another approach. Recently (in 0.7.2) an implicit plotting routine was added to sympy that can plot where an expression evaluates to True. Regretfully it is only a numeric solution, not a symbolic one that you can get from solve but it might be enough:
From the image you can see that there is only a single line where the expression changes sign, so solving for expr==0 might give you what you want. And this is indeed the case:
There is a multivariate inequality solver in mystic, which is built on top of sympy. It uses optimization and the (mathematical) mapping of sets to provide this feature. It's not perfect, but works for many cases.
>>> equations = '''
... 2*A + 3*B >= C
... A*B > D
... C < 4*A
... D == 0
... '''
>>>
>>> import mystic.symbolic as ms
>>> var = list('ABCD')
>>> eqns = ms.simplify(equations, variables=var)
>>> print eqns
D == 0
B > 0
A > C/4
A >= -3*B/2 + C/2
A > D/B
>>>
>>> # generate a constraints function, which maps one space to another
>>> constrain = ms.generate_constraint(ms.generate_solvers(eqns, var))
>>> solution = constrain([1,2,3,4])
>>> print solution
[1, 2, 3, 0]
>>> # here's the solution...
>>> dict(zip(var,solution))
{'A': 1, 'C': 3, 'B': 2, 'D': 0}
>>>
>>> A=1; C=3; B=2; D=0
>>> 2*A + 3*B >= C
True
>>> A*B > D
True
>>> C < 4*A
True
>>> D == 0
True
>>>
Let's do it again, with the suggested test:
>>> equations = """x**2 - y >= 0
... x + y = 0
... """
>>> eqns = ms.simplify(equations, variables=var)
>>> constrain = ms.generate_constraint(ms.generate_solvers(eqns, var))
>>> solution = constrain([1,3])
>>> solution
[-3, 3]
>>> dict(zip(var, solution))
{'y': 3, 'x': -3}
>>> y=3; x=-3
>>> x**2 - y >= 0
True
>>> x+y == 0
True
>>>
mystic uses a combination of sympy and numerical optimization to simplify inequalities; and when presented with an initial guess solution, can (most of the time, but not always) generate a valid solution to the equations. mystic won't actually solve the inequalities per se, but it will (usually) generate a valid solution to the inequalities.

how to combine exponents? (x**a)**b => x**(a*b)?

how to simplify exponents in equations in sympy
from sympy import symbols
a,b,c,d,e,f=symbols('abcdef')
j=(a**b**5)**(b**10)
print j
(a**(b**5))**(b**10) #ans even after using expand simplify
# desired output
a**(b**15)
and if it is not possible with sympy which module should i import in python?
edit
even if i define 'b' as real,and also all other symbols
b=symbols('b',real=True)
not getting simplified exponents
it simplifies only if exponents are constants
a=symbols('a',real=True)
b=symbols('b',real=True)
(a**5)**10
a**50 #simplifies only if exp are numbers
(a**b**5)**b**10
(a**(b**5))**b**10 #no simplification
(xm)n = xmn is true only if m, n are real.
>>> import math
>>> x = math.e
>>> m = 2j*math.pi
>>> (x**m)**m # (e^(2πi))^(2πi) = 1^(2πi) = 1
(1.0000000000000016+0j)
>>> x**(m*m) # e^(2πi×2πi) = e^(-4π²) ≠ 1
(7.157165835186074e-18-0j)
AFAIK, sympy supports complex numbers, so I believe this simplification should not be done unless you can prove b is real.
Edit: It is also false if x is not positive.
>>> x = -2
>>> m = 2
>>> n = 0.5
>>> (x**m)**n
2.0
>>> x**(m*n)
-2.0
Edit(by gnibbler): Here is the original example with Kenny's restrictions applied
>>> from sympy import symbols
>>> a,b=symbols('ab', real=True, positive=True)
>>> j=(a**b**5)**(b**10)
>>> print j
a**(b**15)
a,b,c=symbols('abc',real=True,positive=True)
(a**b**5)**b**10
a**(b**15)#ans
This may be related to this bug.

Categories