Converting between R and Armadillo types

Adapted from the official Armadillo documentation.

armadillo4r provides a set of conversion functions, declared across armadillo4r/wrappers/matrices.hpp, armadillo4r/wrappers/vectors.hpp, armadillo4r/wrappers/cubes.hpp, and armadillo4r/wrappers/fields.hpp, and all automatically available after including <armadillo4r.hpp>. This vignette documents every function and shows a minimal C++ example for each group.

R to Armadillo

Matrices

R matrices are represented in cpp4r as doubles_matrix<> (numeric) or integers_matrix<> (integer). The following functions convert them to Armadillo dense matrices:

cpp4r input Function Armadillo output Notes
doubles_matrix<> as_Mat(x) / as_mat(x) Mat<double> as_mat() is a lowercase alias
integers_matrix<> as_Mat(x) / as_mat(x) Mat<int> same alias applies
integers_matrix<> as_imat(x) imat (Mat<sword>) signed integer matrix
integers_matrix<> as_umat(x) umat (Mat<uword>) unsigned integer matrix; copies element-by-element
doubles_matrix<> as_fmat(x) fmat (Mat<float>) narrows double to float
#include <cpp4r.hpp>
#include <armadillo4r.hpp>

using namespace arma;
using namespace cpp4r;

[[cpp4r::register]]
doubles_matrix<> mat_demo_(const doubles_matrix<>& x,
                           const integers_matrix<>& xi) {
  mat    A  = as_Mat(x);    // double matrix
  imat   Ai = as_imat(xi);  // signed int matrix
  umat   Au = as_umat(xi);  // unsigned int matrix
  fmat   Af = as_fmat(x);   // float matrix

  // use A, Ai, Au, Af ...
  return as_doubles_matrix(A * A.t());
}
x  <- matrix(c(1.5, 2.5, 3.5, 4.5), nrow = 2)
xi <- matrix(1:4, nrow = 2)
mat_demo_(x, xi)

Vectors

R vectors (doubles / integers) map to Armadillo column vectors:

cpp4r input Function Armadillo output Notes
doubles as_Col(x) / as_col(x) Col<double> (vec) as_col() is a lowercase alias
integers as_Col(x) / as_col(x) Col<int> same alias applies
integers as_uvec(x) uvec (Col<uword>) copies element-by-element (no reinterpret)
[[cpp4r::register]]
doubles vec_demo_(const doubles& y, const integers& yi) {
  vec  v  = as_Col(y);    // double column vector
  uvec vu = as_uvec(yi);  // unsigned int column vector

  // use v, vu ...
  return as_doubles(v % v);   // element-wise square
}
vec_demo_(c(1.0, 2.0, 3.0), 1:3)

Cubes

R has no native quasi third-order tensors (“3D matrices”) that maps directly onto Armadillo’s memory layout. armadillo4r therefore represents a cube on the R side as a list of matrices, where every element is a matrix of the same dimensions. Slice s of the Armadillo cube corresponds to element s + 1 of the R list (R is 1-indexed).

The most commonly used cube typedefs are:

Typedef Equivalent Element type
cube / dcube Cube<double> double
fcube Cube<float> float
icube Cube<sword> long long (signed, platform-dependent)
ucube Cube<uword> unsigned int
cx_cube / cx_dcube Cube<cx_double> std::complex<double>
cpp4r input Function Armadillo output Notes
list of doubles_matrix<> as_Cube(x) / as_cube(x) Cube<double> (cube) as_cube() is a lowercase alias
list of integers_matrix<> as_icube(x) Cube<int> note: assigns to Cube<int>, not icube (Cube<sword>)

Both functions throw std::runtime_error if the list is empty or any matrix has dimensions different from the first.

[[cpp4r::register]]
doubles_matrix<> cube_col_means_(const list& slices) {
  cube C = as_Cube(slices);   // list of doubles_matrix<> -> cube

  mat result(C.n_slices, C.n_cols);
  for (uword s = 0; s < C.n_slices; ++s) {
    result.row(s) = mean(C.slice(s), 0);  // column means of each slice
  }

  return as_doubles_matrix(result);
}
slices <- list(
  matrix(1:6,   nrow = 2),   # slice 1
  matrix(7:12,  nrow = 2),   # slice 2
  matrix(13:18, nrow = 2)    # slice 3
)
cube_col_means_(slices)

Fields

An Armadillo field<object_type> stores arbitrary objects (matrices, vectors, strings, …) in a matrix-like or cube-like layout. Unlike Cube, the elements of a field do not need to have the same size — each element is an independent object.

Tip: when all matrices share the same dimensions, prefer Cube over field<mat> because Cube is more memory-efficient and faster.

On the R side a field is always represented as a plain list (or strings for field<std::string>). Element i of the Armadillo field (0-indexed) corresponds to element i + 1 of the R list (1-indexed).

