在 R 包的 rcpp 函数中使用自定义 Rcpp class。 class 和函数都在同一个 .cpp 文件中定义
Using custom Rcpp class in rcpp-function in an R-package. Both class and function are defined in the same .cpp file
我正在尝试使用 Rcpp 加速 R 数组维度的循环。
数组 class 来自 rcpp-gallery: (https://github.com/RcppCore/rcpp-gallery/blob/gh-pages/src/2014-03-21-simple-array-class.Rmd
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <Rcpp.h>
using namespace Rcpp ;
/*
******************************************************************************
Offset and Array classes based on code by Romain Francois copied from
http://comments.gmane.org/gmane.comp.lang.r.rcpp/5932 on 2014-01-07.
******************************************************************************
*/
class Offset{
private:
IntegerVector dim ;
public:
Offset( IntegerVector dim ) : dim(dim) {}
int operator()( IntegerVector ind ){
int ret = ind[0] ;
int offset = 1 ;
for(int d=1; d < dim.size(); d++) {
offset = offset * dim[d-1] ;
ret = ret + ind[d] * offset ;
}
return ret ;
} ;
IntegerVector getDims() const {
return(dim) ;
};
} ;
class Array : public NumericVector {
private:
// NumericVector value;
Offset dims ;
public:
//Rcpp:as
Array( SEXP x) : NumericVector(x),
dims( (IntegerVector)((RObject)x).attr("dim") ) {}
Array( NumericVector x, Offset d ): NumericVector(x),
dims(d) {}
Array( Dimension d ): NumericVector( d ), dims( d ) {}
IntegerVector getDims() const {
return(dims.getDims());
};
NumericVector getValue() const {
return(*((NumericVector*)(this)));
};
inline double& operator()( IntegerVector ind) {
int vecind = dims(ind);
NumericVector value = this->getValue();
return value(vecind);
} ;
// change dims without changing order of elements (!= aperm)
void resize(IntegerVector newdim) {
int n = std::accumulate((this->getDims()).begin(), (this->getDims()).end(), 1,
std::multiplies<int>());
int nnew = std::accumulate(newdim.begin(), newdim.end(), 1,
std::multiplies<int>());
if(n != nnew) stop("old and new old dimensions don't match.");
this->dims = Offset(newdim);
} ;
} ;
namespace Rcpp {
// wrap(): converter from Array to an R array
template <> SEXP wrap(const Array& A) {
IntegerVector dims = A.getDims();
//Dimension dims = A.getDims();
Vector<REALSXP> x = A;
x.attr( "dim" ) = wrap(dims);
return x;
}
}
// [[Rcpp::export]]
int runloop(Array& myarray) {
IntegerVector myarrayDims = myarray.getDims();
for (int j = 0; j < myarrayDims[1]; j++) {
for (int k = 0; k < myarrayDims[2]; k++) {
for (int l = 0; l < myarrayDims[3]; l++) {
for (int i = 0; i < myarrayDims[0]; i++) {
myarray({i, j, k, l}) = i + j + k +l;
}
}
}
}
return 0;
}
从交互式 R 会话获取和执行此代码按预期工作。
library(Rcpp)
sourceCpp(file.path(".", "minimalExample.cpp"))
inputArray <- array(data = rnorm(10^4), dim = c(10, 10, 10, 10))
runloop(inputArray)
inputArray
但是,当我将 .cpp 文件移动到我的 R 包结构的 src 文件夹中时,构建失败,因为无法识别 class 数组 (see screenshot of build errors)
构建失败后RcppExports.cpp内容如下:
// Generated by using Rcpp::compileAttributes() -> do not edit by hand
// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
#include <RcppArmadillo.h>
#include <Rcpp.h>
using namespace Rcpp;
// runloop
int runloop(Array& myarray);
RcppExport SEXP _foobar_runloop(SEXP myarraySEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< Array& >::type myarray(myarraySEXP);
rcpp_result_gen = Rcpp::wrap(runloop(myarray));
return rcpp_result_gen;
END_RCPP
}
static const R_CallMethodDef CallEntries[] = {
{"_foobar_runloop", (DL_FUNC) &_foobar_runloop, 1},
{NULL, NULL, 0}
};
RcppExport void R_init_foobar(DllInfo *dll) {
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}
如何获得我的简单循环 运行?
谢谢:)
ps:我在 R-Studio 中的 sessionInfo() returns:
R version 3.6.1 (2019-07-05)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19041)
Matrix products: default
locale:
[1] LC_COLLATE=English_Germany.1252 LC_CTYPE=English_Germany.1252 LC_MONETARY=English_Germany.1252 LC_NUMERIC=C
[5] LC_TIME=English_Germany.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] Rcpp_1.0.5
loaded via a namespace (and not attached):
[1] compiler_3.6.1 tools_3.6.1
有句话叫先走后走运行。您错过了步行和短跑之间的慢跑步骤 ;-)。
在您提供的单个函数中编译的代码与在 full-blown 包中不同。你想做的可以完成而且已经完成了。简而言之,虽然您在 source 文件中编写了代码,但它还需要出现在 generated file src/RcppExports.cpp
中。
生成代码中的类型 部分的 Rcpp 属性小插图中描述了您现在缺少的一个技巧,我引用(编辑掉 markdown/latex)
Types in Generated Code
In some cases the signatures of the C++ functions that are generated within
RcppExports.cpp
may have additional type requirements beyond the core
standard library and Rcpp
types (e.g. CharacterVector
,
NumericVector
, etc.). Examples might include convenience typedefs,
as/wrap handlers for marshaling between custom types and SEXP, or types
wrapped by the Rcpp XPtr
template.
In this case, you can create a header file that contains these type definitions
(either defined inline or by including other headers) and have this header
file automatically included in RcppExports.cpp
. Headers named with
the convention pkgname_types
are automatically included along with
the generated C++ code. For example, if your package is named fastcode
then any of the following header files would be automatically included in
RcppExports.cpp
:
src/fastcode_types.h
src/fastcode_types.hpp
inst/include/fastcode_types.h
inst/include/fastcode_types.hpp
[...]
我正在尝试使用 Rcpp 加速 R 数组维度的循环。 数组 class 来自 rcpp-gallery: (https://github.com/RcppCore/rcpp-gallery/blob/gh-pages/src/2014-03-21-simple-array-class.Rmd
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
#include <Rcpp.h>
using namespace Rcpp ;
/*
******************************************************************************
Offset and Array classes based on code by Romain Francois copied from
http://comments.gmane.org/gmane.comp.lang.r.rcpp/5932 on 2014-01-07.
******************************************************************************
*/
class Offset{
private:
IntegerVector dim ;
public:
Offset( IntegerVector dim ) : dim(dim) {}
int operator()( IntegerVector ind ){
int ret = ind[0] ;
int offset = 1 ;
for(int d=1; d < dim.size(); d++) {
offset = offset * dim[d-1] ;
ret = ret + ind[d] * offset ;
}
return ret ;
} ;
IntegerVector getDims() const {
return(dim) ;
};
} ;
class Array : public NumericVector {
private:
// NumericVector value;
Offset dims ;
public:
//Rcpp:as
Array( SEXP x) : NumericVector(x),
dims( (IntegerVector)((RObject)x).attr("dim") ) {}
Array( NumericVector x, Offset d ): NumericVector(x),
dims(d) {}
Array( Dimension d ): NumericVector( d ), dims( d ) {}
IntegerVector getDims() const {
return(dims.getDims());
};
NumericVector getValue() const {
return(*((NumericVector*)(this)));
};
inline double& operator()( IntegerVector ind) {
int vecind = dims(ind);
NumericVector value = this->getValue();
return value(vecind);
} ;
// change dims without changing order of elements (!= aperm)
void resize(IntegerVector newdim) {
int n = std::accumulate((this->getDims()).begin(), (this->getDims()).end(), 1,
std::multiplies<int>());
int nnew = std::accumulate(newdim.begin(), newdim.end(), 1,
std::multiplies<int>());
if(n != nnew) stop("old and new old dimensions don't match.");
this->dims = Offset(newdim);
} ;
} ;
namespace Rcpp {
// wrap(): converter from Array to an R array
template <> SEXP wrap(const Array& A) {
IntegerVector dims = A.getDims();
//Dimension dims = A.getDims();
Vector<REALSXP> x = A;
x.attr( "dim" ) = wrap(dims);
return x;
}
}
// [[Rcpp::export]]
int runloop(Array& myarray) {
IntegerVector myarrayDims = myarray.getDims();
for (int j = 0; j < myarrayDims[1]; j++) {
for (int k = 0; k < myarrayDims[2]; k++) {
for (int l = 0; l < myarrayDims[3]; l++) {
for (int i = 0; i < myarrayDims[0]; i++) {
myarray({i, j, k, l}) = i + j + k +l;
}
}
}
}
return 0;
}
从交互式 R 会话获取和执行此代码按预期工作。
library(Rcpp)
sourceCpp(file.path(".", "minimalExample.cpp"))
inputArray <- array(data = rnorm(10^4), dim = c(10, 10, 10, 10))
runloop(inputArray)
inputArray
但是,当我将 .cpp 文件移动到我的 R 包结构的 src 文件夹中时,构建失败,因为无法识别 class 数组 (see screenshot of build errors)
构建失败后RcppExports.cpp内容如下:
// Generated by using Rcpp::compileAttributes() -> do not edit by hand
// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
#include <RcppArmadillo.h>
#include <Rcpp.h>
using namespace Rcpp;
// runloop
int runloop(Array& myarray);
RcppExport SEXP _foobar_runloop(SEXP myarraySEXP) {
BEGIN_RCPP
Rcpp::RObject rcpp_result_gen;
Rcpp::RNGScope rcpp_rngScope_gen;
Rcpp::traits::input_parameter< Array& >::type myarray(myarraySEXP);
rcpp_result_gen = Rcpp::wrap(runloop(myarray));
return rcpp_result_gen;
END_RCPP
}
static const R_CallMethodDef CallEntries[] = {
{"_foobar_runloop", (DL_FUNC) &_foobar_runloop, 1},
{NULL, NULL, 0}
};
RcppExport void R_init_foobar(DllInfo *dll) {
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}
如何获得我的简单循环 运行? 谢谢:)
ps:我在 R-Studio 中的 sessionInfo() returns:
R version 3.6.1 (2019-07-05)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19041)
Matrix products: default
locale:
[1] LC_COLLATE=English_Germany.1252 LC_CTYPE=English_Germany.1252 LC_MONETARY=English_Germany.1252 LC_NUMERIC=C
[5] LC_TIME=English_Germany.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] Rcpp_1.0.5
loaded via a namespace (and not attached):
[1] compiler_3.6.1 tools_3.6.1
有句话叫先走后走运行。您错过了步行和短跑之间的慢跑步骤 ;-)。
在您提供的单个函数中编译的代码与在 full-blown 包中不同。你想做的可以完成而且已经完成了。简而言之,虽然您在 source 文件中编写了代码,但它还需要出现在 generated file src/RcppExports.cpp
中。
生成代码中的类型 部分的 Rcpp 属性小插图中描述了您现在缺少的一个技巧,我引用(编辑掉 markdown/latex)
Types in Generated Code
In some cases the signatures of the C++ functions that are generated within
RcppExports.cpp
may have additional type requirements beyond the core standard library andRcpp
types (e.g.CharacterVector
,NumericVector
, etc.). Examples might include convenience typedefs, as/wrap handlers for marshaling between custom types and SEXP, or types wrapped by the RcppXPtr
template.In this case, you can create a header file that contains these type definitions (either defined inline or by including other headers) and have this header file automatically included in
RcppExports.cpp
. Headers named with the conventionpkgname_types
are automatically included along with the generated C++ code. For example, if your package is namedfastcode
then any of the following header files would be automatically included inRcppExports.cpp
:src/fastcode_types.h src/fastcode_types.hpp inst/include/fastcode_types.h inst/include/fastcode_types.hpp
[...]