I seem to be having a problem with scipy.optimize.fsolve(). The error message is:
TypeError: 'list' object is not callable.
Code:
def eqs(P, z1):
x1 = z1[0]
y1 = z1[1]
x2 = 1 - x1
y2 = 1 - y1
fl1 = Fug(0, fsolve(PR(x1, P), 0.5), x1, P)
fl2 = Fug(1, fsolve(PR(x1, P), 0.5), x2, P)
fg1 = Fug(0, fsolve(PR(y1, P), 150), y1, P)
fg2 = Fug(1, fsolve(PR(y1, P), 150), y2, P)
error = (x1*fl1 - y1*fg1) + ((1-x1)*fl2 - (1-y1)*fg2)
phiphi = x1*fl1 - y1*fg1
return [phiphi, error]
def main():
P = 18
x1 = (19.99 - P) / (19.99 - 3.59)
y1 = IdealCase_y1(x1)
z1 = [x1, y1]
soln = fsolve(eqs(P, z1), z1)
x1, y1 = soln
return soln
I have used lists(The one with []'s) in fsolve before without a problem, so I'm unsure as to where to look for the problem.
The functions eqs(P, z1), and thus Fug(...), as well as IdealCase_y1 run without a problem, however when running main(), python returns the above mentioned error. The idea is to create a function main() which I can input different P values and return x1, y1 as output. the x1 = ... in main is an "informed guess", to tell fsolve where to look, and a y1 guess is then generated from that value.
edit: IdealCase_y1(x1) is a function used to estimate the value of y1 required by fsolve. The traceback is:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 540, in runfile
execfile(filename, namespace)
File "C:/Users/ShahuN/Documents/Project/q2_v0.3.py", line 229, in <module>
test = main()
File "C:/Users/ShahuN/Documents/Project/q2_v0.3.py", line 223, in main
soln = fsolve(eqs(P, z1), [x1, y1])
File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 140, in fsolve
res = _root_hybr(func, x0, args, jac=fprime, **options)
File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 197, in _root_hybr
shape, dtype = _check_func('fsolve', 'func', func, x0, args, n, (n,))
File "C:\Python27\lib\site-packages\scipy\optimize\minpack.py", line 20, in _check_func
res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
TypeError: 'list' object is not callable
if that's what is meant by the traceback.
soln = fsolve(eqs(P, z1), z1)
1)
func should be a callable function.
2)
the expected argument (optional) is tuple not list, you have to convert your list to tuple when you invoke fsolve()
scipy.optimize.fsolve(func, x0, args=(), fprime=None, full_output=0, col_deriv=0, xtol=1.49012e-08, maxfev=0, band=None, epsfcn=None, factor=100, diag=None)[source]
func : callable f(x, *args)
A function that takes at least one (possibly vector) argument.
args : tuple, optional
Any extra arguments to func.
Edit:
You invoke your function eqs in a wrong way, it should look like this:
soln = fsolve(eqs, P, args=(z1))
x1, y1 = soln
Related
I want to use scipy.optimize.minimize on a function with an array type variable input. This is what I hope to do.
I have the following signal,
import numpy as np
time = np.linspace(0, 1, 501)
data = np.cos(2 * np.pi * 4 * time) + np.cos(2 * np.pi * 9 * time) + np.cos(2 * np.pi * 20 * time)
noise = np.sqrt(1 / 25) * np.random.randn(501)
signal = data + noise
and I am hoping to find a curve fit for this signal. Since I created the data myself, I know that a sum of cosine functions will work for this. So the function that I hope to optimize is the following:
def cos_sum(x, P):
assert isinstance(P, np.ndarray)
assert P.shape[0] == P.shape[1]
sums = []
for param in P:
a, b, c = param
sums.append(a * np.cos(b * (x - c)))
sums = np.array(sums)
return np.sum(sums, axis=0)
In order to use minimize to find the correct parameters, I create this residual function.
def resid(params, x):
assert isinstance(params, np.ndarray)
fit = cos_sum(x, params)
residual = np.sqrt(np.mean(np.abs(fit - signal)) ** 2)
return residual
I now need to create a guess. Since I already know how the signal was created, I made the following guess:
guess_A = np.random.normal(1, .2, size=3)
guess_B = 2 * np.pi * np.array([4, 9, 20], dtype=float)
guess_C = np.random.normal(0, .2, size=3)
guess = np.array([guess_A, guess_B, guess_C]).T
However, I am unable to run the following:
from scipy.optimize import minimize
optimization = minimize(resid, guess, args=(time))
and I receive the following error:
Traceback (most recent call last):
File "/Users/nickeisenberg/GitRepos/Python_Misc/Misc/minimize_curvefit_vector_variables.py", line 70, in <module>
optimization = minimize(resid, guess, args=(time))
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_minimize.py", line 676, in minimize
res = _minimize_bfgs(fun, x0, args, jac, callback, **options)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_optimize.py", line 1296, in _minimize_bfgs
sf = _prepare_scalar_function(fun, x0, jac, args=args, epsilon=eps,
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_optimize.py", line 263, in _prepare_scalar_function
sf = ScalarFunction(fun, x0, args, grad, hess,
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py", line 158, in __init__
self._update_fun()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py", line 251, in _update_fun
self._update_fun_impl()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py", line 155, in update_fun
self.f = fun_wrapped(self.x)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py", line 137, in fun_wrapped
fx = fun(np.copy(x), *args)
File "/Users/nickeisenberg/GitRepos/Python_Misc/Misc/minimize_curvefit_vector_variables.py", line 53, in resid
fit = cos_sum(x, params)
File "/Users/nickeisenberg/GitRepos/Python_Misc/Misc/minimize_curvefit_vector_variables.py", line 30, in cos_sum
assert P.shape[0] == P.shape[1]
IndexError: tuple index out of range
Is this possible to do?
The problem is that minimize treats parameters as 1D array. Adding print just before failing assert shows, that it reshaped guess array to 1D array.
Changing cos_sum so that it accepts 1D array of params fixes this problem. Here is the code.
def cos_sum(x, P):
assert isinstance(P, np.ndarray)
sums = []
for i in range(0, P.shape[0], 3):
a, b, c = P[i], P[i+1], P[i+2]
sums.append(a * np.cos(b * (x - c)))
sums = np.array(sums)
return np.sum(sums, axis=0)
Result:
optimization = minimize(resid, guess, args=(time))
print(optimization.x)
[ 0.96805816 25.1679919 0.25020317 1.00261543 56.44511497
0.77872223 1.00966167 125.71622787 0.55004217]
plt.figure(figsize=(8, 4))
plt.plot(data)
plt.plot([cos_sum(t, optimization.x) for t in time], 'C1--')
plt.show()
I am doing a project, where I want to use Euler's Method to show a solution to this Second Order Different equation
0=y''+y'+9.81y
So I started by changing the second-order into a system of first-order equations
y'=u, u'=f(t,y,u)
With initial condition
y(0)=180, u(0)=0
So I get two equation in the end
y[n + 1] = y[n] + u[n] * (t[n + 1] - t[n]), u[n + 1] = u[n] + f(u[0], y[n], t[0]) * (t[n + 1] - t[n])
This is my code
import numpy as np
import matplotlib.pyplot as plt
def odeEuler(f, y0, u0, t):
y = np.zeros(len(t))
u = np.zeros(len(t))
y[0] = y0
u[0] = u0
for n in range(0, len(t) - 1):
y[n + 1] = y[n] + u[n] * (t[n + 1] - t[n])
u[n + 1] = u[n] + f(u[0], y[n], t[0]) * (t[n + 1] - t[n])
return y, u
t = np.linspace(0, 100)
y0 = 180
u0 = 0
f = lambda u, y, t: -9.81 * y - u
y = odeEuler(f, y0, u0, t)
plt.plot(t, y, 'b.-')
plt.legend(['Euler'])
plt.axis([0, 100, 0, 200])
plt.grid(True)
plt.show()
However, when I run the code, it give me the error
Traceback (most recent call last):
File "/Users/huangy15/PycharmProjects/Draft/Damped Driven Pendulum/Praying this works.py", line 22, in <module>
plt.plot(t, y, 'b.-')
File "/Users/huangy15/PycharmProjects/Draft/Damped Driven Pendulum/venv/lib/python3.7/site-packages/matplotlib/pyplot.py", line 3021, in plot
**({"data": data} if data is not None else {}), **kwargs)
File "/Users/huangy15/PycharmProjects/Draft/Damped Driven Pendulum/venv/lib/python3.7/site-packages/matplotlib/axes/_axes.py", line 1605, in plot
lines = [*self._get_lines(*args, data=data, **kwargs)]
File "/Users/huangy15/PycharmProjects/Draft/Damped Driven Pendulum/venv/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 315, in __call__
yield from self._plot_args(this, kwargs)
File "/Users/huangy15/PycharmProjects/Draft/Damped Driven Pendulum/venv/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 501, in _plot_args
raise ValueError(f"x and y must have same first dimension, but "
ValueError: x and y must have same first dimension, but have shapes (50,) and (2, 50)
Can anyone help me check if my idea works, and if not, what other approaches I can take? Thanks!
Your odeEuler function is returning two variables: y and u, you need to select just one of them to plot.
Store the output of the function in two different variables will solve the problem:
y, u = odeEuler(f, y0, u0, t)
I have the following system of 2 matricial equations where a and b are unknown vectors with for each 7 components. D, D1, D2, P1, P2, F1, F2 are matrices (7x7).
# define the equations
def f(x):
a = np.zeros(7)
b = np.zeros(7)
for i in range(7):
a[i] = x[i]
b[i] = x[7+i]
# Looking for an endomorphism that has D eigen values
D = a**2*D1 + b**2*D2
eq1 = np.dot(P1.T*a**2,P1) + np.dot(P1.T*a,b*P2) + np.dot(P2.T*b,a*P1) + np.dot(P2.T*b**2,P2) - np.eye(7)
eq2 = np.dot(F1,a*P1) + np.dot(F1,b*P2) + np.dot(F2,a*P1) + np.dot(F2,b*P2) - np.dot(a*P1 + b*P2,D)
return np.array([eq1,eq2])
# inital guess
x0 = np.ones(14)
print('x0 = ', x0)
# solving
x = fsolve(f, x0)
print(x)
Unfortunately, at the execution, I get :
Traceback (most recent call last):
File "compute_solving_Matricial_Equations_with_vectors_a_and_b_unknown.py", line 110, in <module>
x = fsolve(f, x0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/optimize/minpack.py", line 139, in fsolve
res = _root_hybr(func, x0, args, jac=fprime, **options)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/optimize/minpack.py", line 196, in _root_hybr
shape, dtype = _check_func('fsolve', 'func', func, x0, args, n, (n,))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/optimize/minpack.py", line 32, in _check_func
raise TypeError(msg)
TypeError: fsolve: there is a mismatch between the input and output shape of the 'func' argument 'f'.
I tried previously by doing at the end of f function :
return np.array([eq1,eq2].ravel()
instead of return np.array([eq1,eq2].
But I get the same error. What might be wrong here?
I am handling with (7x7) matrices in my 2 equations but I have only 14 unknown (7 components for vector a and 7 for vector b).
Update 1
Following the advice of #Warren Weckesser, I did to check:
# define the equations
def f(x):
a = np.zeros(7)
b = np.zeros(7)
for i in range(7):
a[i] = x[i]
b[i] = x[7+i]
# Looking for an endomorphism that has D eigen values
#D = D1 + D2
D = a**2*D1 + b**2*D2
eq1 = np.dot(P1.T*a**2,P1) + np.dot(P1.T*a,b*P2) + np.dot(P2.T*b,a*P1) + np.dot(P2.T*b**2,P2) - np.eye(7)
eq2 = np.dot(F1,a*P1) + np.dot(F1,b*P2) + np.dot(F2,a*P1) + np.dot(F2,b*P2) - np.dot(a*P1 + b*P2,D)
print(' shape(a) = ', np.shape(a))
print(' shape(b) = ', np.shape(b))
#return np.array([eq1,eq2]).ravel()
return np.concatenate((eq1, eq2))
and get as output :
Traceback (most recent call last):
File "compute_solving_Matricial_Equations_with_vectors_a_and_b_unknown_FOR_STACKOVER.py", line 89, in <module>
shape(a) = (7,)
shape(b) = (7,)
x = fsolve(f, x0)
File "/opt/intel/intelpython3/lib/python3.7/site-packages/scipy/optimize/minpack.py", line 147, in fsolve
res = _root_hybr(func, x0, args, jac=fprime, **options)
File "/opt/intel/intelpython3/lib/python3.7/site-packages/scipy/optimize/minpack.py", line 213, in _root_hybr
shape, dtype = _check_func('fsolve', 'func', func, x0, args, n, (n,))
File "/opt/intel/intelpython3/lib/python3.7/site-packages/scipy/optimize/minpack.py", line 40, in _check_func
raise TypeError(msg)
TypeError: fsolve: there is a mismatch between the input and output shape of the 'func' argument 'f'.Shape should be (14,) but it is (14, 7).
As you can see, it shows one time the print of shape(a) and shape(b) before failing.
I know there is a question
Fitting only one parameter of a function with many parameters in python
but I have a little bit different situation. Problem with parameters of lambda function.
I am trying to fit Lorentz func
def lorentz(ph, A, xc, w, f0):
return f0 + A * w**2 / (w**2 + (ph - xc)**2)
if I am fitting only one parameter (xc) its working good.
p1, p2, p3, p4 = params
popt, pcov = curve_fit(lambda x, xc: lorentz(x, p1, xc, p3, p4), abjd, adata, bounds=param_bounds)
But if I try to fit only 2 parameters (a, xc) it fails
p1, p2, p3, p4 = params
popt, pcov = curve_fit(lambda x, a, xc: lorentz(x, a, xc, p3, p4), abjd, adata, bounds=param_bounds)
Error message is
Traceback (most recent call last):
File "template.py", line 294, in <module>
popt, pcov = curve_fit(lambda x, a, xc: lorentz(x, a, xc, p3, p4), abjd, adata, bounds=param_bounds)
File "/usr/local/lib/python2.7/dist-packages/scipy/optimize/minpack.py", line 683, in curve_fit
**kwargs)
File "/usr/local/lib/python2.7/dist-packages/scipy/optimize/_lsq/least_squares.py", line 769, in least_squares
f0 = fun_wrapped(x0)
File "/usr/local/lib/python2.7/dist-packages/scipy/optimize/_lsq/least_squares.py", line 764, in fun_wrapped
return np.atleast_1d(fun(x, *args, **kwargs))
File "/usr/local/lib/python2.7/dist-packages/scipy/optimize/minpack.py", line 455, in func_wrapped
return func(xdata, *params) - ydata
TypeError: <lambda>() takes exactly 3 arguments (2 given)
Here is the solution for all 4 parameters of Lorentz function
import numpy as np
from scipy.optimize import curve_fit
def lorentz(ph, A, xc, w, f0):
return f0 + A * w**2 / (w**2 + (ph - xc)**2)
A, xc, w, f0 = 2,2,2,2 # true values
ph = np.linspace(-5, 10, 100)
y = lorentz(ph, A, xc, w, f0)
ydata = y + 0.15 * np.random.normal(size=len(ph)) # sample data
popt, pcov = curve_fit(lambda x, _A, _xc: lorentz(x, _A, _xc, w, f0), ph, ydata,bounds=([1,1], [3, 3]))
A, xc = popt # fitted values (only two)
You can easily add or remove parameters by putting them under the function lorentz() or with lambda
The result looks like this
""" ___ """
from scipy.optimize import root
import numpy as np
LENGTH = 3
def process(x):
return x[0, 0] + x[0, 1] * 5
def draw(process, length):
""" """
X = np.matrix(np.random.normal(0, 10, (length, 2)))
y = np.matrix([process(x) for x in X])
y += np.random.normal(3, 1, len(y))
return y.T, X.T
def maximum_likelyhood(y, X):
def objective(b):
return (X.T * (y - X * b.T))
x0 = np.matrix([0, 0])
res = root(objective, x0=x0)
return res.x
y, X = draw(process, LENGTH)
X = X.transpose()
b = np.matrix([[0], [1]])
print maximum_likelyhood(y, X)
produces a
Traceback (most recent call last):
File "ml.py", line 33, in <module>
maximum_likelyhood(y, X)
File "ml.py", line 26, in maximum_likelyhood
res = root(objective, x0=x0)
File "/usr/local/lib/python2.7/dist-packages/scipy/optimize/_root.py", line 168, in root
sol = _root_hybr(fun, x0, args=args, jac=jac, **options)
File "/usr/local/lib/python2.7/dist-packages/scipy/optimize/minpack.py", line 193, in _root_hybr
ml, mu, epsfcn, factor, diag)
ValueError: object too deep for desired array
I can't even gasp what the problem is is it in the b which goes into the objective
function? or is it in its output?
The problem is that fsolve and root do not accept matrixes as return value of the objective function.
For example this is a solution of above problem:
def maximum_likelyhood(y, X):
def objective(b):
b = np.matrix(b).T
return np.transpose(np.array((X.T * (y - X * b))))[0]
x0 = (1, 1)
res = root(objective, x0=x0)
return res.x