Ответ 1
Прежде всего, отказ от ответственности: я все время использую Rcpp. Фактически, когда (будучи переименованным по времени из Rcpp) RcppTemplate уже осиротел и без обновлений в течение двух лет, я начал поддерживать его под своим начальным именем Rcpp (в соответствии с которым он был внесен в RQuantLib). Это было около года назад, и я сделал пару дополнительных изменений, которые вы можете найти задокументированными в ChangeLog.
Теперь RcppTemplate совсем недавно вернулся через полные тридцать пять месяцев без каких-либо обновлений или исправлений. Он содержит интересный новый код, но кажется, что он не совместим с обратной связью, поэтому я не буду использовать его, где я уже использовал Rcpp.
Rcppbind не поддерживался очень активно, когда я проверял. У Whit Armstrong также есть шаблонный пакет интерфейса, называемый rabstraction.
Inline - это нечто совершенно другое: он упрощает цикл компиляции/ссылки путем "встраивания" вашей программы в строку символов R, которая затем скомпилируется, связывается и загружается. Я поговорил с Олегом о поддержке встроенной поддержки Rcpp, которая была бы приятной.
Swig тоже интересно. Джо Ван сделал отличную работу и завернул все QuantLib для R. Но когда я в последний раз его пробовал, он больше не работал из-за некоторых изменений внутри R. По словам кого-то из команды Swig, Джо все еще может работать над этим. В любом случае, цель Swig - большие библиотеки. Этот проект, вероятно, мог бы сделать с возрождением, но это не лишено технических проблем.
Еще одно упоминание следует перейти к RInside, который работает с Rcpp и позволяет вставлять R внутри приложений на С++.
Итак, чтобы подвести итог: Rcpp работает хорошо для меня, особенно для небольших исследовательских проектов, где вы просто хотите добавить функцию или два. Основное внимание уделяется простоте использования, и это позволяет вам "скрыть" некоторые из внутренних элементов R, с которыми не всегда приятно работать. Я знаю о многих других пользователях, которых я помогал и отправлял по электронной почте. Поэтому я бы сказал, пойти на это.
В учебниках "Введение в HPC с R" есть примеры Rcpp, RInside и inline.
Изменить: Итак, посмотрим на конкретный пример (взятый из слайдов "HPC с R Intro" и заимствованный у Стивена Милборроу, который взял его у Venables и Ripley). Задача состоит в перечислении всех возможных комбинаций определителя матрицы 2x2, содержащей только отдельные цифры в каждой позиции. Это можно сделать умными векторизованными способами (как мы обсудим в слайдах учебника) или грубой силой следующим образом:
#include <Rcpp.h>
RcppExport SEXP dd_rcpp(SEXP v) {
SEXP rl = R_NilValue; // Use this when there is nothing to be returned.
char* exceptionMesg = NULL; // msg var in case of error
try {
RcppVector<int> vec(v); // vec parameter viewed as vector of ints
int n = vec.size(), i = 0;
if (n != 10000)
throw std::length_error("Wrong vector size");
for (int a = 0; a < 9; a++)
for (int b = 0; b < 9; b++)
for (int c = 0; c < 9; c++)
for (int d = 0; d < 9; d++)
vec(i++) = a*b - c*d;
RcppResultSet rs; // Build result set to be returned as list to R
rs.add("vec", vec); // vec as named element with name 'vec'
rl = rs.getReturnList(); // Get the list to be returned to R.
} catch(std::exception& ex) {
exceptionMesg = copyMessageToR(ex.what());
} catch(...) {
exceptionMesg = copyMessageToR("unknown reason");
}
if (exceptionMesg != NULL)
Rf_error(exceptionMesg);
return rl;
}
Если вы сохраните это как, скажем, dd.rcpp.cpp
и установите Rcpp, просто используйте
PKG_CPPFLAGS=`Rscript -e 'Rcpp:::CxxFlags()'` \
PKG_LIBS=`Rscript -e 'Rcpp:::LdFlags()'` \
R CMD SHLIB dd.rcpp.cpp
для создания общей библиотеки. Мы используем Rscript
(или r
), чтобы спросить Rcpp о своих местах заголовка и библиотеки. После построения мы можем загрузить и использовать это из R следующим образом:
dyn.load("dd.rcpp.so")
dd.rcpp <- function() {
x <- integer(10000)
res <- .Call("dd_rcpp", x)
tabulate(res$vec)
}
Точно так же вы можете отправлять векторы, матчи,... различных типов данных R и С++ обратно с легкостью. Надеюсь, что это поможет.
Изменить 2 (примерно через 5 лет):
Таким образом, этот ответ получил только верхнюю позицию и, следовательно, вырос в моей очереди. Прошло много времени с тех пор, как я написал его, и Rcpp получил намного более богатые возможности. Поэтому я очень быстро написал это
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::IntegerVector dd2(Rcpp::IntegerVector vec) {
int n = vec.size(), i = 0;
if (n != 10000)
throw std::length_error("Wrong vector size");
for (int a = 0; a < 9; a++)
for (int b = 0; b < 9; b++)
for (int c = 0; c < 9; c++)
for (int d = 0; d < 9; d++)
vec(i++) = a*b - c*d;
return vec;
}
/*** R
x <- integer(10000)
tabulate( dd2(x) )
*/
который можно использовать следующим образом с кодом в файле /tmp/dd.cpp
R> Rcpp::sourceCpp("/tmp/dd.cpp") # on from any other file and path
R> x <- integer(10000)
R> tabulate( dd2(x) )
[1] 87 132 105 155 93 158 91 161 72 104 45 147 41 96
[15] 72 120 36 90 32 87 67 42 26 120 41 36 27 75
[29] 20 62 16 69 19 28 49 45 12 18 11 57 14 48
[43] 10 18 7 12 6 46 23 10 4 10 4 6 3 38
[57] 2 4 2 3 2 2 1 17
R>
Некоторые из ключевых отличий:
- более простая сборка: просто
sourceCpp()
it; даже выполняет тестовый код R в конце - полнофункциональный
IntegerVector
тип - обертка для обработки исключений, автоматически добавленная генератором кода
sourceCpp()