Problems minimizing a two variable function with "scipy.optimize.brute" - python

I'm trying to minimize a function of two variables using scipy.optimize.brute algorithm, but I've receiving the error TypeError: Fcone() missing 1 required positional argument: 'R'.
Here's my code:
import numpy as np
import scipy.optimize as opt
gamma = 17.
C = 45.
T = 12.
H = 1.2
R = 1.3
H1 = 0.57
def Fcone(alpha, beta, H1, gamma, C, T, H, R):
return np.pi/((np.cos(alpha))**2 * (np.cos(beta))**2) * ((np.cos(alpha))**2
* ((np.cos(beta))**2 * (gamma*H1**3 + 2*H1**2*(C-T-gamma*H) - H*H1*
(2*C-2*T-gamma*H) + H*(gamma*R**2 + H*(C-T)-(gamma*H**2)/3)) -
2*R*(H-H1)*np.cos(beta) * ((gamma*H1/2 - gamma*H/2 + C -T)*
np.sin(beta) - C) + (C*np.sin(beta) + gamma*H/3 - gamma*H1/3
-C + T)*(H-H1)**2) - 2*H1*np.cos(beta)*np.cos(alpha)*(
R*np.cos(beta)*((gamma*H1/2 + C -T -gamma*H)*np.sin(alpha)
- C) + np.sin(alpha)*(H-H1)*((gamma*H1/2 - gamma*H/2 + C -T)
*np.sin(beta)-C)) + (np.cos(beta))**2 * H1**2 *
(gamma*H + C*np.sin(alpha)
-2*gamma*H1/3 -C+T))
ranges = (slice(0, np.pi/2, np.pi/10000), slice(0, np.pi/2, np.pi/10000))
res = opt.brute(Fcone, ranges, args=(H1, gamma, C, T, H, R), finish=None)
Where gamma, C,T, H, R1 and H1 are given parameters. Despite the very large (and probably confusing equation), how can I fix this problem and minimize the function for the two parameters alpha and beta? Thank you!
P.S.: The function alone is running fine when I assign all values for the parameters.

Amend Fcone() as follows...
def Fcone(alpha_beta, H1, gamma, C, T, H, R):
alpha = alpha_beta[0]
beta = alpha_beta[1]
.....
The variables being optimized have to be put into a 1D array, check docs here. Their values will be in res[0]

Related

Differents results from create function in a different way - only length-1 arrays can be converted to Python scalars

I have defined the following functions in python:
from math import *
import numpy as np
import cmath
def BSM_CF(u, s0, T, r, sigma):
realp = -0.5*u**2*sigma**2*T
imagp = u*(s0+(r-0.5*sigma**2)*T)
zc = complex(realp, imagp)
return cmath.exp(zc)
def BSM_characteristic_function(v, x0, T, r, sigma):
cf_value = np.exp(((x0 / T + r - 0.5 * sigma ** 2) * 1j * v -
0.5 * sigma ** 2 * v ** 2) * T)
return cf_value
Parameters:
alpha = 1.5
K = 90
S0 = 100
T = 1
r = 0.05
sigma = 0.2
k = np.log(K / S0)
s0 = np.log(S0 / S0)
g = 1 # factor to increase accuracy
N = 2 ** 2
eta = 0.15
eps = (2*np.pi)/(N*eta)
b = 0.5 * N * eps - k
u = np.arange(1, N + 1, 1)
vo = eta * (u - 1)
v = vo - (alpha + 1) * 1j
BSMCF = BSM_characteristic_function(v, s0, T, r, sigma)
BSMCF_v2 = BSM_CF(0, s0, T, r, sigma)
print(BSMCF)
print(BSMCF_v2)
Both are the same functions. But, I get different results. How can I fix the function BSM_CF to get the same result from the function BSM_characteristic_function? The idea is get an array with len 4 values as in the funtion BSM_characteristic_function
Your calls are not identical. You are passing v in the first call and 0 in the second call. If I pass 0 for both, the results are identical. If I pass v, it complains because you can't call complex on a vector.
Numeric computation is Not always identical to symbolic algebra. For the first formula, you use complex computation as an alternative, which could result rounding errors in complex part. I came across such mistakes quite often as I used Mathematica, which loves to transfer a real formula to a complex one before doing the numeric computation.

