Serving the Quantitative Finance Community

 
pineln
Topic Author
Posts: 5
Joined: October 18th, 2024, 9:23 am

Numerical Methods for ODEs where all variables are Matrices

October 18th, 2024, 10:16 am

I am currently trying to replicate the 'Numerical Results' section of the attached paper for my own interest. My current sticking point is solving the below system of ODEs where all the variables are matrecies:
 \begin{equation} A'(t)=A(t)M^A A(t)+A(t)U^A+(U^A)^TA(t)+R^A\end{equation}
\begin{equation} B'(t)=A(t)M^A B(t)+A(t)V^B+(U^A)^TB(t)\end{equation}


In the above equations all variables except A(t), B(t), A'(t) and B'(t) are known. A'(t) and B'(t) are the first derivatives of A(t) and B(t) respectively and A(T) and B(T) are their values at terminal time t=T and are known, in my case A(T) is a 4 by 4 martix of zeros and B(T) is a vctor of length 4 of zeros.

As I know the terminal values at time T, I have tried to solve using the implicit Euler method where, where I am stepping back in time a small timestep dt until I reach t=0:

\begin{equation} A(t-1)=A(t) - (A(t)M^A A(t)+A(t)U^A+(U^A)^TA(t)+R^A) * 
 dt\end{equation}
\begin{equation} B(t-1)=B(t) - (A(t)M^A B(t)+A(t)V^B+(U^A)^TB(t)) * dt\end{equation}


However, the solutions I am producing at t=0 don't seem to match the output of the paper. So my question is this. Can I use the Euler method in this manor to solve for an entire matrces A(0) and B(0) or am I missing something? Any advice will be greatly appreciated.

I have attached a picture with the matrix definitions and detailed the the variables within them below:



\begin{equation} \alpha_{2} = 0.741 \end{equation}

\begin{equation} \gamma = 3 * 10^{-4}\end{equation}

\begin{equation} n^S= 7 * 10^{-8}\end{equation}

\begin{equation} n^F= 3 * 10^{-8}\end{equation}

\begin{equation} K_E= 8\end{equation}

\begin{equation} K_D= 0\end{equation}

\begin{equation} \Sigma =  \begin{bmatrix}
    19600       & 0 & 0  \\
    0       & 25 & 0  \\
    0   &   0 & 0 &
\end{bmatrix} \end{equation}

\begin{equation} \sum_{}^{tilde} =  \begin{bmatrix}
    25 & 0  \\
    0 & 0
\end{bmatrix} \end{equation}
Attachments
Matrix Definitions.png
Algorithmic Market Making in Spot Precious Metal.pdf
(2.82 MiB) Downloaded 53 times
 
User avatar
Cuchulainn
Posts: 22926
Joined: July 16th, 2004, 7:38 am

Re: Numerical Methods for ODEs where all variables are Matrices

October 18th, 2024, 11:57 am

Just to check: A and B are also matrices, then it is a matrix ode (looks like a Riccati ODE). In this case we can use ODE solvers, indeed.

Euler is not the only kid on the block. It may not be optimal. Others can be found at boost.org and my 2018 C++ book. An example cpp is below.

BTW your scheme looks like EXPLICIT Euler for Backward ODE... all terms on RHS known at time t. That's a concern.
// TestGenericMatrixOde.cpp
//
// Computing exp(At) as:
//
//	dB/dt = A*B for t > 0
//  B(0) = C (identity matrix), where C is a given matrix
//
// (C) Datasim Education BV 2018
//

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <fstream>

#include <boost/numeric/odeint.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>

namespace ublas = boost::numeric::ublas;

using value_type = double;
using state_type = boost::numeric::ublas::matrix<value_type>;

class MatrixOde
{
private:
	// dB/dt = A*B, B(0) = C;
	ublas::matrix<value_type> A_;
	ublas::matrix<value_type> C_;
public:

	MatrixOde(const ublas::matrix<value_type>& A, const ublas::matrix<value_type>& IC)
		: A_(A), C_(IC) {}

    void operator()( const state_type &x , state_type &dxdt , double t ) const
    {

        for( std::size_t i=0 ; i < x.size1();++i )
        {
            for( std::size_t j=0 ; j < x.size2(); ++j )
            {
				dxdt(i, j) = 0.0;
				for (std::size_t k = 0; k < x.size2(); ++k)
				{
					dxdt(i, j) += A_(i,k)*x(k,j);
				}
			}
		}
 	}

};


void write_out(const state_type& U, const double t )
{

	{
		// put your wishes here
	}
}

