20 juillet 2018

Fonction R dans Rcpp

Comment introduire une foncton R dans Rcpp

Il est possible d'utiliser des fonctions codées en R

#include <RcppArmadillo.h>
// [[Rcpp::depends(Matrix,RcppArmadillo)]]
using namespace Rcpp;

// [[Rcpp::export]]
double runifCpp()
{
  Function runif("runif");
  return as<double>(runif(1));
}

Comparaison en temps

library(microbenchmark)
library(ggplot2)

tm <- microbenchmark(runif(1),runifCpp(),times=1000L)
autoplot(tm)
## Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Constat

L'utilisation de fonction codées en R comme runif, rnorm ou autre vont être plus longues à tourner si elles sont implémentées en C++. Il s'agit de fonctions déjà implémentées en C qui sont sont déjà rapides en R.

#include <RcppArmadillo.h>
// [[Rcpp::depends(Matrix,RcppArmadillo)]]
using namespace Rcpp;
using namespace arma;

// [[Rcpp::export]]
double runifCpp2()
{
  return randu();
}

Nouvelle comparaison

tm <- microbenchmark(runif(1),runifCpp(),runifCpp2(),times=1000L)
autoplot(tm)
## Coordinate system already present. Adding new coordinate system, which will replace the existing one.

L'importation de fonctions R

L'importation de fonction R est donc à utiliser avec parcimonie et doit se limiter qu'à certains cas :

  • une fonction R à structure complexe et difficilement transposable
  • dans un package R, utilisation de fonctions qui sont modifiées en fonction du contexte

Exercice

Exercice

  1. Importer la fonction optim de R dans une fonction optimisation C++
  2. Réécrire la fonction de vraissemblance en C++ pour ne prendre que theta en entrée (randn à utiliser)
  3. Faire l'optimisation de la vraissemblance (sans descente de gradient) avec la fonction optimisation
  4. À l'aide du package microbenchmark comparer les temps de l'optimisation en R et en C++

Correction

Optimisation

#include "RcppArmadillo.h"
// [[Rcpp::depends(RcppArmadillo)]]
using namespace arma;
using namespace Rcpp;
  
double norme2(vec x) {
  return as_scalar(sqrt(sum(pow(x,2))));
}

// [[Rcpp::export]]
double frCpp(vec theta) {
  vec X = (randn(1000)+1)/2;
  const double pi = 3.141592653589793238462643383280; 
  int n = X.n_elem;
  double m = theta[0];
  double sigma2 = theta[1];
  return -( -(n/2)*log(sigma2*2*pi) - pow(norme2(X-m),2)/(2*sigma2) ); 
}

Optimisation

#include "RcppArmadillo.h"
// [[Rcpp::depends(RcppArmadillo)]]
using namespace arma;
using namespace Rcpp;

// [[Rcpp::export]]
vec optimisation(vec thetaInit, Function fn){
  Function optim("optim");
  List resOpt = as<List>(optim(thetaInit,fn));
  return resOpt["par"];
}

Optimisation

optimisation(c(0,1),frCpp)
##           [,1]
## [1,] 0.5703562
## [2,] 0.3068187

Optimisation

tm <- microbenchmark(optimisation(c(0,1),frCpp),optim(c(0,1),fr),times=1000L)
autoplot(tm)
## Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Rcpp dans un Package R

Utiliser Rcpp dans un package

Dans un package R utiliser la fonction de devtools

devtools::use_rcpp()

Le lancement de cette fonction :

  • génère un dossier src
  • fait les modifications nécessaires dans le fichier DESCRIPTION
  • créer un fichier .gitignore (si le gestionnaire de version git est utilisé)

Dans le dossier src

Le code C++ doit se situer dans le dossier src. (Fichier > Nouveau > Fichier C++)

Les parties chronophages du package doivent être implémentées dans un fichier dans lequel les fonctions utiles sont exportées par [[Rcpp::export]].


La documentation de fonction Rcpp est aussi gérée par Roxygen

Exercice

Exercice

  1. Créer un nouveau package appelé optimisation
  2. Lancer la commande devtools::use_rcpp()
  3. Copier les fonctions de vraissemblance dans un nouveau fichier C++
  4. Construire le package (Ctrl+Maj+b)
  5. Tester la fonction optimisation du package dans R