将 Rcpp 函数扩展到任何类型的输入向量
Extending Rcpp function to input vector of any type
我有以下函数,它对 NumericVector
和 returns int
类型值进行简单循环。
Rcpp::cppFunction({'
int calc_streak( NumericVector x, int i1, int i2){
int cur_streak=1;
if (NumericVector::is_na(x[0])){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
for(int j = i1; j <= i2 ; ++j) {
if( x[ j ] == x[ j-1 ]){
cur_streak += 1;
} else if(NumericVector::is_na( x[ j ] )){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
}
return cur_streak;
}
"})
calc_streak(c(1,1,1,1),i1=0,i2=3)
# [1] 4
功能对我来说工作正常,但真正的问题是我试图在其他输入类型上扩展此功能。我一直在堆栈 and here 上搜索,但这些示例在我的情况下不起作用,或者我不知道如何正确使用示例。我尝试了几种处理未知输入类型的方法,none 在我的案例中是成功的。
下面三个例子
受 this 启发的最简单的函数 - 创建了 main 函数,该函数 运行 是先前定义的函数之一,具体取决于参数类型 TYPEOF(x)
。 此函数 returns integer
和 numeric
的预期值。 character
会话崩溃
Rcpp::cppFunction('
#include <Rcpp.h>
using namespace Rcpp;
int streak_run_int(IntegerVector x, int i1, int i2){
int cur_streak=1;
if (IntegerVector::is_na(x[0])){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
for(int j = i1; j <= i2 ; ++j) {
if( x[ j ] == x[ j-1 ]){
cur_streak += 1;
} else if(IntegerVector::is_na( x[ j ] )){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
}
return cur_streak;
}
int streak_run_char(CharacterVector x, int i1, int i2){
int cur_streak=1;
if (CharacterVector::is_na(x[0])){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
for(int j = i1; j <= i2 ; ++j) {
if( x[ j ] == x[ j-1 ]){
cur_streak += 1;
} else if(CharacterVector::is_na( x[ j ] )){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
}
return cur_streak;
}
// [[Rcpp::export]]
int streak_run4(SEXP x, int i1, int i2) {
switch (TYPEOF(x)) {
case INTSXP: {
return streak_run_int(as<IntegerVector>(x), i1, i2);
}
case STRSXP: {
return streak_run_char(as<CharacterVector>(x), i1, i2);
}
default: { return 0; }
}
}
')
# expected results for int and real - for character session crashes
streak_run4( c(1,1,1,1),i1=0, i2=3)
streak_run4( as.integer(c(1,1,1,1)),i1=0, i2=3)
streak_run4( as.character(c(1,1,1,1)),i1=0, i2=3)
第二个函数的思路完全一样,只是使用模板而不是定义多个函数。结果与上面相同 - character
输入
时会话崩溃
Rcpp::cppFunction('
#include <Rcpp.h>
using namespace Rcpp;
namespace impl {
template <int RTYPE>
int streak_run_impl(const Vector<RTYPE>& x, int i1, int i2)
{
int cur_streak=1;
if (Vector<RTYPE>::is_na(x[0])){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
for(int j = i1; j <= i2 ; ++j) {
if( x[ j ] == x[ j-1 ]){
cur_streak += 1;
} else if(Vector<RTYPE>::is_na( x[ j ] )){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
}
return cur_streak;
}
}
// [[Rcpp::export]]
int streak_run3(SEXP x, int i1, int i2) {
switch (TYPEOF(x)) {
case INTSXP: {
return impl::streak_run_impl(as<IntegerVector>(x), i1, i2);
}
case REALSXP: {
return impl::streak_run_impl(as<NumericVector>(x), i1, i2);
}
case STRSXP: {
return impl::streak_run_impl(as<CharacterVector>(x), i1, i2);
}
case LGLSXP: {
return impl::streak_run_impl(as<LogicalVector>(x), i1, i2);
}
case CPLXSXP: {
return impl::streak_run_impl(as<ComplexVector>(x), i1, i2);
}
default: {
return 0;
}
}
}
')
streak_run3( c(1,1,1,1),i1=0, i2=3)
streak_run3( as.integer(c(1,1,1,1)),i1=0, i2=3)
streak_run3( as.character(c(1,1,1,1)),i1=0, i2=3)
还有一个是受this article的启发,这次连C++函数都编译不出来,报错use of overloaded operator '==' is ambiguous
。无论如何,在检查了上述两个示例之后,我不希望有任何其他结果。
Rcpp::cppFunction('
#include <Rcpp.h>
using namespace Rcpp;
class streak_run2_impl {
private:
int i1;
int i2;
public:
streak_run2_impl(int i1, int i2) : i1(i1), i2(i2) {}
template <int RTYPE>
IntegerVector operator()(const Vector<RTYPE>& x)
{
int cur_streak=1;
if (Vector<RTYPE>::is_na(x[0])){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
for(int j = i1; j <= i2 ; ++j) {
if( x[ j ] == x[ j-1 ] ){
cur_streak += 1;
} else if(Vector<RTYPE>::is_na( x[ j ] )){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
}
return cur_streak;
}
};
// [[Rcpp::export]]
RObject streak_run2(RObject x, int i1 = 0, int i2=6){
RCPP_RETURN_VECTOR(streak_run2_impl(i1, i2), x);
}
')
所以我的问题是:
如何正确定义此函数以获得任何 R class?
输入向量的结果
我很乐意提供任何建议。
我认为示例中的主要错误是您在 j = 0
开始循环,所以调用了 operator[](-1)
。以下对我有用。进行以下func.cpp
#include <Rcpp.h>
#include <algorithm>
using namespace Rcpp;
template <int RTYPE>
int streak_run_impl(const Vector<RTYPE>& x, int i1, int i2)
{
int cur_streak = 1;
if (Vector<RTYPE>::is_na(x[0])){
cur_streak = NA_INTEGER;
} else {
cur_streak = 1;
}
for(int j = std::max(i1, 1) /* have to start at one at least */;
j < std::min(i2 + 1, (int)x.size()) /* check size of x */; ++j){
if(x[j] == x[j - 1]){
cur_streak += 1;
} else if(Vector<RTYPE>::is_na(x[j])){
cur_streak = NA_INTEGER;
} else {
cur_streak = 1;
}
}
return cur_streak;
}
// [[Rcpp::export]]
int streak_run3(SEXP x, int i1, int i2) {
switch (TYPEOF(x)) {
case INTSXP: {
return streak_run_impl(as<IntegerVector>(x), i1, i2);
}
case REALSXP: {
return streak_run_impl(as<NumericVector>(x), i1, i2);
}
case STRSXP: {
return streak_run_impl(as<CharacterVector>(x), i1, i2);
}
case LGLSXP: {
return streak_run_impl(as<LogicalVector>(x), i1, i2);
}
case CPLXSXP: {
return streak_run_impl(as<ComplexVector>(x), i1, i2);
}
default: {
return 0;
}
}
}
然后 运行 此 R 脚本的工作目录设置为 .cpp
文件
Rcpp::sourceCpp("func.cpp")
streak_run3(c(1,1,1,1), i1=0, i2=3)
streak_run3(as.integer(c(1,1,1,1)), i1=0, i2=3)
streak_run3(as.character(c(1,1,1,1)), i1=0, i2=3)
首先,很好post!不幸的是,您链接的上述资源中的 none 与您的问题相关,因为它是由于原型函数中未发现的完全不同的错误所致。对于 why 原型在调用时返回了一个有效值,这纯属运气。
正如@BenjaminChristoffersen 指出的那样,代码 运行 发生 undefined behavior (UB) due to an out-of-bounds (OOB) 错误。他的解决方案将有效 "fix" 问题。
但是,要在将来自行诊断此问题,请从使用元素访问器 []
切换到 ()
,后者会检查您请求的元素是否在范围内。例如j在0到n - 1?
例如
if (Vector<RTYPE>::is_na( x( 0 ) )){
// ------------------------^---^
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
for(int j = i1; j <= i2 ; ++j) {
if( x( j ) == x( j-1 )){
// ^---^-----^-----^
cur_streak += 1;
} else if(Vector<RTYPE>::is_na( x( j ) )){
// --------------------------- ^ ^
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
}
运行 相同的命令然后给出:
streak_run3( c(1,1,1,1),i1=0, i2=3)
输出:
Error in streak_run3(c(1, 1, 1, 1), i1 = 0, i2 = 3) :
Index out of bounds: [index=-1; extent=4].
输入:
streak_run3( as.integer(c(1,1,1,1)),i1=0, i2=3)
输出:
Error in streak_run3(as.integer(c(1, 1, 1, 1)), i1 = 0, i2 = 3) :
Index out of bounds: [index=-1; extent=4].
输入:
streak_run3( as.character(c(1,1,1,1)),i1=0, i2=3)
输出:
Error in streak_run3(as.character(c(1, 1, 1, 1)), i1 = 0, i2 = 3) :
Index out of bounds: [index=-1; extent=4].
我有以下函数,它对 NumericVector
和 returns int
类型值进行简单循环。
Rcpp::cppFunction({'
int calc_streak( NumericVector x, int i1, int i2){
int cur_streak=1;
if (NumericVector::is_na(x[0])){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
for(int j = i1; j <= i2 ; ++j) {
if( x[ j ] == x[ j-1 ]){
cur_streak += 1;
} else if(NumericVector::is_na( x[ j ] )){
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
}
return cur_streak;
}
"})
calc_streak(c(1,1,1,1),i1=0,i2=3)
# [1] 4
功能对我来说工作正常,但真正的问题是我试图在其他输入类型上扩展此功能。我一直在堆栈
受 this 启发的最简单的函数 - 创建了 main 函数,该函数 运行 是先前定义的函数之一,具体取决于参数类型
TYPEOF(x)
。 此函数 returnsinteger
和numeric
的预期值。character
会话崩溃Rcpp::cppFunction(' #include <Rcpp.h> using namespace Rcpp; int streak_run_int(IntegerVector x, int i1, int i2){ int cur_streak=1; if (IntegerVector::is_na(x[0])){ cur_streak = NumericVector::get_na(); } else { cur_streak = 1; } for(int j = i1; j <= i2 ; ++j) { if( x[ j ] == x[ j-1 ]){ cur_streak += 1; } else if(IntegerVector::is_na( x[ j ] )){ cur_streak = NumericVector::get_na(); } else { cur_streak = 1; } } return cur_streak; } int streak_run_char(CharacterVector x, int i1, int i2){ int cur_streak=1; if (CharacterVector::is_na(x[0])){ cur_streak = NumericVector::get_na(); } else { cur_streak = 1; } for(int j = i1; j <= i2 ; ++j) { if( x[ j ] == x[ j-1 ]){ cur_streak += 1; } else if(CharacterVector::is_na( x[ j ] )){ cur_streak = NumericVector::get_na(); } else { cur_streak = 1; } } return cur_streak; } // [[Rcpp::export]] int streak_run4(SEXP x, int i1, int i2) { switch (TYPEOF(x)) { case INTSXP: { return streak_run_int(as<IntegerVector>(x), i1, i2); } case STRSXP: { return streak_run_char(as<CharacterVector>(x), i1, i2); } default: { return 0; } } } ') # expected results for int and real - for character session crashes streak_run4( c(1,1,1,1),i1=0, i2=3) streak_run4( as.integer(c(1,1,1,1)),i1=0, i2=3) streak_run4( as.character(c(1,1,1,1)),i1=0, i2=3)
第二个函数的思路完全一样,只是使用模板而不是定义多个函数。结果与上面相同 -
时会话崩溃character
输入Rcpp::cppFunction(' #include <Rcpp.h> using namespace Rcpp; namespace impl { template <int RTYPE> int streak_run_impl(const Vector<RTYPE>& x, int i1, int i2) { int cur_streak=1; if (Vector<RTYPE>::is_na(x[0])){ cur_streak = NumericVector::get_na(); } else { cur_streak = 1; } for(int j = i1; j <= i2 ; ++j) { if( x[ j ] == x[ j-1 ]){ cur_streak += 1; } else if(Vector<RTYPE>::is_na( x[ j ] )){ cur_streak = NumericVector::get_na(); } else { cur_streak = 1; } } return cur_streak; } } // [[Rcpp::export]] int streak_run3(SEXP x, int i1, int i2) { switch (TYPEOF(x)) { case INTSXP: { return impl::streak_run_impl(as<IntegerVector>(x), i1, i2); } case REALSXP: { return impl::streak_run_impl(as<NumericVector>(x), i1, i2); } case STRSXP: { return impl::streak_run_impl(as<CharacterVector>(x), i1, i2); } case LGLSXP: { return impl::streak_run_impl(as<LogicalVector>(x), i1, i2); } case CPLXSXP: { return impl::streak_run_impl(as<ComplexVector>(x), i1, i2); } default: { return 0; } } } ') streak_run3( c(1,1,1,1),i1=0, i2=3) streak_run3( as.integer(c(1,1,1,1)),i1=0, i2=3) streak_run3( as.character(c(1,1,1,1)),i1=0, i2=3)
还有一个是受this article的启发,这次连C++函数都编译不出来,报错
use of overloaded operator '==' is ambiguous
。无论如何,在检查了上述两个示例之后,我不希望有任何其他结果。Rcpp::cppFunction(' #include <Rcpp.h> using namespace Rcpp; class streak_run2_impl { private: int i1; int i2; public: streak_run2_impl(int i1, int i2) : i1(i1), i2(i2) {} template <int RTYPE> IntegerVector operator()(const Vector<RTYPE>& x) { int cur_streak=1; if (Vector<RTYPE>::is_na(x[0])){ cur_streak = NumericVector::get_na(); } else { cur_streak = 1; } for(int j = i1; j <= i2 ; ++j) { if( x[ j ] == x[ j-1 ] ){ cur_streak += 1; } else if(Vector<RTYPE>::is_na( x[ j ] )){ cur_streak = NumericVector::get_na(); } else { cur_streak = 1; } } return cur_streak; } }; // [[Rcpp::export]] RObject streak_run2(RObject x, int i1 = 0, int i2=6){ RCPP_RETURN_VECTOR(streak_run2_impl(i1, i2), x); } ')
所以我的问题是:
如何正确定义此函数以获得任何 R class?
输入向量的结果
我很乐意提供任何建议。
我认为示例中的主要错误是您在 j = 0
开始循环,所以调用了 operator[](-1)
。以下对我有用。进行以下func.cpp
#include <Rcpp.h>
#include <algorithm>
using namespace Rcpp;
template <int RTYPE>
int streak_run_impl(const Vector<RTYPE>& x, int i1, int i2)
{
int cur_streak = 1;
if (Vector<RTYPE>::is_na(x[0])){
cur_streak = NA_INTEGER;
} else {
cur_streak = 1;
}
for(int j = std::max(i1, 1) /* have to start at one at least */;
j < std::min(i2 + 1, (int)x.size()) /* check size of x */; ++j){
if(x[j] == x[j - 1]){
cur_streak += 1;
} else if(Vector<RTYPE>::is_na(x[j])){
cur_streak = NA_INTEGER;
} else {
cur_streak = 1;
}
}
return cur_streak;
}
// [[Rcpp::export]]
int streak_run3(SEXP x, int i1, int i2) {
switch (TYPEOF(x)) {
case INTSXP: {
return streak_run_impl(as<IntegerVector>(x), i1, i2);
}
case REALSXP: {
return streak_run_impl(as<NumericVector>(x), i1, i2);
}
case STRSXP: {
return streak_run_impl(as<CharacterVector>(x), i1, i2);
}
case LGLSXP: {
return streak_run_impl(as<LogicalVector>(x), i1, i2);
}
case CPLXSXP: {
return streak_run_impl(as<ComplexVector>(x), i1, i2);
}
default: {
return 0;
}
}
}
然后 运行 此 R 脚本的工作目录设置为 .cpp
文件
Rcpp::sourceCpp("func.cpp")
streak_run3(c(1,1,1,1), i1=0, i2=3)
streak_run3(as.integer(c(1,1,1,1)), i1=0, i2=3)
streak_run3(as.character(c(1,1,1,1)), i1=0, i2=3)
首先,很好post!不幸的是,您链接的上述资源中的 none 与您的问题相关,因为它是由于原型函数中未发现的完全不同的错误所致。对于 why 原型在调用时返回了一个有效值,这纯属运气。
正如@BenjaminChristoffersen 指出的那样,代码 运行 发生 undefined behavior (UB) due to an out-of-bounds (OOB) 错误。他的解决方案将有效 "fix" 问题。
但是,要在将来自行诊断此问题,请从使用元素访问器 []
切换到 ()
,后者会检查您请求的元素是否在范围内。例如j在0到n - 1?
例如
if (Vector<RTYPE>::is_na( x( 0 ) )){
// ------------------------^---^
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
for(int j = i1; j <= i2 ; ++j) {
if( x( j ) == x( j-1 )){
// ^---^-----^-----^
cur_streak += 1;
} else if(Vector<RTYPE>::is_na( x( j ) )){
// --------------------------- ^ ^
cur_streak = NumericVector::get_na();
} else {
cur_streak = 1;
}
}
运行 相同的命令然后给出:
streak_run3( c(1,1,1,1),i1=0, i2=3)
输出:
Error in streak_run3(c(1, 1, 1, 1), i1 = 0, i2 = 3) :
Index out of bounds: [index=-1; extent=4].
输入:
streak_run3( as.integer(c(1,1,1,1)),i1=0, i2=3)
输出:
Error in streak_run3(as.integer(c(1, 1, 1, 1)), i1 = 0, i2 = 3) :
Index out of bounds: [index=-1; extent=4].
输入:
streak_run3( as.character(c(1,1,1,1)),i1=0, i2=3)
输出:
Error in streak_run3(as.character(c(1, 1, 1, 1)), i1 = 0, i2 = 3) :
Index out of bounds: [index=-1; extent=4].