cpp4r input Function Armadillo output Notes
list of doubles_matrix<> as_field_mat(x) field<mat> matrices may differ in size
list of integers_matrix<> as_field_imat(x) field<imat> matrices may differ in size
list of doubles as_field_vec(x) field<vec> vectors may differ in length
strings as_field_str(x) field<std::string>

All four functions throw std::runtime_error if the input list is empty.

[[cpp4r::register]]
list field_mat_demo_(const list& mats) {
  // Ragged list of matrices -> field<mat>
  field<mat> F = as_field_mat(mats);

  // Normalise each matrix independently
  for (uword i = 0; i < F.n_elem; ++i) {
    F(i) = normalise(F(i));  // L2-normalise columns
  }

  // field<mat> -> list of doubles_matrix<>
  return as_doubles_matrix_field(F);
}
mats <- list(
  matrix(1:6,  nrow = 2),   # 2x3 matrix
  matrix(1:12, nrow = 4)    # 4x3 matrix  (different nrow!)
)
field_mat_demo_(mats)

Armadillo to R

Matrices

Armadillo input Function cpp4r output
Mat<double> / mat / fmat as_doubles_matrix(A) doubles_matrix<>
Mat<int> / imat / umat as_integers_matrix(A) integers_matrix<>
Mat<cx_double> / cx_mat as_complexes_matrix(A) complexes_matrix<>
[[cpp4r::register]]
doubles_matrix<> mat_out_demo_(const doubles_matrix<>& x) {
  mat A = as_Mat(x);
  return as_doubles_matrix(A.t() * A);  // mat -> doubles_matrix<>
}
x <- matrix(1:9, nrow = 3) * 1.0
mat_out_demo_(x)

Vectors

Armadillo input Function cpp4r output
Col<double> / vec as_doubles(v) doubles
Col<int> / ivec as_integers(v) integers
uvec as_integers(v) integers
[[cpp4r::register]]
doubles vec_out_demo_(const doubles& y) {
  return as_doubles(normalise(as_Col(y)));  // vec -> doubles
}
vec_out_demo_(c(3.0, 4.0))   # should give c(0.6, 0.8)

Cubes

Armadillo input Function cpp4r output
Cube<double> / cube as_doubles_matrix_list(C) list of doubles_matrix<>
Cube<int> / icube as_integers_matrix_list(C) list of integers_matrix<>
ucube as_integers_matrix_list(C) list of integers_matrix<>

Slice s of the cube becomes element s + 1 of the returned R list.

[[cpp4r::register]]
list random_cube_(const int n_rows, const int n_cols, const int n_slices) {
  cube C(n_rows, n_cols, n_slices, fill::randn);
  return as_doubles_matrix_list(C);  // cube -> list of doubles_matrix<>
}
set.seed(42)
result <- random_cube_(3L, 4L, 2L)

length(result)    # 2  (one element per slice)
dim(result[[1]])  # 3 4

Fields

Armadillo input Function cpp4r output
field<mat> as_doubles_matrix_field(F) list of doubles_matrix<>
field<imat> as_integers_matrix_field(F) list of integers_matrix<>
field<vec> as_doubles_field(F) list of doubles
field<std::string> as_strings_field(F) strings

Element i of the field (0-indexed) becomes element i + 1 of the returned R list (1-indexed). Because field elements may differ in size, the returned list is potentially ragged.

[[cpp4r::register]]
list build_field_(const integers& sizes) {
  // Build a field<vec> where each vector has a different length
  field<vec> F(sizes.size());

  for (uword i = 0; i < F.n_elem; ++i) {
    F(i) = randn<vec>(sizes[static_cast<int>(i)]);  // random vector of length sizes[i]
  }

  return as_doubles_field(F);  // field<vec> -> list of doubles
}
build_field_(c(3L, 5L, 2L))   # list of three vectors of lengths 3, 5, 2

Generic conversion with cpp4r::as_sexp()

For cases where the return type is determined at compile time, cpp4r::as_sexp() provides a single generic entry point that dispatches to the appropriate conversion based on the Armadillo type:

Armadillo input as_sexp() output
vec / fvec doubles
ivec / uvec integers
mat / fmat doubles_matrix<>
imat / umat integers_matrix<>
rowvec / frowvec doubles_matrix<> (1-row matrix)
irowvec / urowvec integers_matrix<> (1-row matrix)
[[cpp4r::register]]
SEXP as_sexp_demo_(const doubles& y) {
  return cpp4r::as_sexp(arma::sort(as_Col(y)));  // vec -> doubles (dispatched automatically)
}
as_sexp_demo_(c(3.0, 1.0, 2.0))   # returns c(1, 2, 3)

References

Loading...