Programming a PDE in Python with Brownian path

I'm currently trying to simulate a PDE including a Brownian path (one of the terms includes, that when going one timestep 'dt' further the change is weighted by a normal distributed variable with mean 0 and variance dt).
For this I used Fast Fourier Transform to get a system of ODEs which I can solve much more easily (at least that's what I thought). This lead me to the following code.
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
#Defining some parameters a, b, c, which are included in the PDE
a = 10
b = 1.5
c = 20
#Creating the mesh
L = 100
N = 100
dx = L/N
x = np.arange(0, L, dx)
dt=0.01
t = np.linspace(0, 1, 100)
#Frequency for the Fourier Transformation
kappa= 2*np.pi*np.fft.fftfreq(N, d=dx)
#Initial condition for function u and its Fast Fourier Transformation
u0= np.zeros_like(x)
u0[int((L/4-L/10)/dx):int((L/4+L/10)/dx)]=2.5
u0[int((3*L/4-L/10)/dx):int((3*L/4+L/10)/dx)]=2.5
u0hat = np.fft.fft(u0)
u0hat_ri= np.concatenate((u0hat.real, u0hat.imag))
#Define the function describing the Transformation from the PDE to the system of ODEs
def func(uhat_ri, t, kappa, a, b, c):
uhat = uhat_ri[:N] +(1j)*uhat_ri[N:]
#Define the weighted change by the Brownian path B
mean = [0]*len(uhat)
diag = [0.1] * len(uhat)
cov = np.diag(diag)
B = np.random.multivariate_normal(mean, cov)
d_uhat = -a**2 * (np.power(kappa, 2))* uhat-c*(1j)*kappa*uhat + b* (1j) * kappa * uhat * B
d_uhat_ri = np.concatenate((d_uhat.real, d_uhat.imag))
return d_uhat_ri
#Solve the ODE with odeint
uhat_ri = odeint(func, u0hat_ri, t, args=(kappa, a, b, c))
uhat = uhat_ri[:, :N] + (1j) * uhat_ri[:, N:]
u = np.zeros_like(uhat)
#Inverse Transform the Solution
for k in range(len(t)):
u[:, k] = np.fft.ifft(uhat[k, :])
u = u.real
This program works if I exclude the Brownian path B in func
def func(uhat_ri, t, kappa, a, b, c):
uhat = uhat_ri[:N] +(1j)*uhat_ri[N:]
d_uhat = -a**2 * (np.power(kappa, 2))* uhat-c*(1j)*kappa*uhat + b* (1j) * kappa * uhat
d_uhat_ri = np.concatenate((d_uhat.real, d_uhat.imag))
return d_uhat_ri
But it takes a long time to execute when including B and also it tells me:
C:\Users\leo_h\AppData\Local\Programs\Python\Python39\lib\site-packages\scipy\integrate\odepack.py:247: ODEintWarning: Excess work done on this call (perhaps wrong Dfun type). Run with full_output = 1 to get quantitative information.
warnings.warn(warning_msg, ODEintWarning)
EDIT/ANSWER:
I solved the problem, by putting the change in the Brownian path out of func. I guess it was just too much for odeint to cope with the function (or it generated a new Brownian path for each t?)
mean = [0]*len(u0hat)
diag = [2] * len(u0hat)
cov = np.diag(diag)
B = np.random.multivariate_normal(mean, cov)
def func(uhat_ri, t, kappa, a, b, c, B):
uhat = uhat_ri[:N] +(1j)*uhat_ri[N:]
d_uhat = np.zeros_like(uhat)
d_uhat = -a**2 * (np.power(kappa, 2)) * uhat-c * (1j) * kappa * uhat + b * B * (1j) * kappa * uhat
d_uhat_ri = np.concatenate((d_uhat.real, d_uhat.imag))
return d_uhat_ri
uhat_ri = odeint(func, u0hat_ri, t, args=(kappa, a, b, c, B))

How to solve the differential equation?

I want to solve the deferential equation
dydt = r * (Y ** p) * (1 - (Y / K) ** alpha)
I tried to write the code like :
def func(Y, r, p, K, alpha):
dydt = r * (Y ** p) * (1 - (Y / K) ** alpha)
return dydt
t = np.linspace(0, len(df), len(df))
# I used 1 to initialize my parameters ( is there a better way ?)
r = 1; p = 1; K = 1; alpha = 1
y0 = r,p,K,alpha
ret = odeint(func, y0, t)
but when I try to execute the third block I get
TypeError: func() missing 3 required positional arguments: 'p', 'K', and 'alpha'
However I tried to use ret = odeint(func, y0, t, args=(p,K, alpha))
but this resulted in a three straight lines, when the equation is supposed to return a logistic curve.
how can I try to put r in the argument and why I need to specify the arguments? how can I get the final shape (logistic curve)
Note: to understand the parameters: Y represents the cumulative number of cases at time t, r is the growth rateat the early stage, and K is the final epidemic size.𝑝∈[0,1]is a parameter that allows the model to capture different growth profiles including the constant incidence (𝑝=0), sub-exponential growth (0<𝑝<1)and exponential growth (𝑝=1).
def func(Y, t, r, p, K, alpha):
return r * (Y ** p) * (1 - (Y / K) ** alpha)
You must add the t parameter in the ODEINT method.
y0 = 0.5 # Your initial condition.
params = (1, 1, 1, 1) # r, p, K, alpha
sol = odeint(func, y0, t, args=params)
From the source! Scipy ODEINT

Explicit Euler method doesn't behave how I expect

I have implemented the following explicit euler method in python:
def explicit_euler(df, x0, h, N):
"""Solves an ODE IVP using the Explicit Euler method.
Keyword arguments:
df - The derivative of the system you wish to solve.
x0 - The initial value of the system you wish to solve.
h - The step size.
N - The number off steps.
"""
x = np.zeros(N)
x[0] = x0
for i in range(0, N-1):
x[i+1] = x[i] + h * df(x[i])
return x
Following the article on wikipedia I can plot the function and verify that I get the same plot: . I believe that here the method I have written is working correctly.
Next I tried to use it to solve the last system given on this page and instead of the plot shown there I obtain this:
I am not sure why my plot doesn't match the one shown on the webpage. The explicit euler method seems to work fine when I use it to solve systems where the slope doesn't change, but for an oscillating function it never seems to mimic it at all. Not even showing the expected error gain as indicated on the linked webpage. I am not sure what is wrong with the method I have implemented.
Here is the code used for plotting and the derivative:
def g(t):
return -0.5 * np.exp(t * 0.5) * np.sin(5 * t) + 5 * np.exp(t * 0.5)
* np.cos(5 * t)
h = 0.001
x0 = 0
tn = 4
N = int(tn / h)
x = ee.explicit_euler(f, x0, h, N)
t = np.arange(0, tn, h)
fig = plt.figure()
plt.plot(t, x, label="Explicit Euler")
plt.plot(t, (np.exp(0.5 * t) * np.sin(5 * t)), label="Analytical
solution")
#plt.plot(t, np.exp(0.5 * t), label="Analytical solution")
plt.xlabel('Timesteps t')
plt.ylabel('x(t)=e^(0.5*t) * sin(5*t)')
plt.legend()
plt.grid()
plt.show()
Edit:
As requested here is the current equation I am applying the method to:
y'-y=-0.5*e^(t/2)*sin(5t)+5e^(t/2)*cos(5t)
Where y(0)=0.
I would like to make clear however that this behaviour doesn't occur just for this equation but all equations where the slope has a change in sign, or oscillating behaviour.
Edit 2:
Ok thanks. Yes the code below does indeed work. But I have one further question. In the simple example I had for the exponential function, I had defined a method:
def f(x):
return x
for the system f'(x)=x. This gave the output of my first graph which looks correct. I then defined another function:
def k(x):
return cos(x)
for the system f'(x)=cos(x), this does not give expected output. But when I change the function definition to
def k(t, x):
return cos(t)
I get the expected output. If I change my function
def f(t, x):
return t
I get an incorrect output. Am I always actually evaluating the function at a time step and is it just by chance for the system x'=x that at each time step the value is just the value of x?
I had understood that the Euler method used the value of the previously calculated value in order to get the next value. But if I run code for my function k(x)=cos(x), I get output pictured below, which must be incorrect. This now uses the updated code you provided.
def k(t, x):
return np.cos(x)
h = 0.1 # Step size
x0 = (0, 0) # Initial point of iteration
tn = 10 # Time step to iterate to
N = int(tn / h) # Number of steps
x = ee.explicit_euler(k, x0, h, N)
t = np.arange(0, tn, h)
The problem is that you have incorrectly raised the function g, you want to solve the equation:
From where we observe that:
y' = y -0.5*e^(t/2)*sin(5t)+5e^(t/2)*cos(5t)
Then we define the function f(t, y) = y -0.5*e^(t/2)*sin(5t)+5e^(t/2)*cos(5t) as:
def f(t, y):
return y -0.5 * np.exp(t * 0.5) * np.sin(5 * t) + 5 * np.exp(t * 0.5) * np.cos(5 * t)
The initial point of iteration is f0=(t(0), y(0)):
f0 = (0, 0)
Then from Euler's equations:
def explicit_euler(df, x0, h, N):
"""Solves an ODE IVP using the Explicit Euler method.
Keyword arguments:
df - The derivative of the system you wish to solve.
x0 - The initial value of the system you wish to solve.
h - The step size.
N - The number off steps.
"""
x = np.zeros(N)
t, x[0] = x0
for i in range(0, N-1):
x[i+1] = x[i] + h * df(t ,x[i])
t += h
return x
Complete Code:
def explicit_euler(df, x0, h, N):
"""Solves an ODE IVP using the Explicit Euler method.
Keyword arguments:
df - The derivative of the system you wish to solve.
x0 - The initial value of the system you wish to solve.
h - The step size.
N - The number off steps.
"""
x = np.zeros(N)
t, x[0] = x0
for i in range(0, N-1):
x[i+1] = x[i] + h * df(t ,x[i])
t += h
return x
def df(t, y):
return -0.5 * np.exp(t * 0.5) * np.sin(5 * t) + 5 * np.exp(t * 0.5) * np.cos(5 * t) + y
h = 0.001
f0 = (0, 0)
tn = 4
N = int(tn / h)
x = explicit_euler(df, f0, h, N)
t = np.arange(0, tn, h)
fig = plt.figure()
plt.plot(t, x, label="Explicit Euler")
plt.plot(t, (np.exp(0.5 * t) * np.sin(5 * t)), label="Analytical solution")
#plt.plot(t, np.exp(0.5 * t), label="Analytical solution")
plt.xlabel('Timesteps t')
plt.ylabel('x(t)=e^(0.5*t) * sin(5*t)')
plt.legend()
plt.grid()
plt.show()
Screenshot:
Dump y' and what is on the right side is what you should place in the df function.
We will modify the variables to maintain the same standard for the variables, and will y be the dependent variable, and t the independent variable.
Equation 2: In this case the equation f'(x)=cos(x) will be rewritten to:
y'=cos(t)
Then:
def df(t, y):
return np.cos(t)
In conclusion, if we have an equation of the following form:
y' = f(t, y)
Then:
def df(t, y):
return f(t, y)

RK4 implementation to solve Lotka Volterra Diff-EQ

I am trying to understand what's wrong with the code I have butchered together. The code below is one of many implementations I have done today to solve the Lotka Volterra Differential equations (2 Systems), it is the one that I have brought the closest to the desired result.
import matplotlib.pyplot as plt
import numpy as np
from pylab import *
def rk4( f, x0, t ):
"""
4th order Runge-Kutta method implementation to solve x' = f(x,t) with x(t[0]) = x0.
USE:
x = rk4(f, x0, t)
INPUT:
f - function of x and t equal to dx/dt.
x0 - the initial condition(s).
Specifies the value of x # t = t[0] (initial).
Can be a scalar of a vector (NumPy Array)
Example: [x0, y0] = [500, 20]
t - a time vector (array) at which the values of the solution are computed at.
t[0] is considered as the initial time point
h = t[i+1] - t[i] determines the step size h as suggested by the algorithm
Example: t = np.linspace( 0, 500, 200 ), creates 200 time points between 0 and 500
increasing the number of points in the intervall automatically decreases the step size
OUTPUT:
x - An array containing the solution evaluated at each point in the t array.
"""
n = len( t )
x = np.array( [ x0 ] * n ) # creating an array of length n
for i in xrange( n - 1 ):
h = t[i+1] - t[i] # step size, dependent on the time vector.
# starting below - the implementation of the RK4 algorithm:
# for further informations visit http://en.wikipedia.org/wiki/Runge-Kutta_methods
# k1 is the increment based on the slope at the beginning of the interval (same as Euler)
# k2 is the increment based on the slope at the midpoint of the interval (with x + 0.5 * k1)
# k3 is AGAIN the increment based on the slope at the midpoint (with x + 0.5 * k2)
# k4 is the increment based on the slope at the end of the interval
k1 = f( x[i], t[i] )
k2 = f( x[i] + 0.5 * k1, t[i] + 0.5 * h )
k3 = f( x[i] + 0.5 * k2, t[i] + 0.5 * h )
k4 = f( x[i] + h * k3, t[i] + h )
# finally computing the weighted average and storing it in the x-array
x[i+1] = x[i] + h * ( ( k1 + 2.0 * ( k2 + k3 ) + k4 ) / 6.0 )
return x
# model
def model(state,t):
"""
A function that creates an array containing the Lotka Volterra Differential equation
Parameter assignement convention:
a natural growth rate of the preys
b chance of being eaten by a predator
c dying rate of the predators per week
d chance of catching a prey
"""
x,y = state # will corresponding to initial conditions
# consider it as a vector too
a = 0.08
b = 0.002
c = 0.2
d = 0.0004
return np.array([ x*(a-b*y) , -y*(c - d*x) ]) # corresponds to [dx/dt, dy/dt]
################################################################
# initial conditions for the system
x0 = 500
y0 = 20
# vector of times
t = np.linspace( 0, 500, 1000 )
result = rk4( model, [x0,y0], t )
print result
plt.plot(t,result)
plt.xlabel('Time')
plt.ylabel('Population Size')
plt.legend(('x (prey)','y (predator)'))
plt.title('Lotka-Volterra Model')
plt.show()
The above code produces the following output
however if I move the from pylab import * code right above the initial conditions I get the correct output
why does this happen and how can I fix this?
pylab defines its own implementation of rk4, which it takes from matplotlib:
In [1]: import pylab
In [2]: pylab.rk4
Out[2]: <function matplotlib.mlab.rk4>
When you do a wildcard import like from pylab import *, you will override any local functions with the same name.
In particular, here you're redefining your own rk4 implementation (ie, the code you've written is never used).
This is why you should never do a wildcard import like that. pylab is particularly problematic, in that it defines several functions (such as any and all) which have completely different outputs than the python builtins for certain inputs.
Anyway, the root cause of your problem seems to be that your RK4 implementation is incorrect.
You need to use the step size in your calculation of k_n.
For example, here's a small snippet of my own RK4 implementation (which, I'll admit, is tuned for speed rather than readability):
while not target(xs):
...
# Do RK4
self.f(xs, self.k1)
self.f(xs + halfh*self.k1, self.k2)
self.f(xs + halfh*self.k2, self.k3)
self.f(xs + self.h*self.k3, self.k4)
xs += sixthh*(self.k1 + self.k2 + self.k2 + self.k3 + self.k3 \
+ self.k4)
You'll note that the entire state vector is multiplied by h, not just the time component.
Try fixing that up in your own code and seeing if the result is the same.
(In my opinion, the habit of wiki etc of treating time as a special case is a cause of a lot of these problems. Your time vector, ts, is simply a special derivative where t' = 1.)
So for your own code, I believe, but haven't tested, that something like this should work:
k1 = f( x[i], t[i] )
k2 = f( x[i] + 0.5 * h * k1, t[i] + 0.5 * h ) ## changed to use h
k3 = f( x[i] + 0.5 * h * k2, t[i] + 0.5 * h ) ## changed to use h
k4 = f( x[i] + h * k3, t[i] + h )
Try
import pylab
help(pylab.rk4)
You'll find a long explanation of the pylab.rk4 command.
This is why it's not a good idea to use from x import *. It's much better to do import pylab as py and then this won't be an issue.
Be aware that even with moving your import command, any later call you might have to rk4 will fail.

Categories