Nova Interface C++11 STL do pessoal do RStudio
O {cpp11}
é uma nova interface entre R e C++ desenvolvida pela equipe do RStudio.
Ainda é muito nova com apenas 13 links reversos de pacotes do CRAN, e com um total de 3.759.798 downloads (de 01/01/2016 à 31/12/2020).
{cpp11}
As mudanças que motivaram {cpp11}
incluem:
ALTREP
.UTF-8
1 em todos os lugares.{cpp11}
no seu código C++A sistemática é bem similar ao {Rcpp}
e bem simples também. Primeiro, instale o pacote {cpp11}
no R.
Segundo, includa no começo de todos seus arquivos .cpp
e códigos C++:
#include <cpp11.hpp>
using namespace cpp11;
namespace writable = cpp11::writable;
Terceiro, para cada função que desejar ser exportada de volta ao ambiente de R, inclua o seguinte prefixo antes da definição da função:
cpp11::register]] ReturnType functionName(){return x;} [[
{Rcpp}
vs {cpp11}
O {cpp11}
possui os mesmos tipos de dados que o {Rcpp}
, mas ele permite um melhor controle pois conseguimos especificar o que é somente leitura e o que é “gravável” (writable
). Além disso os headers são bem organizados e você não precisa trazer uma tralha toda que nem no {Rcpp}
. Caso queira usar apenas strings use o header <cpp11/strings.hpp>
. Abaixo uma tabela de referência de {Rcpp}
vs {cpp11}
.
Rcpp | cpp11 (somente leitura) | cpp11 ("gravável") | cpp11 header |
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Além disso, na tabela abaixo é possível ver a comparação entre as escalares de R vs {cpp11}
:
R | cpp11 |
---|---|
|
|
|
|
|
|
|
|
{cpp11}
para o ambiente R{cpp11}
funciona quase que de maneira idêntica que o {Rcpp}
, apenas a nomenclatura muda. {Rcpp}
usa camelCase
e {cpp11}
usa snake_case
. Veja abaixo ma tabela comparativa:
Rcpp | cpp11 |
---|---|
|
|
|
|
Vamos reutilizar o exemplo sum_of_squares
do tutorial 2. Como incorporar C++ no R - {Rcpp}.
Soma dos quadrados é algo que ocorre bastante em computação científica, especialmente quando estamos falando de regressão, mínimos quadrados, ANOVA etc. Vamos comparar a função usando um std::acummulate
de C+11 STL2 tanto no {Rcpp}
quanto no {cpp11}
. Lembrando que esta implementação será uma função que aceita como parâmetro um vetor de números reais (C++ double
/ R numeric
) e computa a soma de todos os elementos do vetor elevados ao quadrado.
Para ser uma comparação justa, vamos usar também do tutorial 2. Como incorporar C++ no R - {Rcpp}, a função sum_of_squares_rcpp_sugar()
que usa {Rcpp}
Sugar.
#include <Rcpp.h>
#include <numeric>
using namespace Rcpp;
// [[Rcpp::plugins("cpp11")]]
// [[Rcpp::export]]
double sum_of_squares_rcpp(NumericVector v){
double sum_of_elems = 0;
std::accumulate(v.cbegin(),
sum_of_elems +=
v.cend(),0.0,
double i, double j) {return i + (j * j);});
[] (return sum_of_elems;
}
// [[Rcpp::export]]
double sum_of_squares_rcpp_sugar(NumericVector v){
return(sum(v*v));
}
#include "cpp11/doubles.hpp" // aqui usando somente o header doubles
#include <numeric>
using namespace cpp11;
namespace writable = cpp11::writable;
cpp11::register]] double sum_of_squares_cpp11(doubles v){
[[double sum_of_elems = 0;
std::accumulate(v.cbegin(),
sum_of_elems +=
v.cend(),0.0,
double i, double j) {return i + (j * j);});
[] (return sum_of_elems;
}
set.seed(123)
b1 <- bench::press(
n = 10^c(4:6),
{
v = rnorm(n)
bench::mark(
Rcpp = sum_of_squares_rcpp(v),
cpp11 = sum_of_squares_cpp11(v),
Rcppsugar = sum_of_squares_rcpp_sugar(v),
check = FALSE,
relative = TRUE
)
})
b1
# A tibble: 9 x 7
expression n min median `itr/sec` mem_alloc `gc/sec`
<bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Rcpp 10000 1.02 1.02 1.12 Inf NaN
2 cpp11 10000 1.24 1.19 1 NaN NaN
3 Rcppsugar 10000 1 1 1.18 Inf Inf
4 Rcpp 100000 1.00 1 1.04 Inf NaN
5 cpp11 100000 1.03 1.03 1 NaN NaN
6 Rcppsugar 100000 1 1.00 1.03 Inf NaN
7 Rcpp 1000000 1 1.00 1.02 Inf NaN
8 cpp11 1000000 1.01 1.02 1 NaN NaN
9 Rcppsugar 1000000 1.00 1 1.02 Inf Inf
Quando usada a biblioteca padrão C++11 STL tanto {cpp11}
quanto {Rcpp}
e {Rcpp}
Sugar, pelo menos neste simples benchmark e no meu computador, possuem um desempenho similar para um vetor com function () , {, length(peek_mask(“n()”)$current_rows()), } elementos. É claro que solução do {Rcpp}
Sugar é muito mais elegante e simples com uma única linha na função.
{cpp11}
e RmarkdownNa mesma lógica de {Rcpp}
, para usar o {cpp11}
em documentos rmarkdown basta colocar cpp11
no chunk ao invés de r
. Além disso é necessário instalar o pacote {decor}
. Não esqueça de chamar um library(cpp11)
no arquivo rmarkdown.
{cpp11}
no seu pacote RPara adicionar {cpp11}
a um pacote existente, coloque seus arquivos C++ no diretório src/
e adicione no arquivo DESCRIPTION
:
LinkingTo: cpp11
A maneira mais fácil de configurar isso automaticamente é chamar usethis::use_cpp11()
do pacote {usethis}
.
Antes de construir o pacote, você precisará executar cpp11::cpp_register()
. Esta função verifica os arquivos C++ em busca de atributos [[cpp11::register]]
e gera o código de ligação necessário para disponibilizar as funções em R. Execute novamente cpp11::cpp_register()
sempre que as funções forem adicionadas, removidas ou seus nomes forem alterados. Se você estiver usando {devtools}
para desenvolver seu pacote, isso é feito automaticamente pelo pacote {pkgbuild}
quando seu pacote tem LinkingTo: cpp11
em seu arquivo DESCRIPTION
.
R version 4.0.4 (2021-02-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.10
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods
[7] base
other attached packages:
[1] gt_0.2.2 cpp11_0.2.6 dplyr_1.0.5
loaded via a namespace (and not attached):
[1] Rcpp_1.0.6 tidyr_1.1.3 png_0.1-7
[4] ps_1.6.0 assertthat_0.2.1 rprojroot_2.0.2
[7] digest_0.6.27 utf8_1.1.4 R6_2.5.0
[10] backports_1.2.1 evaluate_0.14 highr_0.8
[13] httr_1.4.2 ggplot2_3.3.3 pillar_1.5.1
[16] rlang_0.4.10 curl_4.3 rstudioapi_0.13
[19] callr_3.5.1 jquerylib_0.1.3 checkmate_2.0.0
[22] rmarkdown_2.7 textshaping_0.3.2 desc_1.3.0
[25] stringr_1.4.0 igraph_1.2.6 munsell_0.5.0
[28] compiler_4.0.4 xfun_0.22 pkgconfig_2.0.3
[31] systemfonts_1.0.1 htmltools_0.5.1.1 downlit_0.2.1
[34] tidyselect_1.1.0 tibble_3.1.0 fansi_0.4.2
[37] crayon_1.4.1 brio_1.1.1 commonmark_1.7
[40] crandep_0.1.1 grid_4.0.4 jsonlite_1.7.2
[43] gtable_0.3.0 lifecycle_1.0.0 DBI_1.1.1
[46] magrittr_2.0.1 scales_1.1.1 bench_1.1.1
[49] profmem_0.6.0 cli_2.3.1 stringi_1.5.3
[52] debugme_1.1.0 farver_2.1.0 xml2_1.3.2
[55] decor_1.0.0 bslib_0.2.4 ellipsis_0.3.1
[58] ragg_1.1.1 generics_0.1.0 vctrs_0.3.6
[61] distill_1.2 tools_4.0.4 cranlogs_2.1.1
[64] glue_1.4.2 purrr_0.3.4 processx_3.4.5
[67] parallel_4.0.4 yaml_2.2.1 colorspace_2.0-0
[70] rvest_1.0.0 knitr_1.31 sass_0.3.1
If you see mistakes or want to suggest changes, please create an issue on the source repository.
Text and figures are licensed under Creative Commons Attribution CC BY-SA 4.0. Source code is available at https://github.com/storopoli/Rcpp, unless otherwise noted. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: "Figure from ...".
For attribution, please cite this work as
Storopoli (2021, Feb. 2). Rcpp - A interface entre R e C++: `{cpp11}`. Retrieved from https://storopoli.github.io/Rcpp/5-cpp11.html
BibTeX citation
@misc{storopoli2021cpp11, author = {Storopoli, Jose}, title = {Rcpp - A interface entre R e C++: `{cpp11}`}, url = {https://storopoli.github.io/Rcpp/5-cpp11.html}, year = {2021} }