I think it is pretty clear from the title as to what I am trying to accomplish. So, let us get on with the code:
import math
import numpy as np
import scipy
#from scipy import scipy.optimize.fsolve as sci_solve
x0 = -5
def function(x):
x**5 + x**4 + x**3 + x**2 + x + 1
#print sci_solve(function, x0)
print scipy.optimize.fsolve(function, x0)
Okay, so when I run this code, I get [-5.]. When did it simply print my initial value, and not the roots of this equation? Also, when I ran the code without # before the lines containing the code #from scipy import scipy.optimize.fsolve as sci_solve and print sci_solve(function, x0), it gave me a syntax error.
What am I doing wrong?
As hcwhsa points out, I neglected to relate to the reader the version of python I am using, and I am terribly sorry for this. I am using version 2.7
I'd never actually heard of the scipy module before this question (so thank you for that), but from the example code given at http://folk.uio.no/inf3330/scripting/doc/python/SciPy/tutorial/old/node18.html, it appears that you need to put a return statement before the polynomial given in after the line def function(x):.
One way to do this:
from scipy import *
x0 = -5
p = poly1d([1, 1, 1, 1, 1, 1])
# evaluate for x = x0
p(x0)
# get roots
roots(p)
This gives you all roots, including complex ones. If you want only real roots, you can iterate over roots(p) (it's an array) and check that each item's imag attribute is 0.0.
Related
I need to find the root of some functions in python, for which I have only numerical data, not the actual functional form. I tried to use scipy.optimize.root, but I am getting some weird result. Here is a minimal code reproducing the issue:
import numpy as np
from scipy.interpolate import CubicSpline
from scipy import optimize
def func(x):
return (x-4)*(np.exp(x)+1)
x = np.random.rand(1000)*10
y = func(x)
data = np.column_stack((x,y))
p = data[:,0].argsort()
x = data[:,0][p]
y = data[:,1][p]
cs = CubicSpline(x, y)
sol = optimize.root(cs, [0], method='hybr')
print(sol.x)
The output of the code is -5.42024365 which is obviously not a root of the function I picked. If I try cs(-5.42024365) I get -0.00305901 (the initial data is randomly generated, so that value will change a bit, but it is clearly not zero). If I try cs(4) I get -4.46575001e-07 which looks more like a root (and it is actually the root I am trying to find). What am I doing wrong. Why is scipy.optimize.root not giving me the right root, even for this simple problem? Thank you!
Here's your function. It has just found the second root.
Good evening.
I'm currently trying to solve the 1D Schrödinger eq. (time independent) with the Numerov method. The derivation of the method is clear to me but I have some problems with the implementation. I tried to look for solutions on google, and there are some (like this one or this one), but I don't really understand what they are doing in their codes...
The Problem:
With some math you can get the equation to this form:
where . For the beginning I'd like to look at the potential V(x)=1 if -a<x<a.
Since I don't have values for the energy or the first values of Psi (which are needed to start the algorithm) I just guessed some...
The code looks like this:
import numpy as np
import matplotlib.pyplot as plt
from scipy.constants import hbar
m= 1e-27
E= 0.5
def numerov_step(psi_1,psi_2,k1,k2,k3,h):
#k1=k_(n-1), k2=k_n, k3=k_(n+1)
#psi_1 = psi_(n-1) and psi_2=psi_n
m = 2*(1-5/12. * h**2 * k2**2)*psi_2
n = (1+1/12.*h**2*k1**2)*psi_1
o = 1 + 1/12. *h**2 *k3**2
return (m-n)/o
def numerov(N,x0,xE,a):
x,dx = np.linspace(x0,xE,N+1,retstep=True)
def V(x,a):
if (np.abs(x)<a):
return 1
else:
return 0
k = np.zeros(N+1)
for i in range(len(k)):
k[i] = 2*m*(E-V(x[i],a))/hbar**2
psi= np.zeros(N+1)
psi[0]=0
psi[1]=0.1
for j in np.arange(2,N):
psi[j+1]= numerov_step(psi[j],psi[j+1],k[j-1],k[j],k[j+1],dx)
return psi
x0 =-10
xE = 10
N =1000
psi=numerov(N,x0,xE,3)
x = np.linspace(x0,xE,N+1)
plt.figure()
plt.plot(x,psi)
plt.show()
Since the plot doesn't look like a wavefunction at all something has to be wrong, but I'm having trobule to find out what it is.. Would be nice if someone could help a little.
Thanks Sito
Unfortunately I don't quite remember the quantum physics so I don't understand some details. Still I see some bugs in your code:
Why inside numerov_step you square k1, k2 and k3?
In your main cycle
for j in np.arange(2,N):
psi[j+1]= numerov_step(psi[j],psi[j+1],k[j-1],k[j],k[j+1],dx)
you messed up with indices. It looks like this line should be
for j in np.arange(2, N):
psi[j] = numerov_step(psi[j - 2], psi[j - 1], k[j - 2], k[j - 1], k[j], dx)
This is the part I don't really understand. Looking into animation at your first link it looks like this equation has good solutions only for certain combinations of V(x) and E and in other cases it quickly goes wild. It looks like both your V(x) and proportion of E to hbar and V(x) are quite different from the referenced articles and this might be one more reason why the solution goes wild.
I would like to use the SymPy packages to find the roots of a fourth-order polynomial equation. Subsequently I would like to plot these roots as a function of the parameters of the polynomial equations. I have written the piece of code below. It seems to calculate everything fine, but I cannot plot the results as I get the error "x and y are not of the same dimension". I think it has something to do with my usage of SymPy, because normally it always works like this.
from sympy import *
from math import *
from numpy import *
import pylab as lab
def RootFunc(root, m, c0, r, En):
A = 2*(m**2 - 0.25 - c0**2)/r**2 + 4
B = 8*En*c0/r
C = -4 - 4*En**2 + ((c0**2 + m**2 -.25)/r**2 + 2)**2
return root.subs([(a,A),(b,B),(c,C)])
# Define necessary symbols
x = symbols('x')
a, b, c = symbols('a b c')
En, r = symbols("En r")
# Fix constants
m = 0
c0 = -2
# Solve equation
eq = x**4 + a*x**2 + b*x + c
sol = solve(eq,x)
root1 = sol[0]
grid = linspace(1,10,10)
sol1 = [RootFunc(root1, m, c0, r, .5) for r in grid]
lab.figure(1)
lab.plot(grid,sol1)
lab.show()
Are you sure that you a running the same script that you've given us here?
I say this because I can copy and paste your example verbatim and it works with absolutely no issue.
Once you've checked, could you post which version of Python, SymPy, NumPy and Matplotlib you're using please?
Edit: I think something got slightly lost in translation when you put up your first minimal working example (MWE). The solution in your MWE was real-valued so it didn't have the same issue as your actual program. However, onto the solution:
Your main issue here is this line
sol1 = [RootFunc(root1, m, c0, help, .5) for help in grid]
RootFunc in this case returns a sympy.core.add.Add which pylab has no concept of and therefore can't plot. In your MWE you recognised that this was the issue and tried calling N() and real() on the return value. Unfortunately this just wraps the sympy.core.add.Add object in a NumPy array. When Pylab tries to plot this array it finds a sympy.core.add.Add object which it has no concept of and therefore just throws an error.
Fortunately SymPy allows you to turn a sympy.core.add.Add object into a number using int(), float() or complex(). Since your roots are complex you should use complex() on the return value and then to get the real component use .real.
So to get it too work you should just change the above line to
sol1 = [complex(RootFunc(root1, m, c0, help, .5)).real for help in grid]
Edit2: Just a quick point about style. You're using a lot of wildcard imports in your code (e.g. from numpy import *), which is fine if you're the only person using the code, it does make it neater after all.
However, if you're going to be posting on a forum like this please could you try to use qualified imports (like you've done for pylab) so that we don't have to go trudging through the documentation for all the modules you've used to try and figure out what you're doing.
One other thing: when you encounter a problem like this it really helps to execute it line by line in the python shell and examine the types (with type()) and values (with print() or repr()) of your variables. For this purpose I would strongly urge you to learn how to use IPython as it can really help.
You might be breaking some things with your imports. Can you try this:
import sympy as sy
import numpy as np
import pylab as lab
def RootFunc(root, A, B):
return root.subs([(a,A),(b,B)])
# Define necessary symbols
x = sy.symbols('x')
a, b = sy.symbols('a b')
# Solve equation
eq = x**4 + a*x**2 + b*x
sol = sy.solve(eq,x)
root1 = sol[1] # first element is trivial solution, so take second one
grid = np.linspace(1,10,10)
sol1 = [np.real(sy.N(RootFunc(root1, 1, x))) for x in grid]
lab.figure(1)
lab.plot(grid,sol1)
lab.show()
I want to draw a Bifurcation diagram of quadratic map in python.
Basically its a plot of x_{n+1}=x_n^2-c and it should look like http://static.sewanee.edu/Physics/PHYSICS123/image99.gif
But I am newbie so I am not sure do I make it right.
My code
import numpy as n
import scipy as s
import pylab as p
xa=0.252
xb=1.99
C=n.linspace(xa,0.001,xb)
iter=100
Y=n.zeros((len(X),iteracje))
i=1
Y0=1
for Y0 in iter:
Y(i+1)=Y0^2-C
for Y0 in iter:
Y(i+1)=Y0^2-C
p.plot(C,Y)
p.show()
My problem is that I don't know how properly write these for loop properly.
Here is some modified code (partial explanation below)
import numpy as n
import scipy as s
import pylab as p
xa=0.252
xb=1.99
C=n.linspace(xa,xb,100)
print C
iter=1000
Y = n.ones(len(C))
for x in xrange(iter):
Y = Y**2 - C #get rid of early transients
for x in xrange(iter):
Y = Y**2 - C
p.plot(C,Y, '.', color = 'k', markersize = 2)
p.show()
First, the linspace command had the wrong format. help(s.linspace) will give you insight into the syntax. The first two arguments are start and stop. The third is how many values. I then made Y a numpy array of the same length as C, but whose values were all 1. Your Y0 was simply the number 1, and it never changed. Then I did some iteration to get past the initial conditions. Then did more iteration plotting each value.
To really understand what I've done, you'll have to look at how numpy handles calculations with arrays.
I'm trying to generate random variables according to a certain ugly distribution, in Python. I have an explicit expression for the PMF, but it involves some products which makes it unpleasant to obtain and invert the CDF (see below code for explicit form of PMF).
In essence, I'm trying to define a random variable in Python by its PMF and then have built-in code do the hard work of sampling from the distribution. I know how to do this if the support of the RV is finite, but here the support is countably infinite.
The code I am currently trying to run as per #askewchan's advice below is:
import scipy as sp
import numpy as np
class x_gen(sp.stats.rv_discrete):
def _pmf(self,k,param):
num = np.arange(1+param, k+param, 1)
denom = np.arange(3+2*param, k+3+2*param, 1)
p = (2+param)*(np.prod(num)/np.prod(denom))
return p
pa_limit = limitrv_gen()
print pa_limit.rvs(alpha,n=1)
However, this returns the error while running:
File "limiting_sim.py", line 42, in _pmf
num = np.arange(1+param, k+param, 1)
TypeError: only length-1 arrays can be converted to Python scalars
Basically, it seems that the np.arange() list isn't working somehow inside the def _pmf() function. I'm at a loss to see why. Can anyone enlighten me here and/or point out a fix?
EDIT 1: cleared up some questions by askewchan, edits reflected above.
EDIT 2: askewchan suggested an interesting approximation using the factorial function, but I'm looking more for an exact solution such as the one that I'm trying to get work with np.arange.
You should be able to subclass rv_discrete like so:
class mydist_gen(rv_discrete):
def _pmf(self, n, param):
return yourpmf(n, param)
Then you can create a distribution instance with:
mydist = mydist_gen()
And generate samples with:
mydist.rvs(param, size=1000)
Or you can then create a frozen distribution object with:
mydistp = mydist(param)
And finally generate samples with:
mydistp.rvs(1000)
With your example, this should work, since factorial automatically broadcasts. But, it might fail for large enough alpha:
import scipy as sp
import numpy as np
from scipy.misc import factorial
class limitrv_gen(sp.stats.rv_discrete):
def _pmf(self, k, alpha):
#num = np.prod(np.arange(1+alpha, k+alpha))
num = factorial(k+alpha-1) / factorial(alpha)
#denom = np.prod(np.arange(3+2*alpha, k+3+2*alpha))
denom = factorial(k + 2 + 2*alpha) / factorial(2 + 2*alpha)
return (2+alpha) * num / denom
pa_limit = limitrv_gen()
alpha = 100
pa_limit.rvs(alpha, size=10)