Here it comes the hard part
import numpy as np
import matplotlib.pyplot as plt
import scipy as sp
import pymc3 as pm
import theano
import theano.tensor as tt
from theano.compile.ops import as_op
def x(t, p):
m, h, px0, py0, g = p
return [px0*t/m, -0.5*g*t**2+py0*t/m+h]
def y(tt0, p):
m, h, px0, py0, g, a = p
t_span = [0, 1] # the whole range for integration
x0 = [0, px0/m, h, py0/m] # the initial condition
def f(t, x): return [x[1], -a/m*x[1], x[3], -g-a/m*x[3]] # the drift
def event(t, x): return x[2]+10 # solve until event(t, x)=0 is verified
event.terminal = True # the event is terminal
evaluation_times = np.array([tt0]) # times to be stored
integration_method = 'RK45' # which method 'RK45', 'RK23', 'Radau', 'BDF', 'LSODA'
solution = sp.integrate.solve_ivp(f, t_span, x0, method = integration_method, # solve the ODE
t_eval=evaluation_times, events=event, atol=1e-3)
return [solution.y[0,0], solution.y[2,0]]
# physical parameters
m, h = 0.1, 1. # mass and starting height
px0, py0 = m*1., m*1. # initial momentum
g = 9.8 # gravity
a = 0.1 # drag coefficient
# number of random samples
n = 1000
P = [m, h, px0, py0, g]
PY = [m, h, px0, py0, g, a]
traj = np.array([x(t, P) for t in np.arange(0,1*(1+1e-12),0.01)])
trajy = np.array([y(t, PY) for t in np.arange(0,1*(1+1e-12),0.01)])
t0 = 0.2;
sigmat = 1e-3; T = np.random.normal(t0,sigmat,n);
sxx = np.array([[0.005**2,0],[0,0.005**2]])
np.random.seed(0)
X = np.random.multivariate_normal(np.array([0,0]), sxx, size=n)
X += np.array([x(t, P) for t in T])
np.random.seed(0)
Y = np.random.multivariate_normal(np.array([0,0]), sxx, size=n)
Y += np.array([y(t, PY) for t in T])
plt.plot(traj[:,0], traj[:,1], color='red')
plt.plot(trajy[:,0], trajy[:,1], color='blue')
plt.scatter(X[:,0], X[:,1], color='red')
plt.scatter(Y[:,0], Y[:,1], color='blue')
plt.xlim([0, 1.1])
plt.ylim([0, 1.1])
plt.show()
the function y(t,p)
works well for determining the trajectory and a cloud of points. However when I used in a pymc model, such as
with pm.Model() as model:
G = pm.Uniform('G', lower=5., upper=15.)
MU = tt.stack(x(T, [m, h, px0, py0, G])).T
# MU = tt.stack(y(T, [m, h, px0, py0, G, a])).T # <-- HERE IS THE PROBLEM
Q = pm.MvNormal('Q', mu=MU, cov=sxx, observed=X)
trace = pm.sample(1000, chains=4, tune=1000)
it seems that it does not work the same way as x(t,p)
does. I think that the problem is that actually when called within pymc3 the input time is a vector (and g too!). I’ve tried to modify the function to consider the input (t=T) as a vector but without success.