使用rmultinom和Rcpp

时间:2014-07-07 19:31:55

标签: c++ r rcpp bayesian mcmc

我想在c ++代码中使用R函数 rmultinom 与Rcpp一起使用。我得到一个关于参数不足的错误 - 我不熟悉这些参数应该是什么,因为他们不同意R中函数使用的参数。我也没有运气使用“:: Rf_foo”从Rcpp代码访问R函数的语法。

以下是我的代码的简化版本(是的,我正在编写一个gibbs采样器)。

#include <Rcpp.h>                                                                                                                                     
using namespace Rcpp;                                                                                                                                 

// C++ implementation of the R which() function.                                                                                                      
int whichC(NumericVector x, double val) {                                                                                                             
  int ind = -1;                                                                                                                                       
  int n = x.size();                                                                                                                                   
  for (int i = 0; i < n; ++i) {                                                                                                                       
    if (x[i] == val) {                                                                                                                                
      if (ind == -1) {                                                                                                                                
        ind = i;                                                                                                                                      
      } else {                                                                                                                                        
        throw std::invalid_argument( "value appears multiple times." );                                                                               
      }                                                                                                                                               
    } // end if                                                                                                                                       
  } // end for                                                                                                                                        
  if (ind != -1) {                                                                                                                                    
    return ind;                                                                                                                                       
  } else {                                                                                                                                            
    throw std::invalid_argument( "value doesn't appear here!" );                                                                                      
    return -1;                                                                                                                                        
  }                                                                                                                                                   
}                                                                                                                                                     

// [[Rcpp::export]]                                                                                                                                   
int multSample(double p1, double p2, double p3) {                                                                                                     
  NumericVector params(3);                                                                                                                            
  params(0) = p1;                                                                                                                                     
  params(1) = p2;                                                                                                                                     
  params(2) = p3;                                                                                                                                     

  // HERE'S THE PROBLEM.                                                                                                                              
  RObject sampled = rmultinom(1, 1, params);                                                                                                          
  int out = whichC(as<NumericVector>(sampled), 1);                                                                                                    
  return out;                                                                                                                                         
}

我是c ++的新手,所以我意识到很多这样的代码可能都是高效且低效的。我愿意接受有关如何改进我的c ++代码的建议,但我的首要任务是听取rmultinom业务。谢谢!

顺便说一句,我为与this thread的相似性道歉,但是

  1. 答案对我的目的不起作用
  2. 差异可能足以保证一个不同的问题(你这么认为吗?)
  3. 一年前发布并回答了这个问题。

3 个答案:

答案 0 :(得分:3)

下面是user95215修改的答案,以便编译,另一个版本更多的是Rcpp风格:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
IntegerVector oneMultinomC(NumericVector probs) {
    int k = probs.size();
    SEXP ans;
    PROTECT(ans = Rf_allocVector(INTSXP, k));
    probs = Rf_coerceVector(probs, REALSXP);
    rmultinom(1, REAL(probs), k, &INTEGER(ans)[0]);
    UNPROTECT(1);
    return(ans);
}

// [[Rcpp::export]]
IntegerVector oneMultinomCalt(NumericVector probs) {
    int k = probs.size();
    IntegerVector ans(k);
    rmultinom(1, probs.begin(), k, ans.begin());
    return(ans);
}

答案 1 :(得分:0)

如果我尝试编译代码,我会收到编译错误:

> Rcpp::sourceCpp('~/scratch/multSample.cpp')
multSample.cpp:33:21: error: no matching function for call to 'rmultinom'
  RObject sampled = rmultinom(1, 1, params);
                    ^~~~~~~~~
/Library/Frameworks/R.framework/Resources/include/Rmath.h:449:6: note: candidate function not viable: requires 4 arguments, but 3 were provided
void    rmultinom(int, double*, int, int*);
        ^
1 error generated.

正如它所暗示的那样,你还没有正确地指定参数。请注意,与其他函数相比,rmultinom接口有点尴尬:它填充*rn指向的内存,而不是返回一个新对象(具有自己新分配的内存)。

如果您查看the R sources,您会看到该界面,并且您可以看到它的使用示例here(实际上,stats制作了一个包装器执行更多参数检查和诸如此类的函数)。但请注意它在这里的使用方式:

rmultinom(size, REAL(prob), k, &INTEGER(ans)[ik]);

换句话说,它通过将该内存的地址传递给INTSXP函数来填充名为ans的{​​{1}}。

因此,如果你想使用rmultinom中的这个函数,你必须做类似的事情 - 但也许这应该采用类似的糖矢量化处理来避免界面的丑陋。

您可以尝试执行以下操作:

Rcpp

或者那种效果。

答案 2 :(得分:0)

Kevin提供的示例和链接使我找到了有效的答案。有一些类型的争论。我编写了一个函数,允许您从多项分布中采样一个向量。代码如下。

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector oneMultinomC(NumericVector probs) {
    int k = probs.size();
    SEXP ans;
    PROTECT(ans = RF_allocVector(INTSXP, k));
    probs = RF_coerceVector(probs, REALSXP);
    rmultinom(1, REAL(probs), k, &INTEGER(ans)[0]);
    UNPROTECT(1);
    return ans;
}

我不明白这里发生了一半的事情。特别是,我不理解“rmultinom&#39;”的第四个论点。我知道它是一个指向存储输出存储位置的指针,但我不理解&#39; [0]&#39;位。尽管如此,它仍然有效。 Gibbs取样,男孩和女孩。