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)
Related
I am trying to minimize the portfolio variance using Python's cvxopt. However, after lots of trying, it doesn't seem to work. The function and my code and the error are pasted below. Thanks for helping!
the minimize problem
objective function: min x.dot(sigma_mv).dot(x.T)
the constraint condition is all x>=0, sum(X) = 1
sigma_mv is the covariance matrix of 800*800, dim = 800
code
dim = sigma_mv.shape[0]
P = 2*sigma_mv
q = np.matrix([0.0])
G = -1*np.identity(dim)
h = np.matrix(np.zeros((dim,1)))
sol = solvers.qp(P,q,G,h)
Traceback (most recent call last):
File "<ipython-input-47-a077fa141ad2>", line 6, in <module>
sol = solvers.qp(P,q)
File "D:\spyder\lib\site-packages\cvxopt\coneprog.py", line 4470, in qp
return coneqp(P, q, G, h, None, A, b, initvals, kktsolver = kktsolver, options = options)
File "D:\spyder\lib\site-packages\cvxopt\coneprog.py", line 1822, in coneqp
raise ValueError("use of function valued P, G, A requires a "\
ValueError: use of function valued P, G, A requires a user-provided kktsolver
You have both equality and inequality constraints so you need to provide all the arguments to the built-in qp solver
Gx <=h
Ax=b
Here x>=0 can be written as -x<=0 So, G matrix will look like -1*(Identity matrix)
and h will a 0 vector
Similarly, your A will be an Identity matrix and b will be a unity vector(all elements =1)
Finally, solve expression should look like :
sol=solvers.qp(P, q, G, h, A, b)
I'm currently trying to fit some parameters to an existing data file. After adding a fitting routine I keep getting the 'TypeError: '*numpy.float64' object is not iterable*' error, which seems to have something to do with the Dl function that i defined. I haven't been able to solve this myself, so I'd be really grateful for any tips concerning this matter.
import pylab as p
import scipy as s
from scipy.integrate import odeint,quad
import numpy as np
import matplotlib.pyplot as plt
import math
z = np.arange(0.00, 1.5, 0.02)
z1, m1, sigma_m = np.loadtxt('data.txt', unpack=True, usecols=[0,1,2])
yerr = sigma_m
def H(z,omega_m,H0):
return H0*p.sqrt(omega_m*(1+z)**3+1-omega_m)
def Dl(z,omega_m,H0):
c = 3*10**5
y = []
for i in z:
y1 = c*(1+i)*quad(f,0.0,i, args=(omega_m,H0))[0]
y.append(y1)
return p.asarray(y)
def f(z,omega_m,H0):
return 1./H(z,omega_m,H0)
def m(z,omega_m,H0,M):
q = []
for j in Dl(z,omega_m,H0):
q1 = M+5*np.log10(j)+25.0
q.append(q1)
return p.asarray(q)
def chi2(omega_m, M):
return sum((m(z1,omega_m,70,M)-m1)/sigma_m)**2
chi2_min=1*10**30
o = np.arange(0.00, 1.5, 0.02)
Mrange = np.arange(-1.5, 1.5, 0.02)
for omega_m in o:
for M in Mrange:
if chi2(omega_m, M) < chi2_min:
omega_min=omega_m
M_min=M
chi2_min=m(omega_min, M_min, 70, M)
print(M_min)
print(chi2_min)
In your routine Dl, the iteration over z is invalid. z is a scalar at each invokation.
Transform your program so that either Dl is given an array or remove the loop in Dl.
Your problem seems to be here:
chi2_min=m(omega_min, M_min, 70, M)
omega_min is a float, which gets passed to Dl() in m() here:
for j in Dl(z,omega_m,H0):
and then Dl() tries to iterate it:
for i in z:
which raises your error
To fix, I recommend you pass omega_min as a list:
chi2_min=m([omega_min], M_min, 70, M)
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.
I am using python ODE to solve Van der Pol equation. What I want to do is to find the number of times the ODE's derivatives is called during one invocation of integrate(t) method. The solver I am using is isoda. I am trying to find the number of times the derivatives is called during one invocation without the jacbian function and the number of times the jacobian function is called when I include the jacobian function.
def modified_vanderpol_integrator_demo(dt_min=1e-3, dt_max=10., mu=100.):
# define a class to store the number of calls
class F:
def __init__(self):
self.callsydot = 0
self.callsjac = 0
def ydot(self,t, y, mu):
self.callsydot += 1
x, v = y[0], y[1]
return array([v, mu*(1- x*x)*v - x])
def jac(self, t, y, mu):
self.callsjac += 1
return array([[0, 1], [2*mu*v*x - 1, mu*(1-x*x)]])
Dt = linspace(dt_min, dt_max, 1000)
Num_of_times1 = []
Num_of_times2 = []
for dt in Dt:
xinitial = array([1.0, 2.0]) # initial value
f1 = F()
r1 = ode(f1.ydot)
r1.set_integrator('lsoda')
r1.set_initial_value(xinitial)
r1.set_f_params(mu)
r1.integrate(dt)
Num_of_times1.append(f1.callsydot)
f2 = F()
r2 = ode(f2.ydot, f2.jac)
r2.set_integrator('lsoda', with_jacobian=True)
r2.set_initial_value(xinitial)
r2.set_f_params(mu)
r2.integrate(dt)
Num_of_times2.append(f2.callsjac)
plt.plot(Dt, Num_of_times1)
plt.plot(Dt, Num_of_times2)
plt.show()
When I run this script, I got the message
create_cb_arglist: Failed to build argument list (siz) with enough arguments (tot-opt) required by user-supplied function (siz,tot,opt=2,3,0).
Traceback (most recent call last):
File "stiffequations.py", line 118, in <module>
modified_vanderpol_integrator_demo(dt_min=1e-3, dt_max=10., mu=100.)
File "stiffequations.py", line 111, in modified_vanderpol_integrator_demo
r2.integrate(dt)
File "/usr/local/lib/python2.7/dist-packages/scipy/integrate/_ode.py", line 394, in integrate
self.f_params, self.jac_params)
File "/usr/local/lib/python2.7/dist-packages/scipy/integrate/_ode.py", line 1193, in run
y1, t, istate = self.runner(*args)
lsoda.error: failed in processing argument list for call-back jac.
Why this happens and how to fix it?
Thanks.
I have found out what is wrong with my script. I forget to set the parameters in the jacobian equation.
r2.set_jac_params(mu)
I was trying to fit a specific function with scipy and I got weird results. I decided to test something I know the answer to so I created this:
from scipy.optimize import curve_fit as cf
import numpy as np
import random
def func(x,a):
return a+X
X =[]
for i in range (10):
V = random.random()
X.append(i+3 + V/10)
print cf(func, np.array(range(10)),np.array(X))
I expected to get something around 3, nevertheless, here the output:
(array([ -2.18158824e-12]), inf)
As a side note, I tried to see what I send something to func and I got this:
print func(np.array(range(10)),3)
Traceback (most recent call last):
File "/tmp/py1759O-P", line 16, in <module>
print func(np.array(range(10)),3)
File "/tmp/py1759O-P", line 6, in func
return a+X
TypeError: unsupported operand type(s) for +: 'int' and 'list
What am I doing wrong?
Don't use x and X as variable names when they carry such different meanings (or perhaps you didn't know Python is case sensitive?):
def func(x,a):
return a+X
X =[]
x is a numpy array, X is a list, and a is a scalar parameter value.
a+X results in an error since you can not add a scalar to a list.
In func, the argument is x, but X is used in the body of the function.
Here's a modified version of your code. It uses a few more features of numpy (e.g. np.random.random() instead of random.random()).
from scipy.optimize import curve_fit as cf
import numpy as np
def func(x, a):
return a + x
n = 10
xdata = np.arange(n)
ydata = func(xdata, 3) + np.random.random(n) / 10
print cf(func, xdata, ydata)
The output is
(array([ 3.04734293]), array([[ 8.19208558e-05]]))