---
title: "std::vector and Rcpp Vectors"
author: "Colin Rundel"
date: "2019-02-28"
output:
  xaringan::moon_reader:
    css: "slides.css"
    lib_dir: libs
    nature:
      highlightStyle: github
      countIncrementalSlides: false

---
exclude: true

```{r setup, message=FALSE, warning=FALSE, include=FALSE}
library(tidyverse)
library(Rcpp)

options(tibble.width = 110, width = 110)
```

```{r global_options}
knitr::opts_chunk$set(cache=TRUE)
```

---

## C Vectors

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
void c_vec() {
  int v[8];
  
  for(int i=0; i!=8; i++) {
    Rcpp::Rcout << "v[" << i << "] = " << v[i] << "\n";  
  }
}
```

```{r}
c_vec()
```

---

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
void c_vec_bad() {
  int v[8];
  
  for(int i=0; i!=12; i++) {
    Rcpp::Rcout << "v[" << i << "] = " << v[i] << "\n";  
  }
}
```

```{r}
c_vec_bad()
```

---

## C dynamic vectors

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
void c_vec_dyn(int n) {
  int *v = (int *)calloc(n, sizeof(int));
  
  for(int i=0; i!=n; i++) {
    Rcpp::Rcout << "v[" << i << "] = " << v[i] << "\n";  
  }
  Rcpp::Rcout << "\n";
  
  free(v);
}
```

```{r}
c_vec_dyn(2)
c_vec_dyn(3)
```

---

## C++ dynamic vectors

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
void cpp_vec_dyn(int n) {
  int *v = new int[n]();
  
  for(int i=0; i!=n; i++) {
    Rcpp::Rcout << "v[" << i << "] = " << v[i] << "\n";  
  }
  Rcpp::Rcout << "\n";
  
  delete[] v;
}
```

```{r}
cpp_vec_dyn(2)
cpp_vec_dyn(3)
```

---

## C++ stl vectors

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
void cpp_stl_vec(int n) {
  std::vector<int> v(n);
  
  for(int i=0; i!=n; i++) {
    Rcpp::Rcout << "v[" << i << "] = " << v[i] << "\n";  
  }
  Rcpp::Rcout << "\n";
}
```

```{r}
cpp_stl_vec(2)
cpp_stl_vec(3)
```

---

## C++ Templates (very briefly)

```{Rcpp}
#include <Rcpp.h>
#include <typeinfo>

template<typename T>
std::string what_am_i() {
  T obj;
  return typeid(obj).name();
}

// [[Rcpp::export]]
void template_ex() {
  Rcpp::Rcout << "bool       : " << what_am_i<bool>() << "\n";
  Rcpp::Rcout << "int        : " << what_am_i<int>() << "\n";
  Rcpp::Rcout << "long int   : " << what_am_i<long int>() << "\n";
  Rcpp::Rcout << "char       : " << what_am_i<char>() << "\n";
  Rcpp::Rcout << "float      : " << what_am_i<float>() << "\n";
  Rcpp::Rcout << "double     : " << what_am_i<double>() << "\n";
  Rcpp::Rcout << "std::string: " << what_am_i<std::string>() << "\n";
}
```

```{r}
template_ex()
```

---

## Initializing std::vector

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::plugins(cpp14)]]

// [[Rcpp::export]]
Rcpp::List init_int_vec() {
  std::vector<int> v1 = {1, 2, 3}; // Requires cpp14
  std::vector<int> v2(2);
  std::vector<int> v3(2, 1);
  std::vector<int> v4(v1);
  std::vector<int> v5(v1.begin(), v1.end());
  std::vector<int> v6(v1.begin(), v1.end()-1);
  std::vector<int> v7;
  v7.push_back(10);
  v7.push_back(9);
  v7.push_back(8);
  
  return Rcpp::List::create(v1,v2,v3,v4,v5,v6,v7);
}
```

```{r}
str(init_int_vec())
```

--- 

