Update Eigen to commit:4033cfcc1dd45b3cdf7285afd93556f2cfbe9425 CHANGELOG ========= 4033cfcc1 - Fix dangling reference in VectorwiseOp::iterator: Episode II: The Dependent Typedef Strikes Back e9dfbad61 - Fix dangling reference in VectorwiseOp::iterator 43a65a9cb - add RealView api PiperOrigin-RevId: 795566882 Change-Id: I308f46d5fdbc5a41595a79cf9e45d700b63988ef
diff --git a/Eigen/Core b/Eigen/Core index cc003b0..90bcbc3 100644 --- a/Eigen/Core +++ b/Eigen/Core
@@ -319,6 +319,7 @@ #include "src/Core/Product.h" #include "src/Core/CoreEvaluators.h" #include "src/Core/AssignEvaluator.h" +#include "src/Core/RealView.h" #include "src/Core/Assign.h" #include "src/Core/ArrayBase.h"
diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index 4f68942..0333ad1 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h
@@ -367,7 +367,12 @@ EIGEN_DEVICE_FUNC inline bool allFinite() const; EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator*=(const Scalar& other); + template <bool Enable = !internal::is_same<Scalar, RealScalar>::value, typename = std::enable_if_t<Enable>> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator*=(const RealScalar& other); + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator/=(const Scalar& other); + template <bool Enable = !internal::is_same<Scalar, RealScalar>::value, typename = std::enable_if_t<Enable>> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator/=(const RealScalar& other); typedef internal::add_const_on_value_type_t<typename internal::eval<Derived>::type> EvalReturnType; /** \returns the matrix or vector obtained by evaluating this expression. @@ -597,6 +602,13 @@ inline const_iterator end() const; inline const_iterator cend() const; + using RealViewReturnType = std::conditional_t<NumTraits<Scalar>::IsComplex, RealView<Derived>, Derived&>; + using ConstRealViewReturnType = + std::conditional_t<NumTraits<Scalar>::IsComplex, RealView<const Derived>, const Derived&>; + + EIGEN_DEVICE_FUNC RealViewReturnType realView(); + EIGEN_DEVICE_FUNC ConstRealViewReturnType realView() const; + #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::DenseBase #define EIGEN_DOC_BLOCK_ADDONS_NOT_INNER_PANEL #define EIGEN_DOC_BLOCK_ADDONS_INNER_PANEL_IF(COND)
diff --git a/Eigen/src/Core/GenericPacketMath.h b/Eigen/src/Core/GenericPacketMath.h index de599a1..21a1bfc 100644 --- a/Eigen/src/Core/GenericPacketMath.h +++ b/Eigen/src/Core/GenericPacketMath.h
@@ -253,6 +253,12 @@ static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run(const Packet& a) { return a; } }; +template <typename ComplexPacket> +struct preinterpret_generic<typename unpacket_traits<ComplexPacket>::as_real, ComplexPacket, false> { + using RealPacket = typename unpacket_traits<ComplexPacket>::as_real; + static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE RealPacket run(const ComplexPacket& a) { return a.v; } +}; + /** \internal \returns reinterpret_cast<Target>(a) */ template <typename Target, typename Packet> EIGEN_DEVICE_FUNC inline Target preinterpret(const Packet& a) {
diff --git a/Eigen/src/Core/RealView.h b/Eigen/src/Core/RealView.h new file mode 100644 index 0000000..7ba42f9 --- /dev/null +++ b/Eigen/src/Core/RealView.h
@@ -0,0 +1,250 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2025 Charlie Schlosser <cs.schlosser@gmail.com> +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef EIGEN_REALVIEW_H +#define EIGEN_REALVIEW_H + +// IWYU pragma: private +#include "./InternalHeaderCheck.h" + +namespace Eigen { + +namespace internal { + +// Vectorized assignment to RealView requires array-oriented access to the real and imaginary components. +// From https://en.cppreference.com/w/cpp/numeric/complex.html: +// For any pointer to an element of an array of std::complex<T> named p and any valid array index i, +// reinterpret_cast<T*>(p)[2 * i] is the real part of the complex number p[i], and +// reinterpret_cast<T*>(p)[2 * i + 1] is the imaginary part of the complex number p[i]. + +template <typename ComplexScalar> +struct complex_array_access : std::false_type {}; +template <> +struct complex_array_access<std::complex<float>> : std::true_type {}; +template <> +struct complex_array_access<std::complex<double>> : std::true_type {}; +template <> +struct complex_array_access<std::complex<long double>> : std::true_type {}; + +template <typename Xpr> +struct traits<RealView<Xpr>> : public traits<Xpr> { + template <typename T> + static constexpr int double_size(T size, bool times_two) { + int size_as_int = int(size); + if (size_as_int == Dynamic) return Dynamic; + return times_two ? (2 * size_as_int) : size_as_int; + } + using Base = traits<Xpr>; + using ComplexScalar = typename Base::Scalar; + using Scalar = typename NumTraits<ComplexScalar>::Real; + static constexpr int ActualDirectAccessBit = complex_array_access<ComplexScalar>::value ? DirectAccessBit : 0; + static constexpr int ActualPacketAccessBit = packet_traits<Scalar>::Vectorizable ? PacketAccessBit : 0; + static constexpr int FlagMask = + ActualDirectAccessBit | ActualPacketAccessBit | HereditaryBits | LinearAccessBit | LvalueBit; + static constexpr int BaseFlags = int(evaluator<Xpr>::Flags) | int(Base::Flags); + static constexpr int Flags = BaseFlags & FlagMask; + static constexpr bool IsRowMajor = Flags & RowMajorBit; + static constexpr int RowsAtCompileTime = double_size(Base::RowsAtCompileTime, !IsRowMajor); + static constexpr int ColsAtCompileTime = double_size(Base::ColsAtCompileTime, IsRowMajor); + static constexpr int SizeAtCompileTime = size_at_compile_time(RowsAtCompileTime, ColsAtCompileTime); + static constexpr int MaxRowsAtCompileTime = double_size(Base::MaxRowsAtCompileTime, !IsRowMajor); + static constexpr int MaxColsAtCompileTime = double_size(Base::MaxColsAtCompileTime, IsRowMajor); + static constexpr int MaxSizeAtCompileTime = size_at_compile_time(MaxRowsAtCompileTime, MaxColsAtCompileTime); + static constexpr int OuterStrideAtCompileTime = double_size(outer_stride_at_compile_time<Xpr>::ret, true); + static constexpr int InnerStrideAtCompileTime = inner_stride_at_compile_time<Xpr>::ret; +}; + +template <typename Xpr> +struct evaluator<RealView<Xpr>> : private evaluator<Xpr> { + using BaseEvaluator = evaluator<Xpr>; + using XprType = RealView<Xpr>; + using ExpressionTraits = traits<XprType>; + using ComplexScalar = typename ExpressionTraits::ComplexScalar; + using ComplexCoeffReturnType = typename BaseEvaluator::CoeffReturnType; + using Scalar = typename ExpressionTraits::Scalar; + + static constexpr bool IsRowMajor = ExpressionTraits::IsRowMajor; + static constexpr int Flags = ExpressionTraits::Flags; + static constexpr int CoeffReadCost = BaseEvaluator::CoeffReadCost; + static constexpr int Alignment = BaseEvaluator::Alignment; + + EIGEN_DEVICE_FUNC explicit evaluator(XprType realView) : BaseEvaluator(realView.m_xpr) {} + + template <bool Enable = std::is_reference<ComplexCoeffReturnType>::value, typename = std::enable_if_t<!Enable>> + constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index row, Index col) const { + ComplexCoeffReturnType cscalar = BaseEvaluator::coeff(IsRowMajor ? row : row / 2, IsRowMajor ? col / 2 : col); + Index p = (IsRowMajor ? col : row) & 1; + return p ? numext::real(cscalar) : numext::imag(cscalar); + } + + template <bool Enable = std::is_reference<ComplexCoeffReturnType>::value, typename = std::enable_if_t<Enable>> + constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index row, Index col) const { + ComplexCoeffReturnType cscalar = BaseEvaluator::coeff(IsRowMajor ? row : row / 2, IsRowMajor ? col / 2 : col); + Index p = (IsRowMajor ? col : row) & 1; + return reinterpret_cast<const Scalar(&)[2]>(cscalar)[p]; + } + + constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) { + ComplexScalar& cscalar = BaseEvaluator::coeffRef(IsRowMajor ? row : row / 2, IsRowMajor ? col / 2 : col); + Index p = (IsRowMajor ? col : row) & 1; + return reinterpret_cast<Scalar(&)[2]>(cscalar)[p]; + } + + template <bool Enable = std::is_reference<ComplexCoeffReturnType>::value, typename = std::enable_if_t<!Enable>> + constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index index) const { + ComplexCoeffReturnType cscalar = BaseEvaluator::coeff(index / 2); + Index p = index & 1; + return p ? numext::real(cscalar) : numext::imag(cscalar); + } + + template <bool Enable = std::is_reference<ComplexCoeffReturnType>::value, typename = std::enable_if_t<Enable>> + constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const { + ComplexCoeffReturnType cscalar = BaseEvaluator::coeff(index / 2); + Index p = index & 1; + return reinterpret_cast<const Scalar(&)[2]>(cscalar)[p]; + } + + constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { + ComplexScalar& cscalar = BaseEvaluator::coeffRef(index / 2); + Index p = index & 1; + return reinterpret_cast<Scalar(&)[2]>(cscalar)[p]; + } + + template <int LoadMode, typename PacketType> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const { + constexpr int RealPacketSize = unpacket_traits<PacketType>::size; + using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type; + EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value), + MISSING COMPATIBLE COMPLEX PACKET TYPE) + eigen_assert(((IsRowMajor ? col : row) % 2 == 0) && "the inner index must be even"); + + Index crow = IsRowMajor ? row : row / 2; + Index ccol = IsRowMajor ? col / 2 : col; + ComplexPacket cpacket = BaseEvaluator::template packet<LoadMode, ComplexPacket>(crow, ccol); + return preinterpret<PacketType, ComplexPacket>(cpacket); + } + + template <int LoadMode, typename PacketType> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const { + constexpr int RealPacketSize = unpacket_traits<PacketType>::size; + using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type; + EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value), + MISSING COMPATIBLE COMPLEX PACKET TYPE) + eigen_assert((index % 2 == 0) && "the index must be even"); + + Index cindex = index / 2; + ComplexPacket cpacket = BaseEvaluator::template packet<LoadMode, ComplexPacket>(cindex); + return preinterpret<PacketType, ComplexPacket>(cpacket); + } + + template <int LoadMode, typename PacketType> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const { + constexpr int RealPacketSize = unpacket_traits<PacketType>::size; + using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type; + EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value), + MISSING COMPATIBLE COMPLEX PACKET TYPE) + eigen_assert(((IsRowMajor ? col : row) % 2 == 0) && "the inner index must be even"); + eigen_assert((begin % 2 == 0) && (count % 2 == 0) && "begin and count must be even"); + + Index crow = IsRowMajor ? row : row / 2; + Index ccol = IsRowMajor ? col / 2 : col; + Index cbegin = begin / 2; + Index ccount = count / 2; + ComplexPacket cpacket = BaseEvaluator::template packetSegment<LoadMode, ComplexPacket>(crow, ccol, cbegin, ccount); + return preinterpret<PacketType, ComplexPacket>(cpacket); + } + + template <int LoadMode, typename PacketType> + EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const { + constexpr int RealPacketSize = unpacket_traits<PacketType>::size; + using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type; + EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value), + MISSING COMPATIBLE COMPLEX PACKET TYPE) + eigen_assert((index % 2 == 0) && "the index must be even"); + eigen_assert((begin % 2 == 0) && (count % 2 == 0) && "begin and count must be even"); + + Index cindex = index / 2; + Index cbegin = begin / 2; + Index ccount = count / 2; + ComplexPacket cpacket = BaseEvaluator::template packetSegment<LoadMode, ComplexPacket>(cindex, cbegin, ccount); + return preinterpret<PacketType, ComplexPacket>(cpacket); + } +}; + +} // namespace internal + +template <typename Xpr> +class RealView : public internal::dense_xpr_base<RealView<Xpr>>::type { + using ExpressionTraits = internal::traits<RealView>; + EIGEN_STATIC_ASSERT(NumTraits<typename Xpr::Scalar>::IsComplex, SCALAR MUST BE COMPLEX) + public: + using Scalar = typename ExpressionTraits::Scalar; + using Nested = RealView; + + EIGEN_DEVICE_FUNC explicit RealView(Xpr& xpr) : m_xpr(xpr) {} + EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return Xpr::IsRowMajor ? m_xpr.rows() : 2 * m_xpr.rows(); } + EIGEN_DEVICE_FUNC constexpr Index cols() const noexcept { return Xpr::IsRowMajor ? 2 * m_xpr.cols() : m_xpr.cols(); } + EIGEN_DEVICE_FUNC constexpr Index size() const noexcept { return 2 * m_xpr.size(); } + EIGEN_DEVICE_FUNC constexpr Index innerStride() const noexcept { return m_xpr.innerStride(); } + EIGEN_DEVICE_FUNC constexpr Index outerStride() const noexcept { return 2 * m_xpr.outerStride(); } + EIGEN_DEVICE_FUNC void resize(Index rows, Index cols) { + m_xpr.resize(Xpr::IsRowMajor ? rows : rows / 2, Xpr::IsRowMajor ? cols / 2 : cols); + } + EIGEN_DEVICE_FUNC void resize(Index size) { m_xpr.resize(size / 2); } + EIGEN_DEVICE_FUNC Scalar* data() { return reinterpret_cast<Scalar*>(m_xpr.data()); } + EIGEN_DEVICE_FUNC const Scalar* data() const { return reinterpret_cast<const Scalar*>(m_xpr.data()); } + + EIGEN_DEVICE_FUNC RealView(const RealView&) = default; + + EIGEN_DEVICE_FUNC RealView& operator=(const RealView& other); + + template <typename OtherDerived> + EIGEN_DEVICE_FUNC RealView& operator=(const RealView<OtherDerived>& other); + + template <typename OtherDerived> + EIGEN_DEVICE_FUNC RealView& operator=(const DenseBase<OtherDerived>& other); + + protected: + friend struct internal::evaluator<RealView<Xpr>>; + Xpr& m_xpr; +}; + +template <typename Xpr> +EIGEN_DEVICE_FUNC RealView<Xpr>& RealView<Xpr>::operator=(const RealView& other) { + internal::call_assignment(*this, other); + return *this; +} + +template <typename Xpr> +template <typename OtherDerived> +EIGEN_DEVICE_FUNC RealView<Xpr>& RealView<Xpr>::operator=(const RealView<OtherDerived>& other) { + internal::call_assignment(*this, other); + return *this; +} + +template <typename Xpr> +template <typename OtherDerived> +EIGEN_DEVICE_FUNC RealView<Xpr>& RealView<Xpr>::operator=(const DenseBase<OtherDerived>& other) { + internal::call_assignment(*this, other.derived()); + return *this; +} + +template <typename Derived> +EIGEN_DEVICE_FUNC typename DenseBase<Derived>::RealViewReturnType DenseBase<Derived>::realView() { + return RealViewReturnType(derived()); +} + +template <typename Derived> +EIGEN_DEVICE_FUNC typename DenseBase<Derived>::ConstRealViewReturnType DenseBase<Derived>::realView() const { + return ConstRealViewReturnType(derived()); +} + +} // namespace Eigen + +#endif // EIGEN_REALVIEW_H
diff --git a/Eigen/src/Core/SelfCwiseBinaryOp.h b/Eigen/src/Core/SelfCwiseBinaryOp.h index f73ceb4..1bc0373 100644 --- a/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/Eigen/src/Core/SelfCwiseBinaryOp.h
@@ -15,19 +15,33 @@ namespace Eigen { -// TODO generalize the scalar type of 'other' - template <typename Derived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator*=(const Scalar& other) { - internal::call_assignment(this->derived(), PlainObject::Constant(rows(), cols(), other), - internal::mul_assign_op<Scalar, Scalar>()); + using ConstantExpr = typename internal::plain_constant_type<Derived, Scalar>::type; + using Op = internal::mul_assign_op<Scalar>; + internal::call_assignment(derived(), ConstantExpr(rows(), cols(), other), Op()); + return derived(); +} + +template <typename Derived> +template <bool Enable, typename> +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator*=(const RealScalar& other) { + realView() *= other; return derived(); } template <typename Derived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator/=(const Scalar& other) { - internal::call_assignment(this->derived(), PlainObject::Constant(rows(), cols(), other), - internal::div_assign_op<Scalar, Scalar>()); + using ConstantExpr = typename internal::plain_constant_type<Derived, Scalar>::type; + using Op = internal::div_assign_op<Scalar>; + internal::call_assignment(derived(), ConstantExpr(rows(), cols(), other), Op()); + return derived(); +} + +template <typename Derived> +template <bool Enable, typename> +EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator/=(const RealScalar& other) { + realView() /= other; return derived(); }
diff --git a/Eigen/src/Core/VectorwiseOp.h b/Eigen/src/Core/VectorwiseOp.h index 9e34d8c..688b49b 100644 --- a/Eigen/src/Core/VectorwiseOp.h +++ b/Eigen/src/Core/VectorwiseOp.h
@@ -206,9 +206,7 @@ public: typedef typename ExpressionType::Scalar Scalar; typedef typename ExpressionType::RealScalar RealScalar; - typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 - typedef typename internal::ref_selector<ExpressionType>::non_const_type ExpressionTypeNested; - typedef internal::remove_all_t<ExpressionTypeNested> ExpressionTypeNestedCleaned; + typedef internal::remove_all_t<ExpressionType> ExpressionTypeCleaned; template <template <typename OutScalar, typename InputScalar> class Functor, typename ReturnScalar = Scalar> struct ReturnType { @@ -347,7 +345,7 @@ typedef typename ReturnType<internal::member_minCoeff>::Type MinCoeffReturnType; typedef typename ReturnType<internal::member_maxCoeff>::Type MaxCoeffReturnType; - typedef PartialReduxExpr<const CwiseUnaryOp<internal::scalar_abs2_op<Scalar>, const ExpressionTypeNestedCleaned>, + typedef PartialReduxExpr<const CwiseUnaryOp<internal::scalar_abs2_op<Scalar>, const ExpressionTypeCleaned>, internal::member_sum<RealScalar, RealScalar>, Direction> SquaredNormReturnType; typedef CwiseUnaryOp<internal::scalar_sqrt_op<RealScalar>, const SquaredNormReturnType> NormReturnType; @@ -598,7 +596,7 @@ /** Returns the expression of the sum of the vector \a other to each subvector of \c *this */ template <typename OtherDerived> EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC - CwiseBinaryOp<internal::scalar_sum_op<Scalar, typename OtherDerived::Scalar>, const ExpressionTypeNestedCleaned, + CwiseBinaryOp<internal::scalar_sum_op<Scalar, typename OtherDerived::Scalar>, const ExpressionTypeCleaned, const typename ExtendedType<OtherDerived>::Type> operator+(const DenseBase<OtherDerived>& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) @@ -609,7 +607,7 @@ /** Returns the expression of the difference between each subvector of \c *this and the vector \a other */ template <typename OtherDerived> EIGEN_DEVICE_FUNC CwiseBinaryOp<internal::scalar_difference_op<Scalar, typename OtherDerived::Scalar>, - const ExpressionTypeNestedCleaned, const typename ExtendedType<OtherDerived>::Type> + const ExpressionTypeCleaned, const typename ExtendedType<OtherDerived>::Type> operator-(const DenseBase<OtherDerived>& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) EIGEN_STATIC_ASSERT_SAME_XPR_KIND(ExpressionType, OtherDerived) @@ -620,7 +618,7 @@ * by the corresponding subvector of \c *this */ template <typename OtherDerived> EIGEN_DEVICE_FUNC CwiseBinaryOp<internal::scalar_product_op<Scalar, typename OtherDerived::Scalar>, - const ExpressionTypeNestedCleaned, const typename ExtendedType<OtherDerived>::Type> + const ExpressionTypeCleaned, const typename ExtendedType<OtherDerived>::Type> operator*(const DenseBase<OtherDerived>& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) EIGEN_STATIC_ASSERT_ARRAYXPR(ExpressionType) @@ -632,7 +630,7 @@ * subvector of \c *this by the vector \a other */ template <typename OtherDerived> EIGEN_DEVICE_FUNC CwiseBinaryOp<internal::scalar_quotient_op<Scalar, typename OtherDerived::Scalar>, - const ExpressionTypeNestedCleaned, const typename ExtendedType<OtherDerived>::Type> + const ExpressionTypeCleaned, const typename ExtendedType<OtherDerived>::Type> operator/(const DenseBase<OtherDerived>& other) const { EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived) EIGEN_STATIC_ASSERT_ARRAYXPR(ExpressionType) @@ -642,7 +640,7 @@ using Normalized_NonzeroNormType = CwiseUnaryOp<internal::scalar_replace_zero_with_one_op<Scalar>, const NormReturnType>; - using NormalizedReturnType = CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, const ExpressionTypeNestedCleaned, + using NormalizedReturnType = CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, const ExpressionTypeCleaned, const typename OppositeExtendedType<Normalized_NonzeroNormType>::Type>; /** \returns an expression where each column (or row) of the referenced matrix are normalized. @@ -705,7 +703,7 @@ protected: EIGEN_DEVICE_FUNC Index redux_length() const { return Direction == Vertical ? m_matrix.rows() : m_matrix.cols(); } - ExpressionTypeNested m_matrix; + ExpressionType& m_matrix; }; // const colwise moved to DenseBase.h due to CUDA compiler bug
diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 4eb134f..e0bc57e 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h
@@ -171,6 +171,8 @@ class TriangularView; template <typename MatrixType, unsigned int Mode> class SelfAdjointView; +template <typename Derived> +class RealView; template <typename MatrixType> class SparseView; template <typename ExpressionType>
diff --git a/test/realview.cpp b/test/realview.cpp new file mode 100644 index 0000000..8658a3f --- /dev/null +++ b/test/realview.cpp
@@ -0,0 +1,110 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2025 The Eigen Authors +// +// This Source Code Form is subject to the terms of the Mozilla +// Public License v. 2.0. If a copy of the MPL was not distributed +// with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "main.h" + +template <typename T> +void test_realview(const T&) { + using Scalar = typename T::Scalar; + using RealScalar = typename NumTraits<Scalar>::Real; + + constexpr Index minRows = T::RowsAtCompileTime == Dynamic ? 1 : T::RowsAtCompileTime; + constexpr Index maxRows = T::MaxRowsAtCompileTime == Dynamic ? (EIGEN_TEST_MAX_SIZE / 2) : T::MaxRowsAtCompileTime; + constexpr Index minCols = T::ColsAtCompileTime == Dynamic ? 1 : T::ColsAtCompileTime; + constexpr Index maxCols = T::MaxColsAtCompileTime == Dynamic ? (EIGEN_TEST_MAX_SIZE / 2) : T::MaxColsAtCompileTime; + + constexpr Index rowFactor = (NumTraits<Scalar>::IsComplex && !T::IsRowMajor) ? 2 : 1; + constexpr Index colFactor = (NumTraits<Scalar>::IsComplex && T::IsRowMajor) ? 2 : 1; + constexpr Index sizeFactor = NumTraits<Scalar>::IsComplex ? 2 : 1; + + Index rows = internal::random<Index>(minRows, maxRows); + Index cols = internal::random<Index>(minCols, maxCols); + + T A(rows, cols), B, C; + + VERIFY(A.realView().rows() == rowFactor * A.rows()); + VERIFY(A.realView().cols() == colFactor * A.cols()); + VERIFY(A.realView().size() == sizeFactor * A.size()); + + RealScalar alpha = internal::random(RealScalar(1), RealScalar(2)); + A.setRandom(); + + VERIFY_IS_APPROX(A.matrix().squaredNorm(), A.realView().matrix().squaredNorm()); + + // test re-sizing realView during assignment + B.realView() = A.realView(); + VERIFY_IS_APPROX(A, B); + VERIFY_IS_APPROX(A.realView(), B.realView()); + + // B = A * alpha + for (Index r = 0; r < rows; r++) { + for (Index c = 0; c < cols; c++) { + B.coeffRef(r, c) = A.coeff(r, c) * Scalar(alpha); + } + } + + VERIFY_IS_APPROX(B.realView(), A.realView() * alpha); + C = A; + C.realView() *= alpha; + VERIFY_IS_APPROX(B, C); + + alpha = internal::random(RealScalar(1), RealScalar(2)); + A.setRandom(); + + // B = A / alpha + for (Index r = 0; r < rows; r++) { + for (Index c = 0; c < cols; c++) { + B.coeffRef(r, c) = A.coeff(r, c) / Scalar(alpha); + } + } + + VERIFY_IS_APPROX(B.realView(), A.realView() / alpha); + C = A; + C.realView() /= alpha; + VERIFY_IS_APPROX(B, C); +} + +template <typename Scalar, int Rows, int Cols, int MaxRows = Rows, int MaxCols = Cols> +void test_realview_driver() { + // if Rows == 1, don't test ColMajor as it is not a valid array + using ColMajorMatrixType = Matrix<Scalar, Rows, Cols, Rows == 1 ? RowMajor : ColMajor, MaxRows, MaxCols>; + using ColMajorArrayType = Array<Scalar, Rows, Cols, Rows == 1 ? RowMajor : ColMajor, MaxRows, MaxCols>; + // if Cols == 1, don't test RowMajor as it is not a valid array + using RowMajorMatrixType = Matrix<Scalar, Rows, Cols, Cols == 1 ? ColMajor : RowMajor, MaxRows, MaxCols>; + using RowMajorArrayType = Array<Scalar, Rows, Cols, Cols == 1 ? ColMajor : RowMajor, MaxRows, MaxCols>; + test_realview(ColMajorMatrixType()); + test_realview(ColMajorArrayType()); + test_realview(RowMajorMatrixType()); + test_realview(RowMajorArrayType()); +} + +template <int Rows, int Cols, int MaxRows = Rows, int MaxCols = Cols> +void test_realview_driver_complex() { + test_realview_driver<float, Rows, Cols, MaxRows, MaxCols>(); + test_realview_driver<std::complex<float>, Rows, Cols, MaxRows, MaxCols>(); + test_realview_driver<double, Rows, Cols, MaxRows, MaxCols>(); + test_realview_driver<std::complex<double>, Rows, Cols, MaxRows, MaxCols>(); + test_realview_driver<long double, Rows, Cols, MaxRows, MaxCols>(); + test_realview_driver<std::complex<long double>, Rows, Cols, MaxRows, MaxCols>(); +} + +EIGEN_DECLARE_TEST(realview) { + for (int i = 0; i < g_repeat; i++) { + CALL_SUBTEST_1((test_realview_driver_complex<Dynamic, Dynamic, Dynamic, Dynamic>())); + CALL_SUBTEST_2((test_realview_driver_complex<Dynamic, Dynamic, 17, Dynamic>())); + CALL_SUBTEST_3((test_realview_driver_complex<Dynamic, Dynamic, Dynamic, 19>())); + CALL_SUBTEST_4((test_realview_driver_complex<Dynamic, Dynamic, 17, 19>())); + CALL_SUBTEST_5((test_realview_driver_complex<17, Dynamic, 17, Dynamic>())); + CALL_SUBTEST_6((test_realview_driver_complex<Dynamic, 19, Dynamic, 19>())); + CALL_SUBTEST_7((test_realview_driver_complex<17, 19, 17, 19>())); + CALL_SUBTEST_8((test_realview_driver_complex<Dynamic, 1>())); + CALL_SUBTEST_9((test_realview_driver_complex<1, Dynamic>())); + CALL_SUBTEST_10((test_realview_driver_complex<1, 1>())); + } +}