Related
I am trying to find the Lotka-Volterra ODE PARAMETERS(alpha,beta,gamma,delta) from a set of (x , y, t) data (full code at the bottom)
Lotka-Volterra Equations
I believe the error is at gradLoss=loss.grad as print(loss) returns a real number while print(gradLoss) returns a 'NoneType', none value. I have been trying to run this code for hours but to no avail because "parameter -= delta*gradLoss" will not compute since gradLoss is not a number.
Here is the code:
parameter = torch.tensor([1.0137, 1.0269, 3.1526, 3.1884])
T = torch.linspace(0,25,51)
T1 = torch.zeros(len(t))
T1 = T[::500]
delta = 1e-2
n = 100
for k in range(n):
parameter = torch.tensor(parameter,requires_grad=True)
X,Y = Euler2(T, parameter[0], parameter[1], parameter[2], parameter[3], x0, y0, 0.001,25001)
loss = torch.norm(torch.tensor(X[0::500])-x)**2/torch.norm(x)**2 + torch.norm(torch.tensor(Y[0::500])-y)**2/torch.norm(y)**2
gradLoss = loss.grad <-- I believe the error is here
#with torch.no_grad():
parameter -= delta*gradLoss
if i%1 == 0:
LOSS = loss.item()
print(i, loss.item(), torch.norm(gradLoss).item())
Thanks for your help!
Best, Sacha
Rest of code:
def Euler2(t,alpha,beta,gamma,delta,x0,y0,dt,n):
alpha = alpha*torch.ones(n)
beta = beta*torch.ones(n)
gamma = gamma*torch.ones(n)
delta = delta*torch.ones(n)
X = np.zeros(n+1)
X[0] = x0
Y = np.zeros(n+1)
Y[0] = y0
for k in range(0,(n)):
X[k+1] = X[k] * (1 + alpha[k] * dt - Y[k] * beta[k] * dt)
Y[k+1] = Y[k] * (1 - gamma[k] * dt + X[k] * delta[k] * dt)
return X,Y
# x - nematodes x 1M
# y - beetle x 1M
# t - time (days)
x = torch.tensor([0.9072, 0.9439, 1.0234, 1.1035, 1.1090, 1.0245, 0.9154, 0.8933, 0.9323,
1.0302, 1.0849, 1.1195, 1.0420, 0.9284, 0.8924, 0.9400, 1.0293, 1.0969,
1.1002, 1.0344, 0.9469, 0.8910, 0.9462, 1.0291, 1.1030, 1.1044, 1.0212,
0.9352, 0.8931, 0.9307, 1.0190, 1.0974, 1.1122, 1.0311, 0.9513, 0.8962,
0.9312, 1.0082, 1.0987, 1.1100, 1.0528, 0.9421, 0.8953, 0.9381, 1.0322,
1.0880, 1.0964, 1.0296, 0.9347, 0.9083, 0.9300])
y = torch.tensor([0.8904, 0.8330, 0.8469, 0.9896, 1.1478, 1.1858, 1.0542, 0.9010, 0.8234,
0.8798, 0.9858, 1.1443, 1.2132, 1.0522, 0.8866, 0.8183, 0.8391, 0.9799,
1.1201, 1.2016, 1.0743, 0.9211, 0.8288, 0.8564, 0.9669, 1.1408, 1.2024,
1.0740, 0.9199, 0.8314, 0.8341, 0.9772, 1.1274, 1.1932, 1.0701, 0.9253,
0.8209, 0.8557, 0.9552, 1.1337, 1.2164, 1.0808, 0.9151, 0.8288, 0.8526,
0.9553, 1.1160, 1.1834, 1.0864, 0.8934, 0.8376])
t = torch.tensor([ 0.0000, 0.5000, 1.0000, 1.5000, 2.0000, 2.5000, 3.0000, 3.5000,
4.0000, 4.5000, 5.0000, 5.5000, 6.0000, 6.5000, 7.0000, 7.5000,
8.0000, 8.5000, 9.0000, 9.5000, 10.0000, 10.5000, 11.0000, 11.5000,
12.0000, 12.5000, 13.0000, 13.5000, 14.0000, 14.5000, 15.0000, 15.5000,
16.0000, 16.5000, 17.0000, 17.5000, 18.0000, 18.5000, 19.0000, 19.5000,
20.0000, 20.5000, 21.0000, 21.5000, 22.0000, 22.5000, 23.0000, 23.5000,
24.0000, 24.5000, 25.0000])
I am struggling to numerically solve Newton's equation for gravity using scipy.integrate.solve_ivp. I can get the coding working when one of the bodies is assumed stationary. However as shown in the picture when I use the code below where I am trying to account for the force of the sun on Jupiter and that of Jupiter on the sun, the suns orbit is not correct. It doesn't seem to wobble but instead just heads off away from the COM.
G = 6.67408e-11
msun = 1988500e24
m_jupiter = 1898.13e24
x_pos_j = 2.939022030646856E+00*au
y_pos_j = -4.169544536356319E+00*au
z_pos_j = -4.843813063988785E-02*au
x_vel_j = 6.083727195546033E-03*v_factor
y_vel_j = 4.708328571996785E-03*v_factor
z_vel_j = -1.556609498459863E-04*v_factor
def f_grav(t, y):
x1, x2, x3, v1, v2, v3 = y
# x1_star, x2_star, x3_star = x_other
dydt = [v1,
v2,
v3,
-(x1-x1_star)*G*m/((x1-x1_star)**2+(x2-x2_star)**2+(x3-x3_star)**2)**(3/2),
-(x2-x2_star)*G*m/((x1-x1_star)**2+(x2-x2_star)**2+(x3-x3_star)**2)**(3/2),
-(x3-x3_star)*G*m/((x1-x1_star)**2+(x2-x2_star)**2+(x3-x3_star)**2)**(3/2)]
return dydt
x_jupiter = np.array([x_pos_j, y_pos_j, z_pos_j])
x_sun = np.array([0, 0, 0])
v_sun = np.array([0, 0, 0])
tStart = 0e0
t_End = 20*year
dt = t_End/3000
# minstep = dt/100
domain = (tStart, dt)
temp_end = dt
x1_star, x2_star, x3_star = [0, 0, 0]
init_j = [x_pos_j, y_pos_j, z_pos_j, x_vel_j, y_vel_j, z_vel_j]
init_sun = [20, -20, 20, 15, -15, 0]
while tStart < t_End:
m=msun
ans_j = solve_ivp(fun=f_grav, t_span=domain, y0=init_j)
x1_star, x2_star, x3_star = ans_j['y'][0:3, -1]
v1_star, v2_star, v3_star = ans_j['y'][3:6, -1]
x_jupiter = np.vstack((x_jupiter, (ans_j['y'][0:3, -1])))
init_j = [x1_star, x2_star, x3_star, v1_star, v2_star, v3_star]
# print(init_j[0:3])
m=m_jupiter
ans_sun = solve_ivp(fun=f_grav, t_span=domain, y0=init_sun)
x1_star, x2_star, x3_star = ans_sun['y'][0:3, -1]
v1_star, v2_star, v3_star = ans_sun['y'][3:6, -1]
v_sun = np.vstack((v_sun, (ans_sun['y'][3:6, -1])))
x_sun = np.vstack((x_sun, (ans_sun['y'][0:3, -1])))
init_sun = [x1_star, x2_star, x3_star, v1_star, v2_star, v3_star]
tStart += dt
temp_end = tStart + dt
domain = (tStart,temp_end)
plt.plot(x_jupiter[:,0], x_jupiter[:,1])
plt.plot(x_sun[:,0], x_sun[:,1])
plt.show()
In the code at any given moment to solve the equation I assume that the other star is stationary but only for dt, which I don't think should effect the results. Is this why my plots are wrong and if so how can I better solve the equation when both bodies are moving. The orbit of Jupiter (blue on right image) looks more less correct but not that of the sun (on both images and is orange).
I am struggling to change my code to solve a system of (Ordinary Differential Equation)ODE from initial value problem to boundary value problem. I have tried myself many times but I think i am making mistakes which are logically incorrect. So instead of pasting the change code, I am pasting below my original code which works fine.
Below mention code is used to solve a system of ODE with function odeint and then I am using Particle Swarm Optimiation(PSO) algorithm for optimisation process. I want to use the same equations with function solve_bvp with boundary conditions t(0) =1 and t(1) = 2. Below mention is the code. Thanks
from scipy import *
from scipy.integrate import odeint
from operator import itemgetter
import matplotlib
matplotlib.use('Agg')
from matplotlib.ticker import FormatStrFormatter
from pylab import *
from itertools import product
import itertools
from numpy import zeros_like
import operator
from pyswarm import pso
modelsOne = []
modelsTwo = []
modelsThree = []
#step 1 start## To build model structure library. HIV model is a three-variable model, so we need three model structure liararys: modelsOne, modelsTwo, modelsThree.
# the model structure library contains all possible structures of the model to be sought.
def ModelsProduct(modelsOne, modelsTwo, modelsThree):
modelsStepOne = list(product("+-",repeat = 4))
modelsStepThree = [('a','a'),('a','b'),('a','c'),('b','b'),('b','c'),('c','c')]
#produce modelsOne
modelsStepTwo = [('b',),('c',)]
for one in modelsStepOne:
for two in modelsStepTwo:
for three in modelsStepThree:
modelsOne.append(one+two+three)
#produce modelsTwo
modelsStepTwo = [('a',),('c',)]
for one in modelsStepOne:
for two in modelsStepTwo:
for three in modelsStepThree:
modelsTwo.append(one+two+three)
#produce modelsThree
modelsStepTwo = [('a',),('b',)]
for one in modelsStepOne:
for two in modelsStepTwo:
for three in modelsStepThree:
modelsThree.append(one+two+three)
return modelsOne, modelsTwo, modelsThree
modelsOne, modelsTwo,modelsThree = ModelsProduct(modelsOne, modelsTwo, modelsThree)
#step 1 end##
VarList = ["a","b","c"]
initial_condi = [100, 150, 50000]
dictVar = {'a':0, 'b': 1, 'c': 2}
ops = { "+": operator.add, "-": operator.sub }
t_range = arange(0.0,60.0,1.0)
def odeFunc(Y, t, x,dictVar):
if x[-3] == 192:
temp1 = 191
else:
temp1 = int(x[-3])
if x[-2] == 192:
temp2 = 191
else:
temp2 = int(x[-2])
if x[-1] == 192:
temp3 = 191
else:
temp3 = int(x[-1])
modelOne = modelsOne[temp1]
modelTwo = modelsTwo[temp2]
modelThree = modelsThree[temp3]
return GenModel(Y, x, modelOne,modelTwo,modelThree, dictVar)
def GenModel(Y,x,modelOne,modelTwo,modelThree, dictVar):
dydt = zeros_like(Y)
dydt[0] = ops[modelOne[0]](dydt[0],x[0]*Y[0])
dydt[0] = ops[modelOne[1]](dydt[0],x[1]*Y[dictVar[modelOne[-3]]])
dydt[0] = ops[modelOne[2]](dydt[0],x[2]*Y[dictVar[modelOne[-2]]]*Y[dictVar[modelOne[-1]]])
dydt[0] = ops[modelOne[3]](dydt[0],x[3])
dydt[1] = ops[modelTwo[0]](dydt[1],x[4]*Y[1])
dydt[1] = ops[modelTwo[1]](dydt[1],x[5]*Y[dictVar[modelTwo[-3]]])
dydt[1] = ops[modelTwo[2]](dydt[1],x[6]*Y[dictVar[modelTwo[-2]]]*Y[dictVar[modelTwo[-1]]])
dydt[1] = ops[modelTwo[3]](dydt[1],x[7])
dydt[2] = ops[modelThree[0]](dydt[2],x[8]*Y[2])
dydt[2] = ops[modelThree[1]](dydt[2],x[9]*Y[dictVar[modelThree[-3]]])
dydt[2] = ops[modelThree[2]](dydt[2],x[10]*Y[dictVar[modelThree[-2]]]*Y[dictVar[modelThree[-1]]])
dydt[2] = ops[modelThree[3]](dydt[2],x[11])
return dydt
## equations
def pendulum_equations(w, t):
T, I, V = w
dT = 80 - 0.15*T - 0.00002*T*V
dI = 0.00002*T*V - 0.55*I
dV = 900*0.55*I - 5.5*V - 0.00002*T*V
return dT, dI, dV
result_init = odeint(pendulum_equations, initial_condi, t_range)
result_init[:,2] = result_init[:,2]/100
def myfunc(xRand):
result_new = odeint(odeFunc, initial_condi, t_range, args=(xRand,dictVar))
result_new[:,2] = result_new[:,2]/100
result_sub = result_new - result_init
return sum(result_sub*result_sub)
x = (0.15,0,0.00002,80,0.55,0,0.00002,0,5.5,495,0.00002,0,122,98,128)
lb = [0]*15
ub = [1,1,0.5,200,1,1,0.5,200,10,1000,0.5,200,192,192,192]
xopt1, fopt1 = pso(myfunc, lb, ub,omega= 0.7298,phip=1.49618,phig=1.49618,maxiter=1000,swarmsize= 1000,minstep=1e-20,minfunc=1e-20,debug = True)
If you have an ODE like
def f_ode(t,u): return [ u[1], -u[0] ]
which you can solve as
tspan = np.linspace(0,1,51);
u_init = [1.0, 0.0]
u = odeint(f_ode, u_init, tspan, tfirst=True)
or as
res = solve_ivp(f_ode, tspan[[0,-1]], u_init, t_eval=tspan)
if res.success:
u=res.y
you can switch to a boundary problem by encoding the necessary functions and initial guess
def f_bc(u0, u1): return [u0[0]-1, u1[0]-2]
t = np.linspace(0,1,11);
u = [ 1+t, 1+0*t]
res = solve_bvp(f_ode,f_bc,t,u)
if res.success:
u = res.sol(tspan)
Note that you have to try out if your version of the new solver functions supports the passing of parameters the same way as odeint. If that is not possible, use lambda constructs as wrappers, or explicitly defined functions.
I have the following function from which I would like to obtain its solution. I'm trying to use Scipy to get them but I observe that the solution being given by Scipy is quite different from that of Matlab, using same settings.
What am I doing wrong?
def WandG(GW,Zin):
G,W = GW # define real variables to be used for the function
R = (G**2)*(Zin.real - 0.1164) +(( 70e-12 * ( W/100 ) )**2)*( 2.9036155068866304e+16*(Zin.real - 0.1164) ) - G
I = (G**2)*( Zin.imag - 18.743998408378143 * (1-W/200) ) + (((W/100)*70e-12)**2)*( 2.9036155068866304e+16*(Zin.imag - 18.743998408378143 * (1-W/200)) ) + 170399985.53071037*(70e-12*(W/100) )
return R,I
sol = optimize.root(WandG, [0.136879496, 47.04],(12.652884410928804+14.632724423763523j), jac=False,tol=1e-14, method='lm',options={'maxiter':100*400,'epsfcn':1e-14,'xtol':1e-14})
The solution using Scipy would be
sol.x[0] = 0.0795283512113496 # G
sol.x[1] = 36.53727146377749 # W
Whereas with MATLAB for the same initial conditions, solver and Zin, it returns, which I trust more since it resembles better to the final result of W which is W=50
G = 0.0794
W = 44.5234
EDIT : added Matlab code
% configuration of fsolve
options = optimoptions('fsolve','Display','iter-detailed','PlotFcn',#optimplotfirstorderopt);
options.StepTolerance = 1e-14;
%options.OptimalityTolerance = 1e-14
options.FunctionTolerance = 1e-14;
options.MaxIterations = 100000;
options.MaxFunctionEvaluations = 400;
options.Algorithm = 'levenberg-marquardt';%'trust-region'%
fun= #WandG;
x0 = [0.136879496', 47.04'];
% Solve the function fun
gw =fsolve(fun,x0,options);
% Function to be solved by fsolve
function F = WandG(x)
F(:,1) = (x(:,1).^2).*(real(Zin) - 0.1164) +(( 70e-12 .* ( x(:,2)./100 ) ).^2).*( w.^2.*(real(Zin) - 0.1164) ) - x(:,1);
F(:,2) = (x(:,1).^2).*( img(Zin) - 18.743998408378143 * (1-x(:,2)./200) ) + (((x(:,2)./100).*70e-12).^2).*( 2.9036155068866304e+16*(img(Zin) - 18.743998408378143 .* (1-x(:,2)./200)) ) + 170399985.53071037.*(70e-12.*(x(:,2)./100) );
end
I want to include a Sparse Gaussian Process model (from GPflow library) into another project. The problem is that I can't call the prediction function for several inputs once, but I have to call it sequentially. I've checked the predictive function predict_F in SGPR class (https://github.com/GPflow/GPflow/blob/master/gpflow/models/sgpr.py) and found that I could precompute a lot of things in advance. Thus, I made a child class of SGPR and wrote a method precompute, modified predictive function:
#params_as_tensors
def precompute(self):
p_num_inducing = len(self.feature)
p_err = self.Y - self.mean_function(self.X)
p_Kuf = self.feature.Kuf(self.kern, self.X)
p_Kuu = self.feature.Kuu(self.kern, jitter=settings.numerics.jitter_level)
p_sigma = tf.sqrt(self.likelihood.variance)
self.p_L = tf.cholesky(p_Kuu)
p_A = tf.matrix_triangular_solve(self.p_L, p_Kuf, lower=True) / p_sigma
p_B = tf.matmul(p_A, p_A, transpose_b=True) + tf.eye(p_num_inducing, dtype=settings.tf_float)
self.p_LB = tf.cholesky(p_B)
p_Aerr = tf.matmul(p_A, p_err)
self.p_c = tf.matrix_triangular_solve(self.p_LB, p_Aerr, lower=True) / p_sigma
#params_as_tensors
def _build_predict(self, Xnew, full_cov=False):
"""
Compute the mean and variance of the latent function at some new points
Xnew. For a derivation of the terms in here, see the associated SGPR
notebook.
"""
Kus = self.feature.Kuf(self.kern, Xnew)
tmp1 = tf.matrix_triangular_solve(self.p_L, Kus, lower=True)
tmp2 = tf.matrix_triangular_solve(self.p_LB, tmp1, lower=True)
mean = tf.matmul(tmp2, self.p_c, transpose_a=True)
if full_cov:
var = self.kern.K(Xnew) + tf.matmul(tmp2, tmp2, transpose_a=True) \
- tf.matmul(tmp1, tmp1, transpose_a=True)
shape = tf.stack([1, 1, tf.shape(self.Y)[1]])
var = tf.tile(tf.expand_dims(var, 2), shape)
else:
var = self.kern.Kdiag(Xnew) + tf.reduce_sum(tf.square(tmp2), 0) \
- tf.reduce_sum(tf.square(tmp1), 0)
shape = tf.stack([1, tf.shape(self.Y)[1]])
var = tf.tile(tf.expand_dims(var, 1), shape)
return mean + self.mean_function(Xnew), var
But when I run the code, there is no difference in speed. I suppose that tensorflow executes all the expressions only when I call predict_f, but I have no idea how to explicitly precompute some tensors. Hope tensorflow gurus can help me, thanks in advance!
I've found a silly but straightforward solution to this problem. Here is a wrapper for the SGPR class, that precomputes some common matrices and then uses them for predictions.
from gpflow.models import GPModel, SGPR
from gpflow.decors import params_as_tensors, autoflow
from gpflow import settings
from gpflow.params import Parameter, DataHolder
import tensorflow as tf
class fastSGPR(SGPR, GPModel):
def __init__(self,X_tr, Y_tr, kernel, Zp):
gpflow.models.SGPR.__init__(self,X_tr, Y_tr, kern=kernel, Z=Zp)
print("Model has been initialized")
#autoflow()
#params_as_tensors
def precompute(self):
print("Precomputing required tensors...")
p_num_inducing = len(self.feature)
p_err = self.Y - self.mean_function(self.X)
p_Kuf = self.feature.Kuf(self.kern, self.X)
p_Kuu = self.feature.Kuu(self.kern, jitter=settings.numerics.jitter_level)
p_sigma = tf.sqrt(self.likelihood.variance)
self.p_L = tf.cholesky(p_Kuu)
p_A = tf.matrix_triangular_solve(self.p_L, p_Kuf, lower=True) / p_sigma
p_B = tf.matmul(p_A, p_A, transpose_b=True) + tf.eye(p_num_inducing, dtype=settings.tf_float)
self.p_LB = tf.cholesky(p_B)
p_Aerr = tf.matmul(p_A, p_err)
self.p_c = tf.matrix_triangular_solve(self.p_LB, p_Aerr, lower=True) / p_sigma
print("Tensors have been precomputed")
return self.p_L, self.p_LB, self.p_c
#autoflow((settings.float_type, [None, None]), (settings.float_type, [None, None]), (settings.float_type, [None, None]), (settings.float_type, [None, None]))
def predict_f(self, Xnew, L, LB, c):
"""
Compute the mean and variance of the latent function(s) at the points
Xnew.
"""
return self._build_predict(Xnew, L, LB, c)
#params_as_tensors
def _build_predict(self, Xnew, L, LB, c, full_cov=False):
"""
Compute the mean and variance of the latent function at some new points
Xnew. For a derivation of the terms in here, see the associated SGPR
notebook.
"""
Kus = self.feature.Kuf(self.kern, Xnew)
tmp1 = tf.matrix_triangular_solve(L, Kus, lower=True)
tmp2 = tf.matrix_triangular_solve(LB, tmp1, lower=True)
mean = tf.matmul(tmp2, c, transpose_a=True)
if full_cov:
var = self.kern.K(Xnew) + tf.matmul(tmp2, tmp2, transpose_a=True) \
- tf.matmul(tmp1, tmp1, transpose_a=True)
shape = tf.stack([1, 1, tf.shape(self.Y)[1]])
var = tf.tile(tf.expand_dims(var, 2), shape)
else:
var = self.kern.Kdiag(Xnew) + tf.reduce_sum(tf.square(tmp2), 0) \
- tf.reduce_sum(tf.square(tmp1), 0)
shape = tf.stack([1, tf.shape(self.Y)[1]])
var = tf.tile(tf.expand_dims(var, 1), shape)
return mean + self.mean_function(Xnew), var
def assign(self, params):
params1 = dict(params)
params1["fastSGPR/kern/variance"] = params1.pop("SGPR/kern/variance")
params1["fastSGPR/kern/lengthscales"] = params1.pop("SGPR/kern/lengthscales")
params1["fastSGPR/likelihood/variance"] = params1.pop("SGPR/likelihood/variance")
params1["fastSGPR/feature/Z"] = params1.pop("SGPR/feature/Z")
SGPR.assign(self,params1)