## Initializing std::vector

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::plugins(cpp14)]]

// [[Rcpp::export]]
Rcpp::List init_dbl_vec() {
  std::vector<double> v1 = {1, 2, 3}; // Requires cpp14
  std::vector<double> v2(2);
  std::vector<double> v3(2, 1);
  std::vector<double> v4(v1);
  std::vector<double> v5(v1.begin(), v1.end());
  std::vector<double> v6(v1.begin(), v1.end()-1);
  std::vector<double> v7;
  v7.push_back(10);
  v7.push_back(9);
  v7.push_back(8);
  
  return Rcpp::List::create(v1,v2,v3,v4,v5,v6,v7);
}
```

```{r}
str(init_dbl_vec())
```

---

## Translating std::vector

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::IntegerVector from_std_vec(std::vector<int> v) {

  return Rcpp::IntegerVector(v.begin(), v.end());
}

// [[Rcpp::export]]
std::vector<int> to_std_vec(Rcpp::IntegerVector rv) {

  return std::vector<int>(rv.begin(), rv.end());
}
```

```{r}
from_std_vec(1:10)
to_std_vec(1:10)
```

---

## Translating std::vectors (SEXPs)

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
SEXP sexp_std_vec(SEXP rv) {

  std::vector<int> v = Rcpp::as< std::vector<int> >(rv);
  return Rcpp::wrap(v);
}

// [[Rcpp::export]]
SEXP sexp_rcpp_vec(SEXP rv) {

  Rcpp::IntegerVector v = Rcpp::as< Rcpp::IntegerVector >(rv);
  return Rcpp::wrap(v);
}
```

```{r}
sexp_std_vec(1:10)
sexp_rcpp_vec(1:10)
```

---

## std::vector methods - access

.small[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
void std_vec_access(std::vector<int> v) {
  Rcpp::Rcout << "v.front() = " << v.front() << "\n";
  Rcpp::Rcout << "v[0]      = " << v[0]      << "\n";
  Rcpp::Rcout << "v.at(0)   = " << v.at(0)   << "\n";
  Rcpp::Rcout << "v.back()  = " << v.back()  << "\n";
  Rcpp::Rcout << "v[5]      = " << v[5]      << "\n";
  Rcpp::Rcout << "v.at(5)   = " << v.at(5)   << "\n";
  Rcpp::Rcout << "\n";
}
```

```{r error=TRUE}
std_vec_access(1:6)
std_vec_access(1:5)
```
]

---

## Rcpp vector methods - access

.small[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
void rcpp_vec_access(Rcpp::IntegerVector v) {
  Rcpp::Rcout << "v[0]      = " << v[0]      << "\n";
  Rcpp::Rcout << "v(0)      = " << v(0)      << "\n";
  Rcpp::Rcout << "v.at(0)   = " << v.at(0)   << "\n";
  Rcpp::Rcout << "v[5]      = " << v[5]      << "\n";
  Rcpp::Rcout << "v(5)      = " << v(5)      << "\n";
  Rcpp::Rcout << "v.at(5)   = " << v.at(5)   << "\n";
  Rcpp::Rcout << "\n";
}
```

```{r error=TRUE}
rcpp_vec_access(1:6)
rcpp_vec_access(1:5)
```
]

---

## Iterators

.tiny[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
void iterators(int n) {
  std::vector<int> sv(n);
  Rcpp::IntegerVector rv(n);
  
  std::iota(sv.begin(), sv.end(), 1);
  std::iota(rv.begin(), rv.end(), 1);
  
  Rcpp::Rcout << " sv.begin()           : " << &*sv.begin() << "\n";
  Rcpp::Rcout << " sv.end()             : " << &*sv.end()   << "\n";
  Rcpp::Rcout << " sv.end() - v.begin() : " <<   sv.end() - sv.begin() << "\n";
  Rcpp::Rcout << "*sv.begin()           : " <<  *sv.begin() << "\n";
  Rcpp::Rcout << "*sv.end()             : " <<  *sv.end()   << "\n";
  Rcpp::Rcout << "*(sv.end()-1)         : " <<  *(sv.end()-1)   << "\n";
  Rcpp::Rcout << "\n";
  Rcpp::Rcout << " rv.begin()           : " << &*rv.begin() << "\n";
  Rcpp::Rcout << " rv.end()             : " << &*rv.end()   << "\n";
  Rcpp::Rcout << " rv.end() - v.begin() : " <<   rv.end() - rv.begin() << "\n";
  Rcpp::Rcout << "*rv.begin()           : " <<  *rv.begin() << "\n";
  Rcpp::Rcout << "*rv.end()             : " <<  *rv.end()   << "\n";
  Rcpp::Rcout << "*(rv.end()-1)         : " <<  *(rv.end()-1)   << "\n";
  Rcpp::Rcout << "\n";
}
```
]

