The `apply()` function has a different "Derived" type, which is why it fails. MatrixBase<Matrix...> and MatrixBase<Block...> are two different types.
If you want a single manipulator like this that can take either a Matrix or a Block, you need to use an Eigen::Ref<Matrix...> (passed by value). See https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html. https://godbolt.org/z/ecxTxY1K5 On Fri, Feb 3, 2023 at 4:54 AM Peter <[email protected]> wrote: > Dear All, > > I'd like to write a class that takes a function and let this function > operate on matrices, or blocks of matrices including columns and rows. > Think of it like scipys LinearOperator, just that we can decide > on which part of a matrix we apply it. > > In trying to implement this we struggled with a conversion problem, that > we do not understand. > In essence it boils down to the following examples, which compiles fine as > is, while it > fails to compile when -DFAIL is set. Note that for simplicity I only used > lvalue calls, in > order to avoid lvalues vs. rvalues problems here. > > In this example I define a functions `mulValue`that just multiplies the > object with a given scalar. > In encapsulating it I'd like to call `mulValue`, that is expects an > Eigen::MatrixBase<Eigen::Matrix>>, > with an Eigen::MatrixBase<Eigen::Block<Matrix>>, which fails to compiles. > > I'm surprised by this, as I thought that this is the goal of MatrixBase, > or did I misunderstand it? > In addition, is there a function declaration that allows me to do that? > Possibly in a way that > allows me to set the manipulation function in python via pybind11? > > #include <iostream> > #include <Eigen/Core> > > > typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> Matrix; > > /// L-Value call > template <typename Derived> > void mulValue(Eigen::MatrixBase<Derived>& m, const double s) > { > m *= s; > }; > > template <typename Derived> > class Manipulator > { > public: > Manipulator(){}; > > void > set_manipulator(std::function<void(Eigen::MatrixBase<Derived>&, const > double)> mulValue_l_) > { > f = mulValue_l_; > }; > > void apply(Eigen::MatrixBase<Derived>& m, const double s) ///< > line 25 > { > f(m, s); > }; > > private: > std::function<void(Eigen::MatrixBase<Derived>&, const double)> > f; > > }; > > int main() > { > Matrix testMatrix(3, 3); > testMatrix.setOnes(); > auto B = testMatrix.block(0, 1, 3, 2); > > /// functional approach works for matrices and blocks > mulValue(testMatrix, 2.0); > mulValue(B, 3.0); > std::cout << testMatrix << std::endl << std::endl; > > /// init Maipulator with class > Manipulator<Matrix> m; > m.set_manipulator(mulValue<Matrix>); > > /// works fine on matrices > std::cout << "testMatrix before m:\n" << testMatrix << std::endl << > std::endl; > m.apply(testMatrix, 3.0); > std::cout << "testMatrix after m:\n" << testMatrix << std::endl << > std::endl; > > /// works for Blocks > Manipulator<Eigen::Block<Matrix>> mB; > mB.set_manipulator(mulValue<Eigen::Block<Matrix>>); > std::cout << "testMatrix before: mB\n" << testMatrix << std::endl << > std::endl; > mB.apply(B, 2.0); > std::cout << "testMatrix aftermpl:\n" << testMatrix << std::endl << > std::endl; > > #ifdef FAIL > /// fails for Blocks > std::cout << "testMatrix before m:\n" << testMatrix << std::endl << > std::endl; > m.apply(B, 2.0); ///< line 65 > std::cout << "testMatrix after m:\n" << testMatrix << std::endl << > std::endl; > #endif > > return 0; > } > > Compiling with -DFAIL leads to > > block.C: In function ‘int main()’: > block.C:65:13: error: cannot convert ‘Eigen::Block<Eigen::Matrix<double, > -1, -1>, -1, -1, false>’ to ‘Eigen::MatrixBase<Eigen::Matrix<double, -1, > -1> >&’ > 65 | m.apply(B, 2.0); ///< line 65 > | ^ > | | > | Eigen::Block<Eigen::Matrix<double, -1, -1>, -1, -1, > false> > block.C:25:48: note: initializing argument 1 of ‘void > Manipulator<Derived>::apply(Eigen::MatrixBase<Derived>&, double) [with > Derived = Eigen::Matrix<double, -1, -1>]’ > 25 | void apply(Eigen::MatrixBase<Derived>& m, const double s) > | > > > > Best regards, > Peter > > > >
