---
title: "03 - Converting between R and Armadillo types"
output:
  litedown::html_format:
    options:
      toc: true
      number_sections: true
vignette: >
  %\VignetteIndexEntry{03 - Converting between R and Armadillo types}
  %\VignetteEngine{litedown::vignette}
  %\VignetteEncoding{UTF-8}
editor:
  markdown:
    wrap: sentence
bibliography: ["references.bib"]
---

**Adapted from the official Armadillo
[documentation](https://arma.sourceforge.net/docs.html).**

`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 |

```cpp
#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());
}
```

```{r, eval=FALSE}
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) |

```cpp
[[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
}
```

```{r, eval=FALSE}
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.

```cpp
[[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);
}
```

```{r, eval=FALSE}
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.

```cpp
[[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);
}
```

```{r, eval=FALSE}
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<>` |

```cpp
[[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<>
}
```

```{r, eval=FALSE}
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` |

```cpp
[[cpp4r::register]]
doubles vec_out_demo_(const doubles& y) {
  return as_doubles(normalise(as_Col(y)));  // vec -> doubles
}
```

```{r, eval=FALSE}
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.

```cpp
[[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<>
}
```

```{r, eval=FALSE}
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.

```cpp
[[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
}
```

```{r, eval=FALSE}
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) |

```cpp
[[cpp4r::register]]
SEXP as_sexp_demo_(const doubles& y) {
  return cpp4r::as_sexp(arma::sort(as_Col(y)));  // vec -> doubles (dispatched automatically)
}
```

```{r, eval=FALSE}
as_sexp_demo_(c(3.0, 1.0, 2.0)) # returns c(1, 2, 3)
```

# References