.smaller[
```{r}
iterators(100)
```
]

---

## (More) Iterators

.smaller[
```{Rcpp}
#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]

// [[Rcpp::export]]
void iterators2(int n) {
  std::vector<int> sv(n);
  
  std::iota(sv.begin(), sv.end(), 1);
  
  auto it = sv.begin();
  
  Rcpp::Rcout << " *(sv.begin())   : " << *(sv.begin())   << "\n";
  Rcpp::Rcout << " *(sv.begin()++) : " << *(sv.begin()++) << "\n";
  Rcpp::Rcout << " *(++sv.begin()) : " << *(++sv.begin()) << "\n";
  Rcpp::Rcout << " *(sv.begin())   : " << *(sv.begin())   << "\n";
  Rcpp::Rcout << " *(it)           : " << *(it)   << "\n";
  Rcpp::Rcout << " *(it++)         : " << *(it++) << "\n";
  Rcpp::Rcout << " *(++it)         : " << *(++it) << "\n";
  Rcpp::Rcout << " *(++it)         : " << *(++it) << "\n";
  Rcpp::Rcout << " *(it++)         : " << *(it++) << "\n";
  Rcpp::Rcout << "\n";
}
```

```{r}
iterators2(10)
```
]

---

## std::vector methods - growing

.small[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
void grow(int n, int m) {
  std::vector<int> v;
  
  for(int i = 0, k = 0; i < n; ++i) {
    for(int j = 0; j < m; ++j, ++k) {
      v.push_back(k);
    }
    Rcpp::Rcout << "iter: " << k
                << " size: " << v.size()
                << " capacity: " << v.capacity()
                << "\n";
  }
  
  Rcpp::Rcout << "\n";
}
```

```{r}
grow(10, 2)
```
]

---

## Growth performance

.smaller[
.columns[
.col[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
int std_vec_grow(int n) {
  std::vector<int> v;

  for(int i = 0; i < n; ++i) {
    v.push_back(i);
  }
  
  return v.size();
}
```
]

.col[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
int rcpp_grow_back(int n) {
  Rcpp::IntegerVector v;

  for(int i = 0; i < n; ++i) {
    v.push_back(i);
  }
  
  return v.size();
}

// [[Rcpp::export]]
int rcpp_grow_front(int n) {
  Rcpp::IntegerVector v;

  for(int i = 0; i < n; ++i) {
    v.push_front(i);
  }
  
  return v.size();
}
```
] ] ]

---

.small[ 
```{r}
bench::mark(
  std_vec_grow(1e3),
  rcpp_grow_back(1e3),
  rcpp_grow_front(1e3)
)
```
]

---

## Allocation performance

.smaller[
.columns[
.col[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
int std_vec_alloc(int n) {
  std::vector<int> v(n);
  for(int i = 0; i < n; ++i) {
    v[i] = i;
  }
  return v.size();
}

// [[Rcpp::export]]
int rcpp_alloc(int n) {
  Rcpp::IntegerVector v(n);
  for(int i = 0; i < n; ++i) {
    v[i] = i;
  }
  return v.size();
}
```
]

