I’m working on coding up an algorithm in C++, based on a Matlab implementation I wrote, and I’ve been using the Eigen library (http://eigen.tuxfamily.org/) for my linear algebra. It’s been relatively straightforward to use so far, but unfortunately it doesn’t (as far as I can tell) have any built in support for N-dimensional matrices. In fact, it appears that N-dimensional matrices aren’t really addressed by any of the standard C++ linear algebra libraries. So, to get my 4-dimensional matrix, I have to make an array of pointers pointing to an array of pointers pointing to my Eigen MatrixXf objects. I initialize my 4-D matrices using this function:
MatrixXf*** initialize_4dMatrix(MatrixXf*** matrix, int sizes[], float value=0.0) { matrix = new MatrixXf** [sizes[0]]; for (int d1 = 0; d1 < sizes[0]; d1++) { matrix[d1] = new MatrixXf* [sizes[1]]; for (int d2 = 0; d2 < sizes[1]; d2++) matrix[d1][d2] = new (MatrixXf)(MatrixXf::Ones(sizes[2],sizes[3]).array() * value); } return matrix; }
and call it with:
int sizes[4] = {1,2,3,4}; MatrixXf ***m = initialize_4dMatrix(m, {1,2,3,4});
To then access the matrices, it’s (*m[d1][d2])(d3,d4);
which isn’t bad for accessing one matrix at a time, but what if I want the jth element of the ith row of every matrix (i.e. element (i,j))? The Python access method m[:,:,i,:]
(or just m[:,:,i]
) would be ideal. Unfortunately, I don’t think there’s any way around writing another function to do it:
static VectorXf* get_elements_across_matrix_array(MatrixXf** matrix, int size, int element[]) { VectorXf* vector = new VectorXf(size); for (int i = 0; i < size; i++) (*vector)[i] = (*matrix[i])(element[0],element[1]); return vector; }
And I would need to write another function that returns a MatrixXf pointer if I wanted to access the ith rows of each matrix.
To delete these matrices I also need to pass into my delete function the sizes of the array. It’s a pain that it can’t dynamically discover the array size, but I don’t think there’s any way around it in C++.
static void delete_4dMatrix(MatrixXf*** matrix, int sizes[]) { for (int d1 = 0; d1 < sizes[0]; d1++) { for (int d2 = 0; d2 < sizes[1]; d2++) delete matrix[d1][d2]; } }
Additionally, I need to have a separate function for initializing my 3D matrices, and any other dimension that I would need the way I have it set up now. Less than ideal. My guess is that there’s a elegant way to handle this with void pointers, but at the moment I only need 3D and 4D matrices so it’s not worth the effort for me to set it up.
So there are a few obstacles to using N-dimensional matrices with Eigen, but it’s really not a problem once you get a handle on it and how to properly reference different elements and matrices through your (N-2)-dimensional array of pointers.
Hi Travis,
Just wanted to thank you for this posting, which has been enormously helpful to me as I am just getting to know Eigen and odeint, which I am using to set up and solve ODEs.
Many thanks!
Aaron
Hi Aaron,
thanks for the kind words! Really glad that you found this useful! đŸ˜€
You’re welcome! I’ve made some progress thanks to your posting, now I am just a bit stuck trying to get Eigen and odeint to work together. I am assuming that you can use an Eigen MatrixXd as the “state_type” for odeint (as below). But that doesn’t seem to work. Have you used Eigen and ideint together? Does this look like the proper way to do it?
typedef Eigen::Matrix state_type;
void odefun( const state_type &u , state_type &dudt , double t )
{
…
}
void write_odefun( const state_type &x , const double t )
{
int i;
cout << t << '\n';
for (i=0; i<=9; i++) {
cout << x(i) << '\n';
}
}
int main(int argc, char **argv)
{
…
state_type u(3,3); // initial conditions
srand((unsigned int) time(0));
u.setRandom(); // picks random numbers from -1 to 1
u*=0.1; // make the random numbers smallish
…
integrate( odefun , u , 0.0 , 100.0 , 0.1 , write_odefun );
…
}
Hmm. I’m unfortunately a bit swamped at the moment, and don’t have time to really dive in, but it seems like there may have been similar problems from others: http://stackoverflow.com/questions/22782224/using-boostodeint-with-eigenmatrix-as-state-vector
and
http://stackoverflow.com/questions/28965694/using-a-stdvectoreigenvector3d-as-state-type-in-odeint
if those don’t do it for you I can try to take a look asap but it might be a bit! Please let me know if you get it! Good luck!!
Thanks for the links! The first one seems highly relevant. I’ll mess around with it a bit and see if I can get it working. If I get really desperate, then I may take you up on your offer! I’m not in a huge hurry. Thanks again!
Everything compiles and runs OK, as long as I comment out the critical line…
integrate( dudt_fun , u , 0.0 , 100.0 , 0.1 , write_dudt );
So essentially once I try to use the ode solving capabilities of odeint, I get a compile error:
error: no matching function for call to ‘integrate(void (&)(state_type&, state_type&, double), state_type&, double, double, double, void (&)(const state_type&, double))’
If you have any ideas, I’d be very grateful!