How to use well scipy.optimize.fmin - python

Hello I'm trying tu use scipy.optimize.fmin to minimize a function. But things aren't going well since my computation seems diverging instead of converging and i got an error. I tried to fixed a tolerance but it is not working.
Here is my code (Main program):
import sys,os
import numpy as np
from math import exp
import scipy
from scipy.optimize import fmin
from carlo import *
A=real()
x_r=0.11245
x_i=0.14587
#C=A.minim
part_real=0.532
part_imag=1.2
R_0 = fmin(A.minim,[part_real,part_imag],xtol=0.0001)
And the class:
import sys,os
import numpy as np
import random, math
import matplotlib.pyplot as plt
import cmath
#import pdb
#pdb.set_trace()
class real:
def __init__(self):
self.nmodes = 4
self.L_ch = 1
self.w = 2
def minim(self,p):
x_r=p[0]
x_i=p[1]
x=complex(x_r,x_i)
self.a=complex(3,4)*(3*np.exp(1j*self.L_ch))
self.T=np.array([[0.0,2.0*self.a],[(0.00645+(x)**2), 4.3*x**2]])
self.Id=np.array([[1,0],[0,1]])
self.disp=np.linalg.det(self.T-self.Id)
print self.disp
return self.disp
The error is:
(-2.16124712985-8.13819476595j)
/usr/local/lib/python2.7/site-packages/scipy/optimize/optimize.py:438: ComplexWarning: Casting complex values to real discards the imaginary part
fsim[0] = func(x0)
(-1.85751684826-8.95377303768j)
/usr/local/lib/python2.7/site-packages/scipy/optimize/optimize.py:450: ComplexWarning: Casting complex values to real discards the imaginary part
fsim[k + 1] = f
(-2.79592712985-8.13819476595j)
(-3.08484130014-7.36240080015j)
(-3.68788935914-6.62639114029j)
/usr/local/lib/python2.7/site-packages/scipy/optimize/optimize.py:475: ComplexWarning: Casting complex values to real discards the imaginary part
fsim[-1] = fxe
(-2.62046851255e+87-1.45013007728e+88j)
(-4.037931857e+87-2.2345341712e+88j)
(-7.45017628087e+87-4.12282179854e+88j)
(-1.14801242605e+88-6.35293780534e+88j)
(-2.11813751435e+88-1.17214723347e+89j)
Warning: Maximum number of function evaluations has been exceeded.
Actually I don't undersatnd why the computation is diverging, maybe I have to use something else instead of using fmin for minimizing?
Someone got an idea?
Thank you very much.

Try to optimize the absolute value instead of the complex value. That gave decent result for me.
f = lambda x: abs(A.minim(x))
R_0 = fmin(f,[part_real,part_imag],xtol=0.0001)
I guess fmin don't work well with complex values.

Related

How could the energy and cos function be in different shapes?

I am trying to write a code that calculates an integral from zero to pi. But it gives an error which I do not understand how to fix. Thank you for your time.
import numpy as np
from math import pi,cos
vtheta=np.linspace(0.0,pi,1000)
def my_function(x):
Energy = np.arange(2.1,300.1,0.1)
return ((1.0)/(Energy-1+np.cos(x)))
print (my_function(vtheta).sum())
As is pointed out in the top comment:
Energy.shape == (2980,), but x.shape == (1000,)
so reduce the number of elements in Energy or increase np.cos(x).
Since energy is just a numpy arrage i reduced it to size=1000.
In order to fix this they need to be the same size, so this ,for example, works:
import numpy as np
from math import pi,cos
vtheta=np.linspace(0.0,pi,1000)
def my_function(x):
Energy = np.arange(2.1,102.1,0.1) #<-- changed 300.1 to 102.1
return ((1.0)/(Energy-1+np.cos(x)))
print (my_function(vtheta).sum())
This is the result (with the above):
39.39900748229355

Exponential fit returns an unreasonable amplitude but looks good when plotted

I'm trying to fit my exponential data, but I am unable to get a decent answer. I'm using scipy and the following code:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import glob
import scipy.optimize
import pylab
def exponential(x, a, k, b):
return a*np.exp(-x/k) + b
def main():
filename = 'tek0071ALL.csv'
df = pd.read_csv(filename, skiprows=14)
t = df['TIME']
ch3 = df['CH3']
idx1 = df.index[df['TIME']==-0.32]
idx2 = df.index[df['TIME']==-0.18]
t= t[idx1.values[0]:idx2.values[0]]
data=ch3[idx1.values[0]:idx2.values[0]]
popt_exponential, pcov_exponential = scipy.optimize.curve_fit(exponential, t, data, p0=[1,.1, 0])
# print(popt_exponential,pcov_exponential)
print(popt_exponential[0])
print(popt_exponential[1])
print(popt_exponential[2])
plt.plot(t,data,'.')
plt.plot(t,exponential(t,popt_exponential[0],popt_exponential[1],popt_exponential[2]))
plt.show()
plt.legend(['Data','Fit'])
main()
This is what the fit looks like:
and I think this means that it's actually a good fit. I think my time constant is correct, and that's what I'm trying to extract. However, the amplitude is really giving me trouble -- I expected the amplitude to be around 0.5 by inspection, but instead I get the following values for equation A*exp(-t/K)+C:
A:1.2424893552249658e-07
K:0.0207112474466181
C: 0.010623336832120528
I'm left wondering if this is correct, and that my amplitude really ought to be so tiny to account for the exponential's behavior.

scipy.optimize get's trapped in local minima. What can I do?

