Skip to content
This repository was archived by the owner on Dec 22, 2024. It is now read-only.

Commit c6a393a

Browse files
author
Jose Storopoli
committed
Adicionei 6-Rcpp_CUDA.Rmd
1 parent 27af8e9 commit c6a393a

37 files changed

+1710
-698
lines changed

1-Porque_CPP.Rmd

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,19 @@ int addCpp(int x, int y, int z){
5757
addCpp(10, 17, 31)
5858
```
5959

60-
Comparando tempo de execução (em ns) com a função `mark()` do pacote `{bench}`:
60+
Comparando tempo de execução com a função `mark()` do pacote `{bench}`:
6161

62-
```{r bench_add}
63-
bench::mark(
62+
```{r bench-add, message=FALSE}
63+
b1 <- bench::mark(
6464
R = addR(10, 17, 31),
6565
Cpp = addCpp(10, 17, 31),
66-
time_unit = "ns"
66+
relative = TRUE
6767
)
68+
b1
69+
```
70+
71+
```{r fig-bench-add, echo=FALSE, fig.cap='Benchmark da função soma: R vs C++'}
72+
ggplot2::autoplot(b1, "violin")
6873
```
6974

7075
Aqui vocês vem que C++ não tem nenhuma vantagem sobre R: é mais verboso, chato de escrever e ainda é mais lenta!
@@ -117,15 +122,25 @@ NumericMatrix gibbsCpp(int N, int thin) {
117122
)
118123
```
119124

120-
E vamos para o benchmark (em µs):
121-
122-
```{r bench_gibbs}
123-
bench::mark(
124-
R = gibbsR(100, 10),
125-
Cpp = gibbsCpp(100, 10),
126-
check = FALSE,
127-
time_unit = "us"
125+
E vamos para o benchmark comparando alguns tamanhos de inputs:
126+
127+
```{r bench-gibbs, message=FALSE}
128+
b2 <- bench::press(
129+
N = 10^c(2:3),
130+
{
131+
bench::mark(
132+
R = gibbsR(N, 10),
133+
Cpp = gibbsCpp(N, 10),
134+
check = FALSE,
135+
relative = TRUE
136+
)
137+
}
128138
)
139+
b2
140+
```
141+
142+
```{r fig-bench-gibbs, echo=FALSE, fig.cap='Benchmarks do Amostrador de Gibbs: R vs C++'}
143+
ggplot2::autoplot(b2, "violin")
129144
```
130145

131146
No meu computador `gibbsCpp()` executa 20x mais rápido que `gibbsR()`!

2-Rcpp.Rmd

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,14 @@ A tabela abaixo apresenta a correspondência dos tipos de dados entre R/`{Rcpp}`
182182
library(gt)
183183
library(dplyr)
184184
tibble::tribble(
185-
~`Tipo de Variável`, ~`Vetor R`, ~`Vetor Rcpp`, ~`Matriz Rcpp`, ~`Escalar Rcpp`, ~`Escalar C++`,
186-
"Lógica", "logical", "LogicalVector", "LogicalMatrix", "-", "bool",
187-
"Inteiro", "integer", "IntegerVector", "IntegerMatrix", "-", "int",
188-
"Real", "numeric", "NumericVector", "NumericMatrix", "-", "double",
189-
"Complexo", "complex", "ComplexVector", "ComplexMatrix", "Rcomplex", "complex",
190-
"String", "character", "CharacterVector (StringVector)", "CharacterMatrix (StringMatrix)", "String", "std::string",
191-
"Date", "Date", "DateVector", "-", "Date", "-",
192-
"Datetime", "POSIXct", "DatetimeVector", "-", "Datetime", "time_t"
185+
~`Tipo de Variável`, ~`Vetor R`, ~`Vetor Rcpp`, ~`Matriz Rcpp`, ~`Escalar Rcpp`, ~`Missing Rcpp`, ~`Escalar C++`,
186+
"Lógica", "logical", "LogicalVector", "LogicalMatrix", "-", "NA_LOGICAL", "bool",
187+
"Inteiro", "integer", "IntegerVector", "IntegerMatrix", "-", "NA_INTEGER", "int",
188+
"Real", "numeric", "NumericVector", "NumericMatrix", "-", "NA_REAL", "double",
189+
"Complexo", "complex", "ComplexVector", "ComplexMatrix", "Rcomplex", "-", "complex",
190+
"String", "character", "CharacterVector (StringVector)", "CharacterMatrix (StringMatrix)", "String", "NA_STRING", "std::string",
191+
"Date", "Date", "DateVector", "-", "Date", "-", "-",
192+
"Datetime", "POSIXct", "DatetimeVector", "-", "Datetime", "-", "time_t"
193193
) %>%
194194
mutate_all(~stringr::str_glue("`{.}`")) %>%
195195
gt() %>%
@@ -341,6 +341,24 @@ DataFrame df = DataFrame::create(v1, v2);
341341
DataFrame df = DataFrame::create( Named("V1") = v1 , _["V2"] = v2 );
342342
```
343343

344+
### `{Rcpp}` `tibble`
345+
346+
Para retornar uma `tibble` do `{tidyverse}` com o `{Rcpp}` é só você notar que uma `tibble` não é nada mais que um `data.frame` com algumas classes extras:
347+
348+
```{r tibble}
349+
df <- tibble::tibble()
350+
class(df)
351+
```
352+
353+
E aí é só adicionar essas classes num `DataFrame` do `{Rcpp}`:
354+
355+
```cpp
356+
DataFrame df = DataFrame::create( Named("V1") = v1 , _["V2"] = v2 );
357+
df.attr("class") = CharacterVector::create("tbl_df", "tbl", "data.frame");
358+
```
359+
360+
Pronto seu objeto `DataFrame` quando for retornado ao R será uma `tibble` do `{tidyverse}`.
361+
344362
## `{Rcpp}` Sugar
345363

346364
Além dos tipos de dados, `{Rcpp}` também tem uma ampla gama de "açúcares" sintáticos (*syntactic sugar*) para as mais variadas operações e funções. Antes de tentar criar algo do zero veja se não há um [`{Rccp}` Sugar para isso já implementado na vinheta](http://dirk.eddelbuettel.com/code/rcpp/Rcpp-sugar.pdf).
@@ -365,19 +383,28 @@ NumericVector mat_mul(const NumericVector& A, const NumericVector& B) {
365383
}
366384
```
367385

368-
```{r bench-mat_mul}
369-
n <- 10^3
370-
X <- matrix(rnorm(n * n), nrow = n)
371-
372-
bench::mark(
373-
R = X %*% X,
374-
Cpp = mat_mul(X, X),
375-
check = FALSE
386+
```{r bench-mat_mul, message=FALSE}
387+
b1 <- bench::press(
388+
n = 10^c(2:3),
389+
{
390+
X = matrix(rnorm(n * n), nrow = n)
391+
bench::mark(
392+
R = X %*% X,
393+
Cpp = mat_mul(X, X),
394+
check = FALSE,
395+
relative = TRUE
396+
)}
376397
)
398+
b1
377399
```
378400

379401

380-
Sucesso! Ganho de 700x `r emo::ji("exploding_head")` para uma matriz de dimensão `r format(n, big.mark = ".", decimal.mark = ",")` x `r format(n, big.mark = ".", decimal.mark = ",")`!
402+
```{r figmatmul, echo=FALSE, fig.cap='Benchmarks de Multiplicação de Matriz: R vs C++'}
403+
ggplot2::autoplot(b1, "violin")
404+
```
405+
406+
407+
Sucesso! Ganho de 200x `r emo::ji("exploding_head")`
381408

382409
## Usando a biblioteca padrão C++11 STL no `{Rcpp}`
383410

@@ -441,27 +468,37 @@ double sum_of_squares_rcpp_sugar(NumericVector v){
441468
}
442469
```
443470

444-
```{r bench_sum_of_squares}
471+
```{r bench-sum_of_squares, message=FALSE}
445472
set.seed(123)
446-
n <- 1000
447-
v <- rnorm(n)
448-
bench::mark(
449-
R = sum_of_squares_R(v),
450-
rcpp = sum_of_squares_rcpp(v),
451-
rcpp20 = sum_of_squares_rcpp20(v),
452-
rcppsugar = sum_of_squares_rcpp_sugar(v),
453-
check = FALSE,
454-
time_unit = "us"
455-
)
473+
474+
b2 <- bench::press(
475+
n = 10^c(1:4),
476+
{
477+
v = rnorm(n)
478+
bench::mark(
479+
R = sum_of_squares_R(v),
480+
rcpp = sum_of_squares_rcpp(v),
481+
rcpp20 = sum_of_squares_rcpp20(v),
482+
rcppsugar = sum_of_squares_rcpp_sugar(v),
483+
check = FALSE,
484+
relative = TRUE
485+
)
486+
})
487+
b2
456488
```
457489

458-
Aqui vemos como a vetorização do R funciona muito bem. É mais rápida que quase todas as implementações em `{Rcpp}`, exceto quando usamos o [`{Rcpp}` Sugar](http://dirk.eddelbuettel.com/code/rcpp/Rcpp-sugar.pdf) já que temos um ganho de 2x para um vetor com `r format(n, big.mark = ".", decimal.mark = ",")` elementos.
490+
```{r figss, echo=FALSE, fig.cap='Benchmarks de Soma dos Quadrados: R vs alternativas C++'}
491+
ggplot2::autoplot(b2, "violin")
492+
```
493+
494+
495+
Aqui vemos como a vetorização do R funciona muito bem. É mais rápida que quase todas as implementações em `{Rcpp}`, exceto quando usamos o [`{Rcpp}` Sugar](http://dirk.eddelbuettel.com/code/rcpp/Rcpp-sugar.pdf) já que temos um ganho de 2x.
459496

460497
## `{Rcpp}` e Boost
461498

462499
[Boost](https://www.boost.org) é um conjunto de bibliotecas para a linguagem de programação C++ que fornece suporte para tarefas e estruturas como álgebra linear, geração de números pseudo-aleatórios, multithreading, processamento de imagem, expressões regulares e teste de unidade. Ele contém ~~uma porrada~~ 164 bibliotecas individuais (versão 1.75) e sua versão inicial foi lançada em 1999.
463500

464-
A maioria das bibliotecas Boost são licenciadas sob a Licença de Software Boost, projetada para permitir que Boost seja usado com projetos de software proprietários e gratuitos. Muitos dos fundadores da Boost estão no comitê internacional de padrões C++, e várias bibliotecas Boost foram aceitas para incorporação no padrão C++11 (por exemplo, smart pointers, `thread`, `regex`, `random`, `ratio`, `tuple`) e no padrão C ++ 17 (por exemplo, `filesystem`, `any`, `optional`, `variant`, `string_view`).
501+
A maioria das bibliotecas Boost são licenciadas sob a Licença de Software Boost, projetada para permitir que Boost seja usado com projetos de software proprietários e gratuitos. Muitos dos fundadores da Boost estão no comitê internacional de padrões C++, e várias bibliotecas Boost foram aceitas para incorporação no padrão C++11 (por exemplo, smart pointers, `thread`, `regex`, `random`, `ratio`, `tuple`) e no padrão C++17 (por exemplo, `filesystem`, `any`, `optional`, `variant`, `string_view`).
465502

466503
Antes de usar o Boost no `{Rcpp}` certifique-se que você tem o Boost instalado no seu sistema operacional:
467504

@@ -516,15 +553,22 @@ int boostGCD(int& a, int& b) {
516553
}
517554
```
518555

519-
```{r bench_GCD}
556+
```{r bench-GCD, message=FALSE}
520557
a <- 7919
521558
b <- 7412
522-
bench::mark(
559+
b3 <- bench::mark(
523560
R = rGCD(a, b),
524561
cpp = cppGCD(a, b),
525-
boost = boostGCD(a, b)
562+
boost = boostGCD(a, b),
563+
relative = TRUE
526564
)
565+
b3
527566
```
567+
568+
```{r figGCD, echo=FALSE, fig.cap='Benchmarks de Máximo Divisor Comum: R vs C++'}
569+
ggplot2::autoplot(b3, "violin")
570+
```
571+
528572
Aqui eu escolhi um número primo bem grande, 7189, e um número aleatório próximo dele, 7412. Como vocês podem ver a solução usando a biblioteca `boost::integer` é 4,5x mais rápida que uma implementação em R e similar com a implementação de C++17.
529573

530574
## `{Rcpp}` e Rmarkdown

3-RcppEigen_RcppArmadillo.Rmd

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -444,29 +444,43 @@ MatrixXd mat_mul_eigen(const MatrixXd& A, const MatrixXd& B){
444444
}
445445
```
446446

447-
```{r bench-mat_mul}
448-
n <- 10^3
449-
X <- matrix(rnorm(n * n), nrow = n)
450-
451-
bench::mark(
452-
Rcpp = mat_mul(X, X),
453-
arma = mat_mul_arma(X, X),
454-
eigen = mat_mul_eigen(X, X),
455-
check = FALSE
456-
)
447+
```{r bench-mat_mul, message=FALSE, warning=FALSE}
448+
b1 <- bench::press(
449+
n = 10^c(1:3),
450+
{
451+
X = matrix(rnorm(n * n), nrow = n)
452+
bench::mark(
453+
Rcpp = mat_mul(X, X),
454+
arma = mat_mul_arma(X, X),
455+
eigen = mat_mul_eigen(X, X),
456+
check = FALSE,
457+
relative = TRUE
458+
)
459+
})
460+
b1
461+
```
462+
463+
```{r figmatmul, echo=FALSE, fig.cap='Benchmarks de Multiplicação de Matriz: `Rcpp` vs `Armadillo` vs `Eigen`'}
464+
ggplot2::autoplot(b1, "violin")
457465
```
458466
467+
459468
No meu computador `{RcppEigen}` é mais rápido que `{RcppArmadillo}`, mas ambos são mais lentos que uma implementação simples com `{Rcpp}`.
460469
461470
### Exemplo -- Matriz Esparsa
462471
463472
Vamos usar `mat_sparse` criada que possui dimensão `r format(dim(mat_sparse)[1], big.mark = ".", decimal.mark = ",")` x `r format(dim(mat_sparse)[2], big.mark = ".", decimal.mark = ",")` e tomar a raiz quadrada de todos os elementos.
464473
465-
```{r bench-sparse_sqrt}
466-
bench::mark(
474+
```{r bench-sparse_sqrt, warning=FALSE, message=FALSE}
475+
b2 <- bench::mark(
467476
arma = sqrt_eigen(mat_sparse),
468-
eigen = sqrt_eigen(mat_sparse)
477+
eigen = sqrt_eigen(mat_sparse),
478+
relative = TRUE
469479
)
480+
b2
481+
```
482+
```{r figsparsesqrt, echo=FALSE, fig.cap='Benchmarks de Matriz Esparsa: `Armadillo` vs `Eigen`'}
483+
ggplot2::autoplot(b2, "violin")
470484
```
471485
472486
Novamente `Eigen` é um pouco mais rápida que `Armadillo`, mas a diferença é pequena.
@@ -528,15 +542,21 @@ Rcpp::List fast_lm_eigen(const VectorXd& y, const MatrixXd& X) {
528542
}
529543
```
530544

531-
```{r bench-fast_lm}
545+
```{r bench-fast_lm, warning=FALSE, message=FALSE}
532546
y <- log(trees$Volume)
533547
X <- cbind(1, log(trees$Girth))
534-
bench::mark(
548+
b3 <- bench::mark(
535549
R = lm(y ~ X),
536550
arma = fast_lm_arma(y, X),
537551
eigen = fast_lm_eigen(y, X),
538-
check = FALSE
552+
check = FALSE,
553+
relative = TRUE
539554
)
555+
b3
556+
```
557+
558+
```{r figfastlm, echo=FALSE, fig.cap='Benchmarks de Regressão Linear: R vs `Armadillo` vs `Eigen`'}
559+
ggplot2::autoplot(b3, "violin")
540560
```
541561
542562
Tanto `Eigen` quanto `Armadillo` são rápidos! Quase 100x mais rápidos `r emo::ji("exploding_head")`. Novamente a diferença entre `Eigen` e `Armadillo` é pequena.

0 commit comments

Comments
 (0)