Core: Centralize shape checks and elide proven runtime assertions libeigen/eigen!3354
diff --git a/Eigen/Core b/Eigen/Core index 4677123..2330b76 100644 --- a/Eigen/Core +++ b/Eigen/Core
@@ -193,6 +193,7 @@ #include "src/Core/util/ForwardDeclarations.h" #include "src/Core/util/StaticAssert.h" #include "src/Core/util/XprHelper.h" +#include "src/Core/util/ShapeChecks.h" #include "src/Core/util/Memory.h" #include "src/Core/util/IntegralConstant.h" #include "src/Core/util/Serializer.h"
diff --git a/Eigen/src/Cholesky/BunchKaufman.h b/Eigen/src/Cholesky/BunchKaufman.h index dd451f4..d35554a 100644 --- a/Eigen/src/Cholesky/BunchKaufman.h +++ b/Eigen/src/Cholesky/BunchKaufman.h
@@ -932,7 +932,7 @@ template <typename MatrixType, int UpLo_> template <typename InputType> BunchKaufman<MatrixType, UpLo_>& BunchKaufman<MatrixType, UpLo_>::compute(const EigenBase<InputType>& a) { - eigen_assert(a.rows() == a.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(a); m_matrix = a.derived(); return computeInPlace(); } @@ -940,7 +940,7 @@ /** \internal Factorizes the matrix held in m_matrix, which is overwritten by the packed factors. */ template <typename MatrixType, int UpLo_> BunchKaufman<MatrixType, UpLo_>& BunchKaufman<MatrixType, UpLo_>::computeInPlace() { - eigen_assert(m_matrix.rows() == m_matrix.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(m_matrix); const Index size = m_matrix.rows(); // L1 norm of the implicit self-adjoint matrix, for rcond(). @@ -995,7 +995,7 @@ template <typename Derived> bool BunchKaufman<MatrixType, UpLo_>::solveInPlace(MatrixBase<Derived>& bAndX) const { eigen_assert(m_isInitialized && "BunchKaufman is not initialized."); - eigen_assert(m_matrix.rows() == bAndX.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(m_matrix, bAndX); bAndX = this->solve(bAndX); return true; }
diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index 5ecbda8..deca15e 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h
@@ -357,7 +357,7 @@ using Scalar = typename MatrixType::Scalar; using RealScalar = typename MatrixType::RealScalar; using IndexType = typename TranspositionType::StorageIndex; - eigen_assert(mat.rows() == mat.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(mat); const Index size = mat.rows(); bool found_zero_pivot = false; bool ret = true; @@ -471,7 +471,8 @@ using RealScalar = typename MatrixType::RealScalar; const Index size = mat.rows(); - eigen_assert(mat.cols() == size && w.size() == size); + EIGEN_INTERNAL_ASSERT_SQUARE(mat); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(w, mat); RealScalar alpha = 1; @@ -554,7 +555,7 @@ template <typename MatrixType, int UpLo_> template <typename InputType> LDLT<MatrixType, UpLo_>& LDLT<MatrixType, UpLo_>::compute(const EigenBase<InputType>& a) { - eigen_assert(a.rows() == a.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(a); const Index size = a.rows(); m_matrix = a.derived(); @@ -600,7 +601,7 @@ using IndexType = typename TranspositionType::StorageIndex; const Index size = w.rows(); if (m_isInitialized) { - eigen_assert(m_matrix.rows() == size); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(m_matrix, w); } else { m_matrix.resize(size, size); m_matrix.setZero(); @@ -711,7 +712,7 @@ template <typename Derived> bool LDLT<MatrixType, UpLo_>::solveInPlace(MatrixBase<Derived>& bAndX) const { eigen_assert(m_isInitialized && "LDLT is not initialized."); - eigen_assert(m_matrix.rows() == bAndX.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(m_matrix, bAndX); bAndX = this->solve(bAndX);
diff --git a/Eigen/src/Cholesky/LLT.h b/Eigen/src/Cholesky/LLT.h index e4ffac8..716f9d5 100644 --- a/Eigen/src/Cholesky/LLT.h +++ b/Eigen/src/Cholesky/LLT.h
@@ -331,7 +331,8 @@ using TempVecSegment = typename TempVectorType::SegmentReturnType; Index n = mat.cols(); - eigen_assert(mat.rows() == n && vec.size() == n); + EIGEN_INTERNAL_ASSERT_SQUARE(mat); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS(vec, mat); TempVectorType temp; @@ -388,7 +389,7 @@ static Index unblocked(MatrixType& mat) { using std::sqrt; - eigen_assert(mat.rows() == mat.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(mat); const Index size = mat.rows(); for (Index k = 0; k < size; ++k) { Index rs = size - k - 1; // remaining size @@ -409,7 +410,7 @@ template <typename MatrixType> static Index blocked(MatrixType& m) { - eigen_assert(m.rows() == m.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(m); Index size = m.rows(); // The unblocked kernel walks row k of the factor, which strides through memory: it wins up to about 48 columns, // and beyond that 16-column blocks keep those walks short while amortizing the level-3 updates. @@ -501,7 +502,7 @@ template <typename MatrixType, int UpLo_> template <typename InputType> LLT<MatrixType, UpLo_>& LLT<MatrixType, UpLo_>::compute(const EigenBase<InputType>& a) { - eigen_assert(a.rows() == a.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(a); const Index size = a.rows(); m_matrix.resize(size, size); if (!internal::is_same_dense(m_matrix, a.derived())) m_matrix = a.derived(); @@ -525,7 +526,7 @@ template <typename VectorType> LLT<MatrixType_, UpLo_>& LLT<MatrixType_, UpLo_>::rankUpdate(const VectorType& v, const RealScalar& sigma) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(VectorType); - eigen_assert(v.size() == m_matrix.cols()); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS(v, m_matrix); eigen_assert(m_isInitialized); if (internal::llt_inplace<typename MatrixType::Scalar, UpLo>::rankUpdate(m_matrix, v, sigma) >= 0) m_info = NumericalIssue; @@ -597,7 +598,7 @@ template <typename Derived> void LLT<MatrixType, UpLo_>::solveInPlace(const MatrixBase<Derived>& bAndX) const { eigen_assert(m_isInitialized && "LLT is not initialized."); - eigen_assert(m_matrix.rows() == bAndX.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(m_matrix, bAndX); matrixL().solveInPlace(bAndX); matrixU().solveInPlace(bAndX); }
diff --git a/Eigen/src/Core/Assign.h b/Eigen/src/Core/Assign.h index baec68b..e4dbd0c 100644 --- a/Eigen/src/Core/Assign.h +++ b/Eigen/src/Core/Assign.h
@@ -25,12 +25,11 @@ enum { SameType = std::is_same<typename Derived::Scalar, typename OtherDerived::Scalar>::value }; EIGEN_STATIC_ASSERT_LVALUE(Derived) - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived, OtherDerived) EIGEN_STATIC_ASSERT( SameType, YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - eigen_assert(rows() == other.rows() && cols() == other.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(*this, other); internal::call_assignment_no_alias(derived(), other.derived()); return derived();
diff --git a/Eigen/src/Core/AssignEvaluator.h b/Eigen/src/Core/AssignEvaluator.h index ae3a1e9..419f090 100644 --- a/Eigen/src/Core/AssignEvaluator.h +++ b/Eigen/src/Core/AssignEvaluator.h
@@ -907,9 +907,7 @@ template <typename DstXprType, typename SrcXprType, typename Functor> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr void resize_if_allowed(DstXprType& dst, const SrcXprType& src, const Functor& /*func*/) { - EIGEN_ONLY_USED_FOR_DEBUG(dst); - EIGEN_ONLY_USED_FOR_DEBUG(src); - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(dst, src); } template <typename DstXprType, typename SrcXprType, typename T1, typename T2> @@ -926,7 +924,8 @@ } #else dst.resize(dstRows, dstCols); - eigen_assert(dst.rows() == dstRows && dst.cols() == dstCols); + EIGEN_INTERNAL_CHECK_SHAPE(dst.rows() == dstRows && dst.cols() == dstCols, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, + internal::matching_shapes<DstXprType, SrcXprType>); #endif } } @@ -1140,7 +1139,7 @@ Index dstCols = src.cols(); if ((dst.rows() != dstRows) || (dst.cols() != dstCols)) dst.resize(dstRows, dstCols); - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(dst, src); src.evalTo(dst); } @@ -1154,7 +1153,7 @@ Index dstCols = src.cols(); if ((dst.rows() != dstRows) || (dst.cols() != dstCols)) dst.resize(dstRows, dstCols); - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(dst, src); src.addTo(dst); } @@ -1166,7 +1165,7 @@ Index dstCols = src.cols(); if ((dst.rows() != dstRows) || (dst.cols() != dstCols)) dst.resize(dstRows, dstCols); - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(dst, src); src.subTo(dst); } };
diff --git a/Eigen/src/Core/CommaInitializer.h b/Eigen/src/Core/CommaInitializer.h index fe67f78..139bd7c 100644 --- a/Eigen/src/Core/CommaInitializer.h +++ b/Eigen/src/Core/CommaInitializer.h
@@ -34,7 +34,7 @@ EIGEN_DEVICE_FUNC constexpr CommaInitializer(XprType& xpr, const Scalar& s) : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1) { - eigen_assert(m_xpr.rows() > 0 && m_xpr.cols() > 0 && "Cannot comma-initialize a 0x0 matrix (operator<<)"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(m_xpr, "Cannot comma-initialize a 0x0 matrix (operator<<)"); m_xpr.coeffRef(0, 0) = s; }
diff --git a/Eigen/src/Core/ConcatOp.h b/Eigen/src/Core/ConcatOp.h index 6ac7732..5f1bbbd 100644 --- a/Eigen/src/Core/ConcatOp.h +++ b/Eigen/src/Core/ConcatOp.h
@@ -107,19 +107,14 @@ (std::is_same<typename LhsType::Scalar, typename RhsType::Scalar>::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) EIGEN_STATIC_ASSERT_SAME_XPR_KIND(LhsType, RhsType) - EIGEN_STATIC_ASSERT(Direction != Horizontal || int(LhsType::RowsAtCompileTime) == Dynamic || - int(RhsType::RowsAtCompileTime) == Dynamic || - int(LhsType::RowsAtCompileTime) == int(RhsType::RowsAtCompileTime), - YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) - EIGEN_STATIC_ASSERT(Direction != Vertical || int(LhsType::ColsAtCompileTime) == Dynamic || - int(RhsType::ColsAtCompileTime) == Dynamic || - int(LhsType::ColsAtCompileTime) == int(RhsType::ColsAtCompileTime), - YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) - EIGEN_IF_CONSTEXPR (Direction == Vertical) { - eigen_assert(lhs.cols() == rhs.cols() && "vcat: number of columns must match"); - } else { - eigen_assert(lhs.rows() == rhs.rows() && "hcat: number of rows must match"); - } + // Select the relation first: C++14 would instantiate static assertions in both branches of an ordinary if. + // TODO(C++17): use if constexpr with EIGEN_INTERNAL_ASSERT_SAME_COLS/EIGEN_INTERNAL_ASSERT_SAME_ROWS directly. + EIGEN_INTERNAL_CHECK_SHAPE( + (Direction == Vertical ? lhs.cols() == rhs.cols() : lhs.rows() == rhs.rows()) && + (Direction == Vertical ? "vcat: number of columns must match" : "hcat: number of rows must match"), + YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, + std::conditional_t<Direction == Vertical, internal::matching_cols<LhsType, RhsType>, + internal::matching_rows<LhsType, RhsType>>); } EIGEN_DEVICE_FUNC constexpr Index rows() const {
diff --git a/Eigen/src/Core/ConditionEstimator.h b/Eigen/src/Core/ConditionEstimator.h index 41e2d87..f0649c0 100644 --- a/Eigen/src/Core/ConditionEstimator.h +++ b/Eigen/src/Core/ConditionEstimator.h
@@ -64,7 +64,7 @@ using RealVector = typename internal::plain_col_type<MatrixType, RealScalar>::type; const bool is_complex = (NumTraits<Scalar>::IsComplex != 0); - eigen_assert(dec.rows() == dec.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(dec); const Index n = dec.rows(); if (n == 0) return RealScalar(0); @@ -149,7 +149,7 @@ typename Decomposition::RealScalar rcond_estimate_helper(typename Decomposition::RealScalar matrix_norm, const Decomposition& dec) { using RealScalar = typename Decomposition::RealScalar; - eigen_assert(dec.rows() == dec.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(dec); if (dec.rows() == 0) return NumTraits<RealScalar>::infinity(); if (numext::is_exactly_zero(matrix_norm)) return RealScalar(0); if (dec.rows() == 1) return RealScalar(1);
diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 82625d0..8064d27 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h
@@ -100,7 +100,7 @@ EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& aLhs, const Rhs& aRhs, const BinaryOp& func = BinaryOp()) : m_lhs(aLhs), m_rhs(aRhs), m_functor(func) { - eigen_assert(aLhs.rows() == aRhs.rows() && aLhs.cols() == aRhs.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(aLhs, aRhs); } EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept {
diff --git a/Eigen/src/Core/CwiseTernaryOp.h b/Eigen/src/Core/CwiseTernaryOp.h index 8672c63..27444b1 100644 --- a/Eigen/src/Core/CwiseTernaryOp.h +++ b/Eigen/src/Core/CwiseTernaryOp.h
@@ -116,7 +116,8 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CwiseTernaryOp(const Arg1& a1, const Arg2& a2, const Arg3& a3, const TernaryOp& func = TernaryOp()) : m_arg1(a1), m_arg2(a2), m_arg3(a3), m_functor(func) { - eigen_assert(a1.rows() == a2.rows() && a1.cols() == a2.cols() && a1.rows() == a3.rows() && a1.cols() == a3.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(a1, a2); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(a1, a3); } EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Index rows() const {
diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 9cdb42b..de5a3b2 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h
@@ -395,7 +395,7 @@ template <typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void swap(const DenseBase<OtherDerived>& other) { EIGEN_STATIC_ASSERT(!OtherDerived::IsPlainObjectBase, THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); - eigen_assert(rows() == other.rows() && cols() == other.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(*this, other); call_assignment(derived(), other.const_cast_derived(), internal::swap_assign_op<Scalar>()); } @@ -404,7 +404,7 @@ */ template <typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void swap(PlainObjectBase<OtherDerived>& other) { - eigen_assert(rows() == other.rows() && cols() == other.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(*this, other); call_assignment(derived(), other.derived(), internal::swap_assign_op<Scalar>()); } @@ -448,7 +448,7 @@ /** \returns the unique coefficient of a 1x1 expression */ EIGEN_DEVICE_FUNC CoeffReturnType value() const { - EIGEN_STATIC_ASSERT_SIZE_1x1(Derived) eigen_assert(this->rows() == 1 && this->cols() == 1); + EIGEN_INTERNAL_ASSERT_SCALAR(*this); return derived().coeff(0, 0); }
diff --git a/Eigen/src/Core/FindCoeff.h b/Eigen/src/Core/FindCoeff.h index d7f87b6..86ba513 100644 --- a/Eigen/src/Core/FindCoeff.h +++ b/Eigen/src/Core/FindCoeff.h
@@ -353,7 +353,7 @@ template <typename Derived, typename IndexType, typename Func> EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar findCoeff(const DenseBase<Derived>& mat, Func& func, IndexType* rowPtr, IndexType* colPtr) { - eigen_assert(mat.rows() > 0 && mat.cols() > 0 && "you are using an empty matrix"); + EIGEN_INTERNAL_ASSERT_NONEMPTY(mat); using Scalar = typename DenseBase<Derived>::Scalar; using FindCoeffImpl = internal::find_coeff_impl<Derived, Func>; Index outer = 0; @@ -368,7 +368,7 @@ template <typename Derived, typename IndexType, typename Func> EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar findCoeff(const DenseBase<Derived>& mat, Func& func, IndexType* indexPtr) { - eigen_assert(mat.size() > 0 && "you are using an empty matrix"); + EIGEN_INTERNAL_ASSERT_NONEMPTY(mat); EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) using Scalar = typename DenseBase<Derived>::Scalar; using FindCoeffImpl = internal::find_coeff_impl<Derived, Func>;
diff --git a/Eigen/src/Core/InnerProduct.h b/Eigen/src/Core/InnerProduct.h index 6957564..d334298 100644 --- a/Eigen/src/Core/InnerProduct.h +++ b/Eigen/src/Core/InnerProduct.h
@@ -23,14 +23,9 @@ struct inner_product_assert { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Lhs) EIGEN_STATIC_ASSERT_VECTOR_ONLY(Rhs) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Lhs, Rhs) -#ifndef EIGEN_NO_DEBUG static EIGEN_DEVICE_FUNC void run(const Lhs& lhs, const Rhs& rhs) { - eigen_assert((lhs.size() == rhs.size()) && "Inner product: lhs and rhs vectors must have same size"); + EIGEN_INTERNAL_ASSERT_SAME_SIZE_MSG(lhs, rhs, "Inner product: lhs and rhs vectors must have same size"); } -#else - static EIGEN_DEVICE_FUNC void run(const Lhs&, const Rhs&) {} -#endif }; template <typename Func, typename Lhs, typename Rhs>
diff --git a/Eigen/src/Core/MatrixNorms.h b/Eigen/src/Core/MatrixNorms.h index 16c206b..a81143f 100644 --- a/Eigen/src/Core/MatrixNorms.h +++ b/Eigen/src/Core/MatrixNorms.h
@@ -369,7 +369,7 @@ template <unsigned int UpLo, typename Derived> EIGEN_DEVICE_FUNC typename Derived::RealScalar selfadjoint_l1_norm(const MatrixBase<Derived>& matrix) { static_assert(UpLo == Upper || UpLo == Lower, "UpLo must be Upper or Lower"); - eigen_assert(matrix.rows() == matrix.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(matrix); return selfadjoint_l1norm<Derived, UpLo>(matrix.derived()).run(); }
diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index cb073fd..860d8fc 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h
@@ -249,7 +249,7 @@ } template <typename Lhs, typename Rhs> void assignProduct(const Lhs& lhs, const Rhs& rhs) { - eigen_assert(lhs.cols() == rhs.rows()); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(lhs, rhs); for (Index i = 0; i < rows(); ++i) indices().coeffRef(i) = lhs.indices().coeff(rhs.indices().coeff(i)); } #endif @@ -271,7 +271,7 @@ template <typename Other> inline PlainPermutationType operator*(const InverseImpl<Other, PermutationStorage>& other) const { const auto& rhs = other.derived().nestedExpression(); - eigen_assert(size() == rhs.size()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(*this, rhs); PlainPermutationType result(size()); // (P * Q.inverse())(Q(i)) = P(i). for (Index i = 0; i < size(); ++i) result.indices().coeffRef(rhs.indices().coeff(i)) = indices().coeff(i);
diff --git a/Eigen/src/Core/PlainObjectBase.h b/Eigen/src/Core/PlainObjectBase.h index 430640d..bebc44f 100644 --- a/Eigen/src/Core/PlainObjectBase.h +++ b/Eigen/src/Core/PlainObjectBase.h
@@ -356,20 +356,22 @@ * Note that copying a row-vector into a vector (and conversely) is allowed. * The resizing, if any, is then done in the appropriate way so that row-vectors * remain row-vectors and vectors remain vectors. + * Resizing a vector from a statically non-vector expression is rejected at + * compile time. With EIGEN_NO_STATIC_ASSERT, or for dynamic source dimensions, + * this precondition is checked by a debug assertion instead. */ template <typename OtherDerived> EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE void resizeLike(const EigenBase<OtherDerived>& _other) { const OtherDerived& other = _other.derived(); + EIGEN_INTERNAL_ASSERT_VECTOR_IF(IsVectorAtCompileTime, other); #ifndef EIGEN_NO_DEBUG internal::check_rows_cols_for_overflow<MaxSizeAtCompileTime, MaxRowsAtCompileTime, MaxColsAtCompileTime>::run( other.rows(), other.cols()); #endif const Index othersize = other.rows() * other.cols(); EIGEN_IF_CONSTEXPR (RowsAtCompileTime == 1) { - eigen_assert(other.rows() == 1 || other.cols() == 1); resize(1, othersize); } else EIGEN_IF_CONSTEXPR (ColsAtCompileTime == 1) { - eigen_assert(other.rows() == 1 || other.cols() == 1); resize(othersize, 1); } else { resize(other.rows(), other.cols()); @@ -724,10 +726,15 @@ template <typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void _resize_to_match(const EigenBase<OtherDerived>& other) { #ifdef EIGEN_NO_AUTOMATIC_RESIZING - eigen_assert((this->size() == 0 || - (IsVectorAtCompileTime ? ((other.rows() == 1 || other.cols() == 1) && this->size() == other.size()) - : (rows() == other.rows() && cols() == other.cols()))) && - "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); + constexpr bool shape_is_proven = IsVectorAtCompileTime ? (internal::vector_dimensions<OtherDerived>::Proven && + internal::matching_sizes<Derived, OtherDerived>::Proven) + : internal::matching_shapes<Derived, OtherDerived>::Proven; + EIGEN_INTERNAL_SHAPE_ASSERT( + shape_is_proven, + (this->size() == 0 || + (IsVectorAtCompileTime ? ((other.rows() == 1 || other.cols() == 1) && this->size() == other.size()) + : (rows() == other.rows() && cols() == other.cols()))) && + "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); if (this->size() == 0) resizeLike(other); EIGEN_ONLY_USED_FOR_DEBUG(other); #else
diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 8c56014..68ca72c 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h
@@ -221,8 +221,7 @@ using AdjointReturnType = typename internal::product_transpose_helper<Lhs, Rhs, Option>::AdjointType; EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Product(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) { - eigen_assert(lhs.cols() == rhs.rows() && "invalid matrix product" && - "if you wanted a coeff-wise or a dot product use the respective explicit functions"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(lhs, rhs); } EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return m_lhs.rows(); } @@ -289,15 +288,19 @@ public: EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index row, Index col) const { - EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); - eigen_assert((Option == LazyProduct) || (this->rows() == 1 && this->cols() == 1)); + EIGEN_INTERNAL_CHECK_SHAPE((Option == LazyProduct) || (this->rows() == 1 && this->cols() == 1), + THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS, + std::conditional_t<Option == LazyProduct, internal::dimension_relation<1, 1>, + internal::fixed_dimensions<Derived, 1, 1>>); return internal::evaluator<Derived>(derived()).coeff(row, col); } EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index i) const { - EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS); - eigen_assert((Option == LazyProduct) || (this->rows() == 1 && this->cols() == 1)); + EIGEN_INTERNAL_CHECK_SHAPE((Option == LazyProduct) || (this->rows() == 1 && this->cols() == 1), + THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS, + std::conditional_t<Option == LazyProduct, internal::dimension_relation<1, 1>, + internal::fixed_dimensions<Derived, 1, 1>>); return internal::evaluator<Derived>(derived()).coeff(i); }
diff --git a/Eigen/src/Core/ProductEvaluators.h b/Eigen/src/Core/ProductEvaluators.h index f0a97cb..bd898a2 100644 --- a/Eigen/src/Core/ProductEvaluators.h +++ b/Eigen/src/Core/ProductEvaluators.h
@@ -179,7 +179,7 @@ using SrcXprType = Product<Lhs, Rhs, Options>; static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(DstXprType& dst, const SrcXprType& src, const internal::add_assign_op<Scalar, Scalar>&) { - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(dst, src); // FIXME shall we handle nested_eval here? generic_product_impl<Lhs, Rhs>::addTo(dst, src.lhs(), src.rhs()); } @@ -192,7 +192,7 @@ using SrcXprType = Product<Lhs, Rhs, Options>; static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(DstXprType& dst, const SrcXprType& src, const internal::sub_assign_op<Scalar, Scalar>&) { - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(dst, src); // FIXME shall we handle nested_eval here? generic_product_impl<Lhs, Rhs>::subTo(dst, src.lhs(), src.rhs()); } @@ -1119,9 +1119,7 @@ template <typename Dest, typename Alpha> static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Dest& dst, const MatrixType& matrix, const DiagonalType& diagonal, const Alpha& alpha) { - eigen_assert(((ProductOrder == OnTheLeft && diagonal.size() == matrix.rows()) || - (ProductOrder == OnTheRight && diagonal.size() == matrix.cols())) && - "invalid matrix product"); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_AXIS_MSG(diagonal, matrix, ProductOrder == OnTheLeft, "invalid matrix product"); const Index rows = matrix.rows(); const Index cols = matrix.cols(); @@ -1259,8 +1257,8 @@ template <bool Accumulate, typename Dest, typename Alpha> static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void runImpl(Dest& dst, const MatrixType& matrix, const DiagonalType& diagonal, const Alpha& alpha) { - eigen_assert(matrix.rows() == matrix.cols() && "SelfAdjointView is only for squared matrices"); - eigen_assert(diagonal.size() == matrix.rows() && "invalid matrix product"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(matrix, "SelfAdjointView is only for squared matrices"); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS_MSG(diagonal, matrix, "invalid matrix product"); const Index size = matrix.rows();
diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index b07e049..524dd92 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h
@@ -276,7 +276,7 @@ template <typename XprType> EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Evaluator& eval, const Func& func, const XprType& xpr) { - eigen_assert(xpr.rows() > 0 && xpr.cols() > 0 && "you are using an empty matrix"); + EIGEN_INTERNAL_ASSERT_NONEMPTY(xpr); const Index innerSize = xpr.innerSize(); const Index outerSize = xpr.outerSize(); using Bounds = redux_max_size<XprType>; @@ -354,7 +354,7 @@ template <typename XprType> EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Evaluator& eval, const Func& func, const XprType& xpr) { const Index size = xpr.size(); - eigen_assert(size > 0 && "you are using an empty matrix"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_SIZE(xpr, size); // Do not generate wide reduction bodies for bounded expressions that cannot // reach their cutoff (GCC can otherwise diagnose their unreachable loads). EIGEN_IF_CONSTEXPR (functor_is_commutative<Func>::value) { @@ -538,7 +538,7 @@ template <typename XprType> EIGEN_DEVICE_FUNC static Scalar run(const Evaluator& eval, const Func& func, const XprType& xpr) { - eigen_assert(xpr.rows() > 0 && xpr.cols() > 0 && "you are using an empty matrix"); + EIGEN_INTERNAL_ASSERT_NONEMPTY(xpr); const Index innerSize = xpr.innerSize(); const Index outerSize = xpr.outerSize(); const Index packetedInnerSize = numext::round_down(innerSize, PacketSize); @@ -639,7 +639,7 @@ template <typename XprType> EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Scalar run(const Evaluator& eval, const Func& func, const XprType& xpr) { EIGEN_ONLY_USED_FOR_DEBUG(xpr); - eigen_assert(xpr.rows() > 0 && xpr.cols() > 0 && "you are using an empty matrix"); + EIGEN_INTERNAL_ASSERT_NONEMPTY(xpr); if (VectorizedSize > 0) { Scalar res = func.predux( redux_vec_linear_unroller<Func, Evaluator, 0, Size / PacketSize>::template run<PacketType>(eval, func)); @@ -792,7 +792,7 @@ template <typename Func> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename internal::traits<Derived>::Scalar DenseBase<Derived>::redux( const Func& func) const { - eigen_assert(this->rows() > 0 && this->cols() > 0 && "you are using an empty matrix"); + EIGEN_INTERNAL_ASSERT_NONEMPTY(*this); using ThisEvaluator = typename internal::redux_evaluator<Derived>; ThisEvaluator thisEval(derived());
diff --git a/Eigen/src/Core/Ref.h b/Eigen/src/Core/Ref.h index 3e725ad..023c5a8 100644 --- a/Eigen/src/Core/Ref.h +++ b/Eigen/src/Core/Ref.h
@@ -118,12 +118,11 @@ // Determine runtime rows and columns. Index rows = expr.rows(); Index cols = expr.cols(); + EIGEN_INTERNAL_ASSERT_VECTOR_IF(PlainObjectType::IsVectorAtCompileTime, expr); EIGEN_IF_CONSTEXPR (PlainObjectType::RowsAtCompileTime == 1) { - eigen_assert(expr.rows() == 1 || expr.cols() == 1); rows = 1; cols = expr.size(); } else EIGEN_IF_CONSTEXPR (PlainObjectType::ColsAtCompileTime == 1) { - eigen_assert(expr.rows() == 1 || expr.cols() == 1); rows = expr.size(); cols = 1; }
diff --git a/Eigen/src/Core/Reshaped.h b/Eigen/src/Core/Reshaped.h index 6cc21a8..f331e18 100644 --- a/Eigen/src/Core/Reshaped.h +++ b/Eigen/src/Core/Reshaped.h
@@ -30,6 +30,9 @@ * This class represents an expression of either a fixed-size or dynamic-size reshape. * It is the return type of DenseBase::reshaped(NRowsType,NColsType) and * most of the time this is the only way it is used. + * The source and reshape must have the same coefficient count. Incompatible + * fixed counts are rejected at compile time, or by a debug assertion when + * EIGEN_NO_STATIC_ASSERT is defined. Dynamic counts are checked in debug builds. * * If you want to directly manipulate reshaped expressions, * for instance if you want to write a function returning such an expression, @@ -115,13 +118,15 @@ EIGEN_DEVICE_FUNC constexpr inline Reshaped(XprType& xpr) : Impl(xpr) { EIGEN_STATIC_ASSERT(RowsAtCompileTime != Dynamic && ColsAtCompileTime != Dynamic, THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE) - eigen_assert(Rows * Cols == xpr.rows() * xpr.cols()); + EIGEN_INTERNAL_ASSERT_RESHAPE_SIZE(xpr, Rows, Cols); } /** Dynamic-size constructor */ EIGEN_DEVICE_FUNC constexpr inline Reshaped(XprType& xpr, Index reshapeRows, Index reshapeCols) : Impl(xpr, reshapeRows, reshapeCols) { + EIGEN_STATIC_ASSERT((internal::reshape_dimensions<XprType, Rows, Cols>::Compatible), + YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) eigen_assert((RowsAtCompileTime == Dynamic || RowsAtCompileTime == reshapeRows) && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == reshapeCols)); eigen_assert(reshapeRows * reshapeCols == xpr.rows() * xpr.cols());
diff --git a/Eigen/src/Core/ScaledPermutationMatrix.h b/Eigen/src/Core/ScaledPermutationMatrix.h index 1d7dc38..a0d48b8 100644 --- a/Eigen/src/Core/ScaledPermutationMatrix.h +++ b/Eigen/src/Core/ScaledPermutationMatrix.h
@@ -210,7 +210,7 @@ typename internal::scaled_permutation_product_result<Derived, OtherDerived, StorageIndex>::type operator*( const DiagonalBase<OtherDerived>& other) const { using Result = typename internal::scaled_permutation_product_result<Derived, OtherDerived, StorageIndex>::type; - eigen_assert(rows() == other.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(*this, other); return Result(indices(), scales().cwiseProduct(other.diagonal())); } @@ -219,7 +219,7 @@ friend typename internal::scaled_permutation_product_result<OtherDerived, Derived, StorageIndex>::type operator*( const DiagonalBase<OtherDerived>& other, const ScaledPermutationBase& scaled) { using Result = typename internal::scaled_permutation_product_result<OtherDerived, Derived, StorageIndex>::type; - eigen_assert(other.rows() == scaled.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(other, scaled); Result result(scaled.rows()); result.indices() = scaled.indices(); for (Index k = 0; k < scaled.rows(); ++k) @@ -230,7 +230,7 @@ /** \returns the scaled permutation \c *this times the permutation \a other */ template <typename OtherDerived> PlainObject operator*(const PermutationBase<OtherDerived>& other) const { - eigen_assert(rows() == other.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(*this, other); PlainObject result(rows()); for (Index k = 0; k < rows(); ++k) { const Index source = other.indices().coeff(k); @@ -243,7 +243,7 @@ /** \returns the scaled permutation permutation \a other times \a scaled */ template <typename OtherDerived> friend PlainObject operator*(const PermutationBase<OtherDerived>& other, const ScaledPermutationBase& scaled) { - eigen_assert(other.rows() == scaled.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(other, scaled); PlainObject result(scaled.rows()); for (Index k = 0; k < scaled.rows(); ++k) result.indices().coeffRef(k) = StorageIndex(other.indices().coeff(scaled.indices().coeff(k))); @@ -254,7 +254,7 @@ /** \returns the scaled permutation \c *this times the inverse permutation \a other */ template <typename OtherDerived> PlainObject operator*(const InverseImpl<OtherDerived, PermutationStorage>& other) const { - eigen_assert(rows() == other.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(*this, other); IndicesType inverse(rows()); internal::invert_permutation_indices(other.derived().nestedExpression().indices(), inverse); PlainObject result(rows()); @@ -270,7 +270,7 @@ template <typename OtherDerived> friend PlainObject operator*(const InverseImpl<OtherDerived, PermutationStorage>& other, const ScaledPermutationBase& scaled) { - eigen_assert(other.rows() == scaled.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(other, scaled); IndicesType inverse(scaled.rows()); internal::invert_permutation_indices(other.derived().nestedExpression().indices(), inverse); PlainObject result(scaled.rows()); @@ -284,7 +284,7 @@ typename internal::scaled_permutation_product_result<Derived, OtherDerived, StorageIndex>::type operator*( const ScaledPermutationBase<OtherDerived>& other) const { using Result = typename internal::scaled_permutation_product_result<Derived, OtherDerived, StorageIndex>::type; - eigen_assert(rows() == other.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(*this, other); Result result(rows()); for (Index k = 0; k < rows(); ++k) { const Index source = other.indices().coeff(k); @@ -380,7 +380,7 @@ EIGEN_DEVICE_FUNC ScaledPermutationMatrix(const PermutationBase<PermutationDerived>& permutation, const DiagonalBase<DiagonalDerived>& diagonal) : m_permutation(permutation), m_scales(diagonal.diagonal()) { - eigen_assert(permutation.rows() == diagonal.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(permutation, diagonal); } /** Constructs the scaled permutation with the given \a indices and \a scales. */ @@ -388,7 +388,7 @@ EIGEN_DEVICE_FUNC ScaledPermutationMatrix(const MatrixBase<IndicesDerived>& indices, const MatrixBase<ScalesDerived>& scales) : m_permutation(indices), m_scales(scales) { - eigen_assert(indices.size() == scales.size()); + EIGEN_INTERNAL_ASSERT_SAME_SIZE(indices, scales); } /** Converts the permutation \a permutation, all scales being one. */ @@ -465,7 +465,7 @@ using Result = typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationDerived, DiagonalDerived, typename PermutationDerived::StorageIndex>::type; - eigen_assert(permutation.rows() == diagonal.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(permutation, diagonal); return Result(permutation.indices(), diagonal.diagonal()); } @@ -478,7 +478,7 @@ using Result = typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationDerived, DiagonalDerived, typename PermutationDerived::StorageIndex>::type; - eigen_assert(permutation.rows() == diagonal.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(permutation, diagonal); Result result(permutation.rows()); result.indices() = permutation.indices(); for (Index k = 0; k < permutation.rows(); ++k) @@ -496,7 +496,7 @@ using Result = typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationType, DiagonalDerived, typename PermutationType::StorageIndex>::type; - eigen_assert(inverse.rows() == diagonal.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(inverse, diagonal); Result result(inverse.rows()); internal::invert_permutation_indices(inverse.derived().nestedExpression().indices(), result.indices()); result.scales() = diagonal.diagonal(); @@ -513,7 +513,7 @@ using Result = typename internal::scaled_permutation_result<typename DiagonalDerived::Scalar, PermutationType, DiagonalDerived, typename PermutationType::StorageIndex>::type; - eigen_assert(inverse.rows() == diagonal.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(inverse, diagonal); Result result(inverse.rows()); internal::invert_permutation_indices(inverse.derived().nestedExpression().indices(), result.indices()); for (Index k = 0; k < inverse.rows(); ++k) @@ -581,14 +581,14 @@ static EIGEN_DEVICE_FUNC void run( DstXprType& dst, const SrcXprType& src, const internal::add_assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>&) { - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(dst, src); for (Index k = 0; k < src.rows(); ++k) dst.coeffRef(src.indices().coeff(k), k) += src.scales().coeff(k); } static EIGEN_DEVICE_FUNC void run( DstXprType& dst, const SrcXprType& src, const internal::sub_assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>&) { - eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(dst, src); for (Index k = 0; k < src.rows(); ++k) dst.coeffRef(src.indices().coeff(k), k) -= src.scales().coeff(k); } };
diff --git a/Eigen/src/Core/SkewSymmetricMatrix3.h b/Eigen/src/Core/SkewSymmetricMatrix3.h index 5dd4c58..6ed7578 100644 --- a/Eigen/src/Core/SkewSymmetricMatrix3.h +++ b/Eigen/src/Core/SkewSymmetricMatrix3.h
@@ -203,7 +203,6 @@ template <typename OtherDerived> EIGEN_DEVICE_FUNC friend EIGEN_STRONG_INLINE DenseSkewSumReturnType<OtherDerived> operator+( const MatrixBase<OtherDerived>& lhs, const SkewSymmetricBase& rhs) { - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(OtherDerived, DenseMatrixType); return lhs.derived() + rhs.toDenseMatrix(); } @@ -220,7 +219,6 @@ template <typename OtherDerived> EIGEN_DEVICE_FUNC friend EIGEN_STRONG_INLINE DenseSkewDifferenceReturnType<OtherDerived> operator-( const MatrixBase<OtherDerived>& lhs, const SkewSymmetricBase& rhs) { - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(OtherDerived, DenseMatrixType); return lhs.derived() - rhs.toDenseMatrix(); } @@ -228,7 +226,6 @@ template <typename OtherDerived> EIGEN_DEVICE_FUNC friend EIGEN_STRONG_INLINE DenseSkewDifferenceReturnType<OtherDerived> operator-( const SkewSymmetricBase& lhs, const MatrixBase<OtherDerived>& rhs) { - EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(OtherDerived, DenseMatrixType); return lhs.toDenseMatrix() - rhs.derived(); } };
diff --git a/Eigen/src/Core/SolveTriangular.h b/Eigen/src/Core/SolveTriangular.h index 25e7be5..fc19027 100644 --- a/Eigen/src/Core/SolveTriangular.h +++ b/Eigen/src/Core/SolveTriangular.h
@@ -194,8 +194,13 @@ EIGEN_DEVICE_FUNC void TriangularViewImpl<MatrixType, Mode, Dense>::solveInPlace( const MatrixBase<OtherDerived>& _other) const { OtherDerived& other = _other.const_cast_derived(); - eigen_assert(derived().cols() == derived().rows() && ((Side == OnTheLeft && derived().cols() == other.rows()) || - (Side == OnTheRight && derived().cols() == other.cols()))); + EIGEN_INTERNAL_ASSERT_SQUARE(derived()); + // TODO(C++17): use if constexpr (Side == OnTheLeft) with PRODUCT_SHAPE/SAME_COLS checks directly. + EIGEN_INTERNAL_CHECK_SHAPE( + (Side == OnTheLeft ? derived().cols() == other.rows() : derived().cols() == other.cols()), + YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, + std::conditional_t<Side == OnTheLeft, internal::product_dimensions<MatrixType, OtherDerived>, + internal::matching_cols<MatrixType, OtherDerived>>); eigen_assert((!(int(Mode) & int(ZeroDiag))) && bool(int(Mode) & (int(Upper) | int(Lower)))); // If solving for a 0x0 matrix, nothing to do, simply return. if (derived().cols() == 0) return;
diff --git a/Eigen/src/Core/SolverBase.h b/Eigen/src/Core/SolverBase.h index 87e176b..d2938ac 100644 --- a/Eigen/src/Core/SolverBase.h +++ b/Eigen/src/Core/SolverBase.h
@@ -145,10 +145,9 @@ protected: template <bool Transpose_, typename Rhs> void _check_solve_assertion(const Rhs& b) const { - EIGEN_ONLY_USED_FOR_DEBUG(b); eigen_assert(derived().m_isInitialized && "Solver is not initialized."); - eigen_assert((Transpose_ ? derived().cols() : derived().rows()) == b.rows() && - "SolverBase::solve(): invalid number of rows of the right hand side matrix b"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(derived(), b, Transpose_, + "SolverBase::solve(): invalid number of rows of the right hand side matrix b"); } };
diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index cb32472..15cf038 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h
@@ -246,7 +246,7 @@ using Scalar = typename MatrixType::Scalar; using Packet = typename internal::packet_traits<typename MatrixType::Scalar>::type; const Index PacketSize = internal::packet_traits<Scalar>::size; - eigen_assert(m.rows() == m.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(m); int row_start = 0; for (; row_start + PacketSize <= m.rows(); row_start += PacketSize) { for (int col_start = row_start; col_start + PacketSize <= m.cols(); col_start += PacketSize) { @@ -328,8 +328,11 @@ * \sa transpose(), adjoint(), adjointInPlace() */ template <typename Derived> EIGEN_DEVICE_FUNC inline void DenseBase<Derived>::transposeInPlace() { - eigen_assert((rows() == cols() || (RowsAtCompileTime == Dynamic && ColsAtCompileTime == Dynamic)) && - "transposeInPlace() called on a non-square non-resizable matrix"); + using ShapeRelation = std::conditional_t<RowsAtCompileTime == Dynamic && ColsAtCompileTime == Dynamic, + internal::dimension_relation<1, 1>, internal::square_dimensions<Derived>>; + EIGEN_INTERNAL_SHAPE_ASSERT(ShapeRelation::Proven, + (rows() == cols() || (RowsAtCompileTime == Dynamic && ColsAtCompileTime == Dynamic)) && + "transposeInPlace() called on a non-square non-resizable matrix"); internal::inplace_transpose_selector<Derived>::run(derived()); }
diff --git a/Eigen/src/Core/TriangularInPlace.h b/Eigen/src/Core/TriangularInPlace.h index be22d2c..262ee69 100644 --- a/Eigen/src/Core/TriangularInPlace.h +++ b/Eigen/src/Core/TriangularInPlace.h
@@ -81,7 +81,7 @@ // against L22, and Eigen's TRMM runs closer to GEMM rate than its TRSM does on a 128-column operand. template <unsigned int Mode, typename MatrixType, std::enable_if_t<MatrixType::SizeAtCompileTime != 0, int> = 0> EIGEN_DEVICE_FUNC void triangular_inverse_lower(MatrixType& mat) { - eigen_assert(mat.rows() == mat.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(mat); const Index n = mat.rows(); if (n < kTriangularInverseMinBlocked) { using Scalar = typename MatrixType::Scalar; @@ -157,7 +157,7 @@ // completed against the columns to its left before the trailing block rows consume the factor. template <typename MatrixType> void triangular_adjoint_square_lower(MatrixType& mat) { - eigen_assert(mat.rows() == mat.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(mat); const Index n = mat.rows(); if (n < kAdjointSquareMinBlocked) { triangular_adjoint_square_unblocked(mat); @@ -223,7 +223,7 @@ EIGEN_DEVICE_FUNC void TriangularViewImpl<MatrixType, Mode, Dense>::inverseInPlace() { EIGEN_STATIC_ASSERT_LVALUE(MatrixType) EIGEN_STATIC_ASSERT((int(Mode) & int(Upper | Lower)) != 0 && (int(Mode) & int(ZeroDiag)) == 0, PROGRAMMING_ERROR) - eigen_assert(derived().rows() == derived().cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(derived()); internal::triangular_inverse_selector<Mode>::run(derived().nestedExpression()); } #endif
diff --git a/Eigen/src/Core/VectorwiseOp.h b/Eigen/src/Core/VectorwiseOp.h index 4c95def..51d564d 100644 --- a/Eigen/src/Core/VectorwiseOp.h +++ b/Eigen/src/Core/VectorwiseOp.h
@@ -383,7 +383,7 @@ */ template <typename BinaryOp> EIGEN_DEVICE_FUNC const typename ReduxReturnType<BinaryOp>::Type redux(const BinaryOp& func = BinaryOp()) const { - eigen_assert(redux_length() > 0 && "you are using an empty matrix"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_AXIS(m_matrix, isVertical); return typename ReduxReturnType<BinaryOp>::Type(_expression(), internal::member_redux<BinaryOp, Scalar>(func)); } @@ -421,7 +421,7 @@ * * \sa DenseBase::minCoeff() */ EIGEN_DEVICE_FUNC const MinCoeffReturnType minCoeff() const { - eigen_assert(redux_length() > 0 && "you are using an empty matrix"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_AXIS(m_matrix, isVertical); return MinCoeffReturnType(_expression()); } @@ -438,7 +438,7 @@ * * \sa DenseBase::maxCoeff() */ EIGEN_DEVICE_FUNC const MaxCoeffReturnType maxCoeff() const { - eigen_assert(redux_length() > 0 && "you are using an empty matrix"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_AXIS(m_matrix, isVertical); return MaxCoeffReturnType(_expression()); }
diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index f5a717b..842c37e 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h
@@ -625,7 +625,8 @@ template <typename Dest> static void scaleAndAddTo(Dest& dst, const Lhs& a_lhs, const Rhs& a_rhs, const Scalar& alpha) { - eigen_assert(dst.rows() == a_lhs.rows() && dst.cols() == a_rhs.cols()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(dst, a_lhs); + EIGEN_INTERNAL_ASSERT_SAME_COLS(dst, a_rhs); if (a_lhs.cols() == 0 || a_lhs.rows() == 0 || a_rhs.cols() == 0) return; if (dst.cols() == 1) {
diff --git a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h index 4751a98..8edb29d 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h
@@ -303,8 +303,9 @@ Index size = mat.cols(); EIGEN_IF_CONSTEXPR (SkipDiag) size--; Index depth = actualLhs.cols(); - eigen_assert(actualLhs.rows() == mat.rows() && actualRhs.cols() == mat.cols() && - actualLhs.cols() == actualRhs.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(actualLhs, mat); + EIGEN_INTERNAL_ASSERT_SAME_COLS(actualRhs, mat); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(actualLhs, actualRhs); if (size <= 0 || depth == 0) return; using BlockingType = @@ -336,7 +337,7 @@ TriangularViewImpl<MatrixType_, Mode_, Dense>::_assignProduct( const ProductType& prod, const typename TriangularViewImpl<MatrixType_, Mode_, Dense>::Scalar& alpha, bool beta) { EIGEN_STATIC_ASSERT((Mode_ & UnitDiag) == 0, WRITING_TO_TRIANGULAR_PART_WITH_UNIT_DIAGONAL_IS_NOT_SUPPORTED); - eigen_assert(derived().nestedExpression().rows() == prod.rows() && derived().cols() == prod.cols()); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(derived(), prod); // The rank-k and rank-1 kernels below update a square triangle. if (derived().rows() != derived().cols()) {
diff --git a/Eigen/src/Core/products/SelfadjointMatrixMatrix.h b/Eigen/src/Core/products/SelfadjointMatrixMatrix.h index 52699e1..638d973 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixMatrix.h +++ b/Eigen/src/Core/products/SelfadjointMatrixMatrix.h
@@ -388,7 +388,8 @@ template <typename Dest> static void run(Dest& dst, const Lhs& a_lhs, const Rhs& a_rhs, const Scalar& alpha) { - eigen_assert(dst.rows() == a_lhs.rows() && dst.cols() == a_rhs.cols()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(dst, a_lhs); + EIGEN_INTERNAL_ASSERT_SAME_COLS(dst, a_rhs); add_const_on_value_type_t<ActualLhsType> lhs = LhsBlasTraits::extract(a_lhs); add_const_on_value_type_t<ActualRhsType> rhs = RhsBlasTraits::extract(a_rhs);
diff --git a/Eigen/src/Core/products/SelfadjointMatrixVector.h b/Eigen/src/Core/products/SelfadjointMatrixVector.h index 85a08d0..212cdc6 100644 --- a/Eigen/src/Core/products/SelfadjointMatrixVector.h +++ b/Eigen/src/Core/products/SelfadjointMatrixVector.h
@@ -339,7 +339,8 @@ using ResScalar = typename Dest::Scalar; using RhsScalar = typename Rhs::Scalar; - eigen_assert(dest.rows() == a_lhs.rows() && dest.cols() == a_rhs.cols()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(dest, a_lhs); + EIGEN_INTERNAL_ASSERT_SAME_COLS(dest, a_rhs); add_const_on_value_type_t<ActualLhsType> lhs = LhsBlasTraits::extract(a_lhs); add_const_on_value_type_t<ActualRhsType> rhs = RhsBlasTraits::extract(a_rhs);
diff --git a/Eigen/src/Core/products/SelfadjointProduct.h b/Eigen/src/Core/products/SelfadjointProduct.h index a58925e..a709dcf 100644 --- a/Eigen/src/Core/products/SelfadjointProduct.h +++ b/Eigen/src/Core/products/SelfadjointProduct.h
@@ -201,7 +201,7 @@ Index size = mat.cols(); Index depth = actualOther.cols(); - eigen_assert(actualOther.rows() == size); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(mat, actualOther); if (size == 0 || depth == 0) return; using BlockingType =
diff --git a/Eigen/src/Core/products/TriangularMatrixVector.h b/Eigen/src/Core/products/TriangularMatrixVector.h index 70d571c..d7bba5c 100644 --- a/Eigen/src/Core/products/TriangularMatrixVector.h +++ b/Eigen/src/Core/products/TriangularMatrixVector.h
@@ -229,7 +229,8 @@ struct triangular_product_impl<Mode, true, Lhs, false, Rhs, true> { template <typename Dest> static void run(Dest& dst, const Lhs& lhs, const Rhs& rhs, const typename Dest::Scalar& alpha) { - eigen_assert(dst.rows() == lhs.rows() && dst.cols() == rhs.cols()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(dst, lhs); + EIGEN_INTERNAL_ASSERT_SAME_COLS(dst, rhs); internal::trmv_selector<Mode, (int(internal::traits<Lhs>::Flags) & RowMajorBit) ? RowMajor : ColMajor>::run( lhs, rhs, dst, alpha); @@ -240,7 +241,8 @@ struct triangular_product_impl<Mode, false, Lhs, true, Rhs, false> { template <typename Dest> static void run(Dest& dst, const Lhs& lhs, const Rhs& rhs, const typename Dest::Scalar& alpha) { - eigen_assert(dst.rows() == lhs.rows() && dst.cols() == rhs.cols()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(dst, lhs); + EIGEN_INTERNAL_ASSERT_SAME_COLS(dst, rhs); Transpose<Dest> dstT(dst); internal::trmv_selector<(Mode & (UnitDiag | ZeroDiag)) | ((Mode & Lower) ? Upper : Lower),
diff --git a/Eigen/src/Core/util/ShapeChecks.h b/Eigen/src/Core/util/ShapeChecks.h new file mode 100644 index 0000000..d725eef --- /dev/null +++ b/Eigen/src/Core/util/ShapeChecks.h
@@ -0,0 +1,267 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 + +#ifndef EIGEN_SHAPE_CHECKS_H +#define EIGEN_SHAPE_CHECKS_H + +// IWYU pragma: private +#include "../InternalHeaderCheck.h" + +namespace Eigen { +namespace internal { + +template <typename T, typename = void> +struct shape_expression { + using type = T; +}; +template <typename T> +struct shape_expression<T, void_t<decltype(std::declval<const T&>().derived())>> { + using type = remove_all_t<decltype(std::declval<const T&>().derived())>; +}; + +// EigenBase extensions may omit either compile-time dimension. +template <typename T, typename = void> +struct shape_rows : std::integral_constant<int, Dynamic> {}; +template <typename T> +struct shape_rows<T, void_t<decltype(traits<remove_all_t<T>>::RowsAtCompileTime)>> + : std::integral_constant<int, traits<remove_all_t<T>>::RowsAtCompileTime> {}; + +template <typename T, typename = void> +struct shape_cols : std::integral_constant<int, Dynamic> {}; +template <typename T> +struct shape_cols<T, void_t<decltype(traits<remove_all_t<T>>::ColsAtCompileTime)>> + : std::integral_constant<int, traits<remove_all_t<T>>::ColsAtCompileTime> {}; + +template <typename T> +struct compile_time_shape { + static constexpr int Rows = shape_rows<T>::value; + static constexpr int Cols = shape_cols<T>::value; + static constexpr int Size = size_at_compile_time(Rows, Cols); +}; + +template <int Left, int Right> +struct dimension_relation { + static constexpr bool Known = Left != Dynamic && Right != Dynamic; + static constexpr bool Compatible = !Known || Left == Right; + static constexpr bool Proven = Known && Compatible; +}; + +template <typename Left, typename Right> +using matching_rows = dimension_relation<compile_time_shape<Left>::Rows, compile_time_shape<Right>::Rows>; +template <typename Left, typename Right> +using matching_cols = dimension_relation<compile_time_shape<Left>::Cols, compile_time_shape<Right>::Cols>; +template <typename Left, typename Right> +using matching_sizes = dimension_relation<compile_time_shape<Left>::Size, compile_time_shape<Right>::Size>; +template <typename SizeExpr, typename MatrixExpr, bool RowAxis> +using size_matches_axis = + dimension_relation<compile_time_shape<SizeExpr>::Size, + RowAxis ? compile_time_shape<MatrixExpr>::Rows : compile_time_shape<MatrixExpr>::Cols>; +template <typename Left, typename Right> +struct matching_shapes { + using Rows = matching_rows<Left, Right>; + using Cols = matching_cols<Left, Right>; + static constexpr bool Known = Rows::Known && Cols::Known; + // Preserve the empty-expression exception of EIGEN_PREDICATE_SAME_MATRIX_SIZE. + static constexpr bool Compatible = (compile_time_shape<Left>::Size == 0 && compile_time_shape<Right>::Size == 0) || + (Rows::Compatible && Cols::Compatible); + static constexpr bool Proven = Rows::Proven && Cols::Proven; +}; +template <typename Left, typename Right> +using product_dimensions = dimension_relation<compile_time_shape<Left>::Cols, compile_time_shape<Right>::Rows>; +template <typename T> +using square_dimensions = dimension_relation<compile_time_shape<T>::Rows, compile_time_shape<T>::Cols>; + +template <typename T, int Rows, int Cols> +using reshape_dimensions = dimension_relation<size_at_compile_time(Rows, Cols), compile_time_shape<T>::Size>; + +template <typename Solver, typename Rhs, bool Transposed = false> +using solver_rhs_dimensions = + dimension_relation<Transposed ? compile_time_shape<Solver>::Cols : compile_time_shape<Solver>::Rows, + compile_time_shape<Rhs>::Rows>; + +template <typename T> +struct vector_dimensions { + static constexpr bool Proven = compile_time_shape<T>::Rows == 1 || compile_time_shape<T>::Cols == 1; + static constexpr bool Known = + Proven || (compile_time_shape<T>::Rows != Dynamic && compile_time_shape<T>::Cols != Dynamic); + static constexpr bool Compatible = !Known || Proven; +}; + +template <int Extent> +struct nonempty_extent { + static constexpr bool Known = Extent != Dynamic; + static constexpr bool Compatible = !Known || Extent > 0; + static constexpr bool Proven = Known && Compatible; +}; + +template <typename T> +using nonempty_dimensions = nonempty_extent<compile_time_shape<T>::Size>; + +template <typename T, int Rows, int Cols> +struct fixed_dimensions { + using RowRelation = dimension_relation<compile_time_shape<T>::Rows, Rows>; + using ColRelation = dimension_relation<compile_time_shape<T>::Cols, Cols>; + static constexpr bool Known = RowRelation::Known && ColRelation::Known; + static constexpr bool Compatible = RowRelation::Compatible && ColRelation::Compatible; + static constexpr bool Proven = RowRelation::Proven && ColRelation::Proven; +}; + +} // namespace internal +} // namespace Eigen + +// These macros are private implementation helpers, not a public assertion API. +// Only EIGEN_INTERNAL_DEBUG_SHAPE_ASSERT uses internal-debug assertion semantics. +// Keep the runtime expression lazy and preserve assertion overrides. +// In particular, a proven check must not call dimension accessors even at -O0. +// An unevaluated use prevents unused-parameter warnings when assertions are disabled. +#define EIGEN_INTERNAL_SHAPE_ASSERT(Proven, Condition) \ + do { \ + EIGEN_IF_CONSTEXPR (!(Proven)) { \ + (void)sizeof(static_cast<bool>(Condition)); \ + eigen_assert(Condition); \ + } \ + } while (false) + +#define EIGEN_INTERNAL_DEBUG_SHAPE_ASSERT(Proven, Condition) \ + do { \ + EIGEN_IF_CONSTEXPR (!(Proven)) { \ + (void)sizeof(static_cast<bool>(Condition)); \ + eigen_internal_assert(Condition); \ + } \ + } while (false) + +// Infer the concrete expression without calling derived() or dimension accessors. +#define EIGEN_INTERNAL_SHAPE_TYPE(Xpr) \ + typename Eigen::internal::shape_expression<Eigen::internal::remove_all_t<decltype(Xpr)>>::type + +// The relation is shared by the static diagnostic and the lazy debug check. +#define EIGEN_INTERNAL_CHECK_SHAPE(Condition, Message, ...) \ + do { \ + using ShapeRelation = __VA_ARGS__; \ + EIGEN_STATIC_ASSERT(ShapeRelation::Compatible, Message) \ + EIGEN_IF_CONSTEXPR (!ShapeRelation::Proven) { \ + (void)sizeof(static_cast<bool>(Condition)); \ + eigen_assert(Condition); \ + } \ + } while (false) + +#define EIGEN_INTERNAL_ASSERT_SAME_ROWS_MSG(Lhs, Rhs, Message) \ + EIGEN_INTERNAL_CHECK_SHAPE( \ + (Lhs).rows() == (Rhs).rows() && (Message), YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, \ + Eigen::internal::matching_rows<EIGEN_INTERNAL_SHAPE_TYPE(Lhs), EIGEN_INTERNAL_SHAPE_TYPE(Rhs)>) +#define EIGEN_INTERNAL_ASSERT_SAME_ROWS(Lhs, Rhs) \ + EIGEN_INTERNAL_ASSERT_SAME_ROWS_MSG(Lhs, Rhs, "Both expressions must have the same number of rows") + +#define EIGEN_INTERNAL_ASSERT_SAME_SHAPE_MSG(Lhs, Rhs, Message) \ + do { \ + using ShapeRelation = \ + Eigen::internal::matching_shapes<EIGEN_INTERNAL_SHAPE_TYPE(Lhs), EIGEN_INTERNAL_SHAPE_TYPE(Rhs)>; \ + EIGEN_STATIC_ASSERT(ShapeRelation::Compatible, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) \ + EIGEN_INTERNAL_SHAPE_ASSERT(ShapeRelation::Rows::Proven, (Lhs).rows() == (Rhs).rows() && (Message)); \ + EIGEN_INTERNAL_SHAPE_ASSERT(ShapeRelation::Cols::Proven, (Lhs).cols() == (Rhs).cols() && (Message)); \ + } while (false) +#define EIGEN_INTERNAL_ASSERT_SAME_SHAPE(Lhs, Rhs) \ + EIGEN_INTERNAL_ASSERT_SAME_SHAPE_MSG(Lhs, Rhs, "Both expressions must have the same dimensions") + +#define EIGEN_INTERNAL_ASSERT_SAME_COLS_MSG(Lhs, Rhs, Message) \ + EIGEN_INTERNAL_CHECK_SHAPE( \ + (Lhs).cols() == (Rhs).cols() && (Message), YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, \ + Eigen::internal::matching_cols<EIGEN_INTERNAL_SHAPE_TYPE(Lhs), EIGEN_INTERNAL_SHAPE_TYPE(Rhs)>) +#define EIGEN_INTERNAL_ASSERT_SAME_COLS(Lhs, Rhs) \ + EIGEN_INTERNAL_ASSERT_SAME_COLS_MSG(Lhs, Rhs, "Both expressions must have the same number of columns") + +#define EIGEN_INTERNAL_ASSERT_SAME_SIZE_MSG(Lhs, Rhs, Message) \ + EIGEN_INTERNAL_CHECK_SHAPE( \ + (Lhs).size() == (Rhs).size() && (Message), YOU_MIXED_VECTORS_OF_DIFFERENT_SIZES, \ + Eigen::internal::matching_sizes<EIGEN_INTERNAL_SHAPE_TYPE(Lhs), EIGEN_INTERNAL_SHAPE_TYPE(Rhs)>) +#define EIGEN_INTERNAL_ASSERT_SAME_SIZE(Lhs, Rhs) \ + EIGEN_INTERNAL_ASSERT_SAME_SIZE_MSG(Lhs, Rhs, "Both expressions must have the same number of coefficients") + +#define EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(Lhs, Rhs, Message) \ + EIGEN_INTERNAL_CHECK_SHAPE( \ + (Lhs).cols() == (Rhs).rows() && (Message), INVALID_MATRIX_PRODUCT, \ + Eigen::internal::product_dimensions<EIGEN_INTERNAL_SHAPE_TYPE(Lhs), EIGEN_INTERNAL_SHAPE_TYPE(Rhs)>) +#define EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(Lhs, Rhs) \ + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG( \ + Lhs, Rhs, \ + "invalid matrix product; " \ + "if you wanted a coeff-wise or a dot product use the respective explicit functions") + +// SizeExpr must use coefficient-count size semantics (rows * cols), not permutation/transposition order. +// Select the axis in the relation so C++14 never instantiates a check for the unused dimension. +#define EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_AXIS_MSG(SizeExpr, MatrixExpr, RowAxis, Message) \ + EIGEN_INTERNAL_CHECK_SHAPE( \ + (SizeExpr).size() == ((RowAxis) ? (MatrixExpr).rows() : (MatrixExpr).cols()) && (Message), \ + YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, \ + Eigen::internal::size_matches_axis<EIGEN_INTERNAL_SHAPE_TYPE(SizeExpr), EIGEN_INTERNAL_SHAPE_TYPE(MatrixExpr), \ + RowAxis>) +#define EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_AXIS(SizeExpr, MatrixExpr, RowAxis) \ + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_AXIS_MSG(SizeExpr, MatrixExpr, RowAxis, \ + "Coefficient count must match the selected matrix dimension") +#define EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS_MSG(SizeExpr, MatrixExpr, Message) \ + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_AXIS_MSG(SizeExpr, MatrixExpr, true, Message) +#define EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS_MSG(SizeExpr, MatrixExpr, Message) \ + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_AXIS_MSG(SizeExpr, MatrixExpr, false, Message) +#define EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(SizeExpr, MatrixExpr) \ + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_AXIS(SizeExpr, MatrixExpr, true) +#define EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS(SizeExpr, MatrixExpr) \ + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_AXIS(SizeExpr, MatrixExpr, false) + +#define EIGEN_INTERNAL_ASSERT_SQUARE_MSG(Xpr, Message) \ + EIGEN_INTERNAL_SHAPE_ASSERT((Eigen::internal::square_dimensions<EIGEN_INTERNAL_SHAPE_TYPE(Xpr)>::Proven), \ + (Xpr).rows() == (Xpr).cols() && (Message)) +#define EIGEN_INTERNAL_ASSERT_SQUARE(Xpr) \ + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(Xpr, "This operation requires a square matrix") + +// TODO(C++17): guard the vector check with if constexpr (Enabled) instead of selecting a dummy relation. +#define EIGEN_INTERNAL_ASSERT_VECTOR_IF(Enabled, Xpr) \ + EIGEN_INTERNAL_CHECK_SHAPE( \ + ((Xpr).rows() == 1 || (Xpr).cols() == 1) && "This operation requires a vector", \ + YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX, \ + std::conditional_t<Enabled, Eigen::internal::vector_dimensions<EIGEN_INTERNAL_SHAPE_TYPE(Xpr)>, \ + Eigen::internal::dimension_relation<1, 1>>) +#define EIGEN_INTERNAL_ASSERT_VECTOR(Xpr) EIGEN_INTERNAL_ASSERT_VECTOR_IF(true, Xpr) + +#define EIGEN_INTERNAL_ASSERT_SCALAR(Xpr) \ + EIGEN_INTERNAL_CHECK_SHAPE( \ + ((Xpr).rows() == 1 && (Xpr).cols() == 1) && "This operation requires a 1-by-1 expression", \ + THIS_METHOD_IS_ONLY_FOR_1x1_EXPRESSIONS, \ + Eigen::internal::fixed_dimensions<EIGEN_INTERNAL_SHAPE_TYPE(Xpr), 1, 1>) + +#define EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(Xpr, Message) \ + EIGEN_INTERNAL_SHAPE_ASSERT((Eigen::internal::nonempty_dimensions<EIGEN_INTERNAL_SHAPE_TYPE(Xpr)>::Proven), \ + (Xpr).rows() > 0 && (Xpr).cols() > 0 && (Message)) +#define EIGEN_INTERNAL_ASSERT_NONEMPTY(Xpr) EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(Xpr, "you are using an empty matrix") + +#define EIGEN_INTERNAL_ASSERT_NONEMPTY_AXIS(Xpr, Vertical) \ + do { \ + using ShapeRelation = Eigen::internal::nonempty_extent< \ + (Vertical) ? Eigen::internal::compile_time_shape<EIGEN_INTERNAL_SHAPE_TYPE(Xpr)>::Rows \ + : Eigen::internal::compile_time_shape<EIGEN_INTERNAL_SHAPE_TYPE(Xpr)>::Cols>; \ + EIGEN_INTERNAL_SHAPE_ASSERT(ShapeRelation::Proven, \ + ((Vertical) ? (Xpr).rows() : (Xpr).cols()) > 0 && "you are using an empty matrix"); \ + } while (false) + +// Size must be the cached coefficient count of Xpr, not an allocation capacity. +#define EIGEN_INTERNAL_ASSERT_NONEMPTY_SIZE_MSG(Xpr, Size, Message) \ + EIGEN_INTERNAL_SHAPE_ASSERT((Eigen::internal::nonempty_dimensions<EIGEN_INTERNAL_SHAPE_TYPE(Xpr)>::Proven), \ + (Size) > 0 && (Message)) +#define EIGEN_INTERNAL_ASSERT_NONEMPTY_SIZE(Xpr, Size) \ + EIGEN_INTERNAL_ASSERT_NONEMPTY_SIZE_MSG(Xpr, Size, "you are using an empty matrix") + +#define EIGEN_INTERNAL_ASSERT_RESHAPE_SIZE(Xpr, Rows, Cols) \ + EIGEN_INTERNAL_CHECK_SHAPE( \ + (Rows) * (Cols) == (Xpr).rows() * (Xpr).cols() && "Reshaping must preserve the number of coefficients", \ + YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, \ + Eigen::internal::reshape_dimensions<EIGEN_INTERNAL_SHAPE_TYPE(Xpr), Rows, Cols>) + +#define EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(Solver, Rhs, Transposed, Message) \ + EIGEN_INTERNAL_CHECK_SHAPE(((Transposed) ? (Solver).cols() : (Solver).rows()) == (Rhs).rows() && (Message), \ + YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, \ + Eigen::internal::solver_rhs_dimensions<EIGEN_INTERNAL_SHAPE_TYPE(Solver), \ + EIGEN_INTERNAL_SHAPE_TYPE(Rhs), Transposed>) +#define EIGEN_INTERNAL_ASSERT_SOLVER_RHS(Solver, Rhs, Transposed) \ + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(Solver, Rhs, Transposed, \ + "solve(): invalid number of rows of the right hand side") + +#endif // EIGEN_SHAPE_CHECKS_H
diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h index fd41a90..d77c790 100644 --- a/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h
@@ -259,7 +259,7 @@ ComplexEigenSolver<MatrixType>& ComplexEigenSolver<MatrixType>::compute(const EigenBase<InputType>& matrix, bool computeEigenvectors) { // this code is inspired from Jampack - eigen_assert(matrix.cols() == matrix.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(matrix); // Do a complex Schur decomposition, A = U T U^* // The eigenvalues are on the diagonal of T.
diff --git a/Eigen/src/Eigenvalues/ComplexQZ.h b/Eigen/src/Eigenvalues/ComplexQZ.h index 12b5b9a..f3a0ff0 100644 --- a/Eigen/src/Eigenvalues/ComplexQZ.h +++ b/Eigen/src/Eigenvalues/ComplexQZ.h
@@ -272,9 +272,8 @@ template <typename MatrixType_> template <typename InputTypeA, typename InputTypeB> void ComplexQZ<MatrixType_>::compute(const EigenBase<InputTypeA>& A, const EigenBase<InputTypeB>& B, bool computeQZ) { - eigen_assert(A.rows() == A.cols() && "A is not a square matrix"); - eigen_assert(A.rows() == B.rows() && A.rows() == B.cols() && - "B is not a square matrix or B is not of the same size as A"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(A, "A is not a square matrix"); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE_MSG(A, B, "B is not a square matrix or B is not of the same size as A"); // Copy A and B, these will be the matrices on which we operate later m_S = A.derived(); m_T = B.derived(); @@ -287,8 +286,8 @@ m_computeQZ = computeQZ; m_n = m_S.rows(); - eigen_assert(m_n == m_S.cols() && "A is not a square matrix"); - eigen_assert(m_n == m_T.rows() && m_n == m_T.cols() && "B is not a square matrix or B is not of the same size as A"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_S, "A is not a square matrix"); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE_MSG(m_S, m_T, "B is not a square matrix or B is not of the same size as A"); m_isInitialized = true; m_global_iter = 0; @@ -417,8 +416,8 @@ void ComplexQZ<MatrixType>::computeSparse(const SparseMatrixType_& A, const SparseMatrixType_& B, bool computeQZ) { m_computeQZ = computeQZ; m_n = A.rows(); - eigen_assert(m_n == A.cols() && "A is not a square matrix"); - eigen_assert(m_n == B.rows() && m_n == B.cols() && "B is not a square matrix or B is not of the same size as A"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(A, "A is not a square matrix"); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE_MSG(A, B, "B is not a square matrix or B is not of the same size as A"); m_isInitialized = true; m_global_iter = 0; m_info = Success;
diff --git a/Eigen/src/Eigenvalues/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h index 7aa3815..c27d813 100644 --- a/Eigen/src/Eigenvalues/ComplexSchur.h +++ b/Eigen/src/Eigenvalues/ComplexSchur.h
@@ -349,7 +349,7 @@ template <typename InputType> ComplexSchur<MatrixType>& ComplexSchur<MatrixType>::compute(const EigenBase<InputType>& matrix, bool computeU) { m_matUisUptodate = false; - eigen_assert(matrix.cols() == matrix.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(matrix); if (matrix.cols() <= 1) { m_matT = matrix.derived().template cast<ComplexScalar>(); @@ -381,7 +381,7 @@ template <typename MatrixType> ComplexSchur<MatrixType>& ComplexSchur<MatrixType>::computeInPlace(bool computeU) { m_matUisUptodate = false; - eigen_assert(m_matT.cols() == m_matT.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(m_matT); if (m_matT.cols() <= 1) { if (computeU) m_matU = ComplexMatrixType::Identity(m_matT.rows(), m_matT.cols());
diff --git a/Eigen/src/Eigenvalues/EigenSolver.h b/Eigen/src/Eigenvalues/EigenSolver.h index 7aefd98..1d434cd 100644 --- a/Eigen/src/Eigenvalues/EigenSolver.h +++ b/Eigen/src/Eigenvalues/EigenSolver.h
@@ -394,7 +394,7 @@ EigenSolver<MatrixType>& EigenSolver<MatrixType>::compute(const EigenBase<InputType>& matrix, bool computeEigenvectors) { check_template_parameters(); - eigen_assert(matrix.cols() == matrix.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(matrix); // Reduce to real Schur form. m_realSchur.compute(matrix.derived(), computeEigenvectors);
diff --git a/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h b/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h index 00ba959..7dfa043 100644 --- a/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h +++ b/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h
@@ -307,7 +307,8 @@ GeneralizedEigenSolver<MatrixType>& GeneralizedEigenSolver<MatrixType>::compute(const EigenBase<InputTypeA>& A, const EigenBase<InputTypeB>& B, bool computeEigenvectors) { - eigen_assert(A.cols() == A.rows() && B.cols() == A.rows() && B.cols() == B.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(A); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(A, B); // Reduce to generalized real Schur form: // A = Q S Z and B = Q T Z m_realQZ.compute(A.derived(), B.derived(), computeEigenvectors);
diff --git a/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h index 92ce974..77e8054 100644 --- a/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h
@@ -196,7 +196,8 @@ template <typename InputTypeA, typename InputTypeB> GeneralizedSelfAdjointEigenSolver<MatrixType>& GeneralizedSelfAdjointEigenSolver<MatrixType>::compute( const EigenBase<InputTypeA>& matA, const EigenBase<InputTypeB>& matB, int options) { - eigen_assert(matA.cols() == matA.rows() && matB.rows() == matA.rows() && matB.cols() == matB.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(matA); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(matA, matB); // Compute the cholesky decomposition of matB = L L' = U'U m_cholB.compute(matB.derived()); @@ -209,7 +210,8 @@ template <typename MatrixType> GeneralizedSelfAdjointEigenSolver<MatrixType>& GeneralizedSelfAdjointEigenSolver<MatrixType>::computeInPlace( int options) { - eigen_assert(m_matC.cols() == m_matC.rows() && m_cholB.rows() == m_matC.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(m_matC); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(m_cholB, m_matC); eigen_assert((options & ~(EigVecMask | GenEigMask)) == 0 && (options & EigVecMask) != EigVecMask && ((options & GenEigMask) == 0 || (options & GenEigMask) == Ax_lBx || (options & GenEigMask) == ABx_lx || (options & GenEigMask) == BAx_lx) &&
diff --git a/Eigen/src/Eigenvalues/HessenbergDecomposition.h b/Eigen/src/Eigenvalues/HessenbergDecomposition.h index c0d792a..189a159 100644 --- a/Eigen/src/Eigenvalues/HessenbergDecomposition.h +++ b/Eigen/src/Eigenvalues/HessenbergDecomposition.h
@@ -300,7 +300,7 @@ void hessenberg_decomposition_inplace(MatrixType& matA, CoeffVectorType& hCoeffs, WorkspaceType& temp) { using Scalar = typename MatrixType::Scalar; using RealScalar = typename NumTraits<Scalar>::Real; - eigen_assert(matA.rows() == matA.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(matA); Index n = matA.rows(); temp.resize(n); for (Index i = 0; i < n - 1; ++i) {
diff --git a/Eigen/src/Eigenvalues/RealQZ.h b/Eigen/src/Eigenvalues/RealQZ.h index e5cd1f1..e44ff26 100644 --- a/Eigen/src/Eigenvalues/RealQZ.h +++ b/Eigen/src/Eigenvalues/RealQZ.h
@@ -536,8 +536,8 @@ template <typename InputTypeA, typename InputTypeB> RealQZ<MatrixType>& RealQZ<MatrixType>::compute(const EigenBase<InputTypeA>& A_in, const EigenBase<InputTypeB>& B_in, bool computeQZ) { - eigen_assert(A_in.rows() == A_in.cols() && B_in.rows() == A_in.cols() && B_in.cols() == A_in.cols() && - "Need square matrices of the same dimension"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(A_in, "Need square matrices of the same dimension"); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE_MSG(A_in, B_in, "Need square matrices of the same dimension"); m_S = A_in.derived(); m_T = B_in.derived(); return computeInPlace(computeQZ); @@ -548,8 +548,8 @@ RealQZ<MatrixType>& RealQZ<MatrixType>::computeInPlace(bool computeQZ) { const Index dim = m_S.cols(); - eigen_assert(m_S.rows() == dim && m_T.rows() == dim && m_T.cols() == dim && - "Need square matrices of the same dimension"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_S, "Need square matrices of the same dimension"); + EIGEN_INTERNAL_ASSERT_SAME_SHAPE_MSG(m_S, m_T, "Need square matrices of the same dimension"); m_isInitialized = true; m_computeQZ = computeQZ;
diff --git a/Eigen/src/Eigenvalues/RealSchur.h b/Eigen/src/Eigenvalues/RealSchur.h index a8fb2df..a47fb3a 100644 --- a/Eigen/src/Eigenvalues/RealSchur.h +++ b/Eigen/src/Eigenvalues/RealSchur.h
@@ -308,7 +308,7 @@ template <typename MatrixType> template <typename InputType> RealSchur<MatrixType>& RealSchur<MatrixType>::compute(const EigenBase<InputType>& matrix, bool computeU) { - eigen_assert(matrix.cols() == matrix.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(matrix); const Index size = matrix.rows(); if (usePaddedWorkspace(size)) { WorkspaceMatrix storage(size + (MatrixType::IsRowMajor ? 0 : 1), size + (MatrixType::IsRowMajor ? 1 : 0)); @@ -342,7 +342,7 @@ RealSchur<MatrixType>& RealSchur<MatrixType>::computeInPlace(TMatrix& matT, bool computeU) { const Scalar considerAsZero = (std::numeric_limits<Scalar>::min)(); const Index n = matT.rows(); - eigen_assert(matT.cols() == n); + EIGEN_INTERNAL_ASSERT_SQUARE(matT); const Scalar maxCoeff = n == 0 ? Scalar(0) : matT.cwiseAbs().template maxCoeff<PropagateNaN>(); if (!(numext::isfinite)(maxCoeff)) {
diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 4c4eff7..de6a142 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h
@@ -480,14 +480,14 @@ EIGEN_DEVICE_FUNC SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>::compute( const EigenBase<InputType>& a_matrix, int options) { const InputType& matrix(a_matrix.derived()); - eigen_assert(matrix.cols() == matrix.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(matrix); m_eivec = matrix.template triangularView<Lower>(); return computeInPlace(options); } template <typename MatrixType> EIGEN_DEVICE_FUNC SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>::computeInPlace(int options) { - eigen_assert(m_eivec.cols() == m_eivec.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(m_eivec); eigen_assert((options & ~(EigVecMask | GenEigMask)) == 0 && (options & EigVecMask) != EigVecMask && "invalid option parameter"); bool computeEigenvectors = (options & ComputeEigenvectors) == ComputeEigenvectors; @@ -992,7 +992,8 @@ } EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE static void run(SolverType& solver, const MatrixType& mat, int options) { - eigen_assert(mat.rows() == Size && mat.cols() == Size); + EIGEN_INTERNAL_CHECK_SHAPE(mat.rows() == Size && mat.cols() == Size, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, + internal::fixed_dimensions<MatrixType, Size, Size>); eigen_assert((options & ~(EigVecMask | GenEigMask)) == 0 && (options & EigVecMask) != EigVecMask && "invalid option parameter"); PlainMatrixType scaledMat = mat.template selfadjointView<Lower>();
diff --git a/Eigen/src/Eigenvalues/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h index a21e573..ba640c6 100644 --- a/Eigen/src/Eigenvalues/Tridiagonalization.h +++ b/Eigen/src/Eigenvalues/Tridiagonalization.h
@@ -354,7 +354,7 @@ using Scalar = typename MatrixType::Scalar; using RealScalar = typename MatrixType::RealScalar; Index n = matA.rows(); - eigen_assert(n == matA.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(matA); eigen_assert(n == hCoeffs.size() + 1 || n == 1); for (Index i = 0; i < n - 1; ++i) { @@ -397,7 +397,7 @@ using Scalar = typename MatrixType::Scalar; using RealScalar = typename MatrixType::RealScalar; const Index n = matA.rows(); - eigen_assert(n == matA.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(matA); eigen_assert(n == hCoeffs.size() + 1); eigen_assert(nb >= 2 && nb < n); @@ -525,7 +525,7 @@ */ template <typename MatrixType, typename CoeffVectorType> EIGEN_DEVICE_FUNC void tridiagonalization_inplace(MatrixType& matA, CoeffVectorType& hCoeffs) { - eigen_assert(matA.rows() == matA.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(matA); eigen_assert(matA.rows() == hCoeffs.size() + 1 || matA.rows() == 1); #if !defined(EIGEN_GPU_COMPILE_PHASE) @@ -590,7 +590,9 @@ typename WorkSpaceType> EIGEN_DEVICE_FUNC void tridiagonalization_inplace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, CoeffVectorType& hcoeffs, WorkSpaceType& workspace, bool extractQ) { - eigen_assert(mat.cols() == mat.rows() && diag.size() == mat.rows() && subdiag.size() == mat.rows() - 1); + EIGEN_INTERNAL_ASSERT_SQUARE(mat); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(diag, mat); + eigen_assert(subdiag.size() == mat.rows() - 1); tridiagonalization_inplace_selector<MatrixType>::run(mat, diag, subdiag, hcoeffs, workspace, extractQ); }
diff --git a/Eigen/src/Geometry/AngleAxis.h b/Eigen/src/Geometry/AngleAxis.h index c190c52..7bd7a6a 100644 --- a/Eigen/src/Geometry/AngleAxis.h +++ b/Eigen/src/Geometry/AngleAxis.h
@@ -137,7 +137,7 @@ EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Vector3 _transformVector(const OtherVectorType& v) const { EIGEN_USING_STD(sin) EIGEN_USING_STD(cos) - eigen_assert(v.size() == 3); + EIGEN_INTERNAL_ASSERT_SAME_SIZE(v, m_axis); // Rodrigues' rotation formula: v' = v*cos(θ) + (k×v)*sin(θ) + k*(k·v)*(1-cos(θ)) const Vector3 v3(v); @@ -231,7 +231,9 @@ EIGEN_STATIC_ASSERT( (std::is_same<Scalar, typename Derived::Scalar>::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - eigen_assert(mat.cols() == 3 && mat.rows() == 3); + // operator= also instantiates this path for quaternion coefficients in C++14. + // TODO(C++17): use fixed-size if constexpr dispatch in operator= before adding a static 3-by-3 check here. + EIGEN_INTERNAL_SHAPE_ASSERT((internal::fixed_dimensions<Derived, 3, 3>::Proven), mat.cols() == 3 && mat.rows() == 3); // Compute a (non-unit) quaternion proportional to the rotation using // Shoemake's algorithm (shared with Quaternion::operator=(MatrixBase)),
diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index 365adc6..195c129 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h
@@ -97,6 +97,9 @@ return Product<Transform<Scalar, Dim, Mode, Options>, Homogeneous>(lhs, rhs); } + /** Reduces all coefficients, including the appended ones. An empty vector's + * homogeneous expression contains one coefficient equal to one. + */ template <typename Func> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename internal::result_of<Func(Scalar, Scalar)>::type redux( const Func& func) const {
diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index 99f081c..39e985c 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h
@@ -477,7 +477,7 @@ typename internal::permutation_type_as_matrix_type<Scalar, OtherDerived>::Type operator*( const PermutationBase<OtherDerived>& other) const { using ResultType = typename internal::permutation_type_as_matrix_type<Scalar, OtherDerived>::Type; - eigen_assert(cols() == other.rows()); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(*this, other); ResultType res = ResultType::Identity(rows(), rows()); applyThisOnTheLeft(res, true); // The permutation product runs in place when its operand is the destination. @@ -490,7 +490,7 @@ typename internal::permutation_type_as_matrix_type<Scalar, Inverse<OtherDerived>>::Type operator*( const InverseImpl<OtherDerived, PermutationStorage>& other) const { using ResultType = typename internal::permutation_type_as_matrix_type<Scalar, Inverse<OtherDerived>>::Type; - eigen_assert(cols() == other.rows()); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(*this, other); ResultType res = ResultType::Identity(rows(), rows()); applyThisOnTheLeft(res, true); res.noalias() = res * other.derived(); @@ -506,7 +506,7 @@ // the identity. Other inputs take the full path. template <typename ResultType, typename OtherDerived> ResultType applyToUpperTriangularOnTheLeft(const EigenBase<OtherDerived>& other, bool upperTriangular) const { - eigen_assert(cols() == other.rows()); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(*this, other); ResultType res; internal::assign_householder_operand(res, other); applyThisOnTheLeft(res, upperTriangular && res.rows() == res.cols()); @@ -608,7 +608,7 @@ typename internal::matrix_type_times_scalar_type<typename VectorsType::Scalar, OtherDerived>::Type operator*( const DiagonalBase<OtherDerived>& other, const HouseholderSequence<VectorsType, CoeffsType, Side>& h) { using ResultType = typename internal::matrix_type_times_scalar_type<typename VectorsType::Scalar, OtherDerived>::Type; - eigen_assert(other.cols() == h.rows()); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(other, h); ResultType res = ResultType::Identity(h.rows(), h.rows()); h.applyThisOnTheLeft(res, true); // The lazy diagonal product multiplies from the left, D(i,i) * H(i,j), as a noncommutative scalar requires, and @@ -642,7 +642,7 @@ const PermutationBase<OtherDerived>& other, const HouseholderSequence<VectorsType, CoeffsType, Side>& h) { using ResultType = typename internal::permutation_type_as_matrix_type<typename VectorsType::Scalar, OtherDerived>::Type; - eigen_assert(other.cols() == h.rows()); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(other, h); ResultType res = ResultType::Identity(h.rows(), h.rows()); h.applyThisOnTheLeft(res, true); // The permutation product runs in place when its operand is the destination. @@ -657,7 +657,7 @@ const HouseholderSequence<VectorsType, CoeffsType, Side>& h) { using ResultType = typename internal::permutation_type_as_matrix_type<typename VectorsType::Scalar, Inverse<OtherDerived>>::Type; - eigen_assert(other.cols() == h.rows()); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(other, h); ResultType res = ResultType::Identity(h.rows(), h.rows()); h.applyThisOnTheLeft(res, true); res.noalias() = other.derived() * res;
diff --git a/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h b/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h index a8e1659..5b30e4e 100644 --- a/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h +++ b/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
@@ -89,8 +89,8 @@ template <typename Rhs> inline Solve<DiagonalPreconditioner, Rhs> solve(const MatrixBase<Rhs>& b) const { eigen_assert(m_isInitialized && "DiagonalPreconditioner is not initialized."); - eigen_assert(m_invdiag.size() == b.rows() && - "DiagonalPreconditioner::solve(): invalid number of rows of the right hand side matrix b"); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS_MSG( + m_invdiag, b, "DiagonalPreconditioner::solve(): invalid number of rows of the right hand side matrix b"); return Solve<DiagonalPreconditioner, Rhs>(*this, b.derived()); }
diff --git a/Eigen/src/IterativeLinearSolvers/DGMRES.h b/Eigen/src/IterativeLinearSolvers/DGMRES.h index a4f341b..0e7ed97 100644 --- a/Eigen/src/IterativeLinearSolvers/DGMRES.h +++ b/Eigen/src/IterativeLinearSolvers/DGMRES.h
@@ -39,7 +39,7 @@ */ template <typename VectorType, typename IndexType> void sortWithPermutation(VectorType& vec, IndexType& perm, typename IndexType::Scalar& ncut) { - eigen_assert(vec.size() == perm.size()); + EIGEN_INTERNAL_ASSERT_SAME_SIZE(vec, perm); for (Index k = 0; k < ncut; k++) { bool flag = false; for (Index j = 0; j < vec.size() - 1; j++) {
diff --git a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h index df2fed3..11fed19 100644 --- a/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +++ b/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h
@@ -393,7 +393,7 @@ template <typename Scalar, typename StorageIndex> template <typename MatrixType_> void IncompleteLUT<Scalar, StorageIndex>::analyzePattern(const MatrixType_& amat) { - eigen_assert((amat.rows() == amat.cols()) && "The factorization should be done on a square matrix"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(amat, "The factorization should be done on a square matrix"); // 1. Compute a static row permutation that makes the diagonal structurally // nonzero. This is a workaround for the lack of partial pivoting in ILUT. // For matrices that already have a nonzero diagonal, this returns the @@ -433,7 +433,7 @@ using std::sqrt; using std::swap; - eigen_assert((amat.rows() == amat.cols()) && "The factorization should be done on a square matrix"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(amat, "The factorization should be done on a square matrix"); Index n = amat.cols(); // Size of the matrix m_lu.resize(n, n); // Declare Working vectors and variables
diff --git a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h index 690d9dd..bcf1d7d 100644 --- a/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +++ b/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h
@@ -276,7 +276,8 @@ template <typename Rhs, typename Guess> inline const SolveWithGuess<Derived, Rhs, Guess> solveWithGuess(const MatrixBase<Rhs>& b, const Guess& x0) const { eigen_assert(m_isInitialized && "Solver is not initialized."); - eigen_assert(derived().rows() == b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(derived(), b, false, + "solve(): invalid number of rows of the right hand side matrix b"); return SolveWithGuess<Derived, Rhs, Guess>(derived(), b.derived(), x0); } @@ -293,8 +294,8 @@ template <typename Rhs, typename Dest> void solveWithGuessInPlace(const Rhs& b, Dest& x) const { eigen_assert(m_isInitialized && "Solver is not initialized."); - eigen_assert(derived().rows() == b.rows() && - "solveWithGuessInPlace(): invalid number of rows of the right hand side b"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(derived(), b, false, + "solveWithGuessInPlace(): invalid number of rows of the right hand side b"); derived()._solve_vector_with_guess_impl(b, x); } @@ -307,7 +308,7 @@ /** \internal */ template <typename Rhs, typename DestDerived> void _solve_with_guess_impl(const Rhs& b, SparseMatrixBase<DestDerived>& aDest) const { - eigen_assert(rows() == b.rows()); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS(derived(), b, false); Index rhsCols = b.cols(); Index size = b.rows(); @@ -340,7 +341,7 @@ template <typename Rhs, typename DestDerived> std::enable_if_t<Rhs::ColsAtCompileTime != 1 && DestDerived::ColsAtCompileTime != 1> _solve_with_guess_impl( const Rhs& b, MatrixBase<DestDerived>& aDest) const { - eigen_assert(rows() == b.rows()); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS(derived(), b, false); Index rhsCols = b.cols(); DestDerived& dest(aDest.derived());
diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h index c4dac91..d40ac70 100644 --- a/Eigen/src/Jacobi/Jacobi.h +++ b/Eigen/src/Jacobi/Jacobi.h
@@ -488,7 +488,7 @@ constexpr bool Vectorizable = (int(evaluator<VectorX>::Flags) & int(evaluator<VectorY>::Flags) & PacketAccessBit) && (int(packet_traits<Scalar>::size) == int(packet_traits<OtherScalar>::size)); - eigen_assert(xpr_x.size() == xpr_y.size()); + EIGEN_INTERNAL_ASSERT_SAME_SIZE(xpr_x, xpr_y); Index size = xpr_x.size(); Index incrx = xpr_x.derived().innerStride(); Index incry = xpr_y.derived().innerStride();
diff --git a/Eigen/src/LU/Determinant.h b/Eigen/src/LU/Determinant.h index ac9e05a..927270c 100644 --- a/Eigen/src/LU/Determinant.h +++ b/Eigen/src/LU/Determinant.h
@@ -86,7 +86,7 @@ */ template <typename Derived> EIGEN_DEVICE_FUNC inline typename internal::traits<Derived>::Scalar MatrixBase<Derived>::determinant() const { - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); using Nested = typename internal::nested_eval<Derived, Base::RowsAtCompileTime>::type; return internal::determinant_impl<internal::remove_all_t<Nested>>::run(derived()); }
diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index 1857d27..bf7a9a0 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h
@@ -349,7 +349,7 @@ */ inline Inverse<FullPivLU> inverse() const { eigen_assert(m_isInitialized && "LU is not initialized."); - eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the inverse of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_lu, "You can't take the inverse of a non-square matrix!"); return Inverse<FullPivLU>(*this); } @@ -509,7 +509,7 @@ template <typename MatrixType, typename PermutationIndex> typename internal::traits<MatrixType>::Scalar FullPivLU<MatrixType, PermutationIndex>::determinant() const { eigen_assert(m_isInitialized && "LU is not initialized."); - eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_lu, "You can't take the determinant of a non-square matrix!"); return Scalar(m_det_pq) * Scalar(m_lu.diagonal().prod()); } @@ -517,7 +517,7 @@ typename FullPivLU<MatrixType, PermutationIndex>::RealScalar FullPivLU<MatrixType, PermutationIndex>::absDeterminant() const { eigen_assert(m_isInitialized && "LU is not initialized."); - eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_lu, "You can't take the determinant of a non-square matrix!"); return isInjective() ? numext::abs(m_lu.diagonal().prod()) : RealScalar(0); } @@ -525,7 +525,7 @@ typename FullPivLU<MatrixType, PermutationIndex>::RealScalar FullPivLU<MatrixType, PermutationIndex>::logAbsDeterminant() const { eigen_assert(m_isInitialized && "LU is not initialized."); - eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_lu, "You can't take the determinant of a non-square matrix!"); return isInjective() ? m_lu.diagonal().cwiseAbs().array().log().sum() : -NumTraits<RealScalar>::infinity(); } @@ -533,7 +533,7 @@ typename FullPivLU<MatrixType, PermutationIndex>::Scalar FullPivLU<MatrixType, PermutationIndex>::signDeterminant() const { eigen_assert(m_isInitialized && "LU is not initialized."); - eigen_assert(m_lu.rows() == m_lu.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_lu, "You can't take the determinant of a non-square matrix!"); return isInjective() ? Scalar(m_det_pq) * m_lu.diagonal().array().sign().prod() : Scalar(0); }
diff --git a/Eigen/src/LU/InverseImpl.h b/Eigen/src/LU/InverseImpl.h index 56327e7..aa4e05d 100644 --- a/Eigen/src/LU/InverseImpl.h +++ b/Eigen/src/LU/InverseImpl.h
@@ -279,7 +279,7 @@ template <typename Derived> EIGEN_DEVICE_FUNC inline Inverse<Derived> MatrixBase<Derived>::inverse() const { EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsInteger, THIS_FUNCTION_IS_NOT_FOR_INTEGER_NUMERIC_TYPES) - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); return Inverse<Derived>(derived()); } @@ -310,7 +310,7 @@ bool& invertible, const RealScalar& absDeterminantThreshold) const { EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived, ResultType) - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); inverse.resize(rows(), cols()); // for 2x2, it's worth giving a chance to avoid evaluating. // for larger sizes, evaluating has negligible cost and limits code size.
diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index a26c774..8cac1d4 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h
@@ -291,7 +291,7 @@ * Step 3: update c = P^-1 c. */ - eigen_assert(rhs.rows() == m_lu.cols()); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS(m_lu, rhs, true); // Step 1 dst = m_lu.template triangularView<Upper>().transpose().template conjugateIf<Conjugate>().solve(rhs); @@ -606,7 +606,7 @@ nb_transpositions = 0; return; } - eigen_assert(lu.cols() == row_transpositions.size()); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS(row_transpositions.indices(), lu); eigen_assert(row_transpositions.size() < 2 || (&row_transpositions.coeffRef(1) - &row_transpositions.coeffRef(0)) == 1); @@ -651,7 +651,7 @@ else m_l1_norm = RealScalar(0); - eigen_assert(m_lu.rows() == m_lu.cols() && "PartialPivLU is only for square (and moreover invertible) matrices"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_lu, "PartialPivLU is only for square (and moreover invertible) matrices"); const Index size = m_lu.rows(); m_rowsTranspositions.resize(size);
diff --git a/Eigen/src/QR/ColPivHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h index e4abaf8..dca45f7 100644 --- a/Eigen/src/QR/ColPivHouseholderQR.h +++ b/Eigen/src/QR/ColPivHouseholderQR.h
@@ -328,7 +328,7 @@ template <typename MatrixType, typename PermutationIndex> typename MatrixType::Scalar ColPivHouseholderQR<MatrixType, PermutationIndex>::determinant() const { eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); Scalar detQ; internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ); return isInjective() ? (detQ * Scalar(m_det_p)) * m_qr.diagonal().prod() : Scalar(0); @@ -338,21 +338,21 @@ typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType, PermutationIndex>::absDeterminant() const { using std::abs; eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); return isInjective() ? abs(m_qr.diagonal().prod()) : RealScalar(0); } template <typename MatrixType, typename PermutationIndex> typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType, PermutationIndex>::logAbsDeterminant() const { eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); return isInjective() ? m_qr.diagonal().cwiseAbs().array().log().sum() : -NumTraits<RealScalar>::infinity(); } template <typename MatrixType, typename PermutationIndex> typename MatrixType::Scalar ColPivHouseholderQR<MatrixType, PermutationIndex>::signDeterminant() const { eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); Scalar detQ; internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ); return isInjective() ? (detQ * Scalar(m_det_p)) * m_qr.diagonal().array().sign().prod() : Scalar(0);
diff --git a/Eigen/src/QR/CompleteOrthogonalDecomposition.h b/Eigen/src/QR/CompleteOrthogonalDecomposition.h index 9b6a520..426b351 100644 --- a/Eigen/src/QR/CompleteOrthogonalDecomposition.h +++ b/Eigen/src/QR/CompleteOrthogonalDecomposition.h
@@ -187,10 +187,10 @@ template <bool Transpose_, typename Rhs> void _check_solve_assertion(const Rhs& b) const { - EIGEN_ONLY_USED_FOR_DEBUG(b); eigen_assert(m_cpqr.m_isInitialized && "CompleteOrthogonalDecomposition is not initialized."); - eigen_assert((Transpose_ ? this->cols() : this->rows()) == b.rows() && - "CompleteOrthogonalDecomposition::solve(): invalid number of rows of the right hand side matrix b"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG( + *this, b, Transpose_, + "CompleteOrthogonalDecomposition::solve(): invalid number of rows of the right hand side matrix b"); } void computeInPlace();
diff --git a/Eigen/src/QR/FullPivHouseholderQR.h b/Eigen/src/QR/FullPivHouseholderQR.h index 880115e..3de6e0c 100644 --- a/Eigen/src/QR/FullPivHouseholderQR.h +++ b/Eigen/src/QR/FullPivHouseholderQR.h
@@ -338,7 +338,7 @@ template <typename MatrixType, typename PermutationIndex> typename MatrixType::Scalar FullPivHouseholderQR<MatrixType, PermutationIndex>::determinant() const { eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); Scalar detQ; internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ); return isInjective() ? (detQ * Scalar(m_det_p)) * m_qr.diagonal().prod() : Scalar(0); @@ -348,21 +348,21 @@ typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType, PermutationIndex>::absDeterminant() const { using std::abs; eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); return isInjective() ? abs(m_qr.diagonal().prod()) : RealScalar(0); } template <typename MatrixType, typename PermutationIndex> typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType, PermutationIndex>::logAbsDeterminant() const { eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); return isInjective() ? m_qr.diagonal().cwiseAbs().array().log().sum() : -NumTraits<RealScalar>::infinity(); } template <typename MatrixType, typename PermutationIndex> typename MatrixType::Scalar FullPivHouseholderQR<MatrixType, PermutationIndex>::signDeterminant() const { eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); Scalar detQ; internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ); return isInjective() ? (detQ * Scalar(m_det_p)) * m_qr.diagonal().array().sign().prod() : Scalar(0);
diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index 1cbb180..4a48441 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h
@@ -338,7 +338,7 @@ template <typename MatrixType> typename MatrixType::Scalar HouseholderQR<MatrixType>::determinant() const { eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); Scalar detQ; internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ); return m_qr.diagonal().prod() * detQ; @@ -348,21 +348,21 @@ typename MatrixType::RealScalar HouseholderQR<MatrixType>::absDeterminant() const { using std::abs; eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); return abs(m_qr.diagonal().prod()); } template <typename MatrixType> typename MatrixType::RealScalar HouseholderQR<MatrixType>::logAbsDeterminant() const { eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); return m_qr.diagonal().cwiseAbs().array().log().sum(); } template <typename MatrixType> typename MatrixType::Scalar HouseholderQR<MatrixType>::signDeterminant() const { eigen_assert(m_isInitialized && "HouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); Scalar detQ; internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ); return detQ * m_qr.diagonal().array().sign().prod(); @@ -424,8 +424,8 @@ eigen_assert(k < mat.cols()); eigen_assert(k < rows); - eigen_assert(hCoeffs.size() == mat.cols()); - eigen_assert(newColumn.size() == rows); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS(hCoeffs, mat); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(newColumn, mat); eigen_assert(tempData); // Store new column in mat at column k
diff --git a/Eigen/src/QR/RandColPivHouseholderQR.h b/Eigen/src/QR/RandColPivHouseholderQR.h index 71cff02..ea4f3b3 100644 --- a/Eigen/src/QR/RandColPivHouseholderQR.h +++ b/Eigen/src/QR/RandColPivHouseholderQR.h
@@ -398,7 +398,7 @@ template <typename MatrixType, typename PermutationIndex> typename MatrixType::Scalar RandColPivHouseholderQR<MatrixType, PermutationIndex>::determinant() const { eigen_assert(m_isInitialized && "RandColPivHouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); Scalar detQ; internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ); return isInjective() ? (detQ * Scalar(m_det_p)) * m_qr.diagonal().prod() : Scalar(0); @@ -408,21 +408,21 @@ typename MatrixType::RealScalar RandColPivHouseholderQR<MatrixType, PermutationIndex>::absDeterminant() const { using std::abs; eigen_assert(m_isInitialized && "RandColPivHouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); return isInjective() ? abs(m_qr.diagonal().prod()) : RealScalar(0); } template <typename MatrixType, typename PermutationIndex> typename MatrixType::RealScalar RandColPivHouseholderQR<MatrixType, PermutationIndex>::logAbsDeterminant() const { eigen_assert(m_isInitialized && "RandColPivHouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); return isInjective() ? m_qr.diagonal().cwiseAbs().array().log().sum() : -NumTraits<RealScalar>::infinity(); } template <typename MatrixType, typename PermutationIndex> typename MatrixType::Scalar RandColPivHouseholderQR<MatrixType, PermutationIndex>::signDeterminant() const { eigen_assert(m_isInitialized && "RandColPivHouseholderQR is not initialized."); - eigen_assert(m_qr.rows() == m_qr.cols() && "You can't take the determinant of a non-square matrix!"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_qr, "You can't take the determinant of a non-square matrix!"); Scalar detQ; internal::householder_determinant<HCoeffsType, Scalar, NumTraits<Scalar>::IsComplex>::run(m_hCoeffs, detQ); return isInjective() ? (detQ * Scalar(m_det_p)) * m_qr.diagonal().array().sign().prod() : Scalar(0);
diff --git a/Eigen/src/SVD/SVDBase.h b/Eigen/src/SVD/SVDBase.h index db95114..724c6d3 100644 --- a/Eigen/src/SVD/SVDBase.h +++ b/Eigen/src/SVD/SVDBase.h
@@ -320,12 +320,11 @@ template <bool Transpose_, typename Rhs> void _check_solve_assertion(const Rhs& b) const { - EIGEN_ONLY_USED_FOR_DEBUG(b); _check_compute_assertions(); eigen_assert(computeU() && computeV() && "SVDBase::solve(): Both unitaries U and V are required to be computed (thin unitaries suffice)."); - eigen_assert((Transpose_ ? cols() : rows()) == b.rows() && - "SVDBase::solve(): invalid number of rows of the right hand side matrix b"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(derived(), b, Transpose_, + "SVDBase::solve(): invalid number of rows of the right hand side matrix b"); } // return true if already allocated
diff --git a/Eigen/src/SparseCholesky/SimplicialCholesky.h b/Eigen/src/SparseCholesky/SimplicialCholesky.h index 92e751b..6eb1c14 100644 --- a/Eigen/src/SparseCholesky/SimplicialCholesky.h +++ b/Eigen/src/SparseCholesky/SimplicialCholesky.h
@@ -180,7 +180,7 @@ eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or " "symbolic()/numeric()"); - eigen_assert(m_matrix.rows() == b.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(m_matrix, b); if (m_info != Success) return; @@ -211,7 +211,7 @@ /** Computes the sparse Cholesky decomposition of \a matrix */ template <bool DoLDLT, bool NonHermitian> void compute(const MatrixType& matrix) { - eigen_assert(matrix.rows() == matrix.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(matrix); Index size = matrix.cols(); CholMatrixType tmp(size, size); ConstCholMatrixPtr pmat; @@ -222,7 +222,7 @@ template <bool DoLDLT, bool NonHermitian> void factorize(const MatrixType& a) { - eigen_assert(a.rows() == a.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(a); Index size = a.cols(); CholMatrixType tmp(size, size); ConstCholMatrixPtr pmat; @@ -245,7 +245,7 @@ template <bool DoLDLT, bool NonHermitian> void analyzePattern(const MatrixType& a) { - eigen_assert(a.rows() == a.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(a); Index size = a.cols(); CholMatrixType tmp(size, size); ConstCholMatrixPtr pmat; @@ -930,7 +930,7 @@ eigen_assert(Base::m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or " "symbolic()/numeric()"); - eigen_assert(Base::m_matrix.rows() == b.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(Base::m_matrix, b); if (Base::m_info != Success) return; @@ -984,7 +984,7 @@ template <typename Derived> template <bool NonHermitian> void SimplicialCholeskyBase<Derived>::ordering(const MatrixType& a, ConstCholMatrixPtr& pmat, CholMatrixType& ap) { - eigen_assert(a.rows() == a.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(a); const Index size = a.rows(); pmat = ≈ // Note that ordering methods compute the inverse permutation
diff --git a/Eigen/src/SparseCholesky/SimplicialCholesky_impl.h b/Eigen/src/SparseCholesky/SimplicialCholesky_impl.h index 85d363b..7ad42e3 100644 --- a/Eigen/src/SparseCholesky/SimplicialCholesky_impl.h +++ b/Eigen/src/SparseCholesky/SimplicialCholesky_impl.h
@@ -323,7 +323,7 @@ const StorageIndex size = StorageIndex(ap.rows()); eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); - eigen_assert(ap.rows() == ap.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(ap); eigen_assert(m_parent.size() == size); eigen_assert(m_workSpace.size() >= 3 * size);
diff --git a/Eigen/src/SparseCore/BlockSparseMatrix.h b/Eigen/src/SparseCore/BlockSparseMatrix.h index a9ef4b3..f046b9b 100644 --- a/Eigen/src/SparseCore/BlockSparseMatrix.h +++ b/Eigen/src/SparseCore/BlockSparseMatrix.h
@@ -1328,7 +1328,7 @@ EIGEN_STATIC_ASSERT( (std::is_same<Scalar, typename OtherDerived::Scalar>::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - eigen_assert(m_matrix.cols() == rhs.rows() && "BlockSparseTriangularView * Dense: dimension mismatch"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(m_matrix, rhs, "BlockSparseTriangularView * Dense: dimension mismatch"); using ResultType = Matrix<Scalar, Dynamic, OtherDerived::ColsAtCompileTime>; ResultType result = ResultType::Zero(m_matrix.rows(), rhs.cols()); for (Index out = 0; out < m_matrix.m_blockOuterSize; ++out) { @@ -1356,7 +1356,7 @@ EIGEN_STATIC_ASSERT( (std::is_same<Scalar, typename OtherDerived::Scalar>::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - eigen_assert(lhs.cols() == tri.m_matrix.rows() && "Dense * BlockSparseTriangularView: dimension mismatch"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(lhs, tri.m_matrix, "Dense * BlockSparseTriangularView: dimension mismatch"); constexpr bool isRM = BSM::IsRowMajor; using ResultType = Matrix<Scalar, OtherDerived::RowsAtCompileTime, Dynamic>; // BSM befriends BlockSparseTriangularView, but GCC <= 11 and MSVC do not @@ -1434,7 +1434,7 @@ constexpr int DiagMode = IsUpper ? Upper : Lower; constexpr bool diagFirst = (IsUpper == BSM::IsRowMajor); Index nb = m_matrix.blockCols(); // == blockRows() for square matrices - eigen_assert(x.rows() == m_matrix.rows() && "solveInPlace: size mismatch"); + EIGEN_INTERNAL_ASSERT_SAME_ROWS_MSG(x, m_matrix, "solveInPlace: size mismatch"); const StorageIndex* innerPtr = m_matrix.innerIndexPtr(); const StorageIndex* outerPtr = m_matrix.outerIndexPtr(); @@ -1484,7 +1484,7 @@ constexpr int DiagMode = IsUpper ? Upper : Lower; constexpr bool diagFirst = (IsUpper == BSM::IsRowMajor); Index nb = m_matrix.blockCols(); // == blockRows() for square matrices - eigen_assert(x.rows() == m_matrix.rows() && "solveInPlace: size mismatch"); + EIGEN_INTERNAL_ASSERT_SAME_ROWS_MSG(x, m_matrix, "solveInPlace: size mismatch"); const StorageIndex* innerPtr = m_matrix.innerIndexPtr(); const StorageIndex* outerPtr = m_matrix.outerIndexPtr(); @@ -1680,7 +1680,7 @@ EIGEN_STATIC_ASSERT( (std::is_same<Scalar, typename OtherDerived::Scalar>::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - eigen_assert(m_matrix.cols() == rhs.rows() && "BlockSparseSelfAdjointView * Dense: dimension mismatch"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(m_matrix, rhs, "BlockSparseSelfAdjointView * Dense: dimension mismatch"); using ResultType = Matrix<Scalar, Dynamic, OtherDerived::ColsAtCompileTime>; ResultType result = ResultType::Zero(m_matrix.rows(), rhs.cols());
diff --git a/Eigen/src/SparseCore/SparseDot.h b/Eigen/src/SparseCore/SparseDot.h index 77ff573..bcd4916 100644 --- a/Eigen/src/SparseCore/SparseDot.h +++ b/Eigen/src/SparseCore/SparseDot.h
@@ -22,12 +22,11 @@ const MatrixBase<OtherDerived>& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived, OtherDerived) EIGEN_STATIC_ASSERT( (std::is_same<Scalar, typename OtherDerived::Scalar>::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - eigen_assert(size() == other.size()); + EIGEN_INTERNAL_ASSERT_SAME_SIZE(*this, other); if (size() == 0) return Scalar(0); internal::evaluator<Derived> thisEval(derived()); @@ -52,12 +51,11 @@ const SparseMatrixBase<OtherDerived>& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) - EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived, OtherDerived) EIGEN_STATIC_ASSERT( (std::is_same<Scalar, typename OtherDerived::Scalar>::value), YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) - eigen_assert(size() == other.size()); + EIGEN_INTERNAL_ASSERT_SAME_SIZE(*this, other); if (size() == 0) return Scalar(0); internal::evaluator<Derived> thisEval(derived());
diff --git a/Eigen/src/SparseCore/SparseSelfAdjointView.h b/Eigen/src/SparseCore/SparseSelfAdjointView.h index 2c756e4..f49089a 100644 --- a/Eigen/src/SparseCore/SparseSelfAdjointView.h +++ b/Eigen/src/SparseCore/SparseSelfAdjointView.h
@@ -69,7 +69,7 @@ SparseMatrix<Scalar, (MatrixTypeNested_::Flags & RowMajorBit) ? RowMajor : ColMajor, StorageIndex>; explicit inline SparseSelfAdjointView(MatrixType& matrix) : m_matrix(matrix) { - eigen_assert(rows() == cols() && "SelfAdjointView is only for squared matrices"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(matrix, "SelfAdjointView is only for squared matrices"); } inline Index rows() const { return m_matrix.rows(); }
diff --git a/Eigen/src/SparseCore/SparseSolverBase.h b/Eigen/src/SparseCore/SparseSolverBase.h index 10f4c63..d91477f 100644 --- a/Eigen/src/SparseCore/SparseSolverBase.h +++ b/Eigen/src/SparseCore/SparseSolverBase.h
@@ -87,7 +87,8 @@ template <typename Rhs> inline Solve<Derived, Rhs> solve(const MatrixBase<Rhs>& b) const { eigen_assert(m_isInitialized && "Solver is not initialized."); - eigen_assert(derived().rows() == b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(derived(), b, false, + "solve(): invalid number of rows of the right hand side matrix b"); return Solve<Derived, Rhs>(derived(), b.derived()); } @@ -98,7 +99,8 @@ template <typename Rhs> inline Solve<Derived, Rhs> solve(const SparseMatrixBase<Rhs>& b) const { eigen_assert(m_isInitialized && "Solver is not initialized."); - eigen_assert(derived().rows() == b.rows() && "solve(): invalid number of rows of the right hand side matrix b"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(derived(), b, false, + "solve(): invalid number of rows of the right hand side matrix b"); return Solve<Derived, Rhs>(derived(), b.derived()); }
diff --git a/Eigen/src/SparseCore/ThreadedSparseProduct.h b/Eigen/src/SparseCore/ThreadedSparseProduct.h index db62f8a..7cadb51 100644 --- a/Eigen/src/SparseCore/ThreadedSparseProduct.h +++ b/Eigen/src/SparseCore/ThreadedSparseProduct.h
@@ -234,13 +234,8 @@ template <bool Adjoint, bool Overwrite> void apply_impl(const ConstVectorRef& x, MutableVectorRef& y, const Scalar& alpha) const { eigen_assert(m_mat && "ThreadedSparseProduct: matrix not set; call analyzePattern() first"); - if (Adjoint) { - eigen_assert(x.size() == m_mat->rows()); - eigen_assert(y.size() == m_mat->cols()); - } else { - eigen_assert(x.size() == m_mat->cols()); - eigen_assert(y.size() == m_mat->rows()); - } + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_AXIS(x, *m_mat, Adjoint); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_AXIS(y, *m_mat, !Adjoint); // The kernel reads x and writes y concurrently across threads; aliasing // (x and y overlap) would mis-compute because some x[k] reads see y // writes from the same SpMV call. Cheap address-range check; cast to
diff --git a/Eigen/src/SparseCore/TriangularSolver.h b/Eigen/src/SparseCore/TriangularSolver.h index 0f306e9..588e6b7 100644 --- a/Eigen/src/SparseCore/TriangularSolver.h +++ b/Eigen/src/SparseCore/TriangularSolver.h
@@ -155,7 +155,8 @@ template <typename ExpressionType, unsigned int Mode> template <typename OtherDerived> void TriangularViewImpl<ExpressionType, Mode, Sparse>::solveInPlace(MatrixBase<OtherDerived>& other) const { - eigen_assert(derived().cols() == derived().rows() && derived().cols() == other.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(derived()); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(derived(), other); eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper | Lower))); enum { copy = internal::traits<OtherDerived>::Flags & RowMajorBit }; @@ -310,7 +311,8 @@ template <typename ExpressionType, unsigned int Mode> template <typename OtherDerived> void TriangularViewImpl<ExpressionType, Mode, Sparse>::solveInPlace(SparseMatrixBase<OtherDerived>& other) const { - eigen_assert(derived().cols() == derived().rows() && derived().cols() == other.rows()); + EIGEN_INTERNAL_ASSERT_SQUARE(derived()); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(derived(), other); eigen_assert((!(Mode & ZeroDiag)) && bool(Mode & (Upper | Lower))); internal::sparse_solve_triangular_sparse_selector<ExpressionType, OtherDerived, Mode>::run(
diff --git a/Eigen/src/SparseLU/SparseLU.h b/Eigen/src/SparseLU/SparseLU.h index f0db58d..7316cf6 100644 --- a/Eigen/src/SparseLU/SparseLU.h +++ b/Eigen/src/SparseLU/SparseLU.h
@@ -613,7 +613,7 @@ void SparseLU<MatrixType, OrderingType>::factorize(const MatrixType& matrix) { using internal::emptyIdxLU; eigen_assert(m_analysisIsOk && "analyzePattern() should be called first"); - eigen_assert((matrix.rows() == matrix.cols()) && "Only for squared matrices"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(matrix, "Only for squared matrices"); m_isInitialized = true;
diff --git a/Eigen/src/SparseQR/SparseQR.h b/Eigen/src/SparseQR/SparseQR.h index e316270..9940138 100644 --- a/Eigen/src/SparseQR/SparseQR.h +++ b/Eigen/src/SparseQR/SparseQR.h
@@ -231,8 +231,8 @@ template <typename Rhs, typename Dest> bool _solve_impl(const MatrixBase<Rhs>& B, MatrixBase<Dest>& dest) const { eigen_assert(m_isInitialized && "The factorization should be called first, use compute()"); - eigen_assert(this->rows() == B.rows() && - "SparseQR::solve() : invalid number of rows in the right hand side matrix"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(*this, B, false, + "SparseQR::solve() : invalid number of rows in the right hand side matrix"); Index rank = this->rank(); @@ -275,15 +275,15 @@ template <typename Rhs> inline Solve<SparseQR, Rhs> solve(const MatrixBase<Rhs>& B) const { eigen_assert(m_isInitialized && "The factorization should be called first, use compute()"); - eigen_assert(this->rows() == B.rows() && - "SparseQR::solve() : invalid number of rows in the right hand side matrix"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(*this, B, false, + "SparseQR::solve() : invalid number of rows in the right hand side matrix"); return Solve<SparseQR, Rhs>(*this, B.derived()); } template <typename Rhs> inline Solve<SparseQR, Rhs> solve(const SparseMatrixBase<Rhs>& B) const { eigen_assert(m_isInitialized && "The factorization should be called first, use compute()"); - eigen_assert(this->rows() == B.rows() && - "SparseQR::solve() : invalid number of rows in the right hand side matrix"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(*this, B, false, + "SparseQR::solve() : invalid number of rows in the right hand side matrix"); return Solve<SparseQR, Rhs>(*this, B.derived()); } @@ -735,7 +735,7 @@ Index diagSize = (std::min)(m, n); res = m_other; if (m_transpose) { - eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes"); + EIGEN_INTERNAL_ASSERT_SAME_ROWS_MSG(m_qr.m_Q, m_other, "Non conforming object sizes"); // Compute res = Q' * other column by column for (Index j = 0; j < res.cols(); j++) { for (Index k = 0; k < diagSize; k++) { @@ -747,7 +747,7 @@ } } } else { - eigen_assert(m_qr.matrixQ().cols() == m_other.rows() && "Non conforming object sizes"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(m_qr.matrixQ(), m_other, "Non conforming object sizes"); res.conservativeResize(rows(), cols());
diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 43d5fdf..ae21d7e 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake
@@ -273,6 +273,8 @@ add_executable(${test_target_ok} ${testname}.cpp) add_executable(${test_target_ko} ${testname}.cpp) + target_link_libraries(${test_target_ok} PRIVATE Eigen3::Eigen) + target_link_libraries(${test_target_ko} PRIVATE Eigen3::Eigen) set_target_properties(${test_target_ok} ${test_target_ko} PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE)
diff --git a/contrib/Eigen/FFT b/contrib/Eigen/FFT index 56addd9..c754a52 100644 --- a/contrib/Eigen/FFT +++ b/contrib/Eigen/FFT
@@ -308,7 +308,7 @@ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) EIGEN_STATIC_ASSERT(int(InputDerived::Flags) & int(ComplexDerived::Flags) & DirectAccessBit, THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES) - eigen_assert((src.rows() == 1 || src.cols() == 1) && "the input of an FFT must be one-dimensional"); + EIGEN_INTERNAL_ASSERT_VECTOR(src); if (nfft < 1) nfft = src.size(); @@ -381,7 +381,7 @@ YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY) EIGEN_STATIC_ASSERT(int(OutputDerived::Flags) & int(ComplexDerived::Flags) & DirectAccessBit, THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_WITH_DIRECT_MEMORY_ACCESS_SUCH_AS_MAP_OR_PLAIN_MATRICES) - eigen_assert((src.rows() == 1 || src.cols() == 1) && "the input of an FFT must be one-dimensional"); + EIGEN_INTERNAL_ASSERT_VECTOR(src); if (nfft < 1) { // automatic FFT size determination if (realfft && HasFlag(HalfSpectrum))
diff --git a/contrib/Eigen/src/MatrixFunctions/MatrixExponential.h b/contrib/Eigen/src/MatrixFunctions/MatrixExponential.h index 14e2b95..0bf8205 100644 --- a/contrib/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/contrib/Eigen/src/MatrixFunctions/MatrixExponential.h
@@ -423,7 +423,7 @@ template <typename Derived> const MatrixExponentialReturnValue<Derived> MatrixBase<Derived>::exp() const { - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); return MatrixExponentialReturnValue<Derived>(derived()); }
diff --git a/contrib/Eigen/src/MatrixFunctions/MatrixFunction.h b/contrib/Eigen/src/MatrixFunctions/MatrixFunction.h index a348da0..917847d 100644 --- a/contrib/Eigen/src/MatrixFunctions/MatrixFunction.h +++ b/contrib/Eigen/src/MatrixFunctions/MatrixFunction.h
@@ -266,12 +266,12 @@ */ template <typename MatrixType> MatrixType matrix_function_solve_triangular_sylvester(const MatrixType& A, const MatrixType& B, const MatrixType& C) { - eigen_assert(A.rows() == A.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(A); eigen_assert(A.isUpperTriangular()); - eigen_assert(B.rows() == B.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(B); eigen_assert(B.isUpperTriangular()); - eigen_assert(C.rows() == A.rows()); - eigen_assert(C.cols() == B.rows()); + EIGEN_INTERNAL_ASSERT_SAME_ROWS(C, A); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(C, B); typedef typename MatrixType::Scalar Scalar; @@ -510,34 +510,34 @@ template <typename Derived> const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::matrixFunction( typename internal::stem_function<typename internal::traits<Derived>::Scalar>::type f) const { - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); return MatrixFunctionReturnValue<Derived>(derived(), f); } template <typename Derived> const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::sin() const { - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar; return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_sin<ComplexScalar>); } template <typename Derived> const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::cos() const { - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar; return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_cos<ComplexScalar>); } template <typename Derived> const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::sinh() const { - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar; return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_sinh<ComplexScalar>); } template <typename Derived> const MatrixFunctionReturnValue<Derived> MatrixBase<Derived>::cosh() const { - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); typedef typename internal::stem_function<Scalar>::ComplexScalar ComplexScalar; return MatrixFunctionReturnValue<Derived>(derived(), internal::stem_function_cosh<ComplexScalar>); }
diff --git a/contrib/Eigen/src/MatrixFunctions/MatrixLogarithm.h b/contrib/Eigen/src/MatrixFunctions/MatrixLogarithm.h index b169ba6..d285b0e 100644 --- a/contrib/Eigen/src/MatrixFunctions/MatrixLogarithm.h +++ b/contrib/Eigen/src/MatrixFunctions/MatrixLogarithm.h
@@ -373,7 +373,7 @@ template <typename Derived> const MatrixLogarithmReturnValue<Derived> MatrixBase<Derived>::log() const { - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); return MatrixLogarithmReturnValue<Derived>(derived()); }
diff --git a/contrib/Eigen/src/MatrixFunctions/MatrixPower.h b/contrib/Eigen/src/MatrixFunctions/MatrixPower.h index d090d95..293a8ac 100644 --- a/contrib/Eigen/src/MatrixFunctions/MatrixPower.h +++ b/contrib/Eigen/src/MatrixFunctions/MatrixPower.h
@@ -135,7 +135,7 @@ template <typename MatrixType> MatrixPowerAtomic<MatrixType>::MatrixPowerAtomic(const MatrixType& T, RealScalar p) : m_A(T), m_p(p) { - eigen_assert(T.rows() == T.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(T); eigen_assert(p > -1 && p < 1); } @@ -369,7 +369,7 @@ * (or destroyed) before evaluation. */ explicit MatrixPower(const MatrixType& A) : m_A(A), m_conditionNumber(0), m_rank(A.cols()), m_nulls(0) { - eigen_assert(A.rows() == A.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(A); } /**
diff --git a/contrib/Eigen/src/MatrixFunctions/MatrixSquareRoot.h b/contrib/Eigen/src/MatrixFunctions/MatrixSquareRoot.h index 4aac6f5..37a8831 100644 --- a/contrib/Eigen/src/MatrixFunctions/MatrixSquareRoot.h +++ b/contrib/Eigen/src/MatrixFunctions/MatrixSquareRoot.h
@@ -170,7 +170,7 @@ */ template <typename MatrixType, typename ResultType> void matrix_sqrt_quasi_triangular(const MatrixType& arg, ResultType& result) { - eigen_assert(arg.rows() == arg.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(arg); result.resize(arg.rows(), arg.cols()); internal::matrix_sqrt_quasi_triangular_diagonal(arg, result); internal::matrix_sqrt_quasi_triangular_off_diagonal(arg, result); @@ -195,7 +195,7 @@ using std::sqrt; typedef typename MatrixType::Scalar Scalar; - eigen_assert(arg.rows() == arg.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(arg); // Compute square root of arg and store it in upper triangular part of result // This uses that the square root of triangular matrices can be computed directly. @@ -242,7 +242,7 @@ typedef typename MatrixType::PlainObject PlainType; template <typename ResultType> static void run(const MatrixType& arg, ResultType& result) { - eigen_assert(arg.rows() == arg.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(arg); // Compute Schur decomposition of arg const RealSchur<PlainType> schurOfA(arg); @@ -265,7 +265,7 @@ typedef typename MatrixType::PlainObject PlainType; template <typename ResultType> static void run(const MatrixType& arg, ResultType& result) { - eigen_assert(arg.rows() == arg.cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(arg); // Compute Schur decomposition of arg const ComplexSchur<PlainType> schurOfA(arg); @@ -337,7 +337,7 @@ template <typename Derived> const MatrixSquareRootReturnValue<Derived> MatrixBase<Derived>::sqrt() const { - eigen_assert(rows() == cols()); + EIGEN_INTERNAL_ASSERT_SQUARE(*this); return MatrixSquareRootReturnValue<Derived>(derived()); }
diff --git a/contrib/Eigen/src/StructuredMatrices/Bccb.h b/contrib/Eigen/src/StructuredMatrices/Bccb.h index 655c036..a95eb31 100644 --- a/contrib/Eigen/src/StructuredMatrices/Bccb.h +++ b/contrib/Eigen/src/StructuredMatrices/Bccb.h
@@ -165,7 +165,7 @@ * cached transform. */ template <typename Derived> explicit Bccb(const MatrixBase<Derived>& generator) : m_g(generator) { - eigen_assert(m_g.rows() > 0 && m_g.cols() > 0 && "Bccb generator must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(m_g, "Bccb generator must be non-empty"); if (m_g.size() > internal::structured_direct_threshold()) { m_symbol = computeSymbol(); m_prodSymbol = computeProdSymbol(m_g); @@ -228,11 +228,8 @@ * multiple right-hand sides. */ template <typename Rhs> Matrix<Scalar, RowsAtCompileTime, Rhs::ColsAtCompileTime> solve(const MatrixBase<Rhs>& b) const { - EIGEN_STATIC_ASSERT(RowsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(RowsAtCompileTime) == int(Rhs::RowsAtCompileTime), - YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(*this, b, false, "right-hand side has the wrong number of rows"); const Index N = rows(); - eigen_assert(b.rows() == N && "right-hand side has the wrong number of rows"); const ComplexArray s = symbol(); const RealArray mods = s.cwiseAbs(); const ComplexArray sinv = internal::structured_pinv_symbol(s, mods, internal::structured_rank_threshold(s, mods)); @@ -370,10 +367,6 @@ * it. */ template <typename Rhs> Product<Bccb, Rhs> operator*(const MatrixBase<Rhs>& x) const { - EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(ColsAtCompileTime) == int(Rhs::RowsAtCompileTime), - INVALID_MATRIX_PRODUCT) - eigen_assert(x.rows() == cols() && "invalid product: dimensions do not match"); return Product<Bccb, Rhs>(*this, x.derived()); } @@ -383,7 +376,7 @@ template <typename Dest, typename Rhs, typename ProductScalar> void addProduct(Dest& dst, const Rhs& rhs, const ProductScalar& alpha) const { const Index N = rows(); - eigen_assert(rhs.rows() == N && "invalid product: dimensions do not match"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(*this, rhs, "invalid product: dimensions do not match"); if (N <= internal::structured_direct_threshold()) { directProduct(dst, rhs, alpha); return;
diff --git a/contrib/Eigen/src/StructuredMatrices/Cauchy.h b/contrib/Eigen/src/StructuredMatrices/Cauchy.h index 99e52b2..f6f5019 100644 --- a/contrib/Eigen/src/StructuredMatrices/Cauchy.h +++ b/contrib/Eigen/src/StructuredMatrices/Cauchy.h
@@ -134,7 +134,8 @@ Cauchy(const MatrixBase<XDerived>& x, const MatrixBase<YDerived>& y) : m_x(x), m_y(y) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(XDerived) EIGEN_STATIC_ASSERT_VECTOR_ONLY(YDerived) - eigen_assert(m_x.size() > 0 && m_y.size() > 0 && "Cauchy node vectors must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(m_x, "Cauchy node vectors must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(m_y, "Cauchy node vectors must be non-empty"); } EIGEN_DEVICE_FUNC Index rows() const { return m_x.size(); } @@ -175,7 +176,7 @@ * a node difference that overflows makes its factor infinite, which turns the * determinant into NaN when it meets a zero or another infinite factor. */ Scalar determinant() const { - eigen_assert(rows() == cols() && "Cauchy::determinant requires a square matrix"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(*this, "Cauchy::determinant requires a square matrix"); const Index n = rows(); Scalar det(1); Index exponent = 0; @@ -222,10 +223,6 @@ * \a v, and \c .noalias() skips it. */ template <typename Rhs> Product<Cauchy, Rhs> operator*(const MatrixBase<Rhs>& v) const { - EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(ColsAtCompileTime) == int(Rhs::RowsAtCompileTime), - INVALID_MATRIX_PRODUCT) - eigen_assert(v.rows() == cols() && "invalid product: dimensions do not match"); return Product<Cauchy, Rhs>(*this, v.derived()); } @@ -238,7 +235,7 @@ template <typename Dest, typename Rhs, typename ProductScalar> void addProduct(Dest& dst, const Rhs& rhs, const ProductScalar& alpha) const { const Index n = cols(); - eigen_assert(rhs.rows() == n && "invalid product: dimensions do not match"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(*this, rhs, "invalid product: dimensions do not match"); // A unit alpha must not multiply: even the identity complex scalar (1,0) // pollutes an (Inf,0) value with NaN through the 0*Inf cross term. const bool unitAlpha = alpha == ProductScalar(1); @@ -351,7 +348,7 @@ * \f$D_x C-C D_y=\mathbf{1}\mathbf{1}^T\f$. \sa solve */ template <int Rows_, int Cols_> CauchyLU& compute(const Cauchy<Scalar, Rows_, Cols_>& C) { - eigen_assert(C.rows() == C.cols() && "CauchyLU requires a square Cauchy matrix"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(C, "CauchyLU requires a square Cauchy matrix"); const Index n = C.rows(); DenseVector x = C.rowNodes(); const DenseVector y = C.colNodes();
diff --git a/contrib/Eigen/src/StructuredMatrices/Circulant.h b/contrib/Eigen/src/StructuredMatrices/Circulant.h index bb1ebc5..e078899 100644 --- a/contrib/Eigen/src/StructuredMatrices/Circulant.h +++ b/contrib/Eigen/src/StructuredMatrices/Circulant.h
@@ -125,7 +125,7 @@ template <typename Derived> explicit Circulant(const MatrixBase<Derived>& col) : m_col(col) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - eigen_assert(m_col.size() > 0 && "Circulant generator must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(m_col, "Circulant generator must be non-empty"); if (m_col.size() > internal::structured_direct_threshold()) { m_symbol = computeSymbol(); m_prodSymbol = computeProdSymbol(m_col); @@ -243,10 +243,6 @@ * aliasing between the destination and \a x, and \c .noalias() skips it. */ template <typename Rhs> Product<Circulant, Rhs> operator*(const MatrixBase<Rhs>& x) const { - EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(ColsAtCompileTime) == int(Rhs::RowsAtCompileTime), - INVALID_MATRIX_PRODUCT) - eigen_assert(x.rows() == cols() && "invalid product: dimensions do not match"); return Product<Circulant, Rhs>(*this, x.derived()); } @@ -258,11 +254,8 @@ * \c x = ifft( fft(b) ./ fft(c) ). Supports multiple right-hand sides. */ template <typename Rhs> Matrix<Scalar, Size_, Rhs::ColsAtCompileTime> solve(const MatrixBase<Rhs>& b) const { - EIGEN_STATIC_ASSERT(RowsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(RowsAtCompileTime) == int(Rhs::RowsAtCompileTime), - YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(*this, b, false, "right-hand side has the wrong number of rows"); const Index n = rows(); - eigen_assert(b.rows() == n && "right-hand side has the wrong number of rows"); const ComplexVector s = symbol(); const RealVector mods = s.cwiseAbs(); const ComplexVector sinv = internal::structured_pinv_symbol(s, mods, internal::structured_rank_threshold(s, mods)); @@ -391,7 +384,7 @@ template <typename Dest, typename Rhs, typename ProductScalar> void addProduct(Dest& dst, const Rhs& rhs, const ProductScalar& alpha) const { const Index n = rows(); - eigen_assert(rhs.rows() == n && "invalid product: dimensions do not match"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(*this, rhs, "invalid product: dimensions do not match"); if (n <= internal::structured_direct_threshold()) { directProduct(dst, rhs, alpha); return;
diff --git a/contrib/Eigen/src/StructuredMatrices/DPR1EigenSolver.h b/contrib/Eigen/src/StructuredMatrices/DPR1EigenSolver.h index 867dc9d..daa1b43 100644 --- a/contrib/Eigen/src/StructuredMatrices/DPR1EigenSolver.h +++ b/contrib/Eigen/src/StructuredMatrices/DPR1EigenSolver.h
@@ -143,7 +143,7 @@ DPR1EigenSolver<RealScalar_>& DPR1EigenSolver<RealScalar_>::compute(const VectorType& d, RealScalar rho, const VectorType& z, int options) { const Index n = d.size(); - eigen_assert(z.size() == n && "d and z must have the same size"); + EIGEN_INTERNAL_ASSERT_SAME_SIZE_MSG(d, z, "d and z must have the same size"); eigen_assert((options & ~EigVecMask) == 0 && (options & EigVecMask) != EigVecMask && "invalid option parameter"); const bool computeVectors = (options & ComputeEigenvectors) == ComputeEigenvectors; m_vectorsComputed = false;
diff --git a/contrib/Eigen/src/StructuredMatrices/DiagonalPlusLowRank.h b/contrib/Eigen/src/StructuredMatrices/DiagonalPlusLowRank.h index 9dd76f7..c8b45d3 100644 --- a/contrib/Eigen/src/StructuredMatrices/DiagonalPlusLowRank.h +++ b/contrib/Eigen/src/StructuredMatrices/DiagonalPlusLowRank.h
@@ -173,9 +173,10 @@ DiagonalPlusLowRank(const MatrixBase<DDerived>& d, const MatrixBase<UDerived>& U, const MatrixBase<VDerived>& V) : m_d(d), m_U(U), m_V(V) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(DDerived) - eigen_assert(m_d.size() > 0 && "DiagonalPlusLowRank must be non-empty"); - eigen_assert(m_U.rows() == m_d.size() && m_V.rows() == m_d.size() && m_U.cols() == m_V.cols() && - "factor dimensions do not match"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(m_d, "DiagonalPlusLowRank must be non-empty"); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS_MSG(m_d, m_U, "factor dimensions do not match"); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS_MSG(m_d, m_V, "factor dimensions do not match"); + EIGEN_INTERNAL_ASSERT_SAME_COLS_MSG(m_U, m_V, "factor dimensions do not match"); } EIGEN_DEVICE_FUNC Index rows() const { return m_d.size(); } @@ -238,10 +239,7 @@ * accuracy degrades accordingly, even for a well-conditioned operator [5]. */ template <typename Rhs> Matrix<Scalar, Size_, Rhs::ColsAtCompileTime> solve(const MatrixBase<Rhs>& b) const { - EIGEN_STATIC_ASSERT(RowsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(RowsAtCompileTime) == int(Rhs::RowsAtCompileTime), - YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) - eigen_assert(b.rows() == rows() && "right-hand side has the wrong number of rows"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(*this, b, false, "right-hand side has the wrong number of rows"); const DiagonalVector dinv = m_d.cwiseInverse(); Matrix<Scalar, Size_, Rhs::ColsAtCompileTime> x = dinv.asDiagonal() * b; internal::dplr_capacitance_impl<Rank_>::subtractSolveCorrection(*this, dinv, x); @@ -318,10 +316,6 @@ * it. */ template <typename Rhs> Product<DiagonalPlusLowRank, Rhs> operator*(const MatrixBase<Rhs>& v) const { - EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(ColsAtCompileTime) == int(Rhs::RowsAtCompileTime), - INVALID_MATRIX_PRODUCT) - eigen_assert(v.rows() == cols() && "invalid product: dimensions do not match"); return Product<DiagonalPlusLowRank, Rhs>(*this, v.derived()); } @@ -331,7 +325,7 @@ * promoted type. */ template <typename Dest, typename Rhs, typename ProductScalar> void addProduct(Dest& dst, const Rhs& rhs, const ProductScalar& alpha) const { - eigen_assert(rhs.rows() == rows() && "invalid product: dimensions do not match"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(*this, rhs, "invalid product: dimensions do not match"); const Matrix<ProductScalar, Size_, Rhs::ColsAtCompileTime> r = rhs; dst += alpha * (m_d.asDiagonal() * r); if (correctionRank() > 0) {
diff --git a/contrib/Eigen/src/StructuredMatrices/Hankel.h b/contrib/Eigen/src/StructuredMatrices/Hankel.h index 65efd15..38a8b2f 100644 --- a/contrib/Eigen/src/StructuredMatrices/Hankel.h +++ b/contrib/Eigen/src/StructuredMatrices/Hankel.h
@@ -134,7 +134,8 @@ EIGEN_STATIC_ASSERT_VECTOR_ONLY(ColDerived) EIGEN_STATIC_ASSERT_VECTOR_ONLY(RowDerived) const Index m = col.size(), n = row.size(); - eigen_assert(m > 0 && n > 0 && "Hankel generators must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_SIZE_MSG(col, m, "Hankel generators must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_SIZE_MSG(row, n, "Hankel generators must be non-empty"); m_h.resize(m + n - 1); m_h.head(m) = col; if (n > 1) m_h.tail(n - 1) = row.tail(n - 1); @@ -210,11 +211,8 @@ * the solution rows. */ template <typename Rhs> Matrix<Scalar, SolveRowsAtCompileTime, Rhs::ColsAtCompileTime> solve(const MatrixBase<Rhs>& b) const { - EIGEN_STATIC_ASSERT(RowsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(RowsAtCompileTime) == int(Rhs::RowsAtCompileTime), - YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) - eigen_assert(rows() == cols() && "Hankel::solve requires a square matrix"); - eigen_assert(b.rows() == rows() && "right-hand side has the wrong number of rows"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(*this, "Hankel::solve requires a square matrix"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(*this, b, false, "right-hand side has the wrong number of rows"); LookAheadLevinson<Scalar> levinson(toToeplitz()); eigen_assert(levinson.info() == Success && "Hankel::solve: the Levinson recursion broke down; " @@ -260,10 +258,6 @@ * aliasing between the destination and \a x, and \c .noalias() skips it. */ template <typename Rhs> Product<Hankel, Rhs> operator*(const MatrixBase<Rhs>& x) const { - EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(ColsAtCompileTime) == int(Rhs::RowsAtCompileTime), - INVALID_MATRIX_PRODUCT) - eigen_assert(x.rows() == cols() && "invalid product: dimensions do not match"); return Product<Hankel, Rhs>(*this, x.derived()); } @@ -278,7 +272,7 @@ template <typename Dest, typename Rhs, typename ProductScalar> void addProduct(Dest& dst, const Rhs& rhs, const ProductScalar& alpha) const { const Index m = rows(), n = cols(); - eigen_assert(rhs.rows() == n && "invalid product: dimensions do not match"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(*this, rhs, "invalid product: dimensions do not match"); const bool small = m == 1 || n == 1 || (m <= internal::structured_direct_threshold() && n <= internal::structured_direct_threshold()); if (small) {
diff --git a/contrib/Eigen/src/StructuredMatrices/KroneckerOperator.h b/contrib/Eigen/src/StructuredMatrices/KroneckerOperator.h index 4e83bda..1a937e7 100644 --- a/contrib/Eigen/src/StructuredMatrices/KroneckerOperator.h +++ b/contrib/Eigen/src/StructuredMatrices/KroneckerOperator.h
@@ -968,7 +968,8 @@ template <typename LhsDerived, typename RhsDerived> KroneckerOperator(const EigenBase<LhsDerived>& a, const EigenBase<RhsDerived>& b) : m_A(a.derived()), m_B(b.derived()) { - eigen_assert(m_A.size() > 0 && m_B.size() > 0 && "KroneckerOperator factors must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(m_A, "KroneckerOperator factors must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(m_B, "KroneckerOperator factors must be non-empty"); LhsOps::prepare(m_A); RhsOps::prepare(m_B); } @@ -1032,12 +1033,10 @@ * \ref leastSquaresSolve for rank-deficient or rectangular factors. */ template <typename Rhs> Matrix<Scalar, ColsAtCompileTime, Rhs::ColsAtCompileTime> solve(const MatrixBase<Rhs>& b) const { - EIGEN_STATIC_ASSERT(RowsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(RowsAtCompileTime) == int(Rhs::RowsAtCompileTime), - YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) const Index n1 = m_A.cols(), n2 = m_B.cols(); - eigen_assert(m_A.rows() == n1 && m_B.rows() == n2 && "KroneckerOperator::solve requires square factors"); - eigen_assert(b.rows() == n1 * n2 && "right-hand side has the wrong number of rows"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_A, "KroneckerOperator::solve requires square factors"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_B, "KroneckerOperator::solve requires square factors"); + EIGEN_INTERNAL_ASSERT_SOLVER_RHS_MSG(*this, b, false, "right-hand side has the wrong number of rows"); const internal::kron_factor_solver<LhsMatrix> solverA(m_A); const internal::kron_factor_solver<RhsMatrix> solverB(m_B); Matrix<Scalar, ColsAtCompileTime, Rhs::ColsAtCompileTime> x(n1 * n2, b.cols()); @@ -1139,8 +1138,8 @@ * matrix, computed by one \c SparseLU solve against the identity (NaN when * the factorization fails). */ KroneckerOperator<typename LhsOps::InverseFactor, typename RhsOps::InverseFactor> inverse() const { - eigen_assert(m_A.rows() == m_A.cols() && m_B.rows() == m_B.cols() && - "KroneckerOperator::inverse requires square factors"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_A, "KroneckerOperator::inverse requires square factors"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_B, "KroneckerOperator::inverse requires square factors"); return {LhsOps::inversed(m_A), RhsOps::inversed(m_B)}; } @@ -1157,8 +1156,8 @@ * underflow on their own) never leave the representable range when the * determinant itself is representable. */ Scalar determinant() const { - eigen_assert(m_A.rows() == m_A.cols() && m_B.rows() == m_B.cols() && - "KroneckerOperator::determinant requires square factors"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_A, "KroneckerOperator::determinant requires square factors"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_B, "KroneckerOperator::determinant requires square factors"); Index exponent = 0; const Scalar mant = balancedDeterminant(exponent); return internal::structured_ldexp_clamped(mant, exponent); @@ -1173,8 +1172,8 @@ * product must then be square -- with the accuracy * KroneckerSum::eigenvalues() describes for a sum. */ ComplexVector eigenvalues() const { - eigen_assert(m_A.rows() == m_A.cols() && m_B.rows() == m_B.cols() && - "KroneckerOperator::eigenvalues requires square factors"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_A, "KroneckerOperator::eigenvalues requires square factors"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_B, "KroneckerOperator::eigenvalues requires square factors"); // Column-major stacking of the nB x nA outer product puts mu_j(B) lambda_i(A) // at index i*nB + j, the Kronecker order. return (RhsSpectrum::eigenvalues(m_B) * LhsSpectrum::eigenvalues(m_A).transpose()).reshaped(); @@ -1185,8 +1184,8 @@ * \c i*n2 + j is \f$ v_i(A) \otimes v_j(B) \f$ and matches * \c eigenvalues()[i*n2 + j]. Assign it to a dense matrix to materialize. */ KroneckerOperator<typename LhsSpectrum::Eigenvectors, typename RhsSpectrum::Eigenvectors> eigenvectors() const { - eigen_assert(m_A.rows() == m_A.cols() && m_B.rows() == m_B.cols() && - "KroneckerOperator::eigenvectors requires square factors"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_A, "KroneckerOperator::eigenvectors requires square factors"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(m_B, "KroneckerOperator::eigenvectors requires square factors"); return {LhsSpectrum::eigenvectors(m_A), RhsSpectrum::eigenvectors(m_B)}; } @@ -1327,10 +1326,6 @@ * \c .noalias() skips it. */ template <typename Rhs> Product<KroneckerOperator, Rhs> operator*(const MatrixBase<Rhs>& x) const { - EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(ColsAtCompileTime) == int(Rhs::RowsAtCompileTime), - INVALID_MATRIX_PRODUCT) - eigen_assert(x.rows() == cols() && "invalid product: dimensions do not match"); return Product<KroneckerOperator, Rhs>(*this, x.derived()); } @@ -1356,7 +1351,7 @@ void addProduct(Dest& dst, const Rhs& rhs, const ProductScalar& alpha) const { using ProductMatrix = Matrix<ProductScalar, Dynamic, Dynamic, ColMajor>; // ColMajor: see DenseMatrix const Index m1 = m_A.rows(), n1 = m_A.cols(), m2 = m_B.rows(), n2 = m_B.cols(), r = rhs.cols(); - eigen_assert(rhs.rows() == n1 * n2 && "invalid product: dimensions do not match"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(*this, rhs, "invalid product: dimensions do not match"); typename internal::nested_eval<Rhs, 1>::type actualRhs(rhs); const bool skipA = LhsOps::isSquareIdentity(m_A), skipB = RhsOps::isSquareIdentity(m_B); ProductMatrix X, BX, Y, work;
diff --git a/contrib/Eigen/src/StructuredMatrices/LookAheadLevinson.h b/contrib/Eigen/src/StructuredMatrices/LookAheadLevinson.h index b4f8c81..f37c4c8 100644 --- a/contrib/Eigen/src/StructuredMatrices/LookAheadLevinson.h +++ b/contrib/Eigen/src/StructuredMatrices/LookAheadLevinson.h
@@ -237,8 +237,9 @@ using internal::structured_tdot; using internal::structured_upshift; - EIGEN_STATIC_ASSERT(Rows_ == Dynamic || Cols_ == Dynamic || Rows_ == Cols_, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) - eigen_assert(T.rows() == T.cols() && "LookAheadLevinson requires a square Toeplitz matrix"); + EIGEN_INTERNAL_CHECK_SHAPE(T.rows() == T.cols() && "LookAheadLevinson requires a square Toeplitz matrix", + YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, + internal::square_dimensions<Toeplitz<Scalar, Rows_, Cols_>>); const Index n = T.rows(); const DenseVector c = T.column(); // (rho_0, sigma_1, ..., sigma_{n-1}) const DenseVector r = T.row(); // (rho_0, rho_1, ..., rho_{n-1})
diff --git a/contrib/Eigen/src/StructuredMatrices/Toeplitz.h b/contrib/Eigen/src/StructuredMatrices/Toeplitz.h index bea571d..235912d 100644 --- a/contrib/Eigen/src/StructuredMatrices/Toeplitz.h +++ b/contrib/Eigen/src/StructuredMatrices/Toeplitz.h
@@ -112,7 +112,8 @@ Toeplitz(const MatrixBase<ColDerived>& col, const MatrixBase<RowDerived>& row) : m_col(col), m_row(row) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(ColDerived) EIGEN_STATIC_ASSERT_VECTOR_ONLY(RowDerived) - eigen_assert(m_col.size() > 0 && m_row.size() > 0 && "Toeplitz generators must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(m_col, "Toeplitz generators must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(m_row, "Toeplitz generators must be non-empty"); // Below the threshold every product takes the direct path and the symbol has // no consumer, so skip the embedding altogether. if (rows() > internal::structured_direct_threshold() || cols() > internal::structured_direct_threshold()) @@ -239,10 +240,6 @@ * \c .noalias() skips it. */ template <typename Rhs> Product<Toeplitz, Rhs> operator*(const MatrixBase<Rhs>& x) const { - EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(ColsAtCompileTime) == int(Rhs::RowsAtCompileTime), - INVALID_MATRIX_PRODUCT) - eigen_assert(x.rows() == cols() && "invalid product: dimensions do not match"); return Product<Toeplitz, Rhs>(*this, x.derived()); } @@ -252,7 +249,7 @@ template <typename Dest, typename Rhs, typename ProductScalar> void addProduct(Dest& dst, const Rhs& rhs, const ProductScalar& alpha) const { const Index m = rows(), n = cols(); - eigen_assert(rhs.rows() == n && "invalid product: dimensions do not match"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(*this, rhs, "invalid product: dimensions do not match"); const bool small = m <= internal::structured_direct_threshold() && n <= internal::structured_direct_threshold(); if (small) directProduct(dst, rhs, alpha);
diff --git a/contrib/Eigen/src/StructuredMatrices/Vandermonde.h b/contrib/Eigen/src/StructuredMatrices/Vandermonde.h index 6a56aa0..40d011c 100644 --- a/contrib/Eigen/src/StructuredMatrices/Vandermonde.h +++ b/contrib/Eigen/src/StructuredMatrices/Vandermonde.h
@@ -185,7 +185,7 @@ template <typename Derived> Vandermonde(const MatrixBase<Derived>& nodes, Index cols) : m_x(nodes), m_cols(cols) { EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) - eigen_assert(m_x.size() > 0 && m_cols > 0 && "Vandermonde must be non-empty"); + EIGEN_INTERNAL_ASSERT_NONEMPTY_MSG(*this, "Vandermonde must be non-empty"); eigen_assert((Cols_ == Dynamic || Cols_ == cols) && "cols does not match the compile-time column count"); } @@ -224,7 +224,7 @@ * exactly; a node difference that overflows makes the determinant infinite, or * NaN when a zero factor is also present. */ Scalar determinant() const { - eigen_assert(rows() == cols() && "Vandermonde::determinant requires a square matrix"); + EIGEN_INTERNAL_ASSERT_SQUARE_MSG(*this, "Vandermonde::determinant requires a square matrix"); const Index n = rows(); Scalar det(1); internal::structured_exponent_type exponent = 0; @@ -276,10 +276,6 @@ * \c .noalias() skips it. */ template <typename Rhs> Product<Vandermonde, Rhs> operator*(const MatrixBase<Rhs>& a) const { - EIGEN_STATIC_ASSERT(ColsAtCompileTime == Dynamic || Rhs::RowsAtCompileTime == Dynamic || - int(ColsAtCompileTime) == int(Rhs::RowsAtCompileTime), - INVALID_MATRIX_PRODUCT) - eigen_assert(a.rows() == cols() && "invalid product: dimensions do not match"); return Product<Vandermonde, Rhs>(*this, a.derived()); } @@ -292,7 +288,7 @@ * when the polynomial value is representable. */ template <typename Dest, typename Rhs, typename ProductScalar> void addProduct(Dest& dst, const Rhs& rhs, const ProductScalar& alpha) const { - eigen_assert(rhs.rows() == m_cols && "invalid product: dimensions do not match"); + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE_MSG(*this, rhs, "invalid product: dimensions do not match"); // A unit alpha must not multiply: even the identity complex scalar (1,0) // pollutes an (Inf,0) value with NaN through the 0*Inf cross term. const bool unitAlpha = alpha == ProductScalar(1); @@ -416,8 +412,9 @@ * nodes. */ template <int Rows_, int Cols_> BjorckPereyra& compute(const Vandermonde<Scalar, Rows_, Cols_>& V) { - EIGEN_STATIC_ASSERT(Rows_ == Dynamic || Cols_ == Dynamic || Rows_ == Cols_, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES) - eigen_assert(V.rows() == V.cols() && "BjorckPereyra requires a square Vandermonde matrix"); + EIGEN_INTERNAL_CHECK_SHAPE(V.rows() == V.cols() && "BjorckPereyra requires a square Vandermonde matrix", + YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES, + internal::square_dimensions<Vandermonde<Scalar, Rows_, Cols_>>); m_x = V.nodes(); m_order.clear(); m_info = Success; @@ -462,7 +459,7 @@ void _solve_impl(const RhsType& rhs, DstType& dst) const { using RhsScalar = typename RhsType::Scalar; using WorkScalar = typename DstType::Scalar; - using ProductOp = internal::scalar_product_op<Scalar, RhsScalar>; + using ProductOp EIGEN_UNUSED = internal::scalar_product_op<Scalar, RhsScalar>; EIGEN_CHECK_BINARY_COMPATIBILITY(ProductOp, Scalar, RhsScalar) const Index n = m_x.size(); @@ -489,7 +486,7 @@ void _solve_impl_transposed(const RhsType& rhs, DstType& dst) const { using RhsScalar = typename RhsType::Scalar; using WorkScalar = typename DstType::Scalar; - using ProductOp = internal::scalar_product_op<Scalar, RhsScalar>; + using ProductOp EIGEN_UNUSED = internal::scalar_product_op<Scalar, RhsScalar>; EIGEN_CHECK_BINARY_COMPATIBILITY(ProductOp, Scalar, RhsScalar) const Index n = m_x.size();
diff --git a/contrib/Eigen/src/Tensor/TensorAssign.h b/contrib/Eigen/src/Tensor/TensorAssign.h index 0093c24..ac2972a 100644 --- a/contrib/Eigen/src/Tensor/TensorAssign.h +++ b/contrib/Eigen/src/Tensor/TensorAssign.h
@@ -126,7 +126,7 @@ } EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(EvaluatorPointerType) { - eigen_assert(dimensions_match(m_leftImpl.dimensions(), m_rightImpl.dimensions())); + EIGEN_INTERNAL_ASSERT_TENSOR_SHAPE(m_leftImpl, m_rightImpl); m_leftImpl.evalSubExprsIfNeeded(nullptr); // If the lhs provides raw access to its storage area (i.e. if m_leftImpl.data() returns a non // null value), attempt to evaluate the rhs expression in place. Returns true iff in place
diff --git a/contrib/Eigen/src/Tensor/TensorDimensions.h b/contrib/Eigen/src/Tensor/TensorDimensions.h index 2ea34f9..1973eda 100644 --- a/contrib/Eigen/src/Tensor/TensorDimensions.h +++ b/contrib/Eigen/src/Tensor/TensorDimensions.h
@@ -309,6 +309,21 @@ return -1; } +// Fixed rank (DSizes) does not imply fixed extents (Sizes). +template <typename Dims1, typename Dims2> +struct tensor_dimension_relation { + static constexpr bool Compatible = array_size<Dims1>::value == array_size<Dims2>::value; + static constexpr bool Known = !Compatible; + static constexpr bool Proven = false; +}; + +template <std::ptrdiff_t... Left, std::ptrdiff_t... Right> +struct tensor_dimension_relation<Sizes<Left...>, Sizes<Right...>> { + static constexpr bool Known = true; + static constexpr bool Compatible = std::is_same<Sizes<Left...>, Sizes<Right...>>::value; + static constexpr bool Proven = Compatible; +}; + template <typename Dims1, typename Dims2, ptrdiff_t n, ptrdiff_t m> struct sizes_match_below_dim { static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool run(const Dims1&, const Dims2&) { return false; } @@ -335,4 +350,11 @@ } // end namespace Eigen +#define EIGEN_INTERNAL_ASSERT_TENSOR_SHAPE(Lhs, Rhs) \ + EIGEN_INTERNAL_CHECK_SHAPE( \ + Eigen::dimensions_match((Lhs).dimensions(), (Rhs).dimensions()) && "Both tensors must have the same dimensions", \ + YOU_MIXED_TENSORS_OF_DIFFERENT_SIZES, \ + Eigen::internal::tensor_dimension_relation<Eigen::internal::remove_all_t<decltype((Lhs).dimensions())>, \ + Eigen::internal::remove_all_t<decltype((Rhs).dimensions())>>) + #endif // EIGEN_TENSOR_TENSOR_DIMENSIONS_H
diff --git a/contrib/Eigen/src/Tensor/TensorEvaluator.h b/contrib/Eigen/src/Tensor/TensorEvaluator.h index 023f7f3..7fe6965 100644 --- a/contrib/Eigen/src/Tensor/TensorEvaluator.h +++ b/contrib/Eigen/src/Tensor/TensorEvaluator.h
@@ -700,7 +700,7 @@ static_cast<int>(TensorEvaluator<RightArgType, Device>::Layout) || internal::traits<XprType>::NumDimensions <= 1), YOU_MADE_A_PROGRAMMING_MISTAKE); - eigen_assert(dimensions_match(m_leftImpl.dimensions(), m_rightImpl.dimensions())); + EIGEN_INTERNAL_ASSERT_TENSOR_SHAPE(m_leftImpl, m_rightImpl); } typedef typename XprType::Index Index; @@ -830,8 +830,8 @@ (std::is_same<typename internal::traits<Arg1Type>::Index, typename internal::traits<Arg3Type>::Index>::value), STORAGE_INDEX_MUST_MATCH) - eigen_assert(dimensions_match(m_arg1Impl.dimensions(), m_arg2Impl.dimensions()) && - dimensions_match(m_arg1Impl.dimensions(), m_arg3Impl.dimensions())); + EIGEN_INTERNAL_ASSERT_TENSOR_SHAPE(m_arg1Impl, m_arg2Impl); + EIGEN_INTERNAL_ASSERT_TENSOR_SHAPE(m_arg1Impl, m_arg3Impl); } typedef typename XprType::Index Index; @@ -973,8 +973,8 @@ EIGEN_STATIC_ASSERT((static_cast<int>(TensorEvaluator<IfArgType, Device>::Layout) == static_cast<int>(TensorEvaluator<ElseArgType, Device>::Layout)), YOU_MADE_A_PROGRAMMING_MISTAKE); - eigen_assert(dimensions_match(m_condImpl.dimensions(), m_thenImpl.dimensions())); - eigen_assert(dimensions_match(m_thenImpl.dimensions(), m_elseImpl.dimensions())); + EIGEN_INTERNAL_ASSERT_TENSOR_SHAPE(m_condImpl, m_thenImpl); + EIGEN_INTERNAL_ASSERT_TENSOR_SHAPE(m_thenImpl, m_elseImpl); } typedef typename XprType::Index Index;
diff --git a/contrib/test/CMakeLists.txt b/contrib/test/CMakeLists.txt index d63df6a..3186340 100644 --- a/contrib/test/CMakeLists.txt +++ b/contrib/test/CMakeLists.txt
@@ -203,6 +203,8 @@ ei_add_test(tensor_expr) ei_add_test(tensor_fft) ei_add_test(tensor_fixed_size) +ei_add_test(tensor_shape_checks) +ei_add_test(tensor_shape_checks_no_static_assert) ei_add_test(tensor_forced_eval) ei_add_test(tensor_generator) ei_add_test(tensor_ifft)
diff --git a/contrib/test/tensor_shape_checks.cpp b/contrib/test/tensor_shape_checks.cpp new file mode 100644 index 0000000..33add89 --- /dev/null +++ b/contrib/test/tensor_shape_checks.cpp
@@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include "main.h" +#include <contrib/Eigen/Tensor> + +EIGEN_DECLARE_TEST(tensor_shape_checks) { + using namespace Eigen; + STATIC_CHECK((internal::tensor_dimension_relation<Sizes<2, 3>, Sizes<2, 3>>::Proven)); + STATIC_CHECK((!internal::tensor_dimension_relation<Sizes<2, 3>, Sizes<3, 2>>::Compatible)); + STATIC_CHECK((!internal::tensor_dimension_relation<DSizes<Index, 2>, DSizes<Index, 2>>::Proven)); + STATIC_CHECK((!internal::tensor_dimension_relation<Sizes<2, 3>, DSizes<Index, 2>>::Proven)); + STATIC_CHECK((!internal::tensor_dimension_relation<DSizes<Index, 2>, DSizes<Index, 3>>::Compatible)); + TensorFixedSize<double, Sizes<2, 3>> a, b, result; + a.setConstant(2); + b.setConstant(3); + result = a + b; + for (Index i = 0; i < result.size(); ++i) VERIFY_IS_EQUAL(result.data()[i], 5); + Tensor<double, 2> dynamic(2, 3), wrong(3, 2); + dynamic = a; + result = a + dynamic; + for (Index i = 0; i < result.size(); ++i) VERIFY_IS_EQUAL(result.data()[i], 4); + VERIFY_RAISES_ASSERT(result = a + wrong); +#ifdef EIGEN_NO_STATIC_ASSERT + TensorFixedSize<double, Sizes<3, 2>> wrong_fixed; + VERIFY_RAISES_ASSERT(result = a + wrong_fixed); + Tensor<double, 3> wrong_rank(2, 3, 1); + VERIFY_RAISES_ASSERT(EIGEN_INTERNAL_ASSERT_TENSOR_SHAPE(a, wrong_rank)); +#endif +}
diff --git a/contrib/test/tensor_shape_checks_no_static_assert.cpp b/contrib/test/tensor_shape_checks_no_static_assert.cpp new file mode 100644 index 0000000..e08c438 --- /dev/null +++ b/contrib/test/tensor_shape_checks_no_static_assert.cpp
@@ -0,0 +1,4 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#define EIGEN_NO_STATIC_ASSERT +#include "tensor_shape_checks.cpp" // NOLINT(bugprone-suspicious-include): Reuse the suite with static assertions disabled.
diff --git a/doc/TopicAssertions.dox b/doc/TopicAssertions.dox index 5e1bb08..4773ffe 100644 --- a/doc/TopicAssertions.dox +++ b/doc/TopicAssertions.dox
@@ -25,6 +25,11 @@ \section StaticAssert Static assertions +Coefficient-count checks against matrix rows or columns reject provably incompatible fixed dimensions at compile +time, including in release builds. This applies to diagonal products, factorization workspaces and rank updates. +Unknown dimensions retain debug runtime checks, also when \c EIGEN_NO_STATIC_ASSERT disables static diagnostics. +Invalid fixed-size calls that previously compiled and asserted only at runtime can therefore fail to compile. + In the Eigen library, there are many conditions that can and should be detected at compile time. For instance, we use static assertions to prevent the code below from compiling. \code @@ -86,7 +91,38 @@ \endcode They are not downgraded to run-time checks, so the misuse they guard against is reported neither at compile time -nor at run time. \c EIGEN_NO_STATIC_ASSERT is undefined by default. +nor at run time unless the operation also has a runtime assertion. +\c EIGEN_NO_STATIC_ASSERT is undefined by default. + +\subsection ShapeAssertions Shape preconditions + +Shared shape checks reject statically incompatible coefficient counts and product inner dimensions at compile time, +including in release builds. Checks proven valid do not read dimensions at runtime. +Matching rows and columns (including directional concatenation checks) follow the same rule. +Vector adaptation and scalar extraction likewise reject provably invalid shapes, while +allowing dynamically sized inputs that satisfy their preconditions at runtime. +Square-only preconditions remain runtime checks, elided when the matrix is proven square. +This preserves runtime-guarded calls on rectangular fixed-size types in C++14. +Solver right-hand sides are checked against the appropriate fixed dimension, including +the reversed row/column rule for transposed solves. +Nonempty-input checks remain runtime-only so C++14 code can guard reductions on fixed empty expressions. +They are elided for inputs proven nonempty. Empty dense +\c sum() and \c prod() remain valid and return their respective identity values. +Empty \c lpNorm<Infinity>() and \c hypotNorm() likewise remain valid and return zero. +For an empty vector, \c stableNormalized() returns an empty vector and \c stableNormalize() is a no-op; +the internal maximum-absolute-value reduction used by stable normalization has identity zero. +An empty vector's \c homogeneous() expression is not empty: it contains the appended coefficient one, +so its \c sum() and \c prod() return one rather than asserting on the underlying empty vector. +These identity reductions are valid for fixed-size empty inputs in C++14 as well as dynamic inputs. +Tensor shape checks reject different ranks or incompatible fixed extents. Equal rank alone +never proves equality of runtime extents. +Unknown dimensions are checked by debug assertions; maximum storage capacities are +not treated as actual dimensions. Row and column vectors may have equal coefficient counts. + +With \c EIGEN_NO_STATIC_ASSERT, these shared checks retain their debug runtime fallback. +Defining \c EIGEN_NO_DEBUG disables the default runtime assertions, not the static diagnostics. +This stricter validation can reject invalid code that previously compiled and only asserted +when executed in a debug build. */ }
diff --git a/failtest/CMakeLists.txt b/failtest/CMakeLists.txt index c42e6b6..7238008 100644 --- a/failtest/CMakeLists.txt +++ b/failtest/CMakeLists.txt
@@ -111,4 +111,17 @@ CXX_EXTENSIONS OFF) endforeach() +ei_add_failtest("reshape_fixed_count") +ei_add_failtest("shape_same_size") +ei_add_failtest("shape_product") +ei_add_failtest("shape_rank_update") +ei_add_failtest("shape_same_rows") +ei_add_failtest("shape_same_cols") +ei_add_failtest("shape_scalar") +ei_add_failtest("shape_solver_rhs") +ei_add_failtest("shape_tensor") +ei_add_failtest("resize_like_vector_shape") + +ei_add_failtest("shape_size_rows") +ei_add_failtest("shape_size_cols") ei_add_failtest_fixture()
diff --git a/failtest/reshape_fixed_count.cpp b/failtest/reshape_fixed_count.cpp new file mode 100644 index 0000000..8fe2230 --- /dev/null +++ b/failtest/reshape_fixed_count.cpp
@@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/Core> + +int main() { +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::Vector3d vector = Eigen::Vector3d::Ones(); +#else + Eigen::Vector4d vector = Eigen::Vector4d::Ones(); +#endif + const auto reshaped = vector.reshaped(Eigen::fix<2>, Eigen::fix<2>); + const Eigen::Reshaped<decltype(vector), 2, 2> direct(vector); + return reshaped.rows() != 2 || direct.rows() != 2; +}
diff --git a/failtest/resize_like_vector_shape.cpp b/failtest/resize_like_vector_shape.cpp new file mode 100644 index 0000000..e52edf5 --- /dev/null +++ b/failtest/resize_like_vector_shape.cpp
@@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/Core> + +int main() { + Eigen::VectorXd destination; +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::Matrix2d source; +#else + Eigen::RowVector2d source; +#endif + destination.resizeLike(source); + return destination.size() != source.size(); +}
diff --git a/failtest/shape_product.cpp b/failtest/shape_product.cpp new file mode 100644 index 0000000..5334135 --- /dev/null +++ b/failtest/shape_product.cpp
@@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/Core> + +int main() { + Eigen::Matrix<double, 2, 3> lhs; +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::Matrix<double, 4, 2> rhs; +#else + Eigen::Matrix<double, 3, 2> rhs; +#endif + const Eigen::Product<decltype(lhs), decltype(rhs)> product(lhs, rhs); + return product.rows() != 2; +}
diff --git a/failtest/shape_rank_update.cpp b/failtest/shape_rank_update.cpp new file mode 100644 index 0000000..b140658 --- /dev/null +++ b/failtest/shape_rank_update.cpp
@@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/Core> +int main() { + Eigen::Matrix2d value = Eigen::Matrix2d::Zero(); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::Matrix<double, 3, 2> rhs; +#else + Eigen::Matrix2d rhs; +#endif + rhs.setZero(); + value.selfadjointView<Eigen::Lower>().rankUpdate(rhs); +}
diff --git a/failtest/shape_same_cols.cpp b/failtest/shape_same_cols.cpp new file mode 100644 index 0000000..0632615 --- /dev/null +++ b/failtest/shape_same_cols.cpp
@@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/Core> +int main() { + Eigen::Matrix<double, 2, 3> lhs; +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::Matrix<double, 4, 4> rhs; +#else + Eigen::Matrix<double, 4, 3> rhs; +#endif + const auto result = Eigen::vcat(lhs, rhs); + return result.rows() != 6; +}
diff --git a/failtest/shape_same_rows.cpp b/failtest/shape_same_rows.cpp new file mode 100644 index 0000000..b18a6c6 --- /dev/null +++ b/failtest/shape_same_rows.cpp
@@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/Core> +int main() { + Eigen::Matrix<double, 2, 3> lhs; +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::Matrix<double, 3, 4> rhs; +#else + Eigen::Matrix<double, 2, 4> rhs; +#endif + const auto result = Eigen::hcat(lhs, rhs); + return result.cols() != 7; +}
diff --git a/failtest/shape_same_size.cpp b/failtest/shape_same_size.cpp new file mode 100644 index 0000000..51b8383 --- /dev/null +++ b/failtest/shape_same_size.cpp
@@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/Core> + +int main() { + Eigen::Vector3d lhs = Eigen::Vector3d::Ones(); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::RowVector4d rhs = Eigen::RowVector4d::Ones(); +#else + Eigen::RowVector3d rhs = Eigen::RowVector3d::Ones(); +#endif + return lhs.dot(rhs) != 3; +}
diff --git a/failtest/shape_scalar.cpp b/failtest/shape_scalar.cpp new file mode 100644 index 0000000..86ebfa8 --- /dev/null +++ b/failtest/shape_scalar.cpp
@@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/Core> +int main() { +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::Matrix2d value = Eigen::Matrix2d::Zero(); +#else + Eigen::Matrix<double, 1, 1> value = Eigen::Matrix<double, 1, 1>::Zero(); +#endif + return value.value() != 0; +}
diff --git a/failtest/shape_size_cols.cpp b/failtest/shape_size_cols.cpp new file mode 100644 index 0000000..65622ae --- /dev/null +++ b/failtest/shape_size_cols.cpp
@@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/Core> +int main() { + Eigen::Matrix<double, 3, 4> matrix = Eigen::Matrix<double, 3, 4>::Ones(); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::Vector3d vector = Eigen::Vector3d::Ones(); +#else + Eigen::Vector4d vector = Eigen::Vector4d::Ones(); +#endif + const Eigen::MatrixXd result = matrix * vector.asDiagonal(); + return result.sum() != 12; +}
diff --git a/failtest/shape_size_rows.cpp b/failtest/shape_size_rows.cpp new file mode 100644 index 0000000..3a050f5 --- /dev/null +++ b/failtest/shape_size_rows.cpp
@@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/Core> +int main() { + Eigen::Matrix<double, 3, 4> matrix = Eigen::Matrix<double, 3, 4>::Ones(); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::RowVector4d vector = Eigen::RowVector4d::Ones(); +#else + Eigen::RowVector3d vector = Eigen::RowVector3d::Ones(); +#endif + const Eigen::MatrixXd result = vector.asDiagonal() * matrix; + return result.sum() != 12; +}
diff --git a/failtest/shape_solver_rhs.cpp b/failtest/shape_solver_rhs.cpp new file mode 100644 index 0000000..9955d95 --- /dev/null +++ b/failtest/shape_solver_rhs.cpp
@@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <Eigen/LU> +int main() { + Eigen::Matrix<double, 2, 3> matrix = Eigen::Matrix<double, 2, 3>::Zero(); + const auto solver = matrix.fullPivLu(); +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::Vector2d rhs = Eigen::Vector2d::Ones(); +#else + Eigen::Vector3d rhs = Eigen::Vector3d::Ones(); +#endif + const auto solution = solver.transpose().solve(rhs); + return solution.rows() != 2; +}
diff --git a/failtest/shape_tensor.cpp b/failtest/shape_tensor.cpp new file mode 100644 index 0000000..1c18d60 --- /dev/null +++ b/failtest/shape_tensor.cpp
@@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include <contrib/Eigen/Tensor> +int main() { + Eigen::TensorFixedSize<double, Eigen::Sizes<2, 3>> lhs; +#ifdef EIGEN_SHOULD_FAIL_TO_BUILD + Eigen::TensorFixedSize<double, Eigen::Sizes<3, 2>> rhs; +#else + Eigen::TensorFixedSize<double, Eigen::Sizes<2, 3>> rhs; +#endif + lhs.setConstant(2); + rhs.setConstant(3); + Eigen::TensorFixedSize<double, Eigen::Sizes<2, 3>> result; + result = lhs + rhs; + return result(0, 0) != 5; +}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 874d5b8..f17cdef 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt
@@ -271,6 +271,15 @@ ei_add_test(realview) ei_add_test(complex_components) ei_add_test(meta) +ei_add_test(shape_checks) +ei_add_test(shape_check_messages) +ei_add_test(shape_checks_no_static_assert) +ei_add_test(shape_checks_modules) +ei_add_test(shape_checks_modules_no_static_assert) +ei_add_test(shape_size_axis) +ei_add_test(shape_size_axis_no_static_assert) +ei_add_test(shape_size_axis_applications) +ei_add_test(shape_checks_compatibility) ei_add_test(preprocessor_directives) ei_add_test(lru_cache) ei_add_test(maxsizevector)
diff --git a/test/commainitializer.cpp b/test/commainitializer.cpp index e0ae722..af953b5 100644 --- a/test/commainitializer.cpp +++ b/test/commainitializer.cpp
@@ -68,6 +68,12 @@ }; void test_basics() { + MatrixXd empty_rows(0, 2), empty_cols(2, 0); + VERIFY_RAISES_ASSERT((empty_rows << 1.0)); + VERIFY_RAISES_ASSERT((empty_cols << 1.0)); + Matrix<double, 0, 2> fixed_empty; + VERIFY_RAISES_ASSERT((fixed_empty << 1.0)); + Matrix3d m3; Matrix4d m4;
diff --git a/test/lu.cpp b/test/lu.cpp index 6de7859..ad73632 100644 --- a/test/lu.cpp +++ b/test/lu.cpp
@@ -296,8 +296,8 @@ VERIFY_RAISES_ASSERT(lu.kernel()) VERIFY_RAISES_ASSERT(lu.image(tmp)) VERIFY_RAISES_ASSERT(lu.solve(tmp)) - VERIFY_RAISES_ASSERT(lu.transpose().solve(tmp)) - VERIFY_RAISES_ASSERT(lu.adjoint().solve(tmp)) + VERIFY_RAISES_ASSERT(lu.transpose().solve(tmp.transpose())) + VERIFY_RAISES_ASSERT(lu.adjoint().solve(tmp.transpose())) VERIFY_RAISES_ASSERT(lu.determinant()) VERIFY_RAISES_ASSERT(lu.absDeterminant()) VERIFY_RAISES_ASSERT(lu.logAbsDeterminant()) @@ -313,8 +313,8 @@ VERIFY_RAISES_ASSERT(plu.matrixLU()) VERIFY_RAISES_ASSERT(plu.permutationP()) VERIFY_RAISES_ASSERT(plu.solve(tmp)) - VERIFY_RAISES_ASSERT(plu.transpose().solve(tmp)) - VERIFY_RAISES_ASSERT(plu.adjoint().solve(tmp)) + VERIFY_RAISES_ASSERT(plu.transpose().solve(tmp.transpose())) + VERIFY_RAISES_ASSERT(plu.adjoint().solve(tmp.transpose())) VERIFY_RAISES_ASSERT(plu.determinant()) VERIFY_RAISES_ASSERT(plu.absDeterminant()) VERIFY_RAISES_ASSERT(plu.logAbsDeterminant())
diff --git a/test/shape_check_messages.cpp b/test/shape_check_messages.cpp new file mode 100644 index 0000000..2ceeff7 --- /dev/null +++ b/test/shape_check_messages.cpp
@@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#ifndef EIGEN_DEBUG_ASSERTS +#define EIGEN_DEBUG_ASSERTS 1 +#endif +#include "main.h" +#include <Eigen/IterativeLinearSolvers> +#include <Eigen/SparseQR> + +#if !defined(EIGEN_NO_ASSERTION_CHECKING) +template <typename Func> +void check_shape_assertion_message(const char* message, const Func& operation) { + Eigen::eigen_assert_list.clear(); + Eigen::internal::push_assert = true; + operation(); + Eigen::internal::push_assert = false; + bool found = false; + for (const auto& assertion : Eigen::eigen_assert_list) { + found = found || assertion.find(message) != std::string::npos; + } + VERIFY(found); +} +#endif + +EIGEN_DECLARE_TEST(shape_check_messages) { +#if !defined(EIGEN_NO_ASSERTION_CHECKING) + MatrixXd matrix(1, 1); + check_shape_assertion_message("Cannot comma-initialize a 0x0 matrix (operator<<)", [&] { matrix << 1.0; }); + + DiagonalPreconditioner<double> preconditioner(matrix); + const VectorXd rhs = VectorXd::Ones(1); + check_shape_assertion_message("DiagonalPreconditioner::solve()", [&] { (void)preconditioner.solve(rhs); }); + + SparseMatrix<double> sparse = matrix.sparseView(); + SparseQR<SparseMatrix<double>, COLAMDOrdering<int>> qr(sparse); + check_shape_assertion_message("SparseQR::solve()", [&] { (void)qr.solve(rhs); }); + + BlockSparseMatrix<double, ColMajor, 2, 2> blocks(1, 1); + blocks.setIdentity(); + const VectorXd block_rhs = VectorXd::Ones(2); + check_shape_assertion_message("BlockSparseTriangularView * Dense: dimension mismatch", [&] { + const VectorXd result = blocks.triangularView<Lower>() * block_rhs; + VERIFY_IS_EQUAL(result, block_rhs); + }); +#endif +}
diff --git a/test/shape_checks.cpp b/test/shape_checks.cpp new file mode 100644 index 0000000..c1bad9b --- /dev/null +++ b/test/shape_checks.cpp
@@ -0,0 +1,320 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 + +#include "main.h" +#include <Eigen/Dense> +#include <contrib/Eigen/MatrixFunctions> + +struct MissingShape {}; +struct PartialShape {}; +template <int Rows, int Cols> +struct ShapeProbe; +namespace Eigen { +namespace internal { +template <int Rows, int Cols> +struct traits<ShapeProbe<Rows, Cols>> : traits<Matrix<double, Rows, Cols>> {}; +template <> +struct traits<PartialShape> { + static constexpr int RowsAtCompileTime = 3; +}; +} // namespace internal +} // namespace Eigen + +template <int Rows, int Cols> +struct ShapeProbe : MatrixBase<ShapeProbe<Rows, Cols>> { + using Nested = const ShapeProbe&; + mutable int row_reads = 0; + mutable int col_reads = 0; + Index rows() const { + ++row_reads; + return 2; + } + Index cols() const { + ++col_reads; + return 2; + } +}; + +void rank_update_shape_checks() { + Matrix2d b = Matrix2d::Constant(2); + Matrix2d updated = Matrix2d::Zero(); + updated.selfadjointView<Lower>().rankUpdate(b); + VERIFY_IS_EQUAL(Matrix2d(updated.selfadjointView<Lower>()), (b * b.transpose()).eval()); + MatrixXd wrong = MatrixXd::Ones(3, 2); + VERIFY_RAISES_ASSERT(updated.selfadjointView<Lower>().rankUpdate(wrong)); +#ifdef EIGEN_NO_STATIC_ASSERT + Matrix<double, 3, 2> fixed_wrong = wrong; + VERIFY_RAISES_ASSERT(updated.selfadjointView<Lower>().rankUpdate(fixed_wrong)); +#endif +} + +void product_coefficient_shape_checks() { + Matrix2d a = Matrix2d::Identity(), b = Matrix2d::Constant(2); + VERIFY_IS_EQUAL(a.lazyProduct(b).coeff(0, 1), 2); + Vector2d v = Vector2d::Ones(); + VERIFY_IS_EQUAL((v.transpose() * v).coeff(0, 0), 2); + VERIFY_IS_EQUAL((v.transpose() * v).coeff(0), 2); + MatrixXd dynamic_a = a, dynamic_b = b; + VERIFY_RAISES_ASSERT((dynamic_a * dynamic_b).coeff(0, 0)); + VERIFY_RAISES_ASSERT((dynamic_a * dynamic_b).coeff(0)); + MatrixXd scalar = MatrixXd::Constant(1, 1, 3); + VERIFY_IS_EQUAL((scalar * scalar).coeff(0), 9); +} + +void transpose_shape_checks() { + Matrix<double, 2, 3> rectangle; + rectangle << 1, 2, 3, 4, 5, 6; + MatrixXd resizable = rectangle; + resizable.transposeInPlace(); + VERIFY_IS_EQUAL(resizable, rectangle.transpose()); + Matrix<double, 2, Dynamic> partial = Matrix2d::Identity(); + partial.transposeInPlace(); + VERIFY_IS_EQUAL(partial, Matrix2d::Identity()); + partial = rectangle; + VERIFY_RAISES_ASSERT(partial.transposeInPlace()); +#ifdef EIGEN_NO_STATIC_ASSERT + VERIFY_RAISES_ASSERT(rectangle.transposeInPlace()); +#endif +} + +void product_shape_checks() { + transpose_shape_checks(); + product_coefficient_shape_checks(); + rank_update_shape_checks(); + ShapeProbe<2, 2> a, b; + const auto product = a * b; + EIGEN_UNUSED_VARIABLE(product); + VERIFY_IS_EQUAL(a.col_reads + b.row_reads, 0); + const MatrixBase<ShapeProbe<2, 2>>& base_a = a; + const MatrixBase<ShapeProbe<2, 2>>& base_b = b; + EIGEN_INTERNAL_ASSERT_PRODUCT_SHAPE(base_a, base_b); + VERIFY_IS_EQUAL(a.col_reads + b.row_reads, 0); + Matrix2d fixed = Matrix2d::Identity(); + MatrixXd wrong(3, 2); + VERIFY_RAISES_ASSERT((fixed * wrong)); +#ifdef EIGEN_NO_STATIC_ASSERT + Matrix<double, 3, 2> fixed_wrong; + VERIFY_RAISES_ASSERT((Product<Matrix2d, decltype(fixed_wrong)>(fixed, fixed_wrong))); +#endif + Transpositions<2> swaps; + swaps.setIdentity(); + VERIFY_IS_EQUAL((swaps * fixed).eval(), fixed); + VERIFY_IS_EQUAL((fixed * swaps.transpose()).eval(), fixed); +} + +template <int Size, int Order> +void product_destination_shape_checks() { + using MatrixType = Matrix<double, Size, Size, Order>; + const MatrixType identity = MatrixType::Identity(3, 3); + const MatrixType values = MatrixType::Constant(3, 3, 2); + MatrixType result = MatrixType::Zero(3, 3); + result.noalias() += identity * values; + VERIFY_IS_EQUAL(result, values); + result.noalias() -= identity * values; + VERIFY(result.isZero()); + result.noalias() += identity.template selfadjointView<Lower>() * values; + VERIFY_IS_EQUAL(result, values); + result.noalias() -= identity.template triangularView<Upper>() * values; + VERIFY(result.isZero()); + + PermutationMatrix<Size> permutation(3); + permutation.setIdentity(); + DiagonalMatrix<double, Size> diagonal(3); + diagonal.diagonal().setConstant(2); + result.noalias() = identity.template triangularView<Lower>() * diagonal; + VERIFY_IS_EQUAL(result, 2 * identity); + result.noalias() = diagonal * identity.template triangularView<Upper>(); + VERIFY_IS_EQUAL(result, 2 * identity); + result.noalias() = identity.template selfadjointView<Lower>() * diagonal; + VERIFY_IS_EQUAL(result, 2 * identity); + result.setZero(); + const auto scaled = permutation * diagonal; + result += scaled; + VERIFY_IS_EQUAL(result, 2 * identity); + result -= scaled; + VERIFY(result.isZero()); + MatrixXd wrong_destination = MatrixXd::Zero(2, 3); + VERIFY_RAISES_ASSERT(wrong_destination.noalias() += identity * values); + VERIFY_RAISES_ASSERT(wrong_destination.noalias() -= identity * values); + VERIFY_RAISES_ASSERT(wrong_destination += scaled); + VERIFY_RAISES_ASSERT(wrong_destination -= scaled); + result.noalias() += scaled * identity; + VERIFY_IS_EQUAL(result, 2 * identity); + result.noalias() -= scaled * identity; + VERIFY(result.isZero()); + VERIFY_IS_EQUAL((scaled * permutation).toDenseMatrix(), 2 * identity); + VERIFY_IS_EQUAL((permutation * scaled).toDenseMatrix(), 2 * identity); + VERIFY_IS_EQUAL((permutation * permutation.inverse()).toDenseMatrix().template cast<double>(), identity); + const ScaledPermutationMatrix<double, Size> from_coefficients(permutation.indices(), diagonal.diagonal()); + VERIFY_IS_EQUAL(from_coefficients.toDenseMatrix(), 2 * identity); + DiagonalMatrix<double, Dynamic> wrong(2); + VERIFY_RAISES_ASSERT(permutation * wrong); +} + +EIGEN_DECLARE_TEST(shape_checks) { + ShapeProbe<2, 2> fixed_a, fixed_b; + const auto sum = fixed_a + fixed_b; + EIGEN_UNUSED_VARIABLE(sum); + internal::resize_if_allowed(fixed_a, fixed_b, internal::add_assign_op<double, double>()); + VERIFY_IS_EQUAL(fixed_a.row_reads + fixed_b.row_reads + fixed_a.col_reads + fixed_b.col_reads, 0); + ShapeProbe<2, Dynamic> partial_a, partial_b; + const auto partial_sum = partial_a + partial_b; + EIGEN_UNUSED_VARIABLE(partial_sum); + VERIFY_IS_EQUAL(partial_a.row_reads + partial_b.row_reads, 0); +#ifndef EIGEN_NO_DEBUG + VERIFY(partial_a.col_reads > 0 && partial_b.col_reads > 0); +#endif + Matrix2d matrix = Matrix2d::Identity(); + MatrixXd bad(3, 2); + VERIFY_RAISES_ASSERT((matrix + bad)); + VERIFY_RAISES_ASSERT(matrix += bad); + VERIFY_IS_EQUAL(hcat(matrix, matrix).cols(), 4); + VERIFY_IS_EQUAL(vcat(matrix, matrix).rows(), 4); + Matrix<double, 2, 3> concat_wide = Matrix<double, 2, 3>::Ones(); + VERIFY_IS_EQUAL(hcat(matrix, concat_wide).cols(), 5); + VERIFY_IS_EQUAL(vcat(matrix, concat_wide.transpose()).rows(), 5); +#ifdef EIGEN_NO_STATIC_ASSERT + VERIFY_RAISES_ASSERT(hcat(matrix, concat_wide.transpose())); + VERIFY_RAISES_ASSERT(vcat(matrix, concat_wide)); +#endif + Matrix<double, 2, 3> wide = Matrix<double, 2, 3>::Ones(); + const DiagonalMatrix<double, 2> left_diagonal(Vector2d::Constant(2)); + const DiagonalMatrix<double, 3> right_diagonal(Vector3d::Constant(3)); + Matrix<double, 2, 3> triangular_product = left_diagonal * wide.triangularView<Upper>(); + VERIFY_IS_EQUAL(triangular_product, 2 * wide.triangularView<Upper>().toDenseMatrix()); + triangular_product = wide.triangularView<Upper>() * right_diagonal; + VERIFY_IS_EQUAL(triangular_product, 3 * wide.triangularView<Upper>().toDenseMatrix()); + Vector3d vector = Vector3d::Ones(); + RowVector3d row = RowVector3d::Ones(); + VERIFY_IS_EQUAL(vector.dot(row), 3); + VERIFY_IS_EQUAL(vector.reshaped(fix<1>, fix<3>).sum(), 3); + VectorXd dynamic_reshape = vector; + VERIFY_RAISES_ASSERT(dynamic_reshape.reshaped(fix<2>, fix<2>)); +#ifdef EIGEN_NO_STATIC_ASSERT + VERIFY_RAISES_ASSERT(vector.reshaped(fix<2>, fix<2>)); + Vector4d mismatched_vector = Vector4d::Ones(); + VERIFY_RAISES_ASSERT(vector.dot(mismatched_vector)); +#endif + VectorXd bad_vector(2); + VERIFY_RAISES_ASSERT(vector.dot(bad_vector)); + VectorXd resized; + resized.resizeLike(row); + VERIFY_IS_EQUAL(resized.size(), 3); + MatrixXd resize_source = matrix; + VERIFY_RAISES_ASSERT(resized.resizeLike(resize_source)); +#ifdef EIGEN_NO_STATIC_ASSERT + VERIFY_RAISES_ASSERT(resized.resizeLike(matrix)); +#endif + Ref<VectorXd> ref(vector); + Ref<Matrix2d> matrix_ref(matrix); + VERIFY_IS_EQUAL(matrix_ref.rows(), 2); + Matrix2d resized_matrix; + resized_matrix.resizeLike(matrix); +#ifdef EIGEN_NO_STATIC_ASSERT + VERIFY_RAISES_ASSERT(EIGEN_INTERNAL_ASSERT_SCALAR(matrix)); +#endif + VERIFY_IS_EQUAL(ref.size(), 3); + MatrixXd dynamic_matrix = matrix; + VERIFY_RAISES_ASSERT((Ref<VectorXd>(dynamic_matrix))); + VERIFY_IS_EQUAL(matrix.determinant(), 1); + VERIFY_IS_EQUAL(matrix.householderQr().absDeterminant(), 1); + VERIFY_IS_EQUAL(matrix.fullPivLu().determinant(), 1); + VERIFY_IS_EQUAL(matrix.fullPivLu().rcond(), 1); + Matrix3d transpose_source = Matrix3d::Random(); + const Matrix3d transposed = transpose_source.transpose(); + transpose_source.transposeInPlace(); + VERIFY_IS_EQUAL(transpose_source, transposed); + MatrixXd rectangular_transpose = MatrixXd::Random(2, 3); + const MatrixXd rectangular_expected = rectangular_transpose.transpose(); + rectangular_transpose.transposeInPlace(); + VERIFY_IS_EQUAL(rectangular_transpose, rectangular_expected); + VERIFY(matrix.llt().info() == Success); + Vector2d rhs = Vector2d::Ones(); + const auto lu = matrix.fullPivLu(); + VERIFY_IS_EQUAL(lu.solve(rhs).eval(), rhs); + VERIFY_IS_EQUAL(lu.transpose().solve(rhs).eval(), rhs); + Matrix2d nonsymmetric; + nonsymmetric << 2, 1, 0, 3; + const auto partial_lu = nonsymmetric.partialPivLu(); + const Vector2d transpose_solution = partial_lu.transpose().solve(rhs); + VERIFY_IS_APPROX(nonsymmetric.transpose() * transpose_solution, rhs); + VERIFY_RAISES_ASSERT(partial_lu.transpose().solve(VectorXd::Ones(3))); + VERIFY_RAISES_ASSERT(lu.solve(VectorXd::Ones(3))); +#ifdef EIGEN_NO_STATIC_ASSERT + VERIFY_RAISES_ASSERT(lu.solve(Vector3d::Ones())); +#endif + VERIFY_IS_APPROX(matrix.sqrt(), matrix); + VERIFY(SelfAdjointEigenSolver<Matrix2d>(matrix).info() == Success); + MatrixXd rectangle = MatrixXd::Ones(2, 3); + VERIFY_RAISES_ASSERT(rectangle.determinant()); + VERIFY_RAISES_ASSERT(rectangle.householderQr().absDeterminant()); + VERIFY_RAISES_ASSERT(rectangle.fullPivLu().determinant()); + VERIFY_RAISES_ASSERT(rectangle.llt()); + VERIFY_RAISES_ASSERT(wide.fullPivLu().determinant()); + MatrixXd empty(0, 0); + VERIFY_IS_EQUAL(empty.sum(), 0); + const Matrix<double, 0, 0> fixed_empty; + VERIFY_IS_EQUAL(fixed_empty.sum(), 0); + VERIFY_IS_EQUAL(fixed_empty.prod(), 1); + Matrix<double, 3, 0> empty_columns; + Matrix<double, 0, 3> empty_rows; + VERIFY_IS_EQUAL(empty_columns.colwise().maxCoeff().eval().size(), 0); + VERIFY_IS_EQUAL(empty_rows.rowwise().minCoeff().eval().size(), 0); + VERIFY_RAISES_ASSERT(fixed_empty.maxCoeff()); + VERIFY_RAISES_ASSERT(empty_columns.rowwise().maxCoeff()); + VERIFY_RAISES_ASSERT(empty_rows.colwise().minCoeff()); + VERIFY_RAISES_ASSERT(empty.maxCoeff()); + VERIFY_IS_EQUAL(matrix.maxCoeff(), 1); + Index max_row, max_col; + VERIFY_IS_EQUAL(matrix.maxCoeff(&max_row, &max_col), 1); + CALL_SUBTEST(product_shape_checks()); + CALL_SUBTEST((product_destination_shape_checks<3, ColMajor>())); + CALL_SUBTEST((product_destination_shape_checks<3, RowMajor>())); + CALL_SUBTEST((product_destination_shape_checks<Dynamic, ColMajor>())); + CALL_SUBTEST((product_destination_shape_checks<Dynamic, RowMajor>())); + using namespace Eigen::internal; + STATIC_CHECK((dimension_relation<3, 3>::Proven)); + STATIC_CHECK((!dimension_relation<3, 2>::Compatible)); + STATIC_CHECK((dimension_relation<Dynamic, 3>::Compatible)); + STATIC_CHECK((!dimension_relation<Dynamic, 3>::Known)); + STATIC_CHECK((compile_time_shape<MissingShape>::Rows == Dynamic)); + STATIC_CHECK((compile_time_shape<PartialShape>::Rows == 3)); + STATIC_CHECK((compile_time_shape<PartialShape>::Cols == Dynamic)); + STATIC_CHECK((compile_time_shape<Matrix<double, Dynamic, 1, 0, 3, 1>>::Size == Dynamic)); + STATIC_CHECK((matching_sizes<Matrix<double, 2, 3>, Matrix<double, 3, 2>>::Proven)); + STATIC_CHECK((matching_shapes<Matrix<double, 1, 0>, Matrix<double, 0, 1>>::Compatible)); + const Matrix<double, 1, 0> empty_row; + const Matrix<double, 0, 1> empty_column; + VERIFY_RAISES_ASSERT(empty_row + empty_column); + VERIFY_RAISES_ASSERT(internal::resize_if_allowed(empty_row, empty_column, internal::add_assign_op<double, double>())); + STATIC_CHECK((square_dimensions<const Matrix3d&>::Proven)); + int reads = 0; + struct RuntimeDimensions { + mutable int accesses = 0; + Index rows() const { + ++accesses; + return 2; + } + Index cols() const { + ++accesses; + return 3; + } + } runtime_a, runtime_b; + EIGEN_INTERNAL_ASSERT_SAME_ROWS(runtime_a, runtime_b); + EIGEN_INTERNAL_ASSERT_SAME_COLS(runtime_a, runtime_b); +#ifndef EIGEN_NO_DEBUG + VERIFY_IS_EQUAL(runtime_a.accesses, 2); + VERIFY_IS_EQUAL(runtime_b.accesses, 2); +#endif + EIGEN_INTERNAL_SHAPE_ASSERT((dimension_relation<3, 3>::Proven), ++reads == 1); // NOLINT(bugprone-assert-side-effect) + VERIFY_IS_EQUAL(reads, 0); + EIGEN_INTERNAL_ASSERT_NONEMPTY_SIZE(fixed_a, ++reads); // NOLINT(bugprone-assert-side-effect) + VERIFY_IS_EQUAL(reads, 0); +#ifndef EIGEN_NO_DEBUG + // NOLINTBEGIN(bugprone-assert-side-effect) + EIGEN_INTERNAL_SHAPE_ASSERT((dimension_relation<Dynamic, 3>::Proven), ++reads == 1); + // NOLINTEND(bugprone-assert-side-effect) + VERIFY_IS_EQUAL(reads, 1); + VERIFY_RAISES_ASSERT([] { EIGEN_INTERNAL_SHAPE_ASSERT(false, false); }()); +#endif +}
diff --git a/test/shape_checks_compatibility.cpp b/test/shape_checks_compatibility.cpp new file mode 100644 index 0000000..4f3ff4e --- /dev/null +++ b/test/shape_checks_compatibility.cpp
@@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#include "main.h" +#include <Eigen/LU> +#include <Eigen/QR> + +struct RuntimeShape; +namespace Eigen { +namespace internal { +template <> +struct traits<RuntimeShape> { + using StorageKind = Dense; +}; +} // namespace internal +} // namespace Eigen + +struct RuntimeShape : EigenBase<RuntimeShape> { + mutable int reads = 0; + Index rows() const { + ++reads; + return 2; + } + Index cols() const { + ++reads; + return 1; + } +}; + +template <int N> +double guarded_tail_max(const Matrix<double, N, 1>& vector) { + const auto tail = vector.template tail<N - 1>(); + return tail.size() > 0 ? tail.maxCoeff() : 0.0; +} + +template <int N> +Index guarded_column_max_size(const Matrix<double, N, N>& matrix) { + return matrix.cols() > 0 ? matrix.colwise().maxCoeff().size() : 0; +} + +template <int Rows, int Cols> +double guarded_determinants(const Matrix<double, Rows, Cols>& matrix) { + if (matrix.rows() != matrix.cols()) return 0.0; + return matrix.determinant() + matrix.fullPivLu().determinant() + matrix.householderQr().absDeterminant() + + matrix.colPivHouseholderQr().absDeterminant() + matrix.fullPivHouseholderQr().absDeterminant() + + matrix.randColPivHouseholderQr().absDeterminant(); +} + +EIGEN_DECLARE_TEST(shape_checks_compatibility) { + VERIFY_IS_EQUAL(guarded_tail_max<1>(Matrix<double, 1, 1>::Ones()), 0.0); + VERIFY_IS_EQUAL(guarded_tail_max<2>(Vector2d::Constant(7)), 7.0); + VERIFY_IS_EQUAL(guarded_column_max_size(Matrix<double, 0, 0>()), Index(0)); + VERIFY_IS_EQUAL(guarded_column_max_size<2>(Matrix2d::Ones()), Index(2)); + VERIFY_IS_EQUAL((guarded_determinants<3, 4>(Matrix<double, 3, 4>::Zero())), 0.0); + VERIFY_IS_EQUAL((guarded_determinants<2, 2>(Matrix2d::Identity())), 6.0); + Matrix<double, 0, 4> empty_rectangle; + if (empty_rectangle.rows() == empty_rectangle.cols()) empty_rectangle.transposeInPlace(); + VERIFY_RAISES_ASSERT(empty_rectangle.transposeInPlace()); + RuntimeShape source; + VectorXd destination; + destination.resizeLike(source); + VERIFY_IS_EQUAL(destination.size(), 2); + internal::resize_if_allowed(destination, source, internal::add_assign_op<double, double>()); + const EigenBase<RuntimeShape>& base = source; + source.reads = 0; + EIGEN_INTERNAL_ASSERT_SAME_SHAPE(base, destination); +#ifndef EIGEN_NO_DEBUG + VERIFY_IS_EQUAL(source.reads, 2); +#elif defined(EIGEN_NO_ASSERTION_CHECKING) + VERIFY_IS_EQUAL(source.reads, 0); +#endif + VERIFY_RAISES_ASSERT(EIGEN_INTERNAL_ASSERT_SAME_ROWS(base, Vector3d::Zero())); + + using BoundedVector = Matrix<double, Dynamic, 1, 0, 4, 1>; + const BoundedVector a = BoundedVector::Ones(3); + const BoundedVector b = BoundedVector::Ones(4); + VERIFY_RAISES_ASSERT(a.dot(b)); + VERIFY_IS_EQUAL(a.dot(a), 3); + Matrix<double, Dynamic, Dynamic, 0, 4, 4> bounded_matrix = Matrix3d::Identity(); + VERIFY_RAISES_ASSERT(bounded_matrix * b); + VERIFY_IS_EQUAL((bounded_matrix * a).eval(), a); + + const Matrix2d fixed = Matrix2d::Identity(); + Matrix<double, 2, Dynamic> wrong_cols(2, 3); + Matrix<double, Dynamic, 2> wrong_rows(3, 2); + VERIFY_RAISES_ASSERT(fixed + wrong_cols); + VERIFY_RAISES_ASSERT(fixed + wrong_rows); +}
diff --git a/test/shape_checks_modules.cpp b/test/shape_checks_modules.cpp new file mode 100644 index 0000000..2cb7a8b --- /dev/null +++ b/test/shape_checks_modules.cpp
@@ -0,0 +1,141 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 + +#include "main.h" + +#if defined(EIGEN_TEST_PART_1) +#include <Eigen/Eigenvalues> +#include <contrib/Eigen/MatrixFunctions> + +void dense_module_shapes() { + const Matrix2d a = 2 * Matrix2d::Identity(); + const Vector2d v = Vector2d::Ones(); + LLT<Matrix2d> llt(a); + LDLT<Matrix2d> ldlt(a); + llt.rankUpdate(v); + ldlt.rankUpdate(v); + VERIFY_IS_APPROX(llt.reconstructedMatrix(), a + v * v.transpose()); + VERIFY_IS_APPROX(ldlt.reconstructedMatrix(), a + v * v.transpose()); + VectorXd wrong = VectorXd::Ones(3); + VERIFY_RAISES_ASSERT(llt.rankUpdate(wrong)); + VERIFY_RAISES_ASSERT(ldlt.rankUpdate(wrong)); + SelfAdjointEigenSolver<Matrix2d> direct; + direct.computeDirect(a); + VERIFY_IS_EQUAL(direct.info(), Success); + VERIFY_IS_EQUAL(direct.eigenvalues(), Vector2d::Constant(2)); + RealSchur<Matrix2d> schur(a); + VERIFY_IS_EQUAL(schur.info(), Success); + RealQZ<Matrix2d> real_qz(a, a); + VERIFY_IS_EQUAL(real_qz.info(), Success); + ComplexQZ<Matrix2cd> complex_qz(a.cast<std::complex<double>>(), a.cast<std::complex<double>>()); + VERIFY_IS_EQUAL(complex_qz.info(), Success); + GeneralizedSelfAdjointEigenSolver<Matrix2d> generalized(a, a); + VERIFY_IS_EQUAL(generalized.info(), Success); + const Matrix2d solution = internal::matrix_function_solve_triangular_sylvester(a, a, a); + VERIFY_IS_APPROX(a * solution + solution * a, a); + MatrixXd rectangular = MatrixXd::Ones(2, 3); + MatrixXd dynamic_a = a; + VERIFY_RAISES_ASSERT(internal::matrix_function_solve_triangular_sylvester(dynamic_a, dynamic_a, rectangular)); + Vector2d coeffs; + VERIFY_RAISES_ASSERT(internal::tridiagonalization_inplace_unblocked(rectangular, coeffs)); +} +#endif + +#if defined(EIGEN_TEST_PART_2) +#include <Eigen/Sparse> +#include <Eigen/Eigenvalues> + +void sparse_module_shapes() { + SparseMatrix<double> a(3, 3); + a.setIdentity(); + SimplicialLLT<SparseMatrix<double>> llt(a); + SimplicialLDLT<SparseMatrix<double>> ldlt(a); + SparseLU<SparseMatrix<double>> lu(a); + SparseQR<SparseMatrix<double>, COLAMDOrdering<int>> qr(a); + const VectorXd rhs = VectorXd::Ones(3); + VERIFY_IS_APPROX(llt.solve(rhs), rhs); + VERIFY_IS_APPROX(ldlt.solve(rhs), rhs); + VERIFY_IS_APPROX(lu.solve(rhs), rhs); + MatrixXd q = qr.matrixQ(); + VERIFY_IS_APPROX((qr.matrixQ() * rhs).eval(), q * rhs); + VERIFY_IS_APPROX((qr.matrixQ().adjoint() * rhs).eval(), q.adjoint() * rhs); + SparseMatrix<double> rectangular(2, 3); + VERIFY_RAISES_ASSERT(rectangular.selfadjointView<Lower>()); + VERIFY_RAISES_ASSERT(llt.compute(rectangular)); + VERIFY_RAISES_ASSERT(ldlt.compute(rectangular)); + VERIFY_RAISES_ASSERT(lu.compute(rectangular)); + SparseVector<double> empty(0); + VectorXd empty_dense(0); + VERIFY_IS_EQUAL(empty.dot(empty_dense), 0.0); +} +#endif + +#if defined(EIGEN_TEST_PART_3) +#include <contrib/Eigen/StructuredMatrices> + +void structured_module_shapes() { + Vector2d x(1, 2), y(4, 5); + const Cauchy<double, 2, 2> c(x, y); + VERIFY_IS_APPROX(c.determinant(), Matrix2d(c).determinant()); + const Vandermonde<double, 2, 2> v(x, 2); + VERIFY_IS_APPROX(v.determinant(), Matrix2d(v).determinant()); + const Matrix2d identity = Matrix2d::Identity(); + const Matrix<double, 1, 1> one = Matrix<double, 1, 1>::Ones(); + const KroneckerOperator<Matrix2d, Matrix<double, 1, 1>> kron(identity, one); + VERIFY_IS_EQUAL(kron.determinant(), 1); + VERIFY_IS_APPROX(kron.solve(x), x); + VERIFY_IS_APPROX(Matrix2d(kron.inverse()), identity); + VERIFY_IS_APPROX(kron.eigenvalues(), Vector2cd::Ones()); + VERIFY_IS_EQUAL(kron.eigenvectors().rows(), 2); + VectorXd three = VectorXd::LinSpaced(3, 4, 6); + const Cauchy<double> rectangular_c(x, three); + const Vandermonde<double> rectangular_v(x, 3); + VERIFY_RAISES_ASSERT(rectangular_c.determinant()); + VERIFY_RAISES_ASSERT(rectangular_v.determinant()); + CauchyLU<double> clu; + BjorckPereyra<double> bp; + VERIFY_RAISES_ASSERT(clu.compute(rectangular_c)); + VERIFY_RAISES_ASSERT(bp.compute(rectangular_v)); + const Hankel<double> hankel(x, three); + VERIFY_RAISES_ASSERT(hankel.solve(x)); + const Toeplitz<double> toeplitz(x, three); + LookAheadLevinson<double> levinson; + VERIFY_RAISES_ASSERT(levinson.compute(toeplitz)); + MatrixXd tall = MatrixXd::Ones(2, 1), wide = MatrixXd::Ones(1, 2); + const KroneckerOperator<MatrixXd, MatrixXd> rectangular_factors(tall, wide); + VERIFY_IS_EQUAL(rectangular_factors.rows(), rectangular_factors.cols()); + VERIFY_RAISES_ASSERT(rectangular_factors.determinant()); + VERIFY_RAISES_ASSERT(rectangular_factors.inverse()); + VERIFY_RAISES_ASSERT(rectangular_factors.eigenvalues()); + VERIFY_RAISES_ASSERT(rectangular_factors.eigenvectors()); + VERIFY_RAISES_ASSERT(rectangular_factors.solve(x)); + const Cauchy<double, 2, 3> fixed_rectangular(x, three); + VERIFY_RAISES_ASSERT(fixed_rectangular.determinant()); +} +#endif + +#if defined(EIGEN_TEST_PART_4) +#include <contrib/Eigen/FFT> + +void fft_shapes() { + FFT<double> fft; + Vector2d input(1, 2), recovered; + Vector2cd spectrum; + fft.fwd(spectrum, input); + fft.inv(recovered, spectrum); + VERIFY_IS_APPROX(recovered, input); + MatrixXd not_vector = MatrixXd::Ones(2, 2); + VectorXcd output; + VERIFY_RAISES_ASSERT(fft.fwd(output, not_vector)); + MatrixXcd complex_not_vector = MatrixXcd::Ones(2, 2); + VectorXd real_output; + VERIFY_RAISES_ASSERT(fft.inv(real_output, complex_not_vector)); +} +#endif + +EIGEN_DECLARE_TEST(shape_checks_modules) { + CALL_SUBTEST_1(dense_module_shapes()); + CALL_SUBTEST_2(sparse_module_shapes()); + CALL_SUBTEST_3(structured_module_shapes()); + CALL_SUBTEST_4(fft_shapes()); +}
diff --git a/test/shape_checks_modules_no_static_assert.cpp b/test/shape_checks_modules_no_static_assert.cpp new file mode 100644 index 0000000..43273b7 --- /dev/null +++ b/test/shape_checks_modules_no_static_assert.cpp
@@ -0,0 +1,5 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +// EIGEN_SUFFIXES;1;2;3;4 +#define EIGEN_NO_STATIC_ASSERT +#include "shape_checks_modules.cpp" // NOLINT(bugprone-suspicious-include): Reuse the suite with static assertions disabled.
diff --git a/test/shape_checks_no_static_assert.cpp b/test/shape_checks_no_static_assert.cpp new file mode 100644 index 0000000..11bee4c --- /dev/null +++ b/test/shape_checks_no_static_assert.cpp
@@ -0,0 +1,4 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#define EIGEN_NO_STATIC_ASSERT +#include "shape_checks.cpp" // NOLINT(bugprone-suspicious-include): Reuse the suite with static assertions disabled.
diff --git a/test/shape_size_axis.cpp b/test/shape_size_axis.cpp new file mode 100644 index 0000000..7c14e8b --- /dev/null +++ b/test/shape_size_axis.cpp
@@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 + +#include "main.h" + +template <int Rows, int Cols> +struct AxisShapeProbe; +namespace Eigen { +namespace internal { +template <int Rows, int Cols> +struct traits<AxisShapeProbe<Rows, Cols>> { + static constexpr int RowsAtCompileTime = Rows; + static constexpr int ColsAtCompileTime = Cols; +}; +} // namespace internal +} // namespace Eigen + +template <int Rows, int Cols> +struct AxisShapeProbe { + Index row_count, col_count; + mutable int size_reads = 0, row_reads = 0, col_reads = 0; + Index size() const { + ++size_reads; + return row_count * col_count; + } + Index rows() const { + ++row_reads; + return row_count; + } + Index cols() const { + ++col_reads; + return col_count; + } +}; + +struct UnknownAxisShape { + Index size() const { return 3; } + Index rows() const { return 3; } + Index cols() const { return 4; } +}; + +EIGEN_DECLARE_TEST(shape_size_axis) { + using namespace Eigen::internal; + STATIC_CHECK((size_matches_axis<RowVector3d, Matrix<double, 3, 4>, true>::Proven)); + STATIC_CHECK((size_matches_axis<Vector4d, Matrix<double, 3, 4>, false>::Proven)); + STATIC_CHECK((!size_matches_axis<Vector3d, Matrix<double, 3, 4>, false>::Compatible)); + STATIC_CHECK((!size_matches_axis<Matrix<double, Dynamic, 1, 0, 4, 1>, Matrix4d, true>::Known)); + STATIC_CHECK((!size_matches_axis<UnknownAxisShape, Matrix3d, true>::Known)); + + AxisShapeProbe<1, 3> row_vector{1, 3}; + AxisShapeProbe<4, 1> col_vector{4, 1}; + AxisShapeProbe<3, 4> fixed{3, 4}; + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(row_vector, fixed); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS(col_vector, fixed); + VERIFY_IS_EQUAL(row_vector.size_reads + col_vector.size_reads + fixed.row_reads + fixed.col_reads, 0); + + AxisShapeProbe<Dynamic, 4> partial{3, 4}; + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS(col_vector, partial); + VERIFY_IS_EQUAL(col_vector.size_reads + partial.col_reads, 0); + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(row_vector, partial); +#ifndef EIGEN_NO_DEBUG + VERIFY_IS_EQUAL(row_vector.size_reads, 1); + VERIFY_IS_EQUAL(partial.row_reads, 1); +#endif + VERIFY_IS_EQUAL(partial.col_reads, 0); + + const UnknownAxisShape unknown; + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(unknown, fixed); + VERIFY_RAISES_ASSERT(EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS(unknown, fixed)); + AxisShapeProbe<Dynamic, Dynamic> wrong{2, 4}; + VERIFY_RAISES_ASSERT(EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(row_vector, wrong)); +#ifdef EIGEN_NO_STATIC_ASSERT + VERIFY_RAISES_ASSERT(EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_COLS(row_vector, fixed)); +#endif + const Matrix<double, 0, 4> empty; + const Matrix<double, 0, 1> empty_vector; + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(empty_vector, empty); + const Matrix<double, 3, 4> matrix = Matrix<double, 3, 4>::Zero(); + const Vector3d vector = Vector3d::Ones(); + const MatrixBase<Vector3d>& vector_base = vector; + const MatrixBase<Matrix<double, 3, 4>>& matrix_base = matrix; + EIGEN_INTERNAL_ASSERT_SIZE_MATCHES_ROWS(vector_base, matrix_base); +}
diff --git a/test/shape_size_axis_applications.cpp b/test/shape_size_axis_applications.cpp new file mode 100644 index 0000000..3e50202 --- /dev/null +++ b/test/shape_size_axis_applications.cpp
@@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 + +#include "main.h" +#include <Eigen/Dense> +#include <Eigen/Sparse> +#include <contrib/Eigen/StructuredMatrices> + +template <int Order> +void axis_product_checks() { + using Rect = Matrix<double, 3, 4, Order>; + const Rect matrix = Rect::Random(); + const Vector3d left = Vector3d::Constant(2); + const Vector4d right = Vector4d::Constant(3); + Rect result = left.asDiagonal() * matrix.template triangularView<Upper>(); + VERIFY_IS_APPROX(result, 2 * matrix.template triangularView<Upper>().toDenseMatrix()); + result = matrix.template triangularView<Lower>() * right.asDiagonal(); + VERIFY_IS_APPROX(result, 3 * matrix.template triangularView<Lower>().toDenseMatrix()); + const Matrix3d identity = Matrix3d::Identity(); + Matrix3d square = identity.template selfadjointView<Lower>() * left.asDiagonal(); + VERIFY_IS_EQUAL(square, 2 * identity); + const VectorXd wrong = VectorXd::Ones(2); + VERIFY_RAISES_ASSERT(result.noalias() = wrong.asDiagonal() * matrix.template triangularView<Upper>()); + VERIFY_RAISES_ASSERT(result.noalias() = matrix.template triangularView<Lower>() * wrong.asDiagonal()); +} + +EIGEN_DECLARE_TEST(shape_size_axis_applications) { + CALL_SUBTEST((axis_product_checks<ColMajor>())); + CALL_SUBTEST((axis_product_checks<RowMajor>())); + const Matrix3d identity = Matrix3d::Identity(); + const Vector3d vector = Vector3d::Ones(); + const VectorXd wrong = VectorXd::Ones(2); + LLT<Matrix3d> llt(identity); + llt.rankUpdate(vector); + VERIFY_IS_APPROX(llt.reconstructedMatrix(), identity + vector * vector.transpose()); + VERIFY_RAISES_ASSERT(llt.rankUpdate(wrong)); + LDLT<Matrix3d> ldlt(identity); + ldlt.rankUpdate(vector); + VERIFY_IS_APPROX(ldlt.reconstructedMatrix(), identity + vector * vector.transpose()); + VERIFY_RAISES_ASSERT(ldlt.rankUpdate(wrong)); + VERIFY_IS_APPROX(identity.partialPivLu().solve(vector), vector); + SelfAdjointEigenSolver<Matrix3d> eig(identity); + VERIFY_IS_EQUAL(eig.eigenvalues(), vector); + + Matrix<double, 3, 2> qr_matrix = Matrix<double, 3, 2>::Zero(); + Vector2d coefficients; + double workspace[2]; + const Vector3d column = Vector3d::UnitX(); + internal::householder_qr_inplace_update(qr_matrix, coefficients, column, 0, workspace); + VERIFY_RAISES_ASSERT(internal::householder_qr_inplace_update(qr_matrix, coefficients, wrong, 1, workspace)); + const Vector3d column2 = Vector3d::UnitY(); + internal::householder_qr_inplace_update(qr_matrix, coefficients, column2, 1, workspace); + const Matrix3d q = householderSequence(qr_matrix, coefficients); + VERIFY_IS_APPROX(q * qr_matrix.triangularView<Upper>().toDenseMatrix(), identity.leftCols<2>()); + + const SparseMatrix<double> sparse_identity = identity.sparseView(); + DiagonalPreconditioner<double> preconditioner(sparse_identity); + VERIFY_IS_APPROX(preconditioner.solve(vector), vector); + VERIFY_RAISES_ASSERT(preconditioner.solve(wrong)); + const MatrixXd factor = MatrixXd::Ones(3, 1); + DiagonalPlusLowRank<double> lowrank(vector, factor, factor); + VERIFY_IS_APPROX((lowrank * vector).eval(), (identity + factor * factor.transpose()) * vector); + const MatrixXd bad_factor = MatrixXd::Ones(2, 1); + VERIFY_RAISES_ASSERT(DiagonalPlusLowRank<double>(vector, bad_factor, factor)); + VERIFY_RAISES_ASSERT(DiagonalPlusLowRank<double>(vector, factor, bad_factor)); +}
diff --git a/test/shape_size_axis_no_static_assert.cpp b/test/shape_size_axis_no_static_assert.cpp new file mode 100644 index 0000000..2a533ae --- /dev/null +++ b/test/shape_size_axis_no_static_assert.cpp
@@ -0,0 +1,4 @@ +// SPDX-FileCopyrightText: The Eigen Authors +// SPDX-License-Identifier: MPL-2.0 +#define EIGEN_NO_STATIC_ASSERT +#include "shape_size_axis.cpp" // NOLINT(bugprone-suspicious-include): Reuse the suite with static assertions disabled.
diff --git a/test/sparse_threaded_product.cpp b/test/sparse_threaded_product.cpp index ecc1de9..f63ce2b 100644 --- a/test/sparse_threaded_product.cpp +++ b/test/sparse_threaded_product.cpp
@@ -33,6 +33,13 @@ DenseVectorType y_adj_ref = refMat.adjoint() * x_adj; ThreadedSparseProduct<SparseMatrixType> op(A); + { + DenseVectorType wrong_x = DenseVectorType::Zero(cols + 1); + DenseVectorType wrong_adjoint_x = DenseVectorType::Zero(rows + 1); + DenseVectorType y(rows), adjoint_y(cols); + VERIFY_RAISES_ASSERT(op.apply(wrong_x, y)); + VERIFY_RAISES_ASSERT(op.applyAdjoint(wrong_adjoint_x, adjoint_y)); + } VERIFY(op.rows() == A.rows()); VERIFY(op.cols() == A.cols());
diff --git a/test/svd_common.h b/test/svd_common.h index f76cd35..f1e6a6f 100644 --- a/test/svd_common.h +++ b/test/svd_common.h
@@ -551,13 +551,17 @@ RhsType rhs = RhsType::Zero(m.rows()); EIGEN_UNUSED_VARIABLE(rhs); // Only used if asserts are enabled. + using TransposeRhsType = Matrix<typename MatrixType::Scalar, MatrixType::ColsAtCompileTime, 1>; + TransposeRhsType transposeRhs = TransposeRhsType::Zero(m.cols()); + EIGEN_UNUSED_VARIABLE(transposeRhs); + SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner) svd0; VERIFY_RAISES_ASSERT((svd0.matrixU())); VERIFY_RAISES_ASSERT((svd0.singularValues())); VERIFY_RAISES_ASSERT((svd0.matrixV())); VERIFY_RAISES_ASSERT((svd0.solve(rhs))); - VERIFY_RAISES_ASSERT((svd0.transpose().solve(rhs))); - VERIFY_RAISES_ASSERT((svd0.adjoint().solve(rhs))); + VERIFY_RAISES_ASSERT((svd0.transpose().solve(transposeRhs))); + VERIFY_RAISES_ASSERT((svd0.adjoint().solve(transposeRhs))); SVD_STATIC_OPTIONS(MatrixType, QRPreconditioner) svd1(m); VERIFY_RAISES_ASSERT((svd1.matrixU()));
diff --git a/test/zerosized.cpp b/test/zerosized.cpp index 7393a36..7facccd 100644 --- a/test/zerosized.cpp +++ b/test/zerosized.cpp
@@ -55,7 +55,9 @@ fixed << Scalar(2), Scalar(3); dynamic = fixed; VERIFY_IS_EQUAL(double(internal::redux_with_identity(fixed, sum, identity)), 5.0); - VERIFY_IS_EQUAL(double(internal::redux_with_identity(dynamic, sum, std::move(identity))), 5.0); + VERIFY_IS_EQUAL(double(internal::redux_with_identity( + dynamic, sum, ReductionIdentity<Scalar>(runtimeIdentity, lvalueConversions, rvalueConversions))), + 5.0); VERIFY_IS_EQUAL(lvalueConversions, 3); VERIFY_IS_EQUAL(rvalueConversions, 0);