Thanks for your quick reply. It has proved helpful but has not gotten me quite all the way there as yet, probably because I failed to put sufficient details in my first post.
To remedy that I've written some code (below) that gives an explicit example of what we are trying to do. It also incorporates what I was able to deduce either directly or from experiments based on your answer. It is a tinker-toy example but I've included some comments to illustrate the scale of a "real" problem. (The fitting operation requires solving the diffeq system between 100K and 1M times using different parameter vector estimates, which - fortunately - can be readily distributed across a cluster.)
The models that I teach/research deal with genetic network control of plant growth and development, which are often described by systems of diffeqs. Standard ODE solving approaches are adequate, esp. when implemented as in scipy with provisions to pass extra info to the user function that computes the vector of time derivatives. So, if we can solve this problem, it should have wide applications despite the niche aspect of my particular interests.
Toward this end, and to simplify things for students, I was thinking that once it is working, I might write a decorator for f that would do most of the work making driver calls, etc. I'd be happy to share this if there was interest.
I think that the problem in the code that follows has to do with the dx[ ] left hand sides in the f function. I can't get it to run at all without the dx=algopy.zeros_like(p) statement, probably because the right hand sides have an incompatible shape (the error has to do with assigning a sequence to an element). But p has already been altered by the p=algopy.UTPM.init_hessian(p) statement in myEuler. I suspect that the shape of the resulting tensor is such that extract_hessian ends up looking in the wrong place for the values it is supposed to return. The result executes, but the "Hessians" are identically zero.
Here is the code; thanks in advance for any help you can give...
#-------------------------------------------------------------------------------
# Name: Modified LotKa-Volterra equations
# Purpose: To test differentiating a system of diffeq's
# wrt the parameters p=[alpha, beta, gamma, delta]
#
# d_x0/dt = alpha**2*x0-beta**2*x1*x0
# d_x1/dt = gamma**2*x0*x1-delta**2*x1
#
# Author: welchsm
# Created: 19/06/2014
#-------------------------------------------------------------------------------
import algopy
import numpy as np
import matplotlib.pyplot as plt
# Function that calculates time derivatives. The AD task is to calculate
# the partials of these time derivatives wrt to the parameter vector p.
# Although the focus here is on the Hessians, the Jacobean of f wrt p will
# ultimately also be needed.
def f(x,p,e,t):
dx=algopy.zeros_like(p)
dx[0] = (p[0]**2*x[0]-p[1]**2*x[1]*x[0])*e[t]
dx[1] = (p[2]**2*x[0]*x[1]-p[3]**2*x[1])*e[t]
return dx
# The integration routine. Here Euler is used but this will be replaced
# by RK45. Most inputs are clear from context."e" is additional information
# to be passed to f. Normally *args would be used for this.
def myEuler(f,p,x0,t0,tf,dt,Hn,O,e):
X=x0.size # Number of state variables (the x's)
P=p.size # Number of parameters (the p's)
tso=np.zeros(X) # Time integral of state variables
TSO=np.zeros((len(O),X)) # State variables reported at desired time points
HI=np.zeros((len(Hn),P,P)) # Time integral of Hessians
H=np.zeros((len(O),len(Hn),P,P)) # Hessians reported at desired time points
R=0 # Next report number
p=algopy.UTPM.init_hessian(p) # We want the Hessian wrt to p
tso=x0 # Initial value for x
t=t0 # Initial value for time
while t<tf: # Loop thru time interval
dx=f(tso,p,e,t)
# Extract state variarble derivatives for this point in time
# and perform Euler integration
tso+=dt*dx.data[0,0,0:2] # Why is "dx.data[0,0,0:2]" correct?
# It seems messy
t+=dt
# Extract the Hessians for this point in time.
# and perform Euler integration as per Liebnitz Rule
for i,sv in enumerate(Hn):
HI[i]+=dt*algopy.UTPM.extract_hessian(P,dx[sv])
# Check if time to record desired outputs
if t>=O[R]:
TSO[R]=tso
for i in xrange(len(Hn)):
H[R,i]=HI[i]
R+=1
# Done
return TSO,H
def main():
P=4 # Number of parameters to fit (typ. ca. 40)
X=2 # Model state variables (typically. ca. 60)
Hn=[0,1] # State variables for which Hessians needed (typ. <=4)
O=np.arange(0,90)# When are outputs wanted
p=np.array([.25,.12,.10,.07]) # Parameter guesses (set each optimizer interation)
x0=np.array([10.,1.]) # Initial state variable values
e=np.ones(90) # Make-believe scalar weather (normally 4-vectors)
# Integrate diff'eqs
TSO,H=myEuler(f,p,x0,0,89,0.1,Hn,O,e)
# Plot diffeq results
plt.plot(TSO[:,0],TSO[:,1]) # Phase plane plot: x[1](t) vs. x[0](t)
plt.show()
""" Not yet working right - all "Hessian" values are zero """
# Plot d^2x[1]/dp[0]dp[1] vs d^2x[0]/dp[2]dp[3] over time
#plt.plot(H[:,1,0,1],H[:,0,2,3])
#plt.show()
if __name__ == '__main__':
main()