gpt4 book ai didi

c++ - RcppArmadillo 中稀疏和密集矩阵的模板函数

转载 作者:行者123 更新时间:2023-11-30 01:53:58 28 4
gpt4 key购买 nike

我正在尝试使用 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 - 隐式调用 Rcpp::as 的对象,相应的隐式 Rcpp:wrap 也会做正确的事情密集返回密集,稀疏返回稀疏)。

我尝试编写的实际函数当然需要多个参数,而这正是我失败的地方——做类似的事情:

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 版本会是什么样子?

最佳答案

根据@KevinUshey 的评论回答我自己的问题。我对 3 种情况进行矩阵乘法:密集-密集、稀疏-密集和“indMatrix”-密集:

library(inline)
library(Rcpp)
library(RcppArmadillo)
library(Matrix)
library(rbenchmark)

sourceCpp(code="
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>

using namespace Rcpp ;
using namespace arma ;

arma::mat matmult_sp(const arma::sp_mat X, const arma::mat Y){
arma::mat ret = X * Y;
return ret;
};
arma::mat matmult_dense(const arma::mat X, const arma::mat Y){
arma::mat ret = X * Y;
return ret;
};
arma::mat matmult_ind(const SEXP Xr, const arma::mat Y){
// pre-multplication with index matrix is a permutation of Y's rows:
S4 X(Xr);
arma::uvec perm = X.slot("perm");
arma::mat ret = Y.rows(perm - 1);
return ret;
};

//[[Rcpp::export]]
arma::mat matmult_cpp(SEXP Xr, const arma::mat Y) {
if (Rf_isS4(Xr)) {
if(Rf_inherits(Xr, "dgCMatrix")) {
return matmult_sp(as<arma::sp_mat>(Xr), Y) ;
} ;
if(Rf_inherits(Xr, "indMatrix")) {
return matmult_ind(Xr, Y) ;
} ;
stop("unknown class of Xr") ;
} else {
return matmult_dense(as<arma::mat>(Xr), Y) ;
}
}")

n <- 10000
d <- 20
p <- 30

X <- matrix(rnorm(n*d), n, d)
X_sp <- as(diag(n)[,1:d], "dgCMatrix")
X_ind <- as(sample(1:d, n, rep=TRUE), "indMatrix")
Y <- matrix(1:(d*p), d, p)

matmult_cpp(as(X_ind, "ngTMatrix"), Y)
## Error: unknown class of Xr

all.equal(X%*%Y, matmult_cpp(X, Y))
## [1] TRUE

all.equal(as.vector(X_sp%*%Y),
as.vector(matmult_cpp(X_sp, Y)))
## [1] TRUE

all.equal(X_ind%*%Y, matmult_cpp(X_ind, Y))
## [1] TRUE

编辑:这已变成 Rcpp Gallery post .

关于c++ - RcppArmadillo 中稀疏和密集矩阵的模板函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22513529/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com