Question

I want to read data from a file into a matrix in Eigen. I have coded everything but there is one problem that I encounter. I don't know yet beforehand how many data points are in the file, so I want to be able to initialize a matrix without specifying its size. I know that the following way of intializing a matrix works in Eigen:

MatrixXd A;

But now if I then do for instance

A << 1, 2,
     4, 7;

It doesn't work. I had hoped that it would recognise it as a 2x2 matrix in this example, so that I could then work with it. So basically my question is, how can I add data to A, without having to specify its size?

Was it helpful?

Solution

If what you want is read data from a file which does not specify the matrix size explicitly, then I would recommend to push back the entries in a std::vector and at the end of the parsing copy the data from the std::vector using Map:

MatrixXf A;
std::vector<float> entries;
int rows(0), cols(0);
while(...) { entries.push_back(...); /* update rows/cols*/ }
A = MatrixXf::Map(&entries[0], rows, cols);

This will be much more efficient than calling conservativeResize every times.

OTHER TIPS

From the Eigen Tutioral about Matrix


Of course, Eigen is not limited to matrices whose dimensions are known at compile time. The RowsAtCompileTime and ColsAtCompileTime template parameters can take the special value Dynamic which indicates that the size is unknown at compile time, so must be handled as a run-time variable. In Eigen terminology, such a size is referred to as a dynamic size; while a size that is known at compile time is called a fixed size. For example, the convenience typedef MatrixXd, meaning a matrix of doubles with dynamic size, is defined as follows:

typedef Matrix<double, Dynamic, Dynamic> MatrixXd;

And similarly, we define a self-explanatory typedef VectorXi as follows:

typedef Matrix<int, Dynamic, 1> VectorXi;

You can perfectly have e.g. a fixed number of rows with a dynamic number of columns, as in:

Matrix<float, 3, Dynamic>

Here is an example I just quickly made:

Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> myMatrix;
myMatrix.resize(1, 1);
myMatrix(0, 0) = 1.0;
myMatrix.resize(2, 2);
myMatrix(1, 1) = 1.0;
myMatrix.resize(3, 3);
myMatrix(2, 2) = 1.0;
myMatrix.resize(4, 4);
myMatrix(3, 3) = 1.0;

So I had similar (but not exactly the same problem) and thanks to this plot and answers to another problems from this forum I created that code. I have a file with unknown matrix size as an input, which I need to operate on later.

We first read the first line of the file, get the data, put into vector, read the number of columns. Then we read all the rest data from the file, continue parsing to the vector.

void getTimeSeries(const char* TimeSeriesFileName1)
{

std::ifstream ifile(TimeSeriesFileName1, std::ios::in);
std::vector<double> LineOfTimeSeriesFile;
std::string line;
int rows(0), cols(0);
double number;

//get number of columns you have to read the first line
if (ifile.good())
{
  std::getline(ifile, line);
  std::stringstream ss(line);
  while (ss>>number) 
  {
    ++cols;
    LineOfTimeSeriesFile.push_back(number);
  }
  std::cout << cols << std::endl;
}
// consume and discard token from stream.
if (ifile.fail())
{
  ifile.clear();
  std::string token;
  ifile >> token;
}

//Read all the data into a one big vector
do
{
    // read as many numbers as possible.
    for (number = 0; ifile >> number;) {
        LineOfTimeSeriesFile.push_back(number);
    }
    // consume and discard token from stream.
    if (ifile.fail())
    {
        ifile.clear();
        std::string token;
        ifile >> token;
    }
}
while (!ifile.eof());

//get the number of rows
rows = LineOfTimeSeriesFile.size()/cols;
for (std::size_t i=0; i < LineOfTimeSeriesFile.size(); ++i) 
{
    std::cout << LineOfTimeSeriesFile[i] << std::endl;
    std::cout << "Rows: " << cols << ", Cols: " << rows << ", points: " << LineOfTimeSeriesFile.size() << std::endl;
}    

//Here we map the matrix
timeSeriesMatrix = MatrixXd::Map(&LineOfTimeSeriesFile[0], rows, cols);

I would be happy to see some review of this code in terms of efficiency, but I think it is currently OK. Input files are matrices "tab/space"-separated.

It is impossible to do what you ask for. How do you want library to guess the shape of the array? How can it be sure its not 4x1 or 1x4. New lines do not matter for c++ compilers, so your code is the same as m << 1,2,3,4;.

The dynamic arrays are dynamic in the sense their size is not know at a compile time but run-time. However, you still need to set the size/shape of the matrix before putting elements in, because the library needs to know how much space is needs to allocate for the matrix.

By default Matrix m; is of a size 0x0. You need to resize it before putting in elements.

Eg.

#include<Eigen/Core>
#include<iostream>

int main(){
Eigen::MatrixXd m;
m.resize(2,2);
m << 1, 2, 3, 4;
std::cout << m << '\n';
m.resize(1,4);
std::cout << m << '\n';
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top