Why sympy can't calculate? - python

import sympy as sp
import matplotlib.pyplot as plt
# set
Cd = 0.25
g = 9.81
pf = 10**(-6) # Perturbation Fraction
t = 4
v = 36
xr = [int(input('initial guess : '))]
i = 0
Ea = 1
Es = 0.01
# 함수 정의
def f(m):
return sp.sqrt(g * m / Cd) * sp.tanh(sp.sqrt(g * Cd / m) * t) - v
# real root
x = sp.Symbol('x')
ans = sp.solve(f(x)) # sp.solve()로 해 구하기
print(ans)
i want to get real root of f(x).
but this code have some problem in line for # real root
i can't figure out

You should not expect sympy to do miracles. Beyond relatively simple symbolic manipulations, sympy just get stuck, sometimes even returning wrong answers. You have to turn to commercial tools such as Maple or Mathematica in order to crack tough nuts.
Your alternative in most practical cases is to use scipy and get a good numeric solution, which is what you want most of the time rather than a closed form solution.

Sympy is a symbolic math library, trying to find exact symbolic solutions. As such, it doesn't work well with floats, as they are necessarily imprecise.
If your equations are fully numeric, it is usually recommended to employ numeric libraries such as numpy and scipy. If you're already doing symbolic manipulations (e.g. calculating differentials), sympy provides nsolve which calls a numeric solver. As such, it also needs a seed to start its numeric search. In your case it would look like:
# ....
xr = 1
ans = sp.nsolve(f(x), xr)
Result: 142.737633108449
Sympy also has a way to convert a sympy function to numpy format (in numpy things work much faster, but there are no symbolic expressions). sp.lambdify(x, f(x)) creates such a numpy function. Here is how it would look like with your example:
import matplotlib.pyplot as plt
import numpy as np
f_np = sp.lambdify(x, f(x))
xi = np.linspace(1, 1000, 2000)
plt.plot(xi, f_np(xi))
In an interactive environment, you can add a question mark to display the numpy source of the function:
>>> f_np?
Signature: f_np(x)
Docstring:
Created with lambdify. Signature:
func(x)
Expression:
6.26418390534633*sqrt(x)*tanh(6.26418390534633*sqrt(1/x)) - 36
Source code:
def _lambdifygenerated(x):
return (6.26418390534633*sqrt(x)*tanh(6.26418390534633*sqrt(x**(-1.0))) - 36)

If you look at your expression for f(x) you will see that it is highly non-linear (as also shown in the plot that JoahnC showed you):
6.26418390534633*sqrt(x)*tanh(6.26418390534633*sqrt(1/x)) - 36
SymPy cannot give an analytical solution for something that has no such solution. It can, however, give numerical approximations for univariate expressions. That's what nsolve is for. It needs an initial guess for the solution (as you anticipated by asking for xr).
>>> sp.nsolve(f(x), 100)
142.737633108449

Related

How write the symbolic variable in the sympy EDO dsolve

Good afternoon,
I'm coming here as I noticed something unusual in the results of dsolve() in sympy.
from sympy import *
from sympy.abc import x,y
import sympy as s
import numpy as np
n = symbols('n', complex=True)
s.init_printing()
f=Function('x')
eq=Derivative(f(x),x,x)+n**2*f(x)
a=dsolve(eq, f(x))
eq2=Derivative(f(x),x,x)+2**2*f(x)
a2=dsolve(eq2, f(x))
display(a.subs(n,2)==a2)
The generated result is False.
Looking only at the result of 'a' it is already possible to see that there are differences in the results using the symbolic variable 'n'.
Could anyone guide if I'm doing it the right way?
The solution sets are equivalent:
In [2]: a
Out[2]:
-ⅈ⋅n⋅x ⅈ⋅n⋅x
x(x) = C₁⋅ℯ + C₂⋅ℯ
In [3]: a2
Out[3]: x(x) = C₁⋅sin(2⋅x) + C₂⋅cos(2⋅x)
These are just different ways of writing the general solution. If you had declared n to be real then the sin/cos form would be used.
The two forms are related by Euler's formula:
https://en.wikipedia.org/wiki/Linear_differential_equation#Second-order_case

Adding powers of exponential equation in python

