Related
I have the following set of coupled differential equations. I want to get an analytical solution with sympy.
from sympy import *
import numpy as np
init_printing(use_unicode=True)
x, y, z, t, w, V=symbols('x y z t omega V')
c1=Function('c1')
c2=Function('c2')
hq=symbols('hbar',positive=True)
g1=Eq(c2(t)*hq*V*exp(-I*w*t),I*hq*Derivative(c1(t),t))
g2=Eq(c1(t)*hq*V*exp(+I*w*t),I*hq*Derivative(c2(t),t))
eq=(g1,g2)
dsolve(eq,hint='all',ics={c1(0):1,c2(0):0})
When I try to solve the equation system, I get the error:
ValueError: The function cannot be automatically detected for nan.
Unfortunately I can not see my mistake.
Edit:
classify_ode(g1) returns the following hints:
('factorable', 'nth_algebraic', 'separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_variation_of_parameters', 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters', 'nth_algebraic_Integral', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral', 'nth_linear_constant_coeff_variation_of_parameters_Integral', 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters_Integral')
Every one of them produces the error mentioned above.
Manually, one can solve this system by applying the Laplace transform to c1 and c2. This turns the system of ODEs in a system of purely algebraic equations, which is solvable by rearranging and eliminating the coupling between equations. The result is then the transform of the solution, so one has to transform back using the inverse Laplace transform.
Edit 2:
classify_sysode(eq) returns the following:
{'no_of_equation': 2,
'eq': [-c1(t)*exp(-I*omega*t) + I*Derivative(c2(t), t),
-c2(t)*exp(I*omega*t) + I*Derivative(c1(t), t)],
'func': [c2(t), c1(t)],
'order': {c1(t): 1, c2(t): 1},
'func_coeff': {(0, c2(t), 0): 0,
(0, c2(t), 1): I,
(0, c1(t), 0): -exp(-I*omega*t),
(0, c1(t), 1): 0,
(1, c2(t), 0): -exp(I*omega*t),
(1, c2(t), 1): 0,
(1, c1(t), 0): 0,
(1, c1(t), 1): I},
'is_linear': True,
'type_of_equation': 'type6'}
This means that the solver that will be used is Linear, 2 equations, Order 1, Type 6, for a system of the form:
x' = f(t) x + g(t) y
y' = a [f(t) + a h(t)] x + a [g(t) - h(t)] y
But our system looks more like a Type 7, that is, of the form:
x' = f(t) x + g(t) y
y' = h(t) x + p(t) y
with f(t) and p(t) being zero. The suggested method of solution for a type 7 mentioned in the documentation also resembles what Lutz Lehmann mentions in his comment.
For completeness this is the error, which seems to originate from an exception raised by _preprocess:
Traceback (most recent call last):
File "problem_ode.py", line 21, in <module>
dsolve(eq,hint='all',ics={c1(0):1,c2(0):0})
File "/home/quoniam/anaconda3/envs/data/lib/python3.8/site-packages/sympy/solvers/ode.py", line 634, in dsolve
sols = solvefunc(match)
File "/home/quoniam/anaconda3/envs/data/lib/python3.8/site-packages/sympy/solvers/ode.py", line 7405, in sysode_linear_2eq_order1
sol = _linear_2eq_order1_type6(x, y, t, r, eq)
File "/home/quoniam/anaconda3/envs/data/lib/python3.8/site-packages/sympy/solvers/ode.py", line 7731, in _linear_2eq_order1_type6
hint1 = classify_ode(equ)[1]
File "/home/quoniam/anaconda3/envs/data/lib/python3.8/site-packages/sympy/solvers/ode.py", line 976, in classify_ode
eq, func_ = _preprocess(eq, func)
File "/home/quoniam/anaconda3/envs/data/lib/python3.8/site-packages/sympy/solvers/deutils.py", line 84, in _preprocess
raise ValueError('The function cannot be '
ValueError: The function cannot be automatically detected for nan.
Imagine I have two equations with one unknown and I want to use fsolve to solve it:
0 = 0.5*x[0]**2-2
0 = 2-x
Clearly the answer is x=2. I have tried this
import numpy as np; from scipy.optimize import fsolve
def f(x):
r = np.zeros(2)
r[0] = 0.5*x[0]**2-2
r[1] = 2-x[0]
return r
fsolve(f,[0.5])
The error message is "The array returned by a function changed size between calls"
I can't see what is going wrong here. How do I solve this problem?
In general, How do I solve equations where the number of variables is less than the number of equations.
Here is the full message
Traceback (most recent call last):
File "<ipython-input-37-e4f77791f3f6>", line 12, in <module>
fsolve(f,[0.5])
File "... anaconda3/lib/python3.7/site-packages/scipy/optimize/minpack.py", line 148, in fsolve
res = _root_hybr(func, x0, args, jac=fprime, **options)
File ".... /anaconda3/lib/python3.7/site-packages/scipy/optimize/minpack.py", line 227, in _root_hybr
ml, mu, epsfcn, factor, diag)
ValueError: The array returned by a function changed size between calls
In case of overdetermined system (the number of equations is greater than the number of variables)you need to use, for example, least squares approach. In such cases, there are usually no solution in traditional sense. And we need to define, what should we treat as a solution of the system.
Let you have a system of two equations with one scalar variable:
f(x) = 0
g(x) = 0
This system usually inconsistent and have no solution in traditional sense.
Lets add some values eps1 and eps2 to the right part of the system:
f(x) = 0 + eps1
g(x) = 0 + eps2
eps1 and eps2 are some values;
Now, lets find such x when eps1^2 + eps2^2 is rises its minimum value; that will be a solution of the system
in least squares sense.
To get such solution using scipy you can use least_square function.
Lets look at the following piece of code, that solves your system of equations:
import numpy as np
from scipy.optimize import fsolve, least_squares
def f(x):
r = np.zeros(2)
r[0] = 0.5*x**2-2
r[1] = 2-x
return r
least_squares(f, [0.0])
Result:
active_mask: array([0.])
cost: 5.175333019854869e-20
fun: array([ 2.87759150e-10, -1.43879575e-10])
grad: array([7.19397879e-10])
jac: array([[ 2.00000001],
[-1. ]])
message: '`gtol` termination condition is satisfied.'
nfev: 6
njev: 6
optimality: 7.193978788924559e-10
status: 1
success: True
x: array([2.])
I am practicing with SciPy and I encountered an error when trying to use fmin_slsqp. I set up a problem in which I want to maximize an objective function, U, given a set of constraints.
I have two control variables, x[0,t] and x[1,t] and, as you can see, they are indexed by t (time periods). The objective function is:
def obj_fct(x, alpha,beta,Al):
U = 0
x[1,0] = x0
for t in trange:
U = U - beta**t * ( (Al[t]*L)**(1-alpha) * x[1,t]**alpha - x[0,t])
return U
The constraints are defined over these two variables and one of them links the variables from one period (t) to another (t-1).
def constr(x,alpha,beta,Al):
return np.array([
x[0,t],
x[1,0] - x0,
x[1,t] - x[0,t] - (1-delta)*x[1,t-1]
])
Finally, here is the use of fmin_slsqp:
sol = fmin_slsqp(obj_fct, x_init, f_eqcons=constr, args=(alpha,beta,Al))
Leaving aside the fact that there are better ways to solve such dynamic problems, my question is about the syntax. When running this simple code, I get the following error:
Traceback (most recent call last):
File "xxx", line 34, in <module>
sol = fmin_slsqp(obj_fct, x_init, f_eqcons=constr, args=(alpha,beta,Al))
File "D:\Anaconda3\lib\site-packages\scipy\optimize\slsqp.py", line 207, in fmin_slsqp
constraints=cons, **opts)
File "D:\Anaconda3\lib\site-packages\scipy\optimize\slsqp.py", line 311, in _minimize_slsqp
meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in cons['eq']]))
File "D:\Anaconda3\lib\site-packages\scipy\optimize\slsqp.py", line 311, in <listcomp>
meq = sum(map(len, [atleast_1d(c['fun'](x, *c['args'])) for c in cons['eq']]))
File "xxx", line 30, in constr
x[0,t],
IndexError: too many indices for array
[Finished in 0.3s with exit code 1]
What am I doing wrong?
The initial part of the code, assigning values to the parameters, is:
from scipy.optimize import fmin_slsqp
import numpy as np
T = 30
beta = 0.96
L = 1
x0 = 1
gl = 0.02
alpha = 0.3
delta = 0.05
x_init = np.array([1,0.1])
A_l0 = 1000
Al = np.zeros((T+1,1))
Al[1] = A_l0
trange = np.arange(1,T+1,1, dtype='Int8') # does not include period zero
for t in trange: Al[t] = A_l0*(1 + gl)**(t-1)
The array x passed to your objective and constraint functions will be a one-dimensional array (just like your x_init is). You can't index a one-dimensional array with two indices, so expressions such as x[1,0] and x[0,t] will generate an error.
At the moment, I am trying to solve a system of coupled ODEs with complex terms. I am using scipy.integrate.ODE, I have successfully solved a previous problem involving a coupled ODE system with only real terms. In that case I used odeint, which is not suitable for the problem I am facing now. The system has 9 coupled ODEs, and this is my code:
from pylab import *
import numpy as np
from scipy.integrate import ode
#Here I am calculating a parameter H of the system
h=1
w1=0.1
w2=0.12
g=1
H=array([[h/2*(w1+w2),h/2*w1+h*g,h*w2/2,0], [h/2*w1+h*g,h/2*(w1-w2),0,-h*w2/2], [h*w2/2,0,-h/2*(w1-w2),-h/2*w1-h*g],[0,-h*w2/2,-h/2*w1-h*g,-h/2*(w1+w2)]])
#this is the system of ODEs
def resol(p1111, p1212, p2121, p1112, p1121, p1122, p1221, p1222, p2122,t,par):
gamma, h, H = par
i=1j
dp1111 = (H[0,1]*conjugate(p1112)+H[0,2]*conjugate(p1121)+H[0,3]*conjugate(p1122)-H[1,0]*p1112-H[2,0]*p1121-H[3,0]*p1122)*i+delta*(p1212-p1111)
dp1112 = (H[0,0]*p1112+H[0,1]*p1212+H[0,2]*conjugate(p1221)-H[0,1]*p1111-H[1,1]*p1112-H[3,1]*p1122)*i+delta*(conjugate(p1112)-p1112)
dp1121 = (H[0,0]*p1121+H[0,1]*p1221+H[0,2]*p2121-H[0,2]*p1111-H[2,2]*p1121-H[3,2]*p1122)*i+delta*(p1222-p1121)
dp1122 = (H[0,0]*p1122+H[0,1]*p1222+H[0,2]*p2122-H[1,3]*p1112-H[2,3]*p1121-H[3,3]*p1122)*i+delta*(p1221-p1122)
dp1212 = (H[1,0]*p1112+H[1,3]*conjugate(p1222)-H[0,1]*conjugate(p1112)-H[3,1]*p1222)*i+delta*(p1111-p1212)
dp1221 = (H[1,0]*p1121+H[1,1]*p1221+H[1,3]*conjugate(p2122)-H[0,2]*conjugate(p1112)-H[2,2]*p1221-H[3,2]*p1222)*i+delta*(p1122-p1221)
dp1222 = (H[1,0]*p1122+H[1,1]*p1222+H[1,3]*p2122-H[1,3]*p1212-H[2,3]*p1221-H[3,3]*p1222)*i+delta*(p1121-p1222)
dp2121 = (H[2,0]*p1121+H[2,3]*conjugate(p2122)-H[0,2]*conjugate(p1121)-H[3,2]*p2122)*i+delta*(1-p1111-p1212-2*p2121)
dp2122 = (H[2,0]*p1122+H[2,2]*p2122+H[2,3]*(1-p1111-p1212-p2121)-H[1,3]*conjugate(p1221)-H[2,3]*p2121-H[3,3]*p2122)*i+delta*(conjugate(p2122)-p2122)
sol = [dp1111, dp1212, dp2121, dp1112, dp1121, dp1122, dp1221, dp1222, dp2122]
return sol
#I set the Initial values of echa term, note that there are 9 because I have 9 terms
condin=np.array([1/3,0,2/3,0,sqrt(2)/3,0,0,0,0])
#I set the parameters
par=[g, h, H]
#I set the integrator, I don't use jacobian because I it is tedious to calculate it for my system
r=ode(resol).set_integrator('zvode', method='bdf',with_jacobian=False)
#Just defining the time and the steps
t_start = 0.0
t_final = 10.0
delta_t = 0.1
num_steps = np.floor((t_final - t_start)/delta_t) + 1
r.set_initial_value(condin, t_start) #I give initial values to the integrator
r.set_f_params(par) #the parameter aswell
t = np.zeros((num_steps, 1)) #I define a (x,1) dim matrix to save each term of the time
resultados = np.zeros((num_steps, 9)) # the same to save the results but with a (x,9) dim matrix
t[0] = t_start
resultados[0] = condin
k = 1
while r.successful() and k < num_steps:
r.integrate(r.t + delta_t)
t[k] = r.t #save the time and the results
resultados[k] = r.y
k += 1
As you have noticed I define my function as resol(p1111, p1212, p2121, p1112, p1121, p1122, p1221, p1222, p2122,t,par):. When using odeint I wrote it in a different way:
def resol(var,t,par):
p1111, p1212, p2121, p1112, p1121, p1122, p1221, p1222, p2122 = var
gamma, h, H = par
But in that way when using integrate.ode it gives me this error:
p1111, p1212, p2121, p1112, p1121, p1122, p1221, p1222, p2122 = var
TypeError: 'float' object is not iterable
Anyway I solved it by defining the function in the way I posted. The problem is that, when I run the code, I always get this error, and I don't have a clue why:
create_cb_arglist: Failed to build argument list (siz) with enough arguments (tot-opt) required by user-supplied function (siz,tot,opt=3,11,0).
Traceback (most recent call last):
File "Untitled.py", line 48, in <module>
r.integrate(r.t + delta_t)
File "/Users/kilian/src/scipy/scipy/integrate/_ode.py", line 333, in integrate
self.f_params, self.jac_params)
File "/Users/kilian/src/scipy/scipy/integrate/_ode.py", line 760, in run
args[5:]))
vode.error: failed in processing argument list for call-back f.
I don't know if this error is because I am using the function conjugate() to calculate the complex conjugates of the therms inside my function. But I feel that this is not the cause.
If anyone can help me with this I would appreciate it. Thank you in advance
This should solve this issue:
def resol(t, y, par):
p1111, p1212, p2121, p1112, p1121, p1122, p1221, p1222, p2122 = y
gamma, h, H = par
You will get more problems such as that delta needs to be called delta_t (needs renaming) and ComplexWarning: Casting complex values to real discards the imaginary part but it runs.
I'm trying to use Gaussian quadrature to approximate the integral of a function. (More info here: http://austingwalters.com/gaussian-quadrature/). The first function is on the interval [-1,1]. The second function is generalized to [a,b] by change of variable. The problem is that I keep getting the error "'numpy.ndarray' object is not callable". I assume (please correct me if I'm wrong) this means I've tried to call the arrays w and x as functions, but I'm not sure how to fix this.
This is the code
from __future__ import division
from pylab import *
from scipy.special.orthogonal import p_roots
def gauss1(f,n):
[x,w] = p_roots(n+1)
f = (1-x**2)**0.5
for i in range(n+1):
G = sum(w[i]*f(x[i]))
return G
def gauss(f,a,b,n):
[x,w] = p_roots(n+1)
f = (1-x**2)**0.5
for i in range(n+1):
G = 0.5*(b-a)*sum(w[i]*f(0.5*(b-a)*x[i]+ 0.5*(b+a)))
return G
These are the respective error messages
gauss1(f,4)
Traceback (most recent call last):
File "<ipython-input-82-43c8ecf7334a>", line 1, in <module>
gauss1(f,4)
File "C:/Users/Me/Desktop/hw8.py", line 16, in gauss1
G = sum(w[i]*f(x[i]))
TypeError: 'numpy.ndarray' object is not callable
gauss(f,0,1,4)
Traceback (most recent call last):
File "<ipython-input-83-5603d51e9206>", line 1, in <module>
gauss(f,0,1,4)
File "C:/Users/Me/Desktop/hw8.py", line 23, in gauss
G = 0.5*(b-a)*sum(w[i]*f(0.5*(b-a)*x[i]+ 0.5*(b+a)))
TypeError: 'numpy.ndarray' object is not callable
As Will says you're getting confused between arrays and functions.
You need to define the function you want to integrate separately and pass it into gauss.
E.g.
def my_f(x):
return 2*x**2 - 3*x +15
gauss(m_f,2,1,-1)
You also don't need to loop as numpy arrays are vectorized objects.
def gauss1(f,n):
[x,w] = p_roots(n+1)
G=sum(w*f(x))
return G
def gauss(f,n,a,b):
[x,w] = p_roots(n+1)
G=0.5*(b-a)*sum(w*f(0.5*(b-a)*x+0.5*(b+a)))
return G
quadpy, a small project of mine, might help:
import numpy
import quadpy
def f(x):
return numpy.exp(x)
scheme = quadpy.line_segment.gauss_legendre(10)
val = scheme.integrate(f, [0.0, 1.0])
print(val)
1.7182818284590464
There are many other quadrature schemes for 1D.
In gauss1(f,n), you are treating f as if it's a function when it is an array, since you are reassigning it;
def gauss1(f,n):
[x,w] = p_roots(n+1)
f = (1-x**2)**0.5 # This line is your problem.
for i in range(n+1):
G = sum(w[i]*f(x[i]))
return G
You are doing something similar in the second function.
Example: solving using gaussian integral with n = 2 for integral 2+sinX with b = pi/2 and a = 0
import numpy as np
E = np.array([-0.774597, 0.000000, 0.774597])
A = np.array([0.555556, 0.888889, 0.555556])
def gauss(f, a, b, E, A):
x = np.zeros(3)
for i in range(3):
x[i] = (b+a)/2 + (b-a)/2 *E[i]
return (b-a)/2 * (A[0]*f(x[0]) + A[1]*f(x[1]) + A[2]*f(x[2]))
f = lambda x: 2 + np.sin(x)
a = 0.0; b = np.pi/2
areaGau = gauss(f, a, b, E, A)
print("Gaussian integral: ", areaGau)