将 Rcpp 函数扩展到任何类型的输入向量 [英] Extending Rcpp function to input vector of any type

查看:51
本文介绍了将 Rcpp 函数扩展到任何类型的输入向量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下函数,它在 NumericVector 上做一个简单的循环并返回 int 类型值.

I have following function which does a simple loop on NumericVector and returns int type value.

  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

功能对我来说很好,但真正的问题是我试图在其他输入类型上扩展此功能.我一直在搜索堆栈 here此处,但这些示例在我的案例或我不知道如何正确使用示例.我尝试了几种处理未知输入类型的方法,但在我的情况下没有成功.下面三个例子

Function works fine for me but the real issue is when I'm trying to extend this functionality on other input-types. I've been searching on stack here and here, but those examples doesn't work in my case or I don't know how to use examples properly. I've tried few methods dealing with unknown input type, and none was successful in my case. Three examples below

  1. 最简单的灵感来自这个 -创建了 main 函数,它根据参数 TYPEOF(x) 的类型运行先前定义的函数之一.此函数返回integernumeric 的预期值.对于 character 会话崩溃

  1. The simplest one inspired by this - created main function which run one of previously defined functions depending on type of argument TYPEOF(x). This function returns expected value for integer and numeric. For character session crashes

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) 

<小时>

  1. 第二个函数有完全相同的想法,但使用模板而不是定义多个函数.结果与上述相同 - 会话在 character 输入时崩溃

  1. Second function has exactly the same idea, but using template instead of defining multiple functions. Same results as above - session crash on character input

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)

<小时>

  1. 另一个灵感来自这篇文章,并且这次我什至无法编译 C++ 函数,同时有一个错误使用重载运算符 '==' 是模棱两可的.无论如何,在检查了上述两个示例之后,我不期望有任何其他结果.

  1. Another one is inspired by this article, and this time I wasn't even able to compile C++ function, while having an error use of overloaded operator '==' is ambiguous. Anyway, after examining two above examples, I don't expect any other result.

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 类的输入向量的结果?
我很乐意提供任何建议.


So my question is: How to properly define this function to obtain results for input vector of any R class?
I would be obliged for any advices.

推荐答案

我认为示例中的主要错误是您在 j = 0 处开始循环,因此您调用 operator[](-1).以下对我有用.制作以下 func.cpp

I think the main error in examples are that you start your loop at j = 0 so you call operator[](-1). The following works for me. Make the following 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 文件的目录

Then run this R script with the working directory set to that of the .cpp file

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)

这篇关于将 Rcpp 函数扩展到任何类型的输入向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