I'm new to Python, just started two days back. I was trying to perform division on two exponential expressions but the output won't show the powers added.
Following is my code.
from sympy import integrate, symbols, exp
from IPython.display import display, Markdown
x, y = symbols('x,y', positive=True)
fxy = y*exp(-y*(x+1))
fy= exp(-y)
sol = fxy/fy
sol
I guess you're looking for simplify:
>>> sympy.simplify(y * exp(-y*(x +1)) / exp(-y))
y*exp(-x*y)

Sympy gives numerical numpy output in dtype object format

I am using the following piece of code to create symbolic Sympy expressions for the spherical harmonics functions Y_l^m (4-pi-normalized over the full sphere) and their theta derivatives and then want to evaluate them on some evenly spaced grid in theta and phi coordinates:
import numpy as np
from math import pi, cos, sin
import sympy
from sympy import Ynm, simplify, diff, lambdify
from sympy.abc import n,m,theta,phi
resol = 2.5
dtheta_rad_ylm = -resol * pi/180.0
dphi_rad_ylm = resol * pi/180.0
thetaarr_rad_ylm_symm = np.arange(pi+dtheta_rad_ylm/2.0,dtheta_rad_ylm/2.0,dtheta_rad_ylm)
phiarr_rad_ylm = np.arange(0.0,2*pi,dphi_rad_ylm)
phi_grid_rad_ylm, theta_grid_rad_ylm_symm = np.meshgrid(phiarr_rad_ylm, thetaarr_rad_ylm_symm)
lmax = len(thetaarr_rad_ylm_symm)/2 - 1
nmax = (lmax+1)*(lmax+2)/2
ylms_symm_full = np.zeros((lmax+1, lmax+1, len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
dylms_symm_full = np.zeros((lmax+1, lmax+1, len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
for n in np.arange(0,lmax+1):
for m in np.arange(0,n+1):
print "generating resol %s, y_%d_%d" % (resol,n,m)
ylm_symbolic = simplify(2 * sympy.sqrt(sympy.pi) * Ynm(n,m,theta,phi).expand(func=True))
dylm_symbolic = simplify(diff(ylm_symbolic, theta))
# activate and deactivate comments for second-question-related error
# error appears later than the first-question-related error!
ylm_lambda = lambdify((theta,phi), sympy.N(ylm_symbolic), "numpy")
dylm_lambda = lambdify((theta,phi), sympy.N(dylm_symbolic), "numpy")
# ylm_lambda = lambdify((theta,phi), ylm_symbolic, "numpy")
# dylm_lambda = lambdify((theta,phi), dylm_symbolic, "numpy")
# activate and deactivate comments for first-question-related error
ylm_symm_full = np.asarray(ylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm), dtype=complex)
dylm_symm_full = np.asarray(dylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm), dtype=complex)
# ylm_symm_full = ylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm)
# dylm_symm_full = dylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm)
if n == 0 and m == 0:
ylm_symm_full = np.tile(ylm_symm_full, (len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
dylm_symm_full = np.tile(dylm_symm_full, (len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
ylms_symm_full[n,m,:,:] = np.real(ylm_symm_full)
dylms_symm_full[n,m,:,:] = np.real(dylm_symm_full)
There are several other packages providing the functionality of generating numeric Y_l^m without symbolic expressions, like scipy.special.sph_harm. However, it is crucial for me to get an "exact" derivative, i.e. not using any numerical differentiation method as e.g. finite differences (np.gradient). Therefore after getting the symbolic formula for the Y_l^m and simplifying those "as much as possible", lambda functions are created using the numpy backend (to be able to do vectorized calculations) and those are then evaluated on the grid. Finally I only need the real part of the spherical harmonics (I know that I could also create real spherical harmonics with Znm instead of Ynm, but...).
Two questions:
Mostly, the numerical output is then given as a usual 2d-numpy array of dtype complex or np.complex128. In some cases however, Sympy generates the array having a dtype object, this affects particularly the high l spherical harmonics. Array entries are displayed as complex 1-tuples instead of just complex numbers. The problem however is that taking the real part on that array has no effect, resulting in an error, since it is broadcast into an array that has a real dtype. Is there any particular reason for this? I do not see any immediate one, since the output is not inhomogeneous. Any way to change this without having to cast it additionally to dtype complex using np.asarray? It just takes additional computation time, makes the program slightly more complicated, but more importantly confusing.
You may also have noted that I use sympy.N to evaluate the expression already before I create the lambda function. The reason is that the prefactors in front of the spherical harmonics are in some cases of long format and numpy, for whoever knows which reason, cannot compute the sqrt of that number. Note that this is not in general true (np.sqrt(9L) = 3.0), but in this case there's an error message stating that the long object has no attribute sqrt. I suppose this is also related to the lambda function generation. Is there any method to tell Sympy to give already the symbolic expression in float format every time? Or, better, to somehow modify the lambdify call?
The code block should be stand-alone and testable, if you want to check these issues. Just remove the sympy.N and the np.asarray expressions. The first question relates to the error appearing earlier. Y_l^m generation up to the lmax which here is 35 takes roughly 10-15 minutes.
Thanks in advance for your help!
UPDATE: Here are some minimal, complete and verifiable examples. For both please import the required packages:
import numpy as np
from math import pi, cos, sin
import sympy
from sympy import Ynm, simplify, diff, lambdify
from sympy.abc import n,m,theta,phi
Error #1: object dtype problem at an = 31, m = 1:
# minimal, complete and verifiable example (MCVe) #1
# error message:
#---> 43 dylms_symm_full[n,m,:,:] = np.real(dylm_symm_full)
#TypeError: can't convert complex to float
ylm_symbolic = simplify(2 * sympy.sqrt(sympy.pi) * Ynm(31,1,theta,phi).expand(func=True))
dylm_symbolic = simplify(diff(ylm_symbolic, theta))
ylm_lambda = lambdify((theta,phi), ylm_symbolic, "numpy")
dylm_lambda = lambdify((theta,phi), dylm_symbolic, "numpy")
ylm_symm_full = ylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm)
dylm_symm_full = dylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm)
ylms_symm_full = np.zeros((len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
dylms_symm_full = np.zeros((len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
ylms_symm_full[:,:] = np.real(ylm_symm_full)
dylms_symm_full[:,:] = np.real(dylm_symm_full)
print ylm_symm_full
print dylm_symm_full
Error #2: long sqrt attribute problem at n = 32, m = 29:
# minimal, complete and verifiable example (MCVe) #2
# error message:
#---> 33 ylm_symm_full = np.asarray(ylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm), dtype=complex)
#/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/numpy/__init__.pyc in <lambda>(_Dummy_4374, _Dummy_4375)
#AttributeError: 'long' object has no attribute 'sqrt'
ylm_symbolic = simplify(2 * sympy.sqrt(sympy.pi) * Ynm(32,29,theta,phi).expand(func=True))
dylm_symbolic = simplify(diff(ylm_symbolic, theta))
ylm_lambda = lambdify((theta,phi), ylm_symbolic, "numpy")
dylm_lambda = lambdify((theta,phi), dylm_symbolic, "numpy")
ylm_symm_full = np.asarray(ylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm), dtype=complex)
dylm_symm_full = np.asarray(dylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm), dtype=complex)
ylms_symm_full = np.zeros((len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
dylms_symm_full = np.zeros((len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
ylms_symm_full[:,:] = np.real(ylm_symm_full)
dylms_symm_full[:,:] = np.real(dylm_symm_full)
print ylm_symbolic # the symbolic Y_32^29 expression
print type(175844649714253329810) # the number that causes the problem
The question of why your code produces an object array on occasion isn't something we can't easily answer without a MCVe - it can't just happen on occasion, it has to be reproducible.
However if the array is object, it might be easily converted to complex with
arr.astype(np.complex)
With a copy=False parameter you could apply it to all results without much computational cost.
arr.astype(np.complex, copy=False).real
The elements of the object version aren't tuples; they are scalar complex values, and just print that way.
In [187]: arr=np.random.rand(3)+np.random.rand(3)*1j
In [188]: arrO=arr.astype(object)
In [189]: arrO
Out[189]:
array([(0.6129476673822528+0.09323924558124808j),
(0.9540542895309456+0.81929476753951j),
(0.8068967867200485+0.9494305517611881j)], dtype=object)
In [190]: type(arrO[0])
Out[190]: complex
In [191]: arr.real
Out[191]: array([ 0.61294767, 0.95405429, 0.80689679])
In [193]: arrO[0]
Out[193]: (0.6129476673822528+0.09323924558124808j)
In [194]: arrO.astype(np.complex).real
Out[194]: array([ 0.61294767, 0.95405429, 0.80689679])
Some math operations do 'bleed-through' to elements of an object array, but real is not one of them. So as you note np.real(arrO) does not produce what you want.
Looking more at your code, including the stuff that scrolls off the screen I see you are using:
np.asarray(dylm_lambda(...), dtype=complex)
That's the same as my astype(complex, copy=False).
For an already complex array the computational cost is minimal. For an object array it has to make a new array, and the cost more substantial. But if you can't figure out by sympy is creating the object array, you have to live with the cost.

Evaluating trigonometric expressions in sympy

Using python 2.7 with PyCharm Community Edition 2016.2.3 + Anaconda distribution.
I have an input similar to :
from sympy import *
x = symbols('x')
f = cos(x)
print (f.subs(x, 25))
The output is cos(25), . Is there a way to evaluate trigonometric identities such as sin/cos, at a certain angle ? I've tried cos(degrees(x)), but nothing differs. Am I missing some crucial part of documentation or there really isn't a way to do this ? Ty for your help :)
Perform a numerical evaluation using function N:
>>> from sympy import N, symbols, cos
>>> x = symbols('x')
>>> f = cos(x)
>>> f.subs(x, 25)
cos(25)
>>> N(f.subs(x, 25)) # evaluate after substitution
0.991202811863474
To make the computation in degrees, convert the angle to radians, using mpmath.radians, so the computation is performed on a rad value:
>>> import mpmath
>>> f.subs(x, mpmath.radians(25))
0.906307787036650
Importing with * (wildcard imports) isn't a very good idea. Imagine what happens if you equally did from math import *, then one of the cos functions from both modules will be out in the wild.
See the PEP 8 guideline on imports.

Python Numpy - Complex Numbers - Is there a function for Polar to Rectangular conversion?

Is there a built-in Numpy function to convert a complex number in polar form, a magnitude and an angle (degrees) to one in real and imaginary components?
Clearly I could write my own but it seems like the type of thing for which there is an optimised version included in some module?
More specifically, I have an array of magnitudes and an array of angles:
>>> a
array([1, 1, 1, 1, 1])
>>> b
array([120, 121, 120, 120, 121])
And what I would like is:
>>> c
[(-0.5+0.8660254038j),(-0.515038074+0.8571673007j),(-0.5+0.8660254038j),(-0.5+0.8660254038j),(-0.515038074+0.8571673007j)]
There isn't a function to do exactly what you want, but there is angle, which does the hardest part. So, for example, one could define two functions:
def P2R(radii, angles):
return radii * exp(1j*angles)
def R2P(x):
return abs(x), angle(x)
These functions are using radians for input and output, and for degrees, one would need to do the conversion to radians in both functions.
In the numpy reference there's a section on handling complex numbers, and this is where the function you're looking for would be listed (so since they're not there, I don't think they exist within numpy).
There's an error in the previous answer that uses numpy.vectorize - cmath.rect is not a module that can be imported. Numpy also provides the deg2rad function that provides a cleaner piece of code for the angle conversion. Another version of that code could be:
import numpy as np
from cmath import rect
nprect = np.vectorize(rect)
c = nprect(a, np.deg2rad(b))
The code uses numpy's vectorize function to return a numpy style version of the standard library's cmath.rect function that can be applied element wise across numpy arrays.
I used cmath with itertools:
from cmath import rect,pi
from itertools import imap
b = b*pi/180 # convert from deg to rad
c = [x for x in imap(rect,a,b)]
import numpy as np
import cmath.rect
nprect = np.vectorize(rect)
c = nprect(a,b*np.pi/180)
tom10 answer works fine... you can also expand the Euler's formula to:
def P2R(A, phi):
return A * ( np.cos(phi) + np.sin(phi)*1j )

Categories

Resources