1

I'm using Eigen's EIGEN_MATRIXBASE_PLUGIN functionality to implement a CwiseUnary expression and I'm having trouble working out to extend this work with operator=

I'm working with a struct that has two members: .val_ and .d_, and I've added a CwiseUnaryOp to access those:

template<typename T>
struct d_Op {
  EIGEN_EMPTY_STRUCT_CTOR(d_Op)
  typedef T result_type;
  EIGEN_DEVICE_FUNC
  EIGEN_STRONG_INLINE const result_type& 
    operator()(const stan::math::fvar<T> &v) const { return v.d_; }
};

template<typename T>
struct val_Op {
  EIGEN_EMPTY_STRUCT_CTOR(val_Op)
  typedef T result_type;
  EIGEN_DEVICE_FUNC
  EIGEN_STRONG_INLINE const result_type& 
    operator()(const stan::math::fvar<T> &v) const { return v.val_; }
};

inline const CwiseUnaryOp<d_Op<typename stan::partials_type<Scalar>::type>, const Derived>
d_() const { return CwiseUnaryOp<d_Op<typename stan::partials_type<Scalar>::type>,
                                 const Derived>
    (derived(), d_Op<typename stan::partials_type<Scalar>::type>());
}

inline const CwiseUnaryOp<val_Op<typename stan::partials_type<Scalar>::type>, const Derived>
val_() const { return CwiseUnaryOp<val_Op<typename stan::partials_type<Scalar>::type>,
                                 const Derived>
    (derived(), val_Op<typename stan::partials_type<Scalar>::type>());
}

Such that, given a matrix of type Matrix<stan::math::fvar<double>,-1,-1> m, I can simply write: m.val_().

This is all working fine, however I'd like to extend it to write to those values, rather than just reading them (i.e. m.val_() = MatrixXD::Random(int,int)). But I can't figure out how to overload the = operator, giving me errors like this:

test.cpp:30:14: error: no match for ‘operator=’ (operand types are ‘const 
Eigen::CwiseUnaryOp<Eigen::MatrixBase<Eigen::Matrix<stan::math::fvar<double>, 
-1, -1> >::val_Op<double>, const Eigen::Matrix<stan::math::fvar<double>, -1, -1> >’ 
and ‘Eigen::MatrixXd’ {aka ‘Eigen::Matrix<double, -1, -1>’})

Am I missing something very obvious here?

EDIT: Output when using CwiseUnaryView instead:

test.cpp:30:14: error: no match for ‘operator=’ 
(operand types are ‘const Eigen::CwiseUnaryView<Eigen::MatrixBase<Eigen::Matrix<stan::math::fvar<double>, -1, -1> >::val_Op<double>, const Eigen::Matrix<stan::math::fvar<double>, -1, -1> >’ 
and ‘Eigen::MatrixXd’ {aka ‘Eigen::Matrix<double, -1, -1>’})
   a.val_() = inp;
chtz
  • 17,329
  • 4
  • 26
  • 56
AndrewrJ
  • 49
  • 1
  • 8
  • 1
    I haven't read your question carefully, but you're very likely looking for [CwiseUnaryView](https://eigen.tuxfamily.org/dox/classEigen_1_1CwiseUnaryView.html), this is what we use to return writeable real/imaginary parts for complex matrices. – ggael Apr 04 '19 at 19:26
  • Unfortunately this has the same result, I've appended the output to the original post – AndrewrJ Apr 05 '19 at 05:46
  • 1
    You need to return a non-const proxy with a non-const nested type, `CwiseUnaryView<..., Derived>` – ggael Apr 05 '19 at 09:43
  • @ggael It seems the documentation to the corresponding [`unaryViewExpr`](https://eigen.tuxfamily.org/dox/classEigen_1_1MatrixBase.html#a2b928f32954852ffb4a103f49e3cbc18) is wrong (also refers to `unaryExpr`). – chtz Apr 05 '19 at 11:49

1 Answers1

1

Here is a minimal working example with a dummy fvar implementation, and defining the CwiseUnaryView outside any class:

#include <Eigen/Core>

template<class X>
struct fvar
{
    X d_, val_;
};

template<typename T>
struct d_Op {
  EIGEN_EMPTY_STRUCT_CTOR(d_Op)
  typedef T result_type;
  EIGEN_DEVICE_FUNC
  EIGEN_STRONG_INLINE const result_type& 
    operator()(const fvar<T> &v) const { return v.d_; }
  EIGEN_DEVICE_FUNC
  EIGEN_STRONG_INLINE result_type& 
    operator()(fvar<T> &v) const { return v.d_; }
};

void foo(Eigen::Matrix<fvar<float>, 4,4> &out, Eigen::Matrix4f const &in)
{
    Eigen::CwiseUnaryView<d_Op<float>, Eigen::Matrix<fvar<float>, 4,4> > view(out);
    view = in;
}

With optimization enabled, this compiles to a simple loop: https://godbolt.org/z/mgktfv

chtz
  • 17,329
  • 4
  • 26
  • 56