from numpy import *; from scipy.optimize import *; from math import *
def f(X):
x=X[0]; y=X[1]
return x**4-3.5*x**3-2*x**2+12*x+y**2-2*y
bnds = ((1,5), (0, 2))
min_test = minimize(f,[1,0.1], bounds = bnds);
print(min_test.x)
My function f(X)has a local minima at x=2.557, y=1 which I should be able to find.
The code showed above will only give result where x=1. I have tried with different tolerance and alle three method: L-BFGS-B, TNC and SLSQP.
This is the thread I have been looking at so far:
Scipy.optimize: how to restrict argument values
How can I fix this?
I am using Spyder(Python 3.6).
You just encounterd the problem with local optimization: it strongly depends on the start (initial) values you pass in. If you supply [2, 1] it will find the correct minima.
Common solutions are:
use your optimization in a loop with random starting points inside your boundaries
import numpy as np
from numpy import *; from scipy.optimize import *; from math import *
def f(X):
x=X[0]; y=X[1]
return x**4-3.5*x**3-2*x**2+12*x+y**2-2*y
bnds = ((1,3), (0, 2))
for i in range(100):
x_init = np.random.uniform(low=bnds[0][0], high=bnds[0][1])
y_init = np.random.uniform(low=bnds[1][0], high=bnds[1][1])
min_test = minimize(f,[x_init, y_init], bounds = bnds)
print(min_test.x, min_test.fun)
use an algorithm that can break free of local minima, I can recommend scipy's basinhopping()
use a global optimization algorithm and use it's result as initial value for a local algorithm. Recommendations are NLopt's DIRECT or the MADS algorithms (e.g. NOMAD). There is also another one in scipy, shgo, that I have no tried yet.
Try scipy.optimize.basinhopping. It simply just repeat your minimize procedure multiple times and get multiple local minimums. The minimal one is the global minimum.
minimizer_kwargs = {"method": "L-BFGS-B"}
res=optimize.basinhopping(nethedge,guess,niter=100,minimizer_kwargs=minimizer_kwargs)

Using an array in a function error

When I run my code I receive the error "unsupported operand type(s) for ** or pow(): 'numpy.ufunc' and 'float'"
The code is:
import numpy as np
import matplotlib.pyplot as plt
from numpy import sqrt,exp,log
from scipy import linalg
from scipy.optimize import curve_fit
data1 = np.loadtxt('decay1.txt', float,skiprows=1)
t = data1[:,0]
n = data1[:,1]
data2 = np.loadtxt('decay2.txt', float,skiprows=1)
T = data2[:,0]
N = data2[:,1]
def Radio(n,t,tao,b):
return (n*(exp**(-(t/tao)))) + b
guesses = (1,1,1)
guesses2 = (1,1,1)
(p0,p1,p2),cc = curve_fit(Radio,t,n,guesses)
(p02,p12,p22),cc2 = curve_fit(Radio,T,N,guesses2)
yfit = Radio(t,p0,p1,p2)
y2fit = Radio(T,p02,p12,p22)
I have to fit the function to the radioactive decay data, so tell me if I also messed up the code to fit a function to it. Thanks for any help!
numpy.exp is the exponential function and ** is the power operator, so you're trying to raise a function definition to the power (-(t/tao)). I think you wanted
def Radio(n,t,tao,b):
return (n*(exp(-(t/tao)))) + b
With respect to the use of the optimization function, there are a couple of issues. First, you are using n as both the parameter (inside the Radio method) and the dependent variable data (from the problem statement), which is confusing things. I would change that to something like a (as is used in the curve_fit doc. That's not really necessary, but helps readability.
Second, and more importantly, the function to be fit must have the independent variable (in this case, t) as the first argument. I think what is happening to cause a flat fit is that you are actually fitting the curve n->Radio(n) (with all those other variables as parameters) instead of t->Radio(t).

Python fmin(find minimum) for a vector function

I would like to find the minimum of 3dvar function defined as:
J(x)=(x-x_b)B^{-1}(x-x_b)^T + (y-H(x)) R^{-1} (y-H(x))^T (latex code)
with B,H,R,x_b,y given.
I would like to find the argmin(J(x)). However it seems fmin in python does not work. (the function J works correctly)
Here is my code:
import numpy as np
from scipy.optimize import fmin
import math
def dvar_3(x):
B=np.eye(5)
H=np.ones((3,5))
R=np.eye(3)
xb=np.ones(5)
Y=np.ones(3)
Y.shape=(Y.size,1)
xb.shape=(xb.size,1)
value=np.dot(np.dot(np.transpose(x-xb),(np.linalg.inv(B))),(x-xb)) +np.dot(np.dot(np.transpose(Y-np.dot(H,x)),(np.linalg.inv(R))),(Y-np.dot(H,x)))
return value[0][0]
ini=np.ones(5) #
ini.shape=(ini.size,1) #change initial to vertical vector
fmin(dvar_3,ini) #start at initial vector
I receive this error:
ValueError: operands could not be broadcast together with shapes (5,5) (3,3)
How can I solve this problem? Thank you in advance.
reshape argument x in the function dvar_3, the init argument of fmin() needs a one-dim array.
import numpy as np
from scipy.optimize import fmin
import math
def dvar_3(x):
x = x[:, None]
B=np.eye(5)
H=np.ones((3,5))
R=np.eye(3)
xb=np.ones(5)
Y=np.ones(3)
Y.shape=(Y.size,1)
xb.shape=(xb.size,1)
value=np.dot(np.dot(np.transpose(x-xb),(np.linalg.inv(B))),(x-xb)) +np.dot(np.dot(np.transpose(Y-np.dot(H,x)),(np.linalg.inv(R))),(Y-np.dot(H,x)))
return value[0][0]
ini=np.ones(5) #
fmin(dvar_3,ini) #start at initial vector

Categories

Resources