.col[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
int std_vec_alloc_at(int n) {
  std::vector<int> v(n);
  for(int i = 0; i < n; ++i) {
    v.at(i) = i;
  }
  return v.size();
}

// [[Rcpp::export]]
int rcpp_alloc_at(int n) {
  Rcpp::IntegerVector v(n);
  for(int i = 0; i < n; ++i) {
    v.at(i) = i;
  }
  return v.size();
}
```
]
] ]

.smaller[
```{r}
bench::mark(
  std_vec_alloc(1e6),
  rcpp_alloc(1e6),
  std_vec_alloc_at(1e6),
  rcpp_alloc_at(1e6)
)
```
]

---

## Translation performance

.smaller[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
std::vector<int> std_vec_trans(std::vector<int> v) {
  return v;
}

// [[Rcpp::export]]
Rcpp::IntegerVector rcpp_vec_trans(Rcpp::IntegerVector v) {
  return v;
}
```

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
std::vector<int> std_vec_trans_ref(std::vector<int> &v) {
  return v;
}

// [[Rcpp::export]]
Rcpp::IntegerVector rcpp_vec_trans_ref(Rcpp::IntegerVector &v) {
  return v;
}
```
]

---

.small[
```{r}
x = rpois(1e6, 1)

bench::mark(
  std_vec_trans(x),
  rcpp_vec_trans(x),
  std_vec_trans_ref(x),
  rcpp_vec_trans_ref(x)
)
```
]


---

## Sorting performance

.smaller[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
std::vector<double> std_vec_sort(std::vector<double> v) {
  std::sort(v.begin(), v.end());
  
  return v;
}

// [[Rcpp::export]]
Rcpp::NumericVector rcpp_vec_sort(Rcpp::NumericVector v) {
  v.sort();
  
  return v;
}
```

```{r}
x = rnorm(1e6)

bench::mark(
  std_vec_sort(x),
  rcpp_vec_sort(x)
)
```
]


---

## Insert performance

.smaller[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
std::vector<int> std_vec_ins(std::vector<int> v, int n, int pos, int value) {
  for(int i=0; i<n; ++i) {
    v.insert(v.begin() + pos, value);
  }
  
  return v;
}
```

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::IntegerVector rcpp_vec_ins_it(Rcpp::IntegerVector v, int n, int pos, int value) {
  for(int i=0; i<n; ++i) {
    v.insert(v.begin() + pos, value);
  }
  
  return v;
}

// [[Rcpp::export]]
Rcpp::IntegerVector rcpp_vec_ins_pos(Rcpp::IntegerVector v, int n, int pos, int value) {
  for(int i=0; i<n; ++i) {
    v.insert(pos, value);
  }
  
  return v;
}
```
]

---

.small[
```{r}
std_vec_ins(1:4, 5, 2, 0)
```
]

--

.smaller[
```{r}
bench::mark(
  std_vec_ins(1:4, 5, 2, 0),
  rcpp_vec_ins_it(1:4, 5, 2, 0),
  rcpp_vec_ins_pos(1:4, 5, 2, 0)
)
```
]

--

.smaller[
```{r}
x = 1:1e3
bench::mark(
  std_vec_ins(x, 500, 500, 0),
  rcpp_vec_ins_it(x, 500, 500, 0),
  rcpp_vec_ins_pos(x, 500, 500, 0)
)
```
]

---

## Erase performance

