# 03 - 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.

# 1 R to Armadillo

## 1.1 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)

## 1.2 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)

## 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)

## 1.4 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)

# 2 Armadillo to R

## 2.1 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)

## 2.2 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)

## 2.3 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

## 2.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

## 2.5 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)

# 3 References