-
Notifications
You must be signed in to change notification settings - Fork 586
/
029-engine-Rcpp.Rmd
98 lines (68 loc) · 2.66 KB
/
029-engine-Rcpp.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# Call Rcpp from knitr
```{r setup, include=FALSE}
library(knitr)
opts_chunk$set(cache = TRUE) # because the compilation takes time, let's cache it
```
When the chunk option `engine='Rcpp'` is specified (or you write the chunk header as ```` ```{Rcpp} ````), the code chunk will be compiled through **Rcpp** via `sourceCpp()`:
Test for `fibonacci`:
```{Rcpp, fibCpp}
#include <Rcpp.h>
// [[Rcpp::export]]
int fibonacci(const int x) {
if (x == 0 || x == 1) return(x);
return (fibonacci(x - 1)) + fibonacci(x - 2);
}
```
Because `fibonacci` was defined with the `Rcpp::export` attribute it can now be called as a normal R function:
```{r fibTest, dependson='fibCpp'}
fibonacci(10L)
fibonacci(20L)
```
You can define multiple functions (or helper functions that are not exported) within Rcpp code chunks:
```{Rcpp, multipleCpp}
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector convolveCpp(NumericVector a, NumericVector b) {
int na = a.size(), nb = b.size();
int nab = na + nb - 1;
NumericVector xab(nab);
for (int i = 0; i < na; i++)
for (int j = 0; j < nb; j++)
xab[i + j] += a[i] * b[j];
return xab;
}
// [[Rcpp::export]]
List lapplyCpp(List input, Function f) {
List output(input.size());
std::transform(input.begin(), input.end(), output.begin(), f);
output.names() = input.names();
return output;
}
```
If you want to link to code defined in another package (e.g **RcppArmadillo**) then you need to provide an `Rcpp::depends` attribute. For example:
```{Rcpp, lmCpp}
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::export]]
List fastLm(NumericVector yr, NumericMatrix Xr) {
int n = Xr.nrow(), k = Xr.ncol();
arma::mat X(Xr.begin(), n, k, false); // reuses memory and avoids extra copy
arma::colvec y(yr.begin(), yr.size(), false);
arma::colvec coef = arma::solve(X, y); // fit model y ~ X
arma::colvec resid = y - X*coef; // residuals
double sig2 = arma::as_scalar( arma::trans(resid)*resid/(n-k) );
// std.error of estimate
arma::colvec stderrest = arma::sqrt(
sig2 * arma::diagvec( arma::inv(arma::trans(X)*X)) );
return List::create(Named("coefficients") = coef,
Named("stderr") = stderrest
);
}
```
A test:
```{r lmTest, dependson='lmCpp'}
fastLm(rnorm(10), matrix(1:20, ncol = 2))
```
Finally, you can pass additional arguments to `sourceCpp()` via the chunk option `engine.opts`. For example, we can specify `engine.opts=list(showOutput=TRUE, rebuild=FALSE)` to show the output of `R CMD SHLIB`.