Создание простого пакета Rcpp с зависимостью от другого пакета Rcpp - PullRequest
0 голосов
/ 20 октября 2019

Я пытаюсь улучшить скорость вычисления моего цикла с помощью foreach, но внутри этого цикла я определил простую функцию Rcpp. Я сохранил функцию Rcpp как mproduct.cpp, и я вызываю функцию просто используя

sourceCpp("mproduct.cpp")

, и функция Rcpp является простой, которая должна выполнять матричный продукт в C ++:

// [[Rcpp::depends(RcppArmadillo, RcppEigen)]]

#include <RcppArmadillo.h>
#include <RcppEigen.h>

// [[Rcpp::export]]
SEXP MP(const Eigen::Map<Eigen::MatrixXd> A, Eigen::Map<Eigen::MatrixXd> B){
  Eigen::MatrixXd C = A * B;
  return Rcpp::wrap(C);
}

Итак, функция в файле Rcpp - MP, ссылаясь на матричное произведение. Мне нужно выполнить следующий цикл foreach (я упростил код для иллюстрации):

foreach(j=1:n, .package='Rcpp',.noexport= c("mproduct.cpp"),.combine=rbind)%dopar%{
n=1000000
A<-matrix(rnorm(n,1000,1000))
B<-matrix(rnorm(n,1000,1000))
S<-MP(A,B)
return(S)
} 

Поскольку размеры матриц A и B велики, поэтому я хочу использовать foreach для облегчениявычислительные затраты.

Однако приведенный выше код не работает, поскольку он выдает мне сообщение об ошибке:

task 1 failed - "NULL value passed as symbol address"

Причина, по которой я добавил .noexport= c("mproduct.cpp"), состоит в том, чтобы следовать некоторым советам людей, которыерешены похожие проблемы ( Невозможно запустить функцию Rcpp в foreach - "значение NULL передано как адрес символа" ). Но почему-то это не решает мою проблему.

Поэтому я попытался установить свою функцию Rcpp в качестве библиотеки. Я использовал следующий код:

Rcpp.package.skeleton('mp',cpp_files = "<my working directory>")

, но он возвращает мне предупреждающее сообщение:

The following packages are referenced using Rcpp::depends attributes however are not listed in the Depends, Imports or LinkingTo fields of the package DESCRIPTION file: RcppArmadillo, RcppEigen 

, поэтому, когда я попытался установить свой пакет, используя

install.packages("<my working directory>",repos = NULL,type='source')

Я получил предупреждение:

Error in untar2(tarfile, files, list, exdir, restore_times) : 
  incomplete block on file
In R CMD INSTALL
Warning in install.packages :
  installation of package ‘C:/Users/Lenovo/Documents/mproduct.cpp’ had non-zero exit status

Так может ли кто-нибудь помочь мне решить 1) использование foreach с функцией Rcpp MP или 2) установить файл Rcpp в виде пакета?

Спасибо всем большое.

1 Ответ

2 голосов
/ 20 октября 2019

Первым шагом было бы убедиться, что вы оптимизируете правильную вещь. Для меня это будет , а не , как показывает этот простой тест:

set.seed(42)
n <- 1000
A<-matrix(rnorm(n*n), n, n)
B<-matrix(rnorm(n*n), n, n)

MP <- Rcpp::cppFunction("SEXP MP(const Eigen::Map<Eigen::MatrixXd> A, Eigen::Map<Eigen::MatrixXd> B){
  Eigen::MatrixXd C = A * B;
  return Rcpp::wrap(C);
}", depends = "RcppEigen")

bench::mark(MP(A, B), A %*% B)[1:5]
#> # A tibble: 2 x 5
#>   expression      min   median `itr/sec` mem_alloc
#>   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>
#> 1 MP(A, B)    277.8ms    278ms      3.60    7.63MB
#> 2 A %*% B      37.4ms     39ms     22.8     7.63MB

Так что для меня матричный продукт через %*% в несколько раз быстрее, чем через RcppEigen. Однако я использую Linux с OpenBLAS для матричных операций, когда вы работаете в Windows, что часто означает ссылку на BLAS для матричных операций. может быть так, что RcppEigen быстрее в вашей системе. Я не уверен, насколько сложно пользователю Windows получить более быструю реализацию BLAS (https://csgillespie.github.io/efficientR/set-up.html#blas-and-alternative-r-interpreters может содержать некоторые указатели), но я бы посоветовал потратить некоторое время на изучение этого.

Теперь, если выПридя к выводу, что вам нужен RcppEigen или RcppArmadillo в вашем коде, и вы хотите поместить этот код в пакет, вы можете сделать следующее. Вместо Rcpp::Rcpp.package.skeleton() используйте RcppEigen::RcppEigen.package.skeleton() или RcppArmadillo::RcppArmadillo.package.skeleton(), чтобы создать отправную точку для пакета на основе RcppEigen или RcppArmadillo соответственно.

...