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
Cubeoverfield<mat>becauseCubeis 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)