在Rcpp Armadillo中将S4对象转换为矩阵类型

时间:2017-06-12 12:55:40

标签: r rcpp armadillo

RcppArmadillo的项目中,我有一些矩阵(例如mat A,B,C;)和一个S4对象,例如: D(来自R中的外部函数)。由于我需要在这些矩阵和D之间进行一些计算,我想转换" D"在RcppArmadillo中使用合适的数据类型,例如arma::mat D。 可能吗?这样做的最佳方法是什么? 这是一个类似的代码:

#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
Rcpp::List func1(arma::mat A, arma::mat B){

  // Incoming
  Rcpp::List outcome;
  arma::mat rvecs;
  arma::vec rvals;
   Rcpp::Environment Matrix("package:Matrix"); 
   Rcpp::Function nearPD = Matrix["nearPD"];

 // Computation   
 Rcpp::List PD=nearPD(B);
 Rcpp::S4 D = PD["mat"];
 eig_sym(rvals, rvecs, D);
 arma::mat RI12_hat = rvecs * arma::diagmat(1.0/sqrt(rvals)) * rvecs.t();
  arma::mat diff = A - D;

  // Release results
  outcome = Rcpp::List::create(Rcpp::Named("rvals")    = rvals, 
                               Rcpp::Named("RI12_hat") = RI12_hat, 
                               Rcpp::Named("rvecs")    = rvecs);
  return outcome;   
}

其中D是类dpoMatrix的矩阵,计算的正定矩阵和错误消息是&#34; no matching for operator&#34;。

1 个答案:

答案 0 :(得分:3)

不幸的是,dpoMatrix对象还没有as<>()wrap()。但是,使用S4类,我们可以提取必要的组件并使用armadillo's advanced ctor for matrices重用内存。首先,我们必须通过查看dpoMatrix或构建示例来理解documentation for the underlying Matrix class对象。

请考虑以下事项:

B <- matrix(1, 3,3); B[1,3] <- B[3,1] <- 0
n.B <- nearPD(B, corr=TRUE, do2eigen=FALSE)
str(n.B)

这给出了:

List of 7
 $ mat        :Formal class 'dpoMatrix' [package "Matrix"] with 5 slots
  .. ..@ x       : num [1:9] 1 0.761 0.157 0.761 1 ...
  .. ..@ Dim     : int [1:2] 3 3
  .. ..@ Dimnames:List of 2
  .. .. ..$ : NULL
  .. .. ..$ : NULL
  .. ..@ uplo    : chr "U"
  .. ..@ factors : list()
 $ eigenvalues: num [1:3] 2.157 0.843 -0.679
 $ corr       : logi TRUE
 $ normF      : num 0.528
 $ iterations : num 18
 $ rel.tol    : num 6.48e-08
 $ converged  : logi TRUE
 - attr(*, "class")= chr "nearPD"

因此,我们可以从x广告位中检索矩阵的,并使用Dim成员函数检索.slot("name_here")广告位的维度。

实施

话虽如此,我们将按照以下方式快速实施:

#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
Rcpp::List magic_func(arma::mat A, arma::mat B){

  // Incoming
  Rcpp::List outcome;
  arma::mat rvecs;
  arma::vec rvals;
  Rcpp::Environment Matrix("package:Matrix"); // Load the Matrix package in R!
  Rcpp::Function nearPD = Matrix["nearPD"];   // Extract nearPD() R function

  // Compute with R function an S4 object
  Rcpp::List PD = nearPD(B);
  Rcpp::S4 D_s4 = PD["mat"];

  // Convert the S4 object to an Armadillo matrix
  Rcpp::NumericVector temp = Rcpp::NumericVector(D_s4.slot("x"));
  Rcpp::NumericVector dims = D_s4.slot("Dim");

  // Advanced armadillo matrix ctor that reuses memory
  arma::mat D(temp.begin(), // pointer to NumericVector
              dims[0],      // Number of Rows
              dims[1],      // Number of Columns
              false,        // Avoid copying by disabling `copy_aux_mem`
              true);        // Bind memory by enabling `strict`

  // Computation
  eig_sym(rvals, rvecs, D);
  arma::mat RI12_hat = rvecs * arma::diagmat(1.0/sqrt(rvals)) * rvecs.t();
  arma::mat diff = A - D;

  // Return result
  outcome = Rcpp::List::create(Rcpp::Named("rvals")    = rvals, 
                               Rcpp::Named("RI12_hat") = RI12_hat, 
                               Rcpp::Named("rvecs")    = rvecs);
  return outcome;   
}

测试

代码:

set.seed(27)
A = matrix(round(rnorm(9),2), 3, 3)
A = A + t(A)

B = matrix(1, 3, 3); B[1,3] <- B[3,1] <- 0

magic_func(A, B)

结果:

$rvals
             [,1]
[1,] 2.414214e-08
[2,] 1.000000e+00
[3,] 2.414214e+00

$RI12_hat
          [,1]      [,2]      [,3]
[1,]  1609.647 -2275.222  1608.647
[2,] -2275.222  3218.293 -2275.222
[3,]  1608.647 -2275.222  1609.647

$rvecs
           [,1]          [,2]      [,3]
[1,] -0.5000000 -7.071068e-01 0.5000000
[2,]  0.7071068 -7.077672e-16 0.7071068
[3,] -0.5000000  7.071068e-01 0.5000000