【发布时间】:2014-03-21 18:32:02
【问题描述】:
我正在尝试使用RcppArmadillo 定义一个可以处理稀疏和密集矩阵输入的模板函数。我得到了一个非常简单的例子,将密集或稀疏矩阵发送到 C++ 并返回到 R 以像这样工作:
library(inline); library(Rcpp); library(RcppArmadillo)
sourceCpp(code = "
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp ;
using namespace arma ;
template <typename T> T importexport_template(const T X) {
T ret = X ;
return ret ;
};
//[[Rcpp::export]]
SEXP importexport(SEXP X) {
return wrap( importexport_template(X) ) ;
}")
library(Matrix)
X <- diag(3)
X_sp <- as(X, "dgCMatrix")
importexport(X)
## [,1] [,2] [,3]
##[1,] 1 0 0
##[2,] 0 1 0
##[3,] 0 0 1
importexport(X_sp)
##3 x 3 sparse Matrix of class "dgCMatrix"
##
##[1,] 1 . .
##[2,] . 1 .
##[3,] . . 1
我解释这意味着模板基本上可以工作(即,密集的 R 矩阵变成了 arma::mat,而稀疏的 R 矩阵通过隐式调用变成了 arma::sp_mat-object Rcpp::as 和相应的隐含 Rcpp:wraps 然后也做正确的事情,并为密集返回密集,为稀疏返回稀疏)。
我尝试编写的实际函数当然需要多个参数,这就是我失败的地方 - 执行以下操作:
sourceCpp(code ="
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp ;
using namespace arma ;
template <typename T> T scalarmult_template(const T X, double scale) {
T ret = X * scale;
return ret;
};
//[[Rcpp::export]]
SEXP scalarmult(SEXP X, double scale) {
return wrap(scalarmult_template(X, scale) ) ;
}")
失败,因为编译器不知道如何在编译时为 SEXPREC* const 解析 *。
所以我想我需要类似 switch 语句 in this Rcpp Gallery snippet 之类的东西来正确调度到特定的模板函数,但我不知道如何为看起来比 INTSXP 等更复杂的类型编写它。
我想我知道如何访问此类 switch 语句所需的类型,例如:
sourceCpp(code ="
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp ;
using namespace arma ;
//[[Rcpp::export]]
SEXP printtype(SEXP Xr) {
Rcpp::Rcout << TYPEOF(Xr) << std::endl ;
return R_NilValue;
}")
printtype(X)
##14
##NULL
printtype(X_sp)
##25
##NULL
但我不明白如何从那里开始。适用于稀疏和密集矩阵的scalarmult_template 版本会是什么样子?
【问题讨论】:
-
这比较棘手,因为您希望同时在 S4(即 TYPEOF 返回 25)和原始类型上分派。我建议在 R 级别处理调度,然后让你的 C++ 代码更简单。否则,您需要类似
if (Rf_isS4(Xr) && Rf_inherits(Xr, "<MatrixClass>")) {...} -
@KevinUshey:谢谢!我正在根据您的建议添加我自己的问题的答案。