繁体   English   中英

犰狳:arma :: subview的非连续视图

[英]Armadillo: non-contiguous views of arma::subview

有没有办法使用矩阵的非连续视图

即喜欢

arma::mat A = arma::zeros(3,3);
arma::uvec idx = {0,2};
A(idx,idx) += 2;

但是使用矩阵A的子视图?

arma::subview<double> swA = A.submat(0,0,2,2);
swA(idx,idx) += 2.5;

这最后一点不编译为

 error: no match for call to ‘(arma::subview<double>) (arma::uvec&, arma::uvec&)’    
swA(idx,idx) += 2.5;

只是提供一些上下文信息,可以帮助我将arma::subviewc用作函数的参数。 由于A.submat(0,0,2,2)rtype我无法将其作为非常量参数传递给函数,并且在函数内部,我需要能够以非非连续方式访问元素。

一个最小的(非工作)示例也明白我的意思可能是以下内容

#include <iostream>
#include <armadillo>

void f(arma::subview<double> x)
{ 
  arma::uvec i = {0,2};
  arma::uvec j = {1,2};
  x(i,j)  += 2.5;
}

int main ()
{

  arma::mat A = arma::zeros(5,5);
  std::cout << A << std::endl;

  f(A.submat(0,0,2,2));
  std::cout << A << std::endl;

  return 0;
}

gcc再次返回

 error: no match for call to ‘(arma::subview<double>) (arma::uvec&, arma::uvec&)’

解决此问题的愚蠢做法是复制矩阵,将其作为参考传递,然后复制回A:

#include <iostream>
#include <armadillo>

void f(arma::mat& x)
{ 
  arma::uvec i = {0,2};
  arma::uvec j = {1,2};
  x(i,j)  += 2.5;
}

int main ()
{

  arma::mat A = arma::zeros(5,5);
  std::cout << A << std::endl;

  arma::mat B = A.submat(0,0,2,2);
  f(B);
  A.submat(0,0,2,2) = B;
  std::cout << A << std::endl;

  return 0;
}

可以编译并完美运行,但是我需要避免不惜一切代价复制矩阵(A比5x5大得多!)

再次明确,我无法执行以下操作

[...]
void f(arma::mat& x)
{ 
  arma::uvec i = {0,2};
  arma::uvec j = {1,2};
  x(i,j)  += 2.5;
}
[...]
f(A.submat(0,0,2,2));

因为子视图将是一个rtype ,我将从gcc获得

invalid initialization of non-const reference of type ‘arma::mat& {aka arma::Mat<double>&}’ from an rvalue of type ‘arma::mat {aka arma::Mat<double>}

我有麻烦吗(只是一个实现问题,不在开发人员的TODO列表中),还是比我聪明的人有一个优雅的解决方案?

谢谢!

旁注

  • 如果在那里做这样的事情微不足道,我愿意将线性代数库更改为其他库(例如Eigen或其他),但是我宁愿不这样做,因为我已经使用armadillo多年了,而且我一直非常满意...
  • 我知道有可能在我展示的简单代码中使用循环和更简单的子视图来获得相同的结果,但是实际代码更加复杂,并且该子视图将在矩阵运算中使用,因此我必须循环并将子矩阵复制到一个临时对象中,我想避免

当您在arma::matrix<T >operator()调用方法arma::matrix<T >operator() ,他/她/它使用了一个不同的类( subview )。...并且您发现(和我来这里回答的我)一个Rvalue,因此它不能被引用...但是类arma::matrix<T>元素可以由子视图类的对象初始化(因此为什么他们不创建访问函数以将子视图用作左值?,为什么他们甚至要为其创建类子视图?)...我认为他们可以使用一些模板和Move()解决此问题,但从底层继承到像arma::mat这样的高层。 (您要求的问题不仅发生在稀疏矩阵上,甚至发生在密集矩阵上,仅当您放置f(const arma:mat& )但无法修改时,该问题才起作用)

解决方案:没有,我尝试使用std :: move()将子视图的右值欺骗为一个空矩阵,将执行这3个循环的时间基准化为100000次;

/ ************************************ 1 ***************** ***** /

void f(arma::mat &B)
{
}

// [[Rcpp::export]]
int func()
{
  arma::mat A = arma::zeros(50,50);
  //std::cout <<"A:\n"<< A << std::endl;

  arma::uvec i = arma::regspace<arma::uvec>( 0, 1, 10);
  arma::uvec j = arma::regspace<arma::uvec>( 0, 1, 10);
  unsigned p=1;
  do{
    arma::mat B=A(i,j);
    f(B);
    A(i,j)= B;
    p++;
  }while(p<100000);
  return 0;
}

/ ************************** 2 ********************** * /

void f(arma::mat &B)
{
}

// [[Rcpp::export]]
int func2()
{
  arma::mat A = arma::zeros(50,50);
  arma::uvec i = arma::regspace<arma::uvec>( 0, 1, 10);
  arma::uvec j = arma::regspace<arma::uvec>( 0, 1, 10);
  unsigned p=1;
  arma::mat B;
  do{
    B=A(i,j);
    f(B);
    A(i,j) = B;
    p++;
  }while(p<100000);
  return 0;
}

/ ************************ 3 ********************** /

void f(arma::mat &B)
{
}

// [[Rcpp::export]]
int func3()
{
  arma::mat A = arma::zeros(50,50);
  arma::uvec i = arma::regspace<arma::uvec>( 0, 1, 10);
  arma::uvec j = arma::regspace<arma::uvec>( 0, 1, 10);
  unsigned p=1;
  arma::mat B;
  do{
    B=std::move(A(i,j));
    f(B);
    A(i,j)= std::move(B);
    p++;
  }while(p<100000);
  return 0;
}

从R编译和启动显示与构造函数copy或std :: move()没有区别。 甚至使用arma::mat B(std::move(A(i,j))尝试过,时间与func()相同func3()由于变量声明,它比func2()func3() )。

  Unit: milliseconds
    expr      min       lq     mean   median       uq      max neval cld
  func() 20.56159 20.68200 21.22679 20.98329 21.55746 27.62831  1000   b
 func2() 19.21450 19.37398 19.88782 19.66397 20.14731 27.86020  1000  a 
 func3() 19.19892 19.37547 19.89098 19.67835 20.17973 27.19525  1000  a 

这似乎是最快的(如先前的A(i,j)= std :: move(B)将B设置为0的大小,并且当B = A(i,j)时需要重新分配):

arma::mat B;
  do{
    B=std::move(A(i,j));
    f(B);
    A(i,j)= B;
    p++;
  }while(p<100000);
  return 0;

相同的基准

Unit: milliseconds
    expr      min       lq    mean   median       uq      max neval
 func4() 19.22223 19.30687 19.3907 19.33198 19.36293 23.20771  1000

std::move(A(i,j))似乎不影响矩阵A(不会松散其内容),因为A(i,j)是子视图的r值,而不是矩阵本身。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM