---
title: "05 - Sparse matrices"
output:
  litedown::html_format:
    options:
      toc: true
      number_sections: true
vignette: >
  %\VignetteIndexEntry{05 - Sparse matrices}
  %\VignetteEngine{litedown::vignette}
  %\VignetteEncoding{UTF-8}
editor:
  markdown:
    wrap: sentence
bibliography: ["references.bib"]
---

# Supported sparse matrix classes

Since v0.9.0, `armadillo4r` links to the `Matrix` package and uses its public
C API to convert between R sparse matrices and Armadillo `SpMat<double>`. The
`as_SpMat(SEXP)` function accepts any sparse matrix class that the `Matrix`
package can express:

* `CsparseMatrix` subclasses (`dgCMatrix`, `dsCMatrix`, `dtCMatrix`,
  `lgCMatrix`, ...) -- the fast path, read directly via the CHOLMOD bridge.
* `RsparseMatrix` and `TsparseMatrix` subclasses -- transparently coerced to
  `CsparseMatrix` first.
* Symmetric (`dsCMatrix`) matrices are expanded to general (both triangles
  populated) before constructing the `SpMat`.
* Unit-triangular (`dtCMatrix` with `diag = "U"`) matrices have their implicit
  unit diagonal materialized.

`as_dgCMatrix(SpMat<double>)` always returns a general `dgCMatrix`.

The strategy is to use Matrix's `M_sexp_as_cholmod_sparse` to wrap the input
without copying the slot data, then build the Armadillo `SpMat` from the CSC
arrays. The output path uses `M_cholmod_sparse_as_sexp` to construct the
returned `dgCMatrix`.

Note that `cpp4r` does not provide sparse matrices as it does for the dense
data types `doubles_matrix<>` or `integers_matrix<>`. `armadillo4r` uses
`SEXP` to provide a method to convert between R sparse classes and `SpMat`
objects.

Here is an example of how to convert a `dgCMatrix` object to a `SpMat` object
and export the resulting operation to R:

```cpp
[[cpp4r::register]] SEXP sum_matrices_(SEXP x) {
  // Convert from any sparse Matrix object to SpMat
  SpMat<double> A = as_SpMat(x);

  // Create a matrix B with a diagonal of random numbers
  SpMat<double> B(A.n_rows, A.n_cols);
  for (uword i = 0; i < A.n_rows; ++i) {
    B(i, i) = randu<double>();
  }

  A += B; // Add the two matrices

  // Convert back to dgCMatrix and return
  return as_dgCMatrix(A);
}
```
