[英]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列表中),还是比我聪明的人有一个优雅的解决方案?
谢谢!
旁注 :
当您在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.