简体   繁体   中英

c++ Eigen making copy?

Let A be a symmetric matrix and let v be a vector. I extract from A a block of n columns starting from j and multiply it by v using

VectorXd a;
a = A.middleCols(j,n).selfadjointView<Lower>() * v // does not compile

As this does not compile, whereas this

a = MatrixXd(A.middleCols(j,n).selfadjointView<Lower>()) * v

does, I am wondering whether the second version makes a copy of

A.middleCols(j,n).selfadjointView<Lower>()  

or performs the computation directly?

Thanks for any hint.

EDIT: I suspect the problem has something to do with argument types, as I get the error :

invalid argument type 'typename ConstSelfAdjointViewReturnType.... to unary expression' 

Indeed, A is the argument of a function passed by const reference using either of

const MatrixXd& A 
const Ref<const MatrixXd>& A

Here is an example:

// this version doesn't compile
MatrixXd returnSymmetricMatrix(const MatrixXd& A, const VectorXd& v, const MatrixXd& B){
// B is a symmetric matrix

VectorXd a;
a = A.middleCols(3, 4).selfadjointView<Lower>() * v;
MatrixXd M(code_fill(){...}); 
// code_fill is the function filling the lower triangular part of a symmetric matrix
M.block(1, 2, 3, 4).triangularView<Lower>() += B.selfadjointView<Lower>();

return M;
}

// this version compiles
MatrixXd returnSymmetricMatrix(const MatrixXd& A, const VectorXd& v, const MatrixXd& B){
// B is a symmetric matrix

VectorXd a;
a = MatrixXd(A.middleCols(3, 4).selfadjointView<Lower>()) * v;
MatrixXd M(code_fill(){...}); 
// code_fill is the function filling the lower triangular part of a symmetric matrix
Matrix(M.block(1, 2, 3, 4).triangularView<Lower>()) += B.selfadjointView<Lower>();

return M;
}

EDIT2 Regarding my initial question and the example I've added at the Edit section, I am a bit confused regarding the copying. As I understand the difference between the working and the non-working versions, the line

Matrix(M.block(1, 2, 3, 4).triangularView<Lower>()) += B.selfadjointView<Lower>();  

works because its lhs tells to Eigen that M.block(1, 2, 3, 4).triangularView() is actually a matrix rather than a reference to a matrix. Otherwise, the operator += would through an error that this operator is not overloaded for .block(). So my original question is whether Matrix(...) only tells that it's a Matrix to enable the computation, or rather copy the ... into a Matrix? Thanks!

The following expression:

A.middleCols(j,n).selfadjointView<Lower>() 

does not create any copy.

On the other hand, to avoid a temporary for the result of the product, you can add .noalias() :

a.noalias() = M.middleCols(j,n).selfadjointView<Lower>() * v;

This is only needed for the immediate assignment of dense product to allow code like:

a = M * a;

to behave as expected.

EDIT:

regarding your compilation issue, the following compiles fine:

#include <Eigen/Dense>
using namespace Eigen;
int main()
{
  int n = 10;
  MatrixXd M = MatrixXd::Random(n,2*n);
  VectorXd v = VectorXd::Random(n);
  VectorXd a;
  a.noalias() = M.middleCols(2,n).selfadjointView<Upper>() * v;

  const Ref<const MatrixXd>& A = M;
  a.noalias() = A.middleCols(2,n).selfadjointView<Upper>() * v;
}

EDIT2

The following line:

MatrixXd(M.block(1, 2, 3, 4).triangularView<Lower>()) += B.selfadjointView<Lower>();

makes no sense as you are creating a temporary copy that you are assigning to. Recall that here MatrixXd(whatever) calls the Eigen::Matrix constructor. Also assigning a selfadjoint-view to a triangular-view makes no sense. I cannot even think about what could be a reasonable behavior for this. If you only want to update the lower triangular part, then do:

M.block(1, 2, 3, 4).triangularView<Lower>() += B;

In this case, triangularView behaves as a writing mask.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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