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.