AutoDiffScalar: Failing assert when using dynamic-sized type for derivatives
(Note: This is a duplicate of #1437 (closed) which I cannot reopen due to Gitlab migration)
Summary
The (unsupported) AutoDiffScalar triggers an assertion when used with certain expressions while using dynamic-sized derivative storage.
#1437 (closed) was filed as a dup of #1281 (closed) (which was closed as fixed and the example included there now indeed seems to work), but this example still seems to fail.
Environment
- Operating System : macOS
- Architecture : x64
- Eigen Version : 3.4-rc1
- Compiler Version : clang 11
- Compile Flags : -O3 -march=native
- Vector Extension : AVX512
Minimal Example
#include <iostream>
#include "Eigen/Core"
#include "unsupported/Eigen/AutoDiff"
typedef Eigen::AutoDiffScalar<Eigen::VectorXd> AD;
int main (int argc, char const *argv[])
{
AD noDer = 1.0; // no (unsized) .derivatives()
AD hasDer;
hasDer.value() = 1.0;
hasDer.derivatives() = Eigen::VectorXd::Unit(5, 0);
std::cout << (2.0 * noDer - hasDer).derivatives().transpose() << std::endl; // assertion failure
return 0;
}
Steps to reproduce
- Compile the example with Eigen in the include path (leaving asserts enabled).
- Run the example
What is the current bug behavior?
Assertion failed: (aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()), function CwiseBinaryOp, file eigen-3.4-587a6915/Eigen/src/Core/CwiseBinaryOp.h, line 116.
What is the expected correct behavior?
I would expect the example to work (or notify me at compile-time if the expression is invalid) and result in the correctly propagated derivatives.
Anything else that might help
I'm hitting a similar issue in real code (which means my Eigen 3.4 benchmarks may be a bit optimistic).
We seem to have have fixed / worked around this in our Eigen 3.2.9 version by implementing make_coherent_impl for (some?) more expressions, e.g.
+template<class UnaryOpLhs, class DerTypeLhs, class UnaryOpRhs, class DerTypeRhs>
+struct make_coherent_impl<CwiseUnaryOp<UnaryOpLhs, DerTypeLhs>, CwiseUnaryOp<UnaryOpRhs, DerTypeRhs> >
+{
+ typedef CwiseUnaryOp<UnaryOpLhs, DerTypeLhs> A;
+ typedef CwiseUnaryOp<UnaryOpRhs, DerTypeRhs> B;
+ static void run(A& a, B& b)
+ {
+ if (B::SizeAtCompileTime==Dynamic && a.size()!=0 && b.size()==0)
+ {
+ make_coherent_expression(b,a);
+ }
+ else if (A::SizeAtCompileTime==Dynamic && b.size()!=0 && a.size()==0)
+ {
+ make_coherent_expression(a,b);
+ }
+ }
+};
+
+template<typename BinaryOp, typename LhsA, typename LhsB, typename RhsA, typename RhsB>
+struct make_coherent_impl<CwiseBinaryOp<BinaryOp, LhsA, LhsB>, CwiseBinaryOp<BinaryOp, RhsA, RhsB> >
+{
+ typedef CwiseBinaryOp<BinaryOp, LhsA, LhsB> A;
+ typedef CwiseBinaryOp<BinaryOp, RhsA, RhsB> B;
+ static void run(A& a, B& b)
+ {
+ if (B::SizeAtCompileTime==Dynamic && a.size()!=0 && b.size()==0)
+ {
+ make_coherent_expression(b,a);
+ }
+ else if (A::SizeAtCompileTime==Dynamic && b.size()!=0 && a.size()==0)
+ {
+ make_coherent_expression(a,b);
+ }
+ }
+};
+
+template<typename BinaryOp, typename UnaryOp, typename LhsA, typename LhsB, typename DerTypeRhs>
+struct make_coherent_impl<CwiseBinaryOp<BinaryOp, LhsA, LhsB>, CwiseUnaryOp<UnaryOp, DerTypeRhs> >
+{
+ typedef CwiseBinaryOp<BinaryOp, LhsA, LhsB> A;
+ typedef CwiseUnaryOp<UnaryOp, DerTypeRhs> B;
+ static void run(A& a, B& b)
+ {
+ if (B::SizeAtCompileTime==Dynamic && a.size()!=0 && b.size()==0)
+ {
+ make_coherent_expression(b,a);
+ }
+ else if (A::SizeAtCompileTime==Dynamic && b.size()!=0 && a.size()==0)
+ {
+ make_coherent_expression(a,b);
+ }
+ }
+};
+
+template<typename BinaryOp, typename UnaryOpRhs, typename DerTypeLhs, typename RhsA, typename RhsB>
+struct make_coherent_impl<CwiseUnaryOp<UnaryOpRhs, DerTypeLhs>, CwiseBinaryOp<BinaryOp, RhsA, RhsB> >
+{
+ typedef CwiseUnaryOp<UnaryOpRhs, DerTypeLhs> A;
+ typedef CwiseBinaryOp<BinaryOp, RhsA, RhsB> B;
+ static void run(A& a, B& b)
+ {
+ if (B::SizeAtCompileTime==Dynamic && a.size()!=0 && b.size()==0)
+ {
+ make_coherent_expression(b,a);
+ }
+ else if (A::SizeAtCompileTime==Dynamic && b.size()!=0 && a.size()==0)
+ {
+ make_coherent_expression(a,b);
+ }
+ }
+};
+
+template<typename UnaryOp, typename DerTypeLhs, typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
+struct make_coherent_impl<CwiseUnaryOp<UnaryOp, DerTypeLhs>, Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> >
+{
+ typedef CwiseUnaryOp<UnaryOp, DerTypeLhs> A;
+ typedef Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> B;
+ static void run(A& a, B& b)
+ {
+ if (B::SizeAtCompileTime==Dynamic && a.size()!=0 && b.size()==0)
+ {
+ b.resize(a.size());
+ b.setZero();
+ }
+ else if (A::SizeAtCompileTime==Dynamic && b.size()!=0 && a.size()==0)
+ {
+ make_coherent_expression(a,b);
+ }
+ }
+};
+
+template<typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols, typename UnaryOp, typename DerTypeRhs>
+struct make_coherent_impl<Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>, CwiseUnaryOp<UnaryOp, DerTypeRhs> >
+{
+ typedef Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> A;
+ typedef CwiseUnaryOp<UnaryOp, DerTypeRhs> B;
+ static void run(A& a, B& b)
+ {
+ if (B::SizeAtCompileTime==Dynamic && a.size()!=0 && b.size()==0)
+ {
+ make_coherent(b,a);
+ }
+ else if (A::SizeAtCompileTime==Dynamic && b.size()!=0 && a.size()==0)
+ {
+ a.resize(b.size());
+ a.setZero();
+ }
+ }
+};
+
+template<typename BinaryOp, typename LhsA, typename LhsB, typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
+struct make_coherent_impl<CwiseBinaryOp<BinaryOp, LhsA, LhsB>, Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> >
+{
+ typedef CwiseBinaryOp<BinaryOp, LhsA, LhsB> A;
+ typedef Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> B;
+ static void run(A& a, B& b)
+ {
+ if (B::SizeAtCompileTime==Dynamic && a.size()!=0 && b.size()==0)
+ {
+ b.resize(a.size());
+ b.setZero();
+ }
+ else if (A::SizeAtCompileTime==Dynamic && b.size()!=0 && a.size()==0)
+ {
+ make_coherent_expression(a,b);
+ }
+ }
+};
+
+template<typename BinaryOp, typename RhsA, typename RhsB, typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
+struct make_coherent_impl<Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>, CwiseBinaryOp<BinaryOp, RhsA, RhsB> >
+{
+ typedef Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> A;
+ typedef CwiseBinaryOp<BinaryOp, RhsA, RhsB> B;
+ static void run(A& a, B& b)
+ {
+ if (B::SizeAtCompileTime==Dynamic && a.size()!=0 && b.size()==0)
+ {
+ make_coherent_expression(b,a);
+ }
+ else if (A::SizeAtCompileTime==Dynamic && b.size()!=0 && a.size()==0)
+ {
+ a.resize(b.size());
+ a.setZero();
+ }
+ }
+};