knitr::opts_chunk$set(
  comment = "#>",
  collapse = TRUE,
  cache = TRUE, 
  fig.align = "center",
  fig.pos = "t"
)

Introduction

Introduction

Rcpp

Rcpp

local(source("code/07-performance_f5.R", local = TRUE))

Exercise: Are you ready?

install.packages("Rcpp")
efficientTutorial::test_rcpp()

A simple C++ function

A simple C++ function

## R version
add_r = function(x, y) {
  return(x + y)
} 
/* Return type double
 * Two arguments, also doubles
 */
double add_c(double x, double y) {
    double value = x + y;
    return value;
}

Exercise: What differences do you see?

The main function

The cppFunction command

library("Rcpp")
cppFunction("
  double add_c(double x, double y) {
    double value = x + y;
    return value;
  }
")

Rcpp then performs magic!

The magic

add_c

We can call the add_c function in the usual way

add_c(1, 2)

Exercise 1

Exercise 1

vignette("rcpp", package = "efficientTutorial")

C/C++ data types

C/C++ data types

Type | Description ------|----------- char | A single character. int | An integer. float | A single precision floating point number. double | A double-precision floating point number. void | A valueless quantity.

There are also pointer's

The sourceCpp function

The sourceCpp function

.Cpp components

Access Rcpp functions (similar to a library call)

#include <Rcpp.h>

Namespace

Complete file

# include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double add_c(double x, double y) {
  double value = x + y;
  return value;
}

Benefits of a file

  1. Syntax highlighting
  2. It's easy to make errors switching between R and C++ in the same file

To save space, we'll omit the headers for the remainder of the chapter.

Exercise 2

Exercise 2

vignette("rcpp", package = "efficientTutorial")

Vectors and loops

mean_r

mean_r = function(x) {
  n = length(x)
  m = 0
  for (i in seq_along(x))
    m = m + x[i] / n
  m
}

mean_c

double mean_c(NumericVector x){
  int i;
  int n = x.size();
  double mean = 0;

  for(i=0; i<n; i++) {
    mean = mean + x[i]/n;
  }
  return mean;
}
sourceCpp("../src/mean_c.cpp")
cppFunction("double mean_c(NumericVector x) {
  int i;
  int n = x.size();
  double mean = 0;

  for(i=0; i<n; i++) {
    mean = mean + x[i]/n;
  }
  return mean;
}")

Speed comparison

library("microbenchmark")

We generate some normal random numbers for the comparison

x = rnorm(1e4)

Then call the microbenchmark function.

z = microbenchmark(
  mean(x),
  mean_r(x),
  mean_c(x)
)

Results

par(mar = c(3, 3, 2, 1), mgp = c(2, 0.4, 0), tck = -.01,
    cex.axis = 0.9, las = 1)
boxplot(z, ylab = "Time", col = "steelblue")
grid()

Exercise 3

Exercise 3

vignette("rcpp", package = "efficientTutorial")

C++ with sugar on top

The sugared version

NumericVector res_c(NumericVector x, NumericVector y) {
  int i;
  int n = x.size();
  NumericVector residuals(n);
  for(i=0; i<n; i++) {
    residuals[i] = pow(x[i] - y[i], 2);
  }
  return residuals;
}

With Sugar

NumericVector res_sugar(NumericVector x, NumericVector y) {
  return pow(x - y, 2);
}


jr-packages/efficientTutorial documentation built on Feb. 16, 2020, 7:05 p.m.