0
votes

I need use a vector of Eigen matrices in my program. The size of the vector is known. However the matrix size corresponding to each member of the vector can have different size and need to be dynamically allocated. Based on https://eigen.tuxfamily.org/dox/group__TopicStlContainers.html I guess I can declare my matrix as

#define EIGEN_USE_MKL_ALL 
#define EIGEN_USE_LAPACKE

// Additional libraries
#include <iomanip>
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstdlib>
#include <algorithm>
#include "Eigen/Core"
#include "Eigen/LU"
#include "Eigen/StdVector"

int A = 4;
int B = 5;


std::vector<Eigen::MatrixXd > inv_K_mat2(A,B);

This results in the following error during compilation

error C2664: 'std::vector<Eigen::MatrixXd,std::allocator<_Ty>>::vector(std::vector<_Ty,std::allocator<_Ty>> &&,const _Alloc &) noexcept(<expr>)': cannot convert argument 2 from 'int' to 'const _Alloc &'
1>        with
1>        [
1>            _Ty=Eigen::MatrixXd,
1>            _Alloc=std::allocator<Eigen::MatrixXd>
1>        ]
1>        and
1>        [
1>            _Alloc=std::allocator<Eigen::MatrixXd>
1>        ]
1>e:\users\pkuma\work\edem_flex_tire\edem-deformable-tire-develop\compiler\pme_flextire_interface.cpp(107): note: Reason: cannot convert from 'int' to 'const _Alloc'
1>        with
1>        [
1>            _Alloc=std::allocator<Eigen::MatrixXd>
1>        ]

The compilation is successful if I change the declartion as

std::vector<Eigen::Matrix<double, 4, 5 > > inv_K_mat2;

Is there a different way to initialize a vector of Eigen matrices where the size can be dynamically allocated?

1

1 Answers

0
votes

Why are you having this error ?

Let's look at your code :

std::vector<Eigen::MatrixXd> inv_K_mat2(A,B);

You're trying to construct a std::vector of things (in this case, dynamically-sized Eigen matrices). But there is no constructor to std::vector that takes two integers as arguments. There's some versions of the constructor (versions (3) and (4) in the link above) that takes an integer as first argument -- the initial size of the vector -- and optionally a second argument.

In version (3) the second argument is of type const T&, that is, the type contained in the vector : in our case it's MatrixXd. Can you convert integer B to a const MatrixXd& ? No. So the compiler looks at another candidate : constructor version (4).

The compiler assumes the second argument must be an allocator. Can you convert an int to an allocator ? No. This is a problem and this is the meaning of the error message you get :

cannot convert argument 2 from 'int' to 'const _Alloc &'

Why does your second version work ?

Now let's take a look at the next version :

std::vector<Eigen::Matrix<double, 4, 5 > > inv_K_mat2;

In this case this is different. You're constructing a vector of a different type T ( this time, a fixed-size 4×5 Eigen matrix) with no argument to the constructor : version (1) in the link above. This is perfectly fine and the compiler is happy.

Note that in this case, the vector you construct starts off empty (it contains 0 matrices). If you want to construct a vector initialized to contain, say, 42 fixed-size matrices you would do something like this

std::vector<Eigen::Matrix<double, 4, 5 > > inv_K_mat2(42);

Here we are using -- again -- constructor version (3) with an integer argument. Our vector starts off with 42 matrices of fixed size 4×5. Note that of course none of the matrices' elements are initialized. But our good friend constructor (3) allows us to provide an argument of type const T& as an initial value for all the elements. So this gives us something like :

std::vector<Eigen::Matrix<double, 4, 5>> inv_K_mat2(42, Eigen::Matrix<double, 4, 5>::Zero());

This will initialize a vector of 42 fixed-size 4×5 matrices, all set to the value Eigen::Matrix<double, 4, 5>::Zero() (i.e. a 0-initialized fixed-size 4×5 matrix).

How do we make it work for dynamic matrices ?

We're going to use the same strategy as we did for the fixed-size matrices here. The key difference is that for MatrixXd we need to specify the sizes in the constructor of MatrixXd. So we will call again std::vector constructor (3) with our initial size as first argument and a newly constructed MatrixXd of sizes 4 and 5 as second argument.

std::vector<Eigen::MatrixXd> inv_K_mat2(42, Eigen::MatrixXd(4, 5));

Or, if you want to have all the matrices initialized to 0, you use MatrixXd' zero function which allow you to construct a zero matrix of any given sizes as arguments :

std::vector<Eigen::MatrixXd> inv_K_mat2(42, Eigen::MatrixXd::Zero(4, 5));