使用RcppArmadillo修改输入

时间:2016-04-11 20:34:08

标签: c++ r rcpp armadillo

我正在尝试使用RcppArmadillo实现完全旋转的LU分解。幸运的是,我有this Matlab代码可以满足我的需求,但我遇到了一些将其转换为Armadillo的挑战。

我想让我的arma::LU函数像arma::LU一样输入L,U和P,Rcpp函数修改L,U和P矩阵输入而不是返回L,U和P.

我知道通过常规NumericVector example(NumericVector X) { X = 2 * X; return X; } 您可以轻松修改输入:

arma::colvec example(arma::colvec X) {
    X = 2 * X;
    return X;
}

这将返回两次输入的向量,并将输入更改为其原始值的两倍。但是,我很快发现这对RcppArmadillo不起作用。

arma

据我所知,当暴露给R时,这不会改变输入,因为#include <RcppArmadillo.h> using namespace Rcpp; // [[Rcpp::depends(RcppArmadillo)]] int gecpLU(arma::mat L, arma::mat U, arma::mat P, arma::mat Q, arma::mat A) { // Take A and overwrite LUPQ such that A=P*L*U*Q int n=A.n_rows; P.eye(n,n); Q.eye(n,n); arma::mat AA=A; // for (int i=0;i<(n-1);i++) { // delete a whole bunch of stuff not relevant to question // } L.eye(n,n); arma::mat tempmat=arma::trimatl(AA); tempmat.diag()*=0; L=L-tempmat; U=arma::trimatu(AA); return 0; } // [[Rcpp::export]] List test(arma::mat A) { arma::mat L1,U1,P1,L2,U2,P2,Q; arma::lu(L1,U1,P1,A); gecpLU(L2,U2,P2,Q,A); return List::create(_["L1"]=L1, _["U1"]=U1, _["P1"]=P1, _["L2"]=L2, _["U2"]=U2, _["P2"]=P2, _["Q"]=Q); } 对象是R对象的副本,所以你不能直接修改R对象,但我觉得我应该仍然是能像这样编写像Armadillo的LU这样的函数:

gecpLU

在这种情况下,我没有将R矩阵传递给我的arma::mat函数,而是test所以它应该能够修改输入。

当我运行{{1}}时,我得到L1,U1和P1的矩阵,但是L2,U2,P2和Q的矩阵是0x0。我觉得我必须误解一些东西。是否可以使用RcppArmadillo修改输入?如果不是,输出4个矩阵的最佳方法是什么?一个清单?

1 个答案:

答案 0 :(得分:2)

下:

int gecpLU(arma::mat L, arma::mat U, arma::mat P, arma::mat Q, arma::mat A)

您正在为每个矩阵创建新副本,然后在函数结束时将其销毁。

您期望的是对象被修改。为此,您需要在对象类型的末尾追加&,以便编译器知道获取对象的引用。

void gecpLU(arma::mat& L, arma::mat& U, arma::mat& P, arma::mat& Q, arma::mat& A)

注意,我还将gecpLU的返回类型从int更改为void。参见:

#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::depends(RcppArmadillo)]]
void gecpLU(arma::mat& L, arma::mat& U, arma::mat& P, arma::mat& Q, arma::mat& A) {
  // Take A and overwrite LUPQ such that A=P*L*U*Q
  int n=A.n_rows;
  P.eye(n,n);
  Q.eye(n,n);
  arma::mat AA=A;
  // for (int i=0;i<(n-1);i++) {
  // delete a whole bunch of stuff not relevant to question
  // }
  L.eye(n,n);
  arma::mat tempmat=arma::trimatl(AA);
  tempmat.diag()*=0;
  L=L-tempmat;
  U=arma::trimatu(AA);
}

// [[Rcpp::export]]
List test(arma::mat A) {
  arma::mat L1,U1,P1,L2,U2,P2,Q;
  arma::lu(L1,U1,P1,A);
  gecpLU(L2,U2,P2,Q,A);
  return List::create(_["L1"]=L1,
                      _["U1"]=U1,
                      _["P1"]=P1,
                      _["L2"]=L2,
                      _["U2"]=U2,
                      _["P2"]=P2,
                      _["Q"]=Q);
}

简单的临时示例演示通过引用传递(启用修改)与通过副本传递(在最后销毁对象)

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

void reference_obj(arma::vec& y){
  y.fill(1);
}

void copy_obj(arma::vec y){
  y.fill(0);
}

// [[Rcpp::export]]
arma::vec on_reference_mod(arma::vec x) {

  reference_obj(x);

  return x;
}


// [[Rcpp::export]]
arma::vec on_copy_mod(arma::vec x) {

  copy_obj(x);

  return x;
}

/*** R
# Should get a vector of 1's
on_reference_mod(1:10)

# Should get a vector of 1:10
on_copy_mod(1:10)
*/