I keep getting expressions like this image, despite declaring these symbols as reals.
The code to reproduce is:
import sympy as sp
delta = sp.Symbol('delta', real=True)
f = sp.sqrt(1/delta)
prod = sp.conjugate(f)*f
prod.subs(delta,delta)
I expected to get 1/delta
Also trying simplify() does not work either.
According to the official SymPy Docs for conjugate, it looks like the function is supposed to return the complex conjugate for its input. In other words, it takes the complex part of the number and flips the sign.
In your example, you are taking the square root of a variable. If delta = -1, then the resulting conjugate could be unreal and thus different than if delta was any other integer. Thus, SymPy wraps the result in a conjugate object.
If you want to tell Sympy that your variable delta is positive (and thus f must be real), then you should define it as delta = sp.Symbol('delta', real=True, positive=True).
Related
I am solving a physical problem in which I have to work with the unbounded radial solution of the Schroedinger equation in the presence of a point-like charged particle Zeff.
I define the UNBRWAVE function in python as:
import numpy as np
import math as mh
from mpmath import *
a0 = 1/3.7 #edited new
Zeff = 1.0 #edited new
def UNBRWAVE(r, k, L, n, l):
return (2.0*np.pi)**(3.0/2.0)*(2.0*k*r)**L*(np.sqrt(2.0/np.pi)*np.abs(mh.gamma(L+1.0-(1j*Zeff)/(k*a0)))*np.exp(np.pi*Zeff/(2.0*k*a0)))/nh.gamma(2.0*L+1.0+1.0)*np.exp(-1j*k*r)*hyp1f1(L+1.0-(1j*Zeff)/(k*a0), 2.0*(L+1.0), 2.0*1j*k*r)
Where Zeff=1, 1j is the imaginary unit and hyp1f1 is the hypergeometric 1F1 function. The input parameters are r(a real number), k (a real number), L (an integer number), n (an integer number), l(an integer number). Whenever I call this function, like in
UNBRWAVE(10.0, 5.0, 5, 1, 0)
I get the error message
TypeError: can't convert complex to float
I am new in python so I would like to know how to code better this complex function of real arguments to get the values and perform operations with them.
Use scipy.special.gamma() instead of math.gamma(). The latter does not support complex argument and complains that it cannot convert the complex to float.
Following #devesh-kumar-singh advice would help you find the problematic part of the long expression.
The code lacks definition of a0, and nh.gamma contains a typo.
I am very new to programming, and had to use sympy for a school project.
I think I get that using nonlinsolve to return an angle gives an ImageSet with the angle + 2n*pi. However I want it to return only the value of the angle (in the interval [0,pi/2]), and as one value and not an interval.
from sympy import nonlinsolve, symbols,cos
x=symbols('x')
print(nonlinsolve([cos(x)-1],[x]).args[0][0])
I want the result to be 0 and not 2*n*pi.
Clarification : I know that the result is correct, but I only want one value, that I can use algebraically, and I don't know how Sympy works (how to manipulate ImageSets)
So I might be wrong because i dont use sympy, but the solution that solvers return seems to be corect to me.
ImageSet(Lambda(_n, 2*_n*pi), Integers)
From what I understand solver returned lambda function. Cosinus is a cyclic function which means it reapeats it's value every 2PI. So the solver says first solution (_n = 0) is 0, second (_n = 1) is 2pi and so on.
look at the function plot and it will hopefully make sense:
Wolfram Alpha - (cos(x) - 1)
EDIT: I think you need to use intersect method of imageset like this( note that intersect returns all the intersections, here i selected just the first one):
from sympy import nonlinsolve, symbols,cos, Interval
import math
x = symbols('x')
f = nonlinsolve([cos(x)-1], [x]).args[0][0]
sol = f.intersect(Interval(0, math.pi/2)).args[0]
print(sol)
I want to make a series expansion for a function F(e,Eo) up to a certain power of e and integrate over the Eo variable numerically.
What I thought was using SymPy to make the power series in e, and then use MPMath for the numerical integration over Eo.
Below is an example code. I receive the message that it can not create mpf from the expression. I guess the problem has to do with the fact that with the series from SymPy has an O(e**5) term at the end, and later that I want the numerical integration to show a function of e instead of a number.
import sympy as sp
import numpy as np
from mpmath import *
e = sp.symbols('e')
Eo = sp.symbols('Eo')
expr = sp.sin(e-2*Eo).series(e, 0, 5)
F = lambda Eo : expr
I = quad(F, [0, 2*np.pi])
print(I)
It’s evident that I need a different approach, but I would still need the numerical integration for my actual code because it has much more complicated expressions that could not be integrated analytically.
Edit: I should have chosen a complex function of real variables for the example code, I am trying this (the expansion and integration) for functions such as:
expr = (cos(Eo) - e - I*sqrt(1 - e ** 2)*sin(Eo)) ** 2 * (cos(2*(Eo - e*sin(Eo))) + I*sin(2*(Eo - e*sin(Eo))))/(1 - e*cos(Eo)) ** 4
Here is an approach similar to Wrzlprmft's answer but with a different way of handling coefficients, via SymPy's polynomial module:
from sympy import sin, pi, symbols, Integral, Poly
def integrate_coeff(coeff):
partial_integral = coeff.integrate((Eo, 0, 2*pi))
return partial_integral.n() if partial_integral.has(Integral) else partial_integral
e,Eo = symbols("e Eo")
expr = sin(e-sin(2*Eo))
degree = 5
coeffs = Poly(expr.series(e, 0, degree).removeO(), e).all_coeffs()
new_coeffs = map(integrate_coeff, coeffs)
print((Poly(new_coeffs, e).as_expr() + e**degree).series(e, 0, degree))
The main code is three lines: (1) extract coefficients of e up to given degree; (2) integrate each, numerically if we must; (3) print the result, presenting it as a series rather than a polynomial (hence the trick with adding e**degree, to make SymPy aware that the series continues). Output:
-6.81273574401304e-108 + 4.80787886126883*e + 3.40636787200652e-108*e**2 - 0.801313143544804*e**3 - 2.12897992000408e-109*e**4 + O(e**5)
I want the numerical integration to show a function of e instead of a number.
This is fundamentally impossible.
Either your integration is analytical or numerical, and if it is numerical it will only handle and yield numbers for you (the words numerical and number are similar for a reason).
If you want to split the integration into numerical and analytical components, you have to do so yourself – or hope that SymPy automatically splits the integration as needed, which it unfortunately is not yet capable of.
This is how I would do it (details are commented in the code):
from sympy import sin, pi, symbols, Integral
from itertools import islice
e,Eo = symbols("e Eo")
expr = sin(e-sin(2*Eo))
# Create a generator yielding the first five summands of the series.
# This avoids the O(e**5) term.
series = islice(expr.series(e,0,None),5)
integral = 0
for power,summand in enumerate(series):
# Remove the e from the expression
Eo_part = summand/e**power
# … and ensure that it worked:
assert not Eo_part.has(e)
# Integrate the Eo part:
partial_integral = Eo_part.integrate((Eo,0,2*pi))
# If the integral cannot be evaluated analytically, …
if partial_integral.has(Integral):
# … replace it by the numerical estimate:
partial_integral = partial_integral.n()
# Re-attach the e component and add it to the sum:
integral += partial_integral*e**power
Note that I did not use NumPy or MPMath at all (though SymPy uses the latter under the hood for numerical estimates). Unless you really really know what you’re doing, mixing those two with SymPy is a bad idea as they are not even aware of SymPy expressions.
Hi I am writing Python code which returns the associated Legendre function.
Using numpy poly1d function on this part,
firstTerm = (np.poly1d([-1,0,1]))**(m/2.0) # HELP!
It yields an error since it can only be raised to integer.
Is there any other alternative where I can raise the desired function to power 1/2 and etc.?
The reason you can't raise your poly1d to half-integer power is that that would not be a polynomial, since it would contain square roots.
While in principle you could orthogonalize the functions yourself, or construct the functions from something like sympy.special.legendre, but your safest bet is symbolic math. And hey, we already have sympy.functions.special.polynomials.assoc_legendre! Since symbolic math is slow, you should probably use sympy.lambdify to turn each function into a numerical one:
import sympy as sym
x = sym.symbols('x')
n = 3
m = 1
legfun_sym = sym.functions.special.polynomials.assoc_legendre(n,m,x)
legfun_num = sym.lambdify(x,legfun_sym)
print(legfun_sym)
print(legfun_num)
x0 = 0.25
print(legfun_sym.evalf(subs={x:x0}) - legfun_num(x0))
This prints
-sqrt(-x**2 + 1)*(15*x**2/2 - 3/2)
<function <lambda> at 0x7f0a091976e0>
-1.11022302462516e-16
which seems to make sense (the first is the symbolic function at x, the second shows that lambdify indeed creates a lambda from the function, and the last one is the numerical difference of the two functions at the pseudorandom point x0 = 0.25, and is clearly zero within machine precision).
In the documentation of scipy(http://docs.scipy.org/doc/scipy-0.15.0/reference/generated/scipy.special.sph_harm.html) it clearly states that scipy.special.sph_harm returns a complex float. given by the expression shown in the link. When trying trying to insert some values however, i keep on getting only a negligible value of what is expected.
The real(ie. not imaginary) value I believe is something closer to the absolute value expected if you compute the mathematical expression in the link:
from scipy.special import sph_harm,lpmv
m=2;n=5;th=2.1;ph=0.4
print(sph_harm(m,n,th,ph))
#returns (0.36574435883734352+2.5429495084534193e-310j) (essentially no imag.part
def norm(m,n): #sqrt part
return np.sqrt((2*n+1)/(4*np.pi) * \
np.math.factorial(n-m)/np.math.factorial(n+m))
def ie(m,theta): #imaginary exponential part
return np.exp(1j*m*theta)
out=norm(m,n)*ie(m,th)*lpmv(m,n,np.cos(ph)) #lpmv=legendre
print(out,abs(out))
#returns (-0.179310129764-0.31877392206j) 0.365744358837
Is there something wrong with the sph_harm or am I somehow using it wrong?
I am using scipy v0.15.1