.smaller[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
std::vector<int> std_vec_erase(std::vector<int> v, int pos, int n) {
  for(int i=0; i<n; ++i) {
    v.erase(v.begin()+pos);
  }
  
  return v;
}

// [[Rcpp::export]]
std::vector<int> std_vec_erase_range(std::vector<int> v, int pos, int n) {

  v.erase(v.begin()+pos, v.begin()+pos+n);
  
  return v;
}
```

```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::IntegerVector rcpp_vec_erase(Rcpp::IntegerVector v, int pos, int n) {
  for(int i=0; i<n; ++i) {
    v.erase(v.begin()+pos);
  }
  
  return v;
}

// [[Rcpp::export]]
Rcpp::IntegerVector rcpp_vec_erase_range(Rcpp::IntegerVector v, int pos, int n) {

  v.erase(v.begin()+pos, v.begin()+pos+n);
  
  return v;
}
```
]


---

.smaller[
```{r}
std_vec_erase(1:6, 2, 2)
std_vec_erase_range(1:6, 2, 2)
```
]

--

.smaller[
```{r}
bench::mark(
  std_vec_erase(1:6, 2, 2),
  std_vec_erase_range(1:6, 2, 2),
  rcpp_vec_erase(1:6, 2, 2),
  rcpp_vec_erase_range(1:6, 2, 2)
)
```
]

--

.smaller[
```{r}
x = 1:1e3
bench::mark(
  std_vec_erase(x, 250, 500),
  std_vec_erase_range(x, 250, 500),
  rcpp_vec_erase(x, 250, 500),
  rcpp_vec_erase_range(x, 250, 500)
)
```
]

---
class: middle

# Rcpp Sugar

---

## RMSE - Rcpp

.smaller[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
double rcpp_rmse(Rcpp::NumericVector y, Rcpp::NumericVector y_hat) {

  Rcpp::NumericVector diff = y - y_hat;

  return sqrt( Rcpp::sum(diff*diff) / y.size() );
}
```

```{r error=TRUE}
rcpp_rmse(1:10, 1:10)
rcpp_rmse(1:10, 10:1)
rcpp_rmse(1:10, 1:5)
rcpp_rmse(1:5, 1:10)
```
]

---

## RMSE - std::vector

.smaller[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
double std_vec_rmse(std::vector<double> y, std::vector<double> y_hat) {
  double sum = 0.0;
  for(int i=0; i<y.size(); ++i) {
    double diff = y[i] - y_hat[i];
    sum += diff * diff;
  }

  return sqrt( sum / y.size() );
}
```

```{r}
std_vec_rmse(1:10, 1:10)
std_vec_rmse(1:10, 10:1)
std_vec_rmse(1:10, 1:5)
std_vec_rmse(1:5, 1:10)
```
]

---

## Length coercion

.small[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::NumericVector rcpp_len_issue(Rcpp::NumericVector y, Rcpp::NumericVector y_hat) {
  
  return y - y_hat;
}
```


```{r}
rcpp_len_issue(1:10, 1:10)
rcpp_len_issue(1:10, 10:1)
rcpp_len_issue(1, 1:10)
rcpp_len_issue(1:5, 1:10)
```
]

---

## Logical Operators and Predicates

.smaller[
```{Rcpp}
#include <Rcpp.h>

// [[Rcpp::export]]
void rcpp_logical() {
  Rcpp::IntegerVector x = Rcpp::IntegerVector::create(0, 1, NA_INTEGER, 3);
  Rcpp::LogicalVector l = x > 5;
  
  Rcpp::Rcout << "x                       : " << x << "\n";
  Rcpp::Rcout << "x > 2                   : " << Rcpp::LogicalVector(x > 2) << "\n";
  Rcpp::Rcout << "is_na(x)                : " << Rcpp::LogicalVector(Rcpp::is_na(x)) << "\n";
  Rcpp::Rcout << "any(is_na(x))           : " << Rcpp::LogicalVector(Rcpp::any(Rcpp::is_na(x))) << "\n";
  Rcpp::Rcout << "all(x < 5)              : " << Rcpp::LogicalVector(Rcpp::all(x < 5)) << "\n";
  Rcpp::Rcout << "ifelse(is_na(x), -1, x) : " << Rcpp::IntegerVector(Rcpp::ifelse(Rcpp::is_na(x), -1, x)) << "\n";
}
```

```{r}
rcpp_logical()
```
]
