Search code examples
c++optimizationeigeneigen3

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>:

Solution

  • 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.