Convert an Eigen matrix to Triplet form C++
Asked Answered
B

2

9

I think Eigen uses compressed methods to store sparse matrices. Is there any way that I can extract Triplet-format vectors of an Eigen sparse matrix in from of std::vectors?

Thanks.

More info (an example of triplet format) Triplet format of matrix :

A=
3 0 4 0
0 0 1 0
0 2 0 5
4 0 0 0

i = 1 1 2 3 3 4  // row
j = 1 3 3 2 4 1 // column
S = 3 4 1 2 5 4  // values
Brasier answered 23/2, 2015 at 23:55 Comment(0)
P
3

Simply as shown in the tutorial:

#include <Eigen/Sparse>
#include <iostream>

using namespace Eigen;
using std::cout;
using std::endl;

typedef Triplet<int> Trip;

int main(int argc, char *argv[]){

    std::vector<Trip> trp, tmp;

    // I subtracted 1 from the indices so that the output matches your question
    trp.push_back(Trip(1-1,1-1,3));
    trp.push_back(Trip(1-1,3-1,4));
    trp.push_back(Trip(2-1,3-1,1));
    trp.push_back(Trip(3-1,2-1,2));
    trp.push_back(Trip(3-1,4-1,5));
    trp.push_back(Trip(4-1,1-1,4));

    int rows, cols;
    rows = cols = 4;
    SparseMatrix<int> A(rows,cols);

    A.setFromTriplets(trp.begin(), trp.end());
    cout << "Matrix from triplets:" << endl;
    cout << A << endl;            

    cout << endl << "Triplets:" << endl;
    cout << "Row\tCol\tVal" <<endl;
    for (int k=0; k < A.outerSize(); ++k)
    {
        for (SparseMatrix<int>::InnerIterator it(A,k); it; ++it)
        {
            cout << 1+it.row() << "\t"; // row index
            cout << 1+it.col() << "\t"; // col index (here it is equal to k)
            cout << it.value() << endl;
        }
    }

    return 0;
}
Planetesimal answered 25/2, 2015 at 6:25 Comment(4)
Thank you for your reply. But this is how to make a matrix from triplet vectors. I'm looking for "how to get triplet vectors of a matrix which already exist in Eigen format".Brasier
@SinaJ See the second part. Instead of printing it, construct the triplets.Planetesimal
@SinaJ If you want access to the raw pointers, they can be accessed through m.valuePtr(), m.outerIndexPtr() and m.innerIndexPtr() but they are not of the same length (i.e. not naively convertible to triplets).Planetesimal
@bordeo I don’t follow. Are you asking how to take the iterators and use them in the triplet constructor?Planetesimal
G
5

The answer to the question, which is:

// Is there some method such as:

std::vector<Eigen::Triplet<double>> T = SparseMat.to_triplets();

// in Eigen?

Is no, there does not appear to be such a function.

Instead,

std::vector<Eigen::Triplet<double>> to_triplets(Eigen::SparseMatrix<double> & M){
    std::vector<Eigen::Triplet<double>> v;
    for(int i = 0; i < M.outerSize(); i++)
        for(typename Eigen::SparseMatrix<double>::InnerIterator it(M,i); it; ++it)
            v.emplace_back(it.row(),it.col(),it.value());
    return v;
}

auto t = to_triplets(SparseMat);

And if you want to do it faster, open it in an IDE, look around for pointers to the data arrays, and write a convoluted function that will have no effect on runtime, since the matrix is sparse, and copying is linear in terms of nonzero elements.

Gadolinite answered 26/7, 2018 at 20:3 Comment(0)
P
3

Simply as shown in the tutorial:

#include <Eigen/Sparse>
#include <iostream>

using namespace Eigen;
using std::cout;
using std::endl;

typedef Triplet<int> Trip;

int main(int argc, char *argv[]){

    std::vector<Trip> trp, tmp;

    // I subtracted 1 from the indices so that the output matches your question
    trp.push_back(Trip(1-1,1-1,3));
    trp.push_back(Trip(1-1,3-1,4));
    trp.push_back(Trip(2-1,3-1,1));
    trp.push_back(Trip(3-1,2-1,2));
    trp.push_back(Trip(3-1,4-1,5));
    trp.push_back(Trip(4-1,1-1,4));

    int rows, cols;
    rows = cols = 4;
    SparseMatrix<int> A(rows,cols);

    A.setFromTriplets(trp.begin(), trp.end());
    cout << "Matrix from triplets:" << endl;
    cout << A << endl;            

    cout << endl << "Triplets:" << endl;
    cout << "Row\tCol\tVal" <<endl;
    for (int k=0; k < A.outerSize(); ++k)
    {
        for (SparseMatrix<int>::InnerIterator it(A,k); it; ++it)
        {
            cout << 1+it.row() << "\t"; // row index
            cout << 1+it.col() << "\t"; // col index (here it is equal to k)
            cout << it.value() << endl;
        }
    }

    return 0;
}
Planetesimal answered 25/2, 2015 at 6:25 Comment(4)
Thank you for your reply. But this is how to make a matrix from triplet vectors. I'm looking for "how to get triplet vectors of a matrix which already exist in Eigen format".Brasier
@SinaJ See the second part. Instead of printing it, construct the triplets.Planetesimal
@SinaJ If you want access to the raw pointers, they can be accessed through m.valuePtr(), m.outerIndexPtr() and m.innerIndexPtr() but they are not of the same length (i.e. not naively convertible to triplets).Planetesimal
@bordeo I don’t follow. Are you asking how to take the iterators and use them in the triplet constructor?Planetesimal

© 2022 - 2024 — McMap. All rights reserved.