CWiseUnaryView inner/outer stride incorrect with pointer-to-implementation types
Summary
Eigen's CWiseUnaryView determines the inner & outer stride as:
MatrixTypeInnerStride = inner_stride_at_compile_time<MatrixType>::ret
int(MatrixTypeInnerStride) * int(sizeof(typename traits<MatrixType>::Scalar) / sizeof(Scalar))
However when the view is returning a value from a pointer-to-implementation variable, the inner stride should be set using the sizeof of the implementation, not the pointer.
As an example, consider a struct containing two values and view which returns the first value:
struct inner {
double val1_ = 1.0;
double val2_ = 1.0;
};
struct view_inner_op {
EIGEN_EMPTY_STRUCT_CTOR(view_inner_op)
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE const double&
operator()(const inner& v) const { return v.val1_; }
};
The innerStride is correctly set to 2:
int main() {
inner a11, a12;
a11.val1_ = 1.0;
a11.val2_ = 2.0;
a12.val1_ = 1.0;
a12.val2_ = 2.0;
Eigen::Matrix<inner,-1,1> inner_vec(2);
inner_vec << a11, a12;
Eigen::CwiseUnaryView<view_inner_op, Eigen::Matrix<inner,-1,1>> view_inner(inner_vec);
std::cout << Eigen::Map<const Eigen::VectorXd>(&(inner_vec[0].val1_), 4) << std::endl
<< "View innerStride: " << view_inner.innerStride() << std::endl;
return 0;
}
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
1
2
1
2
View innerStride: 2
If we add an additional struct whose only member is a pointer to the first, and subsequently revise the view operation:
struct inner {
double val1_ = 1.0;
double val2_ = 1.0;
};
struct outer {
inner* ptr_;
};
struct view_outer_op {
EIGEN_EMPTY_STRUCT_CTOR(view_outer_op)
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE const double&
operator()(const outer& v) const { return v.ptr_->val1_; }
};
The innerStride is now derived as 1:
int main() {
inner a11, a12;
a11.val1_ = 1.0;
a11.val2_ = 2.0;
a12.val1_ = 1.0;
a12.val2_ = 2.0;
outer a21, a22;
a21.ptr_ = &a11;
a22.ptr_ = &a12;
Eigen::Matrix<outer,-1,1> outer_vec(2);
outer_vec << a21, a22;
Eigen::CwiseUnaryView<view_outer_op, Eigen::Matrix<outer,-1,1>> view_outer(outer_vec);
std::cout << Eigen::Map<const Eigen::VectorXd>(&(outer_vec[0].ptr_->val1_), 4) << std::endl
<< "View innerStride: " << view_outer.innerStride() << std::endl;
return 0;
}
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
1
2
1
2
View innerStride: 1
I believe this could be resolved by adding Stride arguments/parameters to CWiseUnaryView, like those used for Map
Environment
- Operating System : Linux
- Architecture : x64
- Eigen Version : 3.4
- Compiler Version : Gcc10.1
- Compile Flags : -O3
- Vector Extension : N/A