Вопрос

Каков наилучший способ использовать библиотеку C ++ в R, надеюсь, с сохранением структур данных C ++?Я совсем не пользователь C ++, поэтому мне неясны относительные достоинства доступных подходов.Руководство R-ext, похоже, предлагает обернуть каждую функцию C ++ в C.Однако существует по меньшей мере четыре или пять других способов включения C ++.

Существуют пакеты с похожим происхождением в двух вариантах: Rcpp (поддерживается плодовитым overflower Дирком Эддельбюттелем) и RcppTemplate (оба на CRAN), в чем разница между ними?

Доступен другой пакет, rcppbind, на R forge, который утверждает, что использует другой подход к привязке C ++ и R (я не достаточно осведомлен, чтобы сказать).

Встроенный пакет, доступный на CRAN, утверждает, что разрешает встроенный C / C ++, я не уверен, что это отличается от встроенной функциональности, за исключением того, что позволяет коду быть встроенным w / R.

И, наконец, RSwig, который, по-видимому, в дикой природе но неясно, насколько это поддерживается, поскольку страница автора не обновлялся уже много лет.

Мой вопрос заключается в том, каковы относительные достоинства этих различных подходов.Которые являются наиболее портативными и надежными, которые проще всего реализовать.Если бы вы планировали распространять пакет на CRAN, какой из методов вы бы использовали?

Это было полезно?

Решение

Во-первых, отказ от ответственности:Я использую Rcpp все время.Фактически, когда (будучи переименованным к тому времени из Rcpp) RcppTemplate уже был осиротевшим и без обновлений в течение двух лет, я начал поддерживать его под первоначальным именем Rcpp (под которым он был внесен в RQuantLib).Это было около года назад, и я внес пару постепенных изменений, которые вы можете найти задокументированными в журнале изменений.

Теперь RcppTemplate совсем недавно вернулся после полных тридцати пяти месяцев без каких-либо обновлений или исправлений.Он содержит интересный новый код, но, похоже, он не имеет обратной совместимости, поэтому я не буду использовать его там, где я уже использовал Rcpp.

Rcppbind - Привязка поддерживался не очень активно всякий раз, когда я проверял.Уит Армстронг также имеет шаблонный интерфейсный пакет под названием расстраивание.

Встроенный это что-то совершенно другое:это облегчает цикл компиляции / компоновки, "встраивая" вашу программу в виде символьной строки R, которая затем компилируется, связывается и загружается.Я говорил с Олегом о наличии встроенной поддержки Rcpp, что было бы неплохо.

Глоток это тоже интересно.Джо Ван проделал там отличную работу и завернул весь QuantLib для R.Но когда я в последний раз пробовал это, это больше не работало из-за некоторых изменений во внутренних компонентах R.По словам кого-то из команды Swig, Джо, возможно, все еще работает над этим.В любом случае, цель Swig - увеличить размер библиотек.Этот проект, вероятно, не помешал бы возродить, но он не лишен технических проблем.

Еще одно упоминание следует отнести к Ополаскиватель который работает с Rcpp и позволяет встраивать R в приложения на C ++.

Итак, подведем итог: Rcpp у меня это хорошо работает, особенно для небольших исследовательских проектов, где вы просто хотите добавить одну-две функции.Основное внимание уделяется простоте использования, и это позволяет вам "скрыть" некоторые внутренние компоненты R, с которыми не всегда интересно работать.Я знаю несколько других пользователей, которым я время от времени помогал по электронной почте.Так что я бы сказал, остановите свой выбор на этом.

В моих руководствах "Введение в HPC с R" есть несколько примеров Rcpp, RInside и inline.

Редактировать: Итак, давайте посмотрим на конкретный пример (взят из слайдов "HPC with R Intro" и позаимствован у Стивена Милборроу, который позаимствовал его у Венейблса и Рипли).Задача состоит в том, чтобы перечислить все возможные комбинации определителя матрицы 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 и C ++ к другому.Надеюсь, это хоть немного поможет.

Правка 2 (более пяти лет спустя):

Итак, этот ответ только что получил одобрение и, следовательно, появился в моей очереди.A лот с тех пор, как я это написал, прошло много времени, и 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() генератор кода
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top