Alecto
Alecto

Reputation: 10750

Avoiding Allocation with Diagonal Matrices in Eigen

Question

How can I avoid dynamic allocation for small Diagonal Matrices in Eigen?

Context

I'm using Eigen 3.4. I have a N by N Diagonal Matrix W:

auto W = Eigen::DiagonalMatrix<double, Dynamic>(N);

I'd like to avoid allocation if N <= 512 by using a buffer on the stack:

double W_buffer[512];

With normal vectors and matricies, I know I can use Map:

double y_buff[512];
auto y = Eigen::Map<VectorXd>( y_buff, N );

However, when I try the same thing with a Diagonal Matrix, it gives me an error because InnerStrideAtCompileTime isn't a member of Eigen::DiagonalMatrix.

Error message when using Map with DiagonalMatrix

In file included from eigen/Eigen/Core:311,
                 from eigen/Eigen/Dense:1,
                 from build/release/CMakeFiles/bench.dir/cmake_pch.hxx:5,
                 from <command-line>:
eigen/Eigen/src/Core/Map.h: In instantiation of ‘struct Eigen::internal::traits<Eigen::Map<Eigen::DiagonalMatrix<double, -1> > >’:
eigen/Eigen/src/Core/util/ForwardDeclarations.h:34:48:   required from ‘struct Eigen::internal::accessors_level<Eigen::Map<Eigen::DiagonalMatrix<double, -1> > >’
eigen/Eigen/src/Core/util/ForwardDeclarations.h:101:75:   required from ‘class Eigen::Map<Eigen::DiagonalMatrix<double, -1> >’
include/volar/estimators.hpp:203:18:   required from ‘static volar::R volar::PolyLE<Degree>::estimate(volar::R, volar::ViewR, volar::ViewR, const Kernel&) [with Kernel = volar::UniformK; int Degree = 1; volar::R = double; volar::ViewR = volar::View<double>]’
include/volar/kernel_smoothing.hpp:81:64:   required from ‘volar::R volar::LocalRFT<Estimator, Kernel>::operator()(volar::R) const [with Estimator = volar::EigenLinearLE; Kernel = volar::UniformK; volar::R = double]’
bench/core.cpp:43:23:   required from ‘void localRF(benchmark::State&) [with Method = volar::EigenLinearLE; Kernel = volar::UniformK]’
bench/core.cpp:96:1:   required from here
eigen/Eigen/src/Core/Map.h:30:53: error: ‘InnerStrideAtCompileTime’ is not a member of ‘Eigen::DiagonalMatrix<double, -1>’
   30 |                              ? int(PlainObjectType::InnerStrideAtCompileTime)
      |                                                     ^~~~~~~~~~~~~~~~~~~~~~~~
In file included from eigen/Eigen/Core:163,
                 from eigen/Eigen/Dense:1,
                 from build/release/CMakeFiles/bench.dir/cmake_pch.hxx:5,
                 from <command-line>:

Upvotes: 2

Views: 113

Answers (2)

stewpend0us
stewpend0us

Reputation: 59

Instead of trying to Map a DiagonalMatrix you can do it the "normal" way that you describe and use the asDiagonal() method.

Maybe slightly less clean to have to type y.asDiagonal() instead of just y...Maybe you could do something with Eigen::Ref to keep a reference to the diagonal matrix that came from your vector but I'm not sure if that would work.

asDiagonal(): https://eigen.tuxfamily.org/dox/classEigen_1_1MatrixBase.html#a14235b62c90f93fe910070b4743782d0

Upvotes: 1

user4442671
user4442671

Reputation:

The third template parameter of Eigen::DiagonalMatrix, MaxSizeAtCompileTime lets you do just that.

When combined with Eigen::Dynamic, the DiagonalMatrix will have an internal buffer large enough for MaxSizeAtCompileTime, but it will still be dynamically sized.

For example, the following is the equivalent of what you were trying to do with an external buffer:

auto W = Eigen::DiagonalMatrix<double, Eigen::Dynamic, 512>(N)

Obviously, attempting to initialize it with a size greater than MaxSizeAtCompileTime will fail at runtime (with an assert), but that's not any worse than what you have to deal with when using Map.

Upvotes: 2

Related Questions