In [2]:
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate
%matplotlib inline
'''
class IVPResult:
pass
def solve_ivp(f, ts, x0, p=None, integrator='dopri5', store_trajectory=False,\
sens=False, dfx=None, dfp=None):
"""
Solve initial value problem
d/dt x = f(t, x, p); x(t0) = x0.
Evaluate Solution at time points specified in ts, with ts[0] = t0.
"""
if sens:
n = X0.shape[0]
x0 = np.hstack((X0, np.eye(n).flatten(), np.zeros(len(p) * n)))
def g(t, X, p):
var = X[:n]
var2 = X[: n * 3]
return np.hstack((f(t, var, p), dfx(t, var2, p), dfp(t, X, p)))
ivp = scipy.integrate.ode(g)
else:
ivp = scipy.integrate.ode(f)
ivp.set_integrator(integrator)
if store_trajectory:
times = []
points = []
def solout(t, x):
if len(times) == 0 or t != times[-1]:
times.append(t)
points.append(np.copy(x[:x0.shape[0]]))
ivp.set_solout(solout)
ivp.set_initial_value(x0, ts[0])
ivp.set_f_params(p)
result = IVPResult()
result.ts = ts
result.xs = np.zeros([ts.shape[0], x0.shape[0]])
result.success = True
result.xs[0,:] = x0
for ii in range(1,ts.shape[0]):
ivp.integrate(ts[ii])
result.xs[ii,:] = ivp.y[:x0.shape[0]]
if not ivp.successful():
result.success = False
break
if store_trajectory:
result.trajectory_t = np.array(times)
result.trajectory_x = np.array(points)
return result
'''
def dX_dt(t, X, p):
R = X[0]
F = X[1]
alpha, beta, gamma, delta = p
dRdt = alpha * R - beta * F * R
dFdt = gamma * R * F - delta * F
return np.array([dRdt,dFdt])
def dfx(t, X, p):
R = X[0]
F = X[1]
alpha, beta, gamma, delta = p
return np.dot(np.array([alpha - beta * F, - beta * R, gamma * F,\
gamma * R - delta]).reshape((2, 2)),\
X[2:].reshape((2, 2))).flatten()
def dfp(t, X, p):
R = X[0]
F = X[1]
alpha, beta, gamma, delta = p
foo = np.dot(np.array([alpha - beta * F, - beta * R, gamma * F,\
gamma * R - delta]).reshape((2, 2)), \
X[6:].reshape((2, 4)))
return (foo + np.array([[R, - F * R, 0., 0.],[0., 0., R * F,\
-F]])).flatten()
In [2]:
# initial condition
X0 = np.array([20.,10.])
param = (.2, .01, .001, .1)
result = solve_ivp(dX_dt, np.array([0, 300]), X0, p=param,\
integrator='dopri5', store_trajectory=True, sens=True, dfx=dfx, dfp=dfp)
In [3]:
xs = result.xs[-1, :]
x_ = xs[:2]
gx = xs[2:6].reshape((2, 2))
gp = xs[6:].reshape((2, 4))
print('The result for the rabbits and foxes:')
print(x_)
print('G_x(t)')
print(gx)
print('G_p(t)')
print(gp)
In [4]:
def g(X, t=0):
p = param
var = X[:2]
var2 = X[: 2 * 3]
return np.hstack((dX_dt(t, var, p), dfx(t, var2, p), dfp(t, X, p)))
n = 2
X0 = np.hstack((np.array([20., 10.]), np.eye(2).flatten(), np.zeros(8)))
t = np.linspace(0,300,100000)
X, infodict = scipy.integrate.odeint(g, X0, t, full_output=True)
infodict['message']
Out[4]:
In [5]:
xs = X[-1, :]
x__fixed = xs[:2]
gx_fixed = xs[2:6].reshape((2, 2))
gp_fixed = xs[6:].reshape((2, 4))
print('The result for the rabbits and foxes:')
print(x__fixed)
print('G_x(t)')
print(gx_fixed)
print('G_p(t)')
print(gp_fixed)
In [6]:
print('\nDelta R, Delta F')
print(x_ - x__fixed)
print('\nDelta G(t)_x')
print(gx - gx_fixed)
print('\nDelta G(t)_p')
print(gp - gp_fixed)
In [61]:
import scipy.integrate
import scipy.sparse
import numpy as np
import collections
class IVPResult:
pass
def solve_ivp(f, ts, x0, p=None, integrator='dopri5', store_trajectory=False,
sens=False, dfx=None, dfp=None):
"""
Solve initial value problem
d/dt x = f(t, x, p); x(t0) = x0.
Evaluate Solution at time points specified in ts, with ts[0] = t0.
Compute sensitivity matrices evaluated at time points in ts if sens=True.
"""
if sens:
def f_vode(t, xGxGp, p):
x = xGxGp[:x0.shape[0]]
Gx = xGxGp[x0.shape[0]:x0.shape[0]+x0.shape[0]*x0.shape[0]]
Gx = Gx.reshape([x0.shape[0], x0.shape[0]])
Gp = xGxGp[x0.shape[0]+x0.shape[0]*x0.shape[0]:]
Gp = Gp.reshape([x0.shape[0], p.shape[0]])
dx = f(t, x, p)
dfxev = dfx(t, x, p)
dfpev = dfp(t, x, p)
dGx = dfxev.dot(Gx)
dGp = dfxev.dot(Gp) + dfpev
return np.concatenate(
[dx,
dGx.reshape(-1),
dGp.reshape(-1)])
ivp = scipy.integrate.ode(f_vode)
else:
ivp = scipy.integrate.ode(f)
ivp.set_integrator(integrator)
if store_trajectory:
times = []
points = []
def solout(t, x):
if len(times) == 0 or t != times[-1]:
times.append(t)
points.append(np.copy(x[:x0.shape[0]]))
ivp.set_solout(solout)
if sens:
ivp.set_initial_value(np.concatenate(
[x0,
np.eye(x0.shape[0]).reshape(-1),
np.zeros([x0.shape[0], p.shape[0]]).reshape(-1)
]), ts[0])
else:
ivp.set_initial_value(x0, ts[0])
ivp.set_f_params(p)
result = IVPResult()
result.ts = ts
result.xs = np.zeros([ts.shape[0], x0.shape[0]])
if sens:
result.Gxs = np.zeros([ts.shape[0], x0.shape[0], x0.shape[0]])
result.Gps = np.zeros([ts.shape[0], x0.shape[0], p.shape[0]])
result.success = True
result.xs[0,:] = x0
for ii in range(1,ts.shape[0]):
ivp.integrate(ts[ii])
result.xs[ii,:] = ivp.y[:x0.shape[0]]
if sens:
result.Gxs[ii,:,:] = ivp.y[x0.shape[0]:x0.shape[0]+x0.shape[0]*x0.shape[0]].reshape([x0.shape[0], x0.shape[0]])
result.Gps[ii,:,:] = ivp.y[x0.shape[0]+x0.shape[0]*x0.shape[0]:].reshape([x0.shape[0], p.shape[0]])
if not ivp.successful():
result.success = False
break
if store_trajectory:
result.trajectory_t = np.array(times)
result.trajectory_x = np.array(points)
return result
In [62]:
def dX_dt(t, X, p):
R = X[0]
F = X[1]
alpha, beta, gamma, delta = p
dRdt = alpha * R - beta * F * R
dFdt = gamma * R * F - delta * F
return np.array([dRdt,dFdt])
def dfx(t, X, p):
R = X[0]
F = X[1]
alpha, beta, gamma, delta = p
return np.array([alpha - beta * F, - beta * R, gamma * F,\
gamma * R - delta]).reshape((2, 2))
def dfp(t, X, p):
R = X[0]
F = X[1]
alpha, beta, gamma, delta = p
return np.array([[R, - F * R, 0., 0.],[0., 0., R * F, -F]])
# initial condition
X0 = np.array([20.,10.])
param = np.array((.2, .01, .001, .1))
result = solve_ivp(dX_dt, np.array([0, 300]), X0, p=param,\
integrator='dopri5', store_trajectory=True, sens=True, dfx=dfx, dfp=dfp)
In [75]:
result.Gps[1].shape
Out[75]:
In [140]:
def evaluate_parest_single_shooting(f, dfx, dfp, meas_times, meas_values, s0, p):
result = solve_ivp(f, meas_times, s0, p=p, sens=True, dfx=dfx, dfp=dfp)
m = len(meas_times)
nx = len(s0)
nv = nx + len(p)
F = (meas_values - result.xs).reshape((m * nx, 1))
#F = np.linalg.norm(F)
J = np.zeros((m * nx, nv))
#print (J.shape)
dy = np.eye(nx)
for i in range(m):
for j in range(nx):
#print(2 * m + nx)
J[2 * i + j, :] = np.hstack((dy[[j], :].dot(result.Gxs[i]), dy[[j], :].dot(result.Gps[i])))
return F, J
#def gauss_newton(F_J, x0, itmax=100, tol=1e-7, verbose=1):
In [129]:
np.random.seed(31)
meas_times = np.arange(21) * 5
noise = 10. * np.random.rand(21, 2)
x0 = np.array([20., 10.])
result = solve_ivp(dX_dt, meas_times, X0, p=param)
meas_values = result.xs + noise
In [130]:
F, J= evaluate_parest_single_shooting(dX_dt, dfx, dfp, meas_times, meas_values, X0, param)
In [184]:
np.random.seed(31)
meas_times = np.arange(21) * 5
noise = 20. * np.random.rand(21, 2)
x0_init = np.array([20., 10.])
param_init = np.array((.2, .01, .001, .1))
result = solve_ivp(dX_dt, meas_times, x0_init, p=param_init)
meas_values = result.xs + noise
x0 = x0_init * (1 + .3 * np.random.rand(len(x0)))
param = param_init * (1 + .02 * np.random.rand(len(param.shape)))
tau = .5
for i in range(20):
F, J= evaluate_parest_single_shooting(dX_dt, dfx, dfp, meas_times, meas_values, x0, param)
Dx = np.linalg.lstsq(J, F)[0]
#print (Dx.shape)
x0 += tau * Dx.flatten()[:2]
param += tau * Dx.flatten()[2:]
print(np.linalg.norm(F))
In [185]:
print((param - param_init) / param_init)
print((x0 - x0_init)/ x0_init)
print(param)
print(param_init)
In [150]:
Dx
Out[150]:
In [70]:
meas_values.T.reshape((meas_values.size, 1))
Out[70]:
In [68]:
meas_values.reshape(21, 2)
Out[68]:
In [69]:
meas_values
Out[69]:
In [71]:
v = np.arange(8)
In [73]:
v = 0
In [74]:
v
Out[74]:
In [ ]: