代码之家  ›  专栏  ›  技术社区  ›  Amy_777

Rcpp调用的c++计数算法模板

  •  1
  • Amy_777  · 技术社区  · 6 年前

    Rcpp调用的C++计数算法,它可以计算向量中特定元素的出现。 应该使用模板。 我的尝试:

    countRcpp <-'
    #include<iostream>
    #include<vector>
    using namespace std;
    
      int val = as<int>(y);
      NumericVector xx(x);
      NumericVector::iterator iter;
      int m = 0;
    
      for(iter = xx.begin(); iter < xx.end(); iter++){
        if(*iter == val) ++m;}
    
      return(wrap(m));
    '
    countf <- cxxfunction(signature(x = "numeric", y = "numeric"),
                          body = countRcpp,
                          plugin = "Rcpp")
    
    set.seed (1005) # set seed for sampling
    x <- sample(1:5L, size = 10, replace = T) #L is Long integer. Keep the nunmber as integer. 
    x # [1] 1 3 1 3 3 4 1 3 1 2
    y <- 3L
    y
    countf(x,y) 
    
    
    incl <- '
    #include<iostream>
    #include <algorithm>  
    #include <vector> 
    using namespace std;
    
      template <typename S_Type, typename T>
      typename iterator_traits<S_Type>::difference_type 
    
      S_Type countR(S_Type first, S_Type last, const T & val){
        typename iterator_traits<S_Type>::difference_type ret=0;
        while (first !=last){
        if(*first == val) ++ret;
        ++first;
        }
      return ret;
      }
    '
    body_count <- '
    #include<iostream>
    #include<vector>
    #include <algorithm>    
    
    using namespace std;
    
      NumericVector xx(x);
      int n = xx.size();
      NumericVector yy = xx + n;
      int val = as<int>(y);
      int pos = countR(xx, yy, val);
      return wrap(pos);
    '
    countRcpp3 <- cxxfunction(signature(x = "numeric", y = "numeric"),
                  body = body_count,
                  includes = incl,
                  plugin = "Rcpp")
    

    你能给我一些建议吗?或者你会推荐其他符合逻辑的任务吗?提前谢谢。

    1 回复  |  直到 6 年前
        1
  •  4
  •   Ralf Stubner    6 年前

    作为第一步,您可以提取带有签名的函数

    int foo(Rcpp::IntegerVector x, int val)
    

    从你的工作代码。然后可以将其泛化为对任何iterable类型执行操作。签名:

    template <typename T>
    int foo(T x, typename std::iterator_traits<typename T::iterator>::value_type val) 
    

    不过,我们不能把这叫做R。如果R中的函数应该作用于不同的类型,它必须 SEXP 作为论据。 TYPEOF() 然后可用于确定R数据类型。将此集合用于整数向量:

    #include <Rcpp.h>
    
    template <typename T>
    int iter_count(T x, typename std::iterator_traits<typename T::iterator>::value_type val) { 
      int m = 0;
    
      for(typename T::iterator iter = x.begin(); iter < x.end(); ++iter) {
        if(*iter == val) ++m;
     }
    
      return m;
    }
    
    
    // [[Rcpp::export]]
    int count(SEXP x, SEXP val) {
      switch( TYPEOF(x) ) {
      case INTSXP: {
        return iter_count(Rcpp::as<Rcpp::IntegerVector>(x),
                  Rcpp::as<Rcpp::IntegerVector>(val)(0));
      }
      default: {
        Rcpp::stop("incompatible SEXP encountered");
      }
      }  
    }
    
    
    /*** R
    set.seed (1005)
    x <- sample(1:5L, size = 10, replace = T)
    y <- 3L
    count(x,y) 
    */
    

    我在这里使用Rcpp属性:将其保存为 .cpp 文件和使用 Rcpp::sourceCpp("...") 在上面。

    顺便说一下,在你的代码中,这看起来很可疑:

      NumericVector xx(x);
      int n = xx.size();
      NumericVector yy = xx + n;
    

    你想知道 xx ? 然后使用 xx.end() end(xx) ,它不是 NumericVector . 你的代码创建了一个新的 数字向量 其中的内容 二十 已经被 二十 . 这里是使用Rcpp属性的等效代码:

    Rcpp::cppFunction('NumericVector foo(NumericVector xx) {
      int n = xx.size();
      NumericVector yy = xx + n;
      return yy;
    }
    ')
    
    set.seed(42)
    foo(runif(3))
    # [1] 3.914806 3.937075 3.286140