有没有办法使用矩阵的非连续视图
即。喜欢在
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
s作为函数参数的上下文。由于A.submat(0,0,2,2)
是rtype
,我无法将其作为非const参数传递给函数,而在函数内部,我需要能够以非非连续的方式访问元素。
最小(非工作)示例也可以看出我的意思可能是以下
#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列表中),还是有一个比我聪明的人有优雅的解决方案?
谢谢!
侧注:
答案 0 :(得分:-1)
subview
时,他/她/它使用了不同的类(arma::matrix<T >operator()
)......当你找到时(和我来这里回答)这是一个Rvalue所以它不能被引用...但是类arma::matrix<T>
的元素可以由类子视图的对象初始化(那么为什么它们不创建使用子视图作为左值的访问函数?为什么他们甚至创建了类子视图?)...我认为他们可以通过一些模板和Move()
来解决这个问题,但是从底层继承到像arma::mat
这样的上层calsses。
(你要求的问题不仅发生在稀疏矩阵上,即使在密集矩阵上,它只有在你放f(const arma:mat& )
但你不能修改它时才有效)
解决方案:没有,我尝试使用std :: move()将子视图的rvalue欺骗为一个空矩阵,标记时间来执行这些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编译和启动显示与构造函数副本或std :: move()没有区别。尝试arma::mat B(std::move(A(i,j))
没有区别,时间与func()
相同(由于变量声明而略高于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值,而不是矩阵本身。