# [Rcpp-devel] Sparse matrix and RcppEigen

Wagner Bonat wbonat at gmail.com
Wed Jun 10 12:51:33 CEST 2015

```Hello !

I tried to use your suggestions. The code compiled, but the result does not
make sense. Have a look,

My really simple R function

my.partialsolveR <- function(Omega, invSqrtV){solve(chol(Omega), invSqrtV)}

partialsolveCS <- '
using namespace Rcpp;
using namespace Eigen;
const SparseMatrix<double> Omega(as<SparseMatrix<double> >(Omegas));
const SparseMatrix<double> invSqrtV(as<SparseMatrix<double> >(invSqrtVs));
Eigen::SimplicialLLT<SparseMatrix<double>, Eigen::Upper> solver(Omega);
SparseMatrix<double> L = solver.matrixL();
Eigen::SimplicialLLT<SparseMatrix<double>, Eigen::Lower> solver2(L);
SparseMatrix<double> L2 = solver2.solve(invSqrtV);
return wrap(L2);'

my.partialsolveCS <- cxxfunction(signature(Omegas = "dgCMatrix", invSqrtVs
= "dgCMatrix"),

body = partialsolveCS,
plugin = "RcppEigen")

I know that this type of conversion is not recommended but consider only
for this example.

Omega <- Matrix(c(1,0.8,0.8,1),2,2)
invSqrtV <- Diagonal(2,1)
Omega.M <- as(as.matrix(Omega),"dgCMatrix")
invSqrtV.M <- as(as.matrix(invSqrtV),"dgCMatrix")

my.partialsolveR(Omega,invSqrtV)
2 x 2 Matrix of class "dgeMatrix"
[,1]      [,2]
[1,]    1 -1.333333
[2,]    0  1.666667

my.partialsolveCS(Omega.M, invSqrtV.M)
2 x 2 sparse Matrix of class "dgCMatrix"

[1,] .             .
[2,] 2.121996e-314 .

As you can see there are something wrong in the code. I tried change
Eigen::Lower for Eigen::Upper and vice-versa, but did not work.

Thank you again !!

2015-06-10 5:48 GMT+02:00 Balamuta, James Joseph <balamut2 at illinois.edu>:

>  Regarding the code not compiling….
>
>
>
> Try:
>
>
>
> src <- '
>
> using Eigen::Map;
>
> using Eigen::SparseMatrix;
>
> using Eigen::LLT;
>
>
>
> const SparseMatrix<double> Omega(as<SparseMatrix<double> >(Omegas));
>
> const SparseMatrix<double> invSqrtV(as<SparseMatrix<double> >(invSqrtVs));
>
>
>
> // First solver associated with Omega matrix (taken w.r.t to Upper
> triangular view)
>
> Eigen::SimplicialLLT<SparseMatrix<double> , Eigen::Upper > solver(Omega);
>
>
>
> SparseMatrix<double> L = solver.matrixL();
>
>
>
> // Second solver using the lower matrix
>
> Eigen::SimplicialLLT<SparseMatrix<double> , Eigen::Lower > solver2(L);
>
>
>
> SparseMatrix<double> L2 = solver2.solve(invSqrtV);
>
>
>
> return wrap(L2);'
>
>
>
>
>
> The other issue is how the matrices are passed in.
>
>
>
> Before passing into C++, you are converting the objects into actual R
> matrices without any sparse properties:
>
>
>
> e.g.
>
> Omega.m <- as.matrix(Omega)
>
> Vinvsqrt.m <- as.matrix(Vinvsqrt)
>
>
>
> The matrices must be of the appropriate sparse type in R to be translated
> into sparse C++ objects.
>
>
>
> This leads to the slots being formatted as:
>
>  my.partial.solveC <- cxxfunction(signature(Omegas = "dgCMatrix",
> invSqrtVs = " ddiMatrix "), body = src, plugin = "RcppEigen")
>
>
>
>
>
> However, there is an issue with how the second matrix is typed.
>
>
>
> Specifically, it is typed as: ddiMatrix.
>
> This leads to an error when calling the compile statement of: “Error: No
> such slot.”
>
>
> So, I have a funny feeling the conversions in place do not account for the
> sparse diagonal matrix class (ddiMatrix).
>
>  It is at this point, that I can’t advise you anymore outside of saying
> you may want to consider building the invSqrtV and Omega matrices within
> Eigen to avoid this conversion issue.
>
>
>
> Sincerely,
>
>
>
> JJB
>
>
>
>
>
> *From:* rcpp-devel-bounces at lists.r-forge.r-project.org [mailto:
> rcpp-devel-bounces at lists.r-forge.r-project.org] *On Behalf Of *Wagner
> Bonat
> *Sent:* Tuesday, June 09, 2015 6:50 AM
> *To:* Yixuan Qiu
> *Cc:* rcpp-devel at lists.r-forge.r-project.org
> *Subject:* Re: [Rcpp-devel] Sparse matrix and RcppEigen
>
>
>
> Dear all,
>
> As requested I will try provide a better explanation. Consider the code
> below:
>
>
>
> Let C = V^{1/2}%*%Omega%*%V^{1/2} and C^{1/2} be the Cholesky
> decomposition, such that C^{1/2}%*%C^{1/2}^T = C.
> My goal is to compute Omega^{-1/2}%*%V{-1/2}.
> My idea is to use that I know V^{-1/2} and rewrite C^{-1} =
> V^{-1/2}%*%Omega^{-1}%*%V^{-1/2} =
> V^{-1/2}%*%Omega^{-1/2}%*%(Omega^{-1/2}%*%V^{-1/2})^T
> The main term now is Omega^{-1/2}%*%V^{-1/2} for computing it my idea is
> first compute the Cholesky denoted by Omega^{1/2} and then using the
> triangular structure to solve a system to get Omega^{-1/2}%*%V^{-1/2}.
>
> Some auxiliary functions to provide an example.
>
>
> # Inverse of square root of V
> build.invSqrtV <- function(mu, power,n.sample){Diagonal(n.sample,
> 1/sqrt(mu^power))}
>
> ## Omega matrix - It is an example of dense structure.
> build.Omega <- function(par,U){par[1]*exp(-U/par[2])}
>
> ## Small sample size
> x1 <- seq(0,1,l=30)
> x2 <- seq(0,1,l=30)
> grid <- expand.grid(x1,x2)
> U <- forceSymmetric(as.matrix(dist(grid)))
> cov <- seq(-1,1,l=900)
> X <- model.matrix(~ cov)
> mu <- exp(X%*%c(1,0.5))
>
> Vinvsqrt <- build.invSqrtV(mu, power = 2, n.sample =900)
> Omega <- build.Omega(par=c(1,0.25),U)
>
>
>
> ## R function
>
> my.partial.solveR <- function(Omega,invSqrtV){ solve(t(chol(Omega)),
> invSqrtV)}
> result1 <- my.partial.solveR(Omega, Vinvsqrt)
>
> ## Now using RcppEigen
> src <- '
> using namespace Rcpp;
> using namespace Eigen;
> const Map<MatrixXd> Omega(as<Map<MatrixXd> >(Omegas));
> const Map<MatrixXd> invSqrtV(as<Map<MatrixXd> >(invSqrtVs));
> MatrixXd LT = Omega.llt().matrixL().solve(invSqrtV);
> return wrap(LT);'
>
> ## Here I need to convert from dsyMatrix to matrix
> Omega.m <- as.matrix(Omega)
> Vinvsqrt.m <- as.matrix(Vinvsqrt)
> my.partial.solveC <- cxxfunction(signature(Omegas = "mat", invSqrtVs =
> "mat"), body = src, plugin = "RcppEigen")
> result2 <- my.partial.solveC(Omega.m,Vinvsqrt.m)
>
> ## Comparing the results
> tt <- abs(result1) - abs(result2)
> sum(tt)
>
> ## Comparing the computational time
> benchmark(my.partial.solveR(Omega, Vinvsqrt), my.partial.solveC(Omega.m,
> Vinvsqrt.m), order = "relative")
>
>                     test replications elapsed relative
> 2 my.partial.solveC(Omega.m, Vinvsqrt.m)       100   8.901    1.000
> 1     my.partial.solveR(Omega, Vinvsqrt)          100  25.414    2.855
>
> You can see that the C++ code is much faster than my R code.
>
> But, now consider that my Omega matrix is sparse
> z <- rep(1,10)
> Z <- z%*%t(z)
> listZ <- list()
> for(i in 1:90){listZ[[i]] <- Z}
> Omega <- Diagonal(900,1) + 0.8*bdiag(listZ)
> Omega.m <- as.matrix(Omega)
>
> benchmark(my.partial.solveR(Omega, Vinvsqrt), my.partial.solveC(Omega.m,
> Vinvsqrt.m), order = "relative")
>
>
>                             test replications elapsed relative
> 1     my.partial.solveR(Omega, Vinvsqrt)          100   0.101    1.000
> 2 my.partial.solveC(Omega.m, Vinvsqrt.m)       100   8.901   88.129
>
>
>
> Now, the results are completely different because my C++ code does not
> take into account the sparse structure.
>
> My idea is reproduze the same idea using SparseMatrix class. I try the
> following function, but it does not work, since there is no solve method
> associated with the solver. So, I do not know how to use the triangular
> structure to solve the linear system
>
> src <- '
> using Eigen::Map;
> using Eigen::SparseMatrix;
> using Eigen::LLT;
>
> const SparseMatrix<double> Omega(as<SparseMatrix<double> >(Omegas));
> const SparseMatrix<double> invSqrtV(as<SparseMatrix<double> >(invSqrtVs));
> Eigen::SimplicialLLT<SparseMatrix<double>, Eigen::Upper> solver;
> solver.compute(Omega);
> SparseMatrix<double> L = solver.matrixL().solve(invSqrtV); #### Do not work
> return wrap(L);'
>
>
>
> Any help is welcome.
>
> Thank you!
>
>
> --
>
> Wagner Hugo Bonat
>
> ----------------------------------------------------------------------------------------------
> Department of Mathematics and Computer Science (IMADA)
> University of Southern Denmark (SDU) and
> Laboratório de Estatística e Geoinformação (LEG)
> Universidade Federal do Paraná (UFPR)
>
> _______________________________________________
> Rcpp-devel mailing list
> Rcpp-devel at lists.r-forge.r-project.org
> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
>

--
Wagner Hugo Bonat
----------------------------------------------------------------------------------------------
Department of Mathematics and Computer Science (IMADA)
University of Southern Denmark (SDU) and
Laboratório de Estatística e Geoinformação (LEG)