Search code examples
pythonrecursiondifferential-equationsodeint

Solve system of recursive differential equation in Python


So I am trying to solve the following system of differential equations in Python.

System of differential equations

As you can see, for each n in {0,1,2,3,...} the system depends on the solution to the previous system.

I have tried solving the system for n=0 and found a solution R(0|t) that I can insert in R(1|t) and Python solves the system without problems. I have defined the solution R(0|t) as r0(t) and implemented the solution for n=1 as follows:

def model(z,t):
    dxdt = -3.273*z[0] + 3.2*z[1] + r0(t)
    dydt = 3.041*z[0] - 3.041*z[1]
    dzdt = [dxdt, dydt]
    return dzdt

z0 = [0,0]

t = np.linspace(0,90, 90)

z1 = odeint(model, z0, t)

However I would like to generalize this solution by calling the solution to the system for n-1 when solving for n. As the differential equations only has entry different from zero in the upper right corner of the matrix we only need the solution of z1 from the previous solution. I have tried

def model0(z,t):
    dxdt = -3.273*z[0] + 3.2*z[1] 
    dydt = 3.041*z[0] - 3.041*z[1]
    dzdt = [dxdt, dydt]
    return dzdt

z0 = [1,1]

t = np.linspace(0,90)

def model1(z,t):
    dxdt = -3.273*z[0] + 3.2*z[1] + 0.071*odeint(model0, z0, t)[t,1]
    dydt = 3.041*z[0] - 3.041*z[1]
    dzdt = [dxdt, dydt]
    return dzdt


z1 = [0,0]


z = odeint(model1, z1, t)

Without any luck. Has anyone any experience in solving these recursive systems of odes in Python?

Thanks in advance.

Updated with code for 6x6 matrices and 6 function:


A = np.array([[h1h1, h1h2, h1h3, h1a1, h1a2, h1a3], 
              [h2h1, h2h2, h2h3, h2a1, h2a2, h2a3],
              [h3h1, h2h3, h3h3, h3a1, h3a2, h3a3],
              [a1h1, a1h2, a1h3, a1a1, a1a2, a1a3],
              [a2h1, a2h2, a2h3, a2a1, a2a2, a2a3],
              [a3h1, a3h2, a3h3, a3a1, a3a2, a3a3]
              ])


B = np.array([[0, 0, 0, 0, 0,    0], 
              [0, 0, 0, 0, 0,    0],
              [0, 0, 0, 0, h3a0, 0],
              [0, 0, 0, 0, 0,    0],
              [0, 0, 0, 0, 0,    0],
              [0, 0, 0, 0, 0,    0],
              ])


def model0n(u,t):
    Ra = u.reshape([-1,6])
    n = len(Ra) - 1
    dRa = np.zeros(Ra.shape)
    dRa[0] = A @ Ra[0]
    for i in range(1,n+1): 
        dRa[i] = A @ Ra[i] + B @ Ra[i-1]
    return dRa.flatten()

u0 = [1,1,1,1,1,1,0,0,0,0,0,0]
t = np.linspace(0,90,90+1)

u = odeint(model0n,u0,t)

The above results in the following plot for u[:,0]: Plot for u[:,0] which is supposed to be probabilities

For n=0 it provides results doing the matrix product 'manualy':


def modeln0manually(z,t):
    d1dt = h1h1*z[0] + h1h2 * z[1] + h1h3*z[2] + h1a1*z[3] + h1a2*z[4] + h1a3*z[5]
    d2dt = h2h1*z[0] + h2h2 * z[1] + h2h3*z[2] + h2a1*z[3] + h2a2*z[4] + h2a3*z[5]
    d3dt = h3h1*z[0] + h3h2 * z[1] + h3h3*z[2] + h3a1*z[3] + h3a2*z[4] + h3a3*z[5]
    d4dt = a1h1*z[0] + a1h2 * z[1] + a1h3*z[2] + a1a1*z[3] + a1a2*z[4] + a1a3*z[5]
    d5dt = a2h1*z[0] + a2h2 * z[1] + a2h3*z[2] + a2a1*z[3] + a2a2*z[4] + a2a3*z[5]
    d6dt = a3h1*z[0] + a3h2 * z[1] + a3h3*z[2] + a3a1*z[3] + a3a2*z[4] + a3a3*z[5]
    drdt = [d1dt, d2dt, d3dt, d4dt, d5dt, d6dt]    
    return drdt    


u0 = [1,1,1,1,1,1]
t = np.linspace(0,90)
z = odeint(modeln0manually, u0, t)

Resulting in the plot for u[:,0]: Plot of u[:,0] as it is supposed to be


Solution

  • Your system is coupled, even if in triangular way. So the most compact way is to solve it as a coupled system

    A = np.array([[-3.273, 3.2], [3.041, -3.041]])
    B = np.array([[0, 0.071], [0, 0]])
    
    def model0n(u,t):
        Ra = u.reshape([-1,2])
        n = len(Ra) - 1
        dRa = np.zeros(Ra.shape)
        dRa[0] = A @ Ra[0]
        for i in range(1,n+1): 
            dRa[i] = A @ Ra[i] + B @ Ra[i-1]
        return dRa.flatten()
    
    u0 = [1,1,0,0]
    t = np.linspace(0,90,90+1)
    u = odeint(model0n,u0,t)