Search code examples
c++reigenrcpp

Inverting a sparse matrix using eigen


I'm trying to use a sparse solver as SimplicialLLT to inverse a symmetric positive-definite matrix and return it.

I get a matrix from R using Rcpp to connect R and cpp, I take this matrix as an argument of the function cpp_sparse_solver, use sparseView() to turn it to SparseMatrix, declare the solver, compute and solve the system with an identity matrix as argument to invert it. However, I get the error "Eigen::MatrixXd is not a template". I'm not an expert at cpp, so I'd like some tips about possible mistakes.

#include <cmath>
#include <Rcpp.h>
#include <RcppEigen.h>
#include <stdio.h>
#include <R.h>
#include <Rmath.h>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/OrderingMethods>
#include <Eigen/SparseCholesky>

using namespace Eigen;
using namespace Rcpp;
using namespace std;

// [[Rcpp::depends(RcppEigen)]]
//' Inverts matrices inside cpp
//' @param matrix Matrix to be inverted
//' @export
// [[Rcpp::export]]
MatrixXd cpp_sparse_solver(Eigen::MatrixXd<double> matrix){
  // START
  // Declaring objects
  int n = matrix.rows();
  MatrixXd I = Matrix<double, n, n>::Identity();
  matrix_s = matrix.sparseView();
  SimplicialLLT<Eigen::SparseMatrix<double>, Lower, NaturalOrdering<int>> solver;
  matrix_s.makeCompressed();
  solver.compute(matrix_s);
  MatrixXd Ainv = solver.solve(I);
  return Ainv;
}

Solution

  • There were a number of things wrong in your code, and a few other stylistic things I would do differently. Below is version which actually compiles and it differs in having

    • reduced the number of headers to the single one you need
    • removed the namespace flattening statements which mostly cause trouble
    • updated some types

    Code

    #include <RcppEigen.h>
    
    // [[Rcpp::depends(RcppEigen)]]
    //' Inverts matrices inside cpp
    //' @param matrix Matrix to be inverted
    //' @export
    // [[Rcpp::export]]
    Eigen::MatrixXd cpp_sparse_solver(Eigen::MatrixXd matrix){
        int n = matrix.rows();
        Eigen::MatrixXd I = Eigen::MatrixXd::Identity(n,n);
        Eigen::SparseMatrix<double> matrix_s = matrix.sparseView();
        Eigen::SimplicialLLT<Eigen::SparseMatrix<double>, Eigen::Lower, 
                             Eigen::NaturalOrdering<int>> solver;
        matrix_s.makeCompressed();
        solver.compute(matrix_s);
        Eigen::MatrixXd Ainv = solver.solve(I);
        return Ainv;
    }