int main()
{

	namespace Bode = boost::numeric::odeint;

 	std::size_t N = 2;
	ublas::identity_matrix<value_type> C(N);
	ublas::matrix<value_type> A(N,N);
	//A(0, 0) = A(1, 1) = 3.0; A(0, 1) = 1.0; A(1, 0) = 0.0;
	A(0, 0) = 6.0;  A(0, 1) = -1.0; A(1,0) = 9.0; A(1, 1) = 0.0;
/*	A(0, 0) = 0.0;  A(0, 1) = 1.0; A(0, 2) = 2.0; 
	A(1, 0) = 0.0;  A(0, 1) = 0.0; A(0, 2) = -1.0;
	A(2, 0) = 0.0;  A(2, 1) = 0.0; A(2, 2) = 0.0;*/

	ublas::matrix<value_type> B(N,N);

	// Initialise the solution matrix B
	B = C;

	MatrixOde ode(A, C);
	double L = 0.0;
	double T = 3.0;
	double dt = 0.001;

	std::size_t steps = Bode::integrate(ode, B, L, T, dt, write_out); 

	std::cout << "Value at time: " << T << '\n';
	std::cout << B << '\n';

	// Computing the exact matrix
	ublas::matrix<value_type> check(N, N);
	double e = std::exp(3.0*T);
	check(0, 0) = (1.0 + 3.0*T)*e;
	check(0, 1) = -T*e;
	check(1, 0) = 9.0*T*e;
	check(1, 1) = (1.0 - 3.0*T)*e;
	std::cout << check << '\n';

	// Sanity check; 1X1 matrix case dB/t = B on (0,5), B(0) = I
	{ // dB/dt = A*B, B(0) = C

		std::size_t N = 1;
		ublas::identity_matrix<value_type> C(N);
		ublas::matrix<value_type> A(N, N);
		A(0, 0) = 1.0;
		ublas::matrix<value_type> B(N, N);

		// Initialise the solution matrix B
		B = C;

		MatrixOde ode(A, C);
		double L = 0.0;
		double T = 5.0;
		double dt = 0.001;

		std::size_t steps = Bode::integrate(ode, B, L, T, dt, write_out);

		std::cout << "Value at time: " << T << '\n';
		std::cout << B << ", " << std::exp(5.0) <<  '\n'; // 148.413
	}

    return 0;
}

 
User avatar
Cuchulainn
Posts: 22926
Joined: July 16th, 2004, 7:38 am

Re: Numerical Methods for ODEs where all variables are Matrices

October 18th, 2024, 12:05 pm

And Python
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.odeint.html

import numpy as np
from scipy.integrate import odeint


def deriv(A, t, Ab):
    return np.dot(Ab, A)


Ab = np.array([[-0.25,    0,    0],
               [ 0.25, -0.2,    0],
               [    0,  0.2, -0.1]])

time = np.linspace(0, 25, 101)
A0 = np.array([10, 20, 30])

MA = odeint(deriv, A0, time, args=(Ab,))
 
User avatar
Cuchulainn
Posts: 22926
Joined: July 16th, 2004, 7:38 am

Re: Numerical Methods for ODEs where all variables are Matrices

October 18th, 2024, 12:37 pm

The ODE part dA/dt = ... is quadratic in A, so nonlinear ==> small dt for Euler (afair I need 1,000,000 steps).

With Boost odeint Bulirsch-Stoer ==> 22 steps.
 
pineln
Topic Author
Posts: 5
Joined: October 18th, 2024, 9:23 am

Re: Numerical Methods for ODEs where all variables are Matrices

October 18th, 2024, 2:29 pm

Thank you so much for all your help, I really appreciate it. I have validated my Euler scheme using the scipy odeint - so I must be making my error(s) elswhere.
 
User avatar
Cuchulainn
Posts: 22926
Joined: July 16th, 2004, 7:38 am

Re: Numerical Methods for ODEs where all variables are Matrices

October 18th, 2024, 10:24 pm

You're welcome.
 
User avatar
Cuchulainn
Posts: 22926
Joined: July 16th, 2004, 7:38 am

Re: Numerical Methods for ODEs where all variables are Matrices

November 5th, 2024, 5:01 pm

Thank you so much for all your help, I really appreciate it. I have validated my Euler scheme using the scipy odeint - so I must be making my error(s) elswhere.
How's it going?
 
pineln
Topic Author
Posts: 5
Joined: October 18th, 2024, 9:23 am

Re: Numerical Methods for ODEs where all variables are Matrices

November 5th, 2024, 5:54 pm

After changing out my Euler scheme for scipy odeint I was still not seeing the same behaviour as Figure 2 (page 9) of the paper suggested so I began deriving the matrices shown on page 9 by hand and found a small error in the papers definition of matrix R_A. After correcting this I began to see the same behaviour as the paper suggested.
 
With this in mind tried to generate Figure 3 (page 9) to try and add an additional way of comparing my model to the papers. However, when trying to resolve the system with any value of K_S or K_F > 0 (see page 7) the solution seems to blow up - regardless how many time steps are used or if I use the papers definition of R_A instead of my own. 
 
This makes me think that I am still missing something from equation 4 (page 6) that should be in the matrices that form the equations for A'(t) and B'(t), as the authors must have resolved these in order to get their results. However, after checking my working a number of times I sadly can't seem to spot what I am missing.

You may have seen my other post about the working to get the equations for A'(t) and B'(t) where you can see the small difference between my definition of R_A and that noted in the paper. Any, insight on what I may be missing would be greatly apprecitated.
 
User avatar
Cuchulainn
Posts: 22926
Joined: July 16th, 2004, 7:38 am

Re: Numerical Methods for ODEs where all variables are Matrices

November 5th, 2024, 7:31 pm

Maybe contact the authors directly? Hopefully they might be nice and help out.
 
pineln
Topic Author
Posts: 5
Joined: October 18th, 2024, 9:23 am

Re: Numerical Methods for ODEs where all variables are Matrices

December 4th, 2024, 5:08 pm

Short update. After correcting sevral errors in the paper I have managed to replicate all of its output. Thank you for all your help.
 
User avatar
Cuchulainn
Posts: 22926
Joined: July 16th, 2004, 7:38 am

Re: Numerical Methods for ODEs where all variables are Matrices

December 4th, 2024, 5:36 pm

Short update. After correcting sevral errors in the paper I have managed to replicate all of its output. Thank you for all your help.
Well done :-)

Just out of curiosity: how much effort is a Monte Carlo simulation as a sanity check?