Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Eigen MatrixXd push back in c++

Tags:

c++

matrix

eigen

Eigen is a well known matrix Library in c++. I am having trouble finding an in built function to simply push an item on to the end of a matrix. Currently I know that it can be done like this:

Eigen::MatrixXd matrix(10, 3);
long int count = 0;
long int topCount = 10;
for (int i = 0; i < listLength; ++i) {
    matrix(count, 0) = list.x;
    matrix(count, 1) = list.y;
    matrix(count, 2) = list.z;
    count++;
    if (count == topCount) {
        topCount *= 2;
        matrix.conservativeResize(topCount, 3);
    }
}
matrix.conservativeResize(count, 3);

And this will work (some of the syntax may be out). But its pretty convoluted for a simple thing to do. Is there already an in built function?

like image 320
Fantastic Mr Fox Avatar asked Jan 02 '13 23:01

Fantastic Mr Fox


2 Answers

There is no such function for Eigen matrices. The reason for this is such a function would either be very slow or use excessive memory.

For a push_back function to not be prohibitively expensive it must increase the matrix's capacity by some factor when it runs out of space as you have done. However when dealing with matrices, memory usage is often a concern so having a matrix's capacity be larger than necessary could be problematic. If it instead increased the size by rows() or cols() each time the operation would be O(n*m). Doing this to fill an entire matrix would be O(n*n*m*m) which for even moderately sized matrices would be quite slow.

Additionally, in linear algebra matrix and vector sizes are nearly always constant and known beforehand. Often when resizeing a matrix you don't care about the previous values in the matrix. This is why Eigen's resize function does not retain old values, unlike std::vector's resize.

The only case I can think of where you wouldn't know the matrix's size beforehand is when reading from a file. In this case I would either load the data first into a standard container such as std::vector using push_back and then copy it into an already sized matrix, or if memory is tight run through the file once to get the size and then a second time to copy the values.

like image 106
David Brown Avatar answered Oct 29 '22 18:10

David Brown


There is no such function, however, you can build something like this yourself:

using Eigen::MatrixXd;
using Eigen::Vector3d;

template <typename DynamicEigenMatrix>
void push_back(DynamicEigenMatrix& m, Vector3d&& values, std::size_t row)
{
    if(row >= m.rows()) {
        m.conservativeResize(row + 1, Eigen::NoChange);
    }
    m.row(row) = values;
}


int main()
{
    MatrixXd matrix(10, 3);
    for (std::size_t i = 0; i < 10; ++i) {
       push_back(matrix, Vector3d(1,2,3), i);
    }
    std::cout << matrix << "\n";
    return 0;
}

If this needs to perform too many resizes though, it's going to be horrendously slow.

like image 38
Yuushi Avatar answered Oct 29 '22 17:10

Yuushi