Eigen  5.0.1
 
Loading...
Searching...
No Matches
RealView.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2025 Charlie Schlosser <cs.schlosser@gmail.com>
5//
6// This Source Code Form is subject to the terms of the Mozilla
7// Public License v. 2.0. If a copy of the MPL was not distributed
8// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9// SPDX-License-Identifier: MPL-2.0
10
11#ifndef EIGEN_REALVIEW_H
12#define EIGEN_REALVIEW_H
13
14// IWYU pragma: private
15#include "./InternalHeaderCheck.h"
16
17namespace Eigen {
18
19namespace internal {
20
21// Write access and vectorization requires array-oriented access to the real and imaginary components.
22// From https://en.cppreference.com/w/cpp/numeric/complex.html:
23// For any pointer to an element of an array of std::complex<T> named p and any valid array index i,
24// reinterpret_cast<T*>(p)[2 * i] is the real part of the complex number p[i], and
25// reinterpret_cast<T*>(p)[2 * i + 1] is the imaginary part of the complex number p[i].
26
27template <typename T>
28struct complex_array_access : std::false_type {};
29template <typename T>
30struct complex_array_access<std::complex<T>> : std::true_type {};
31
32template <typename Xpr>
33struct traits<RealView<Xpr>> : public traits<Xpr> {
34 template <typename T>
35 static constexpr int double_size(T size, bool times_two) {
36 int size_as_int = int(size);
37 if (size_as_int == Dynamic) return Dynamic;
38 return times_two ? (2 * size_as_int) : size_as_int;
39 }
40
41 using Base = traits<Xpr>;
42 using ComplexScalar = typename Base::Scalar;
43 using Scalar = typename NumTraits<ComplexScalar>::Real;
44
45 static constexpr bool ArrayAccess = complex_array_access<ComplexScalar>::value;
46 // Real and imaginary parts interleave with a uniform stride only when the complex coefficients are adjacent.
47 static constexpr int ActualDirectAccessBit =
48 ArrayAccess && inner_stride_at_compile_time<Xpr>::value == 1 ? DirectAccessBit : 0;
49 static constexpr int ActualLvalueBit = !std::is_const<Xpr>::value && ArrayAccess ? LvalueBit : 0;
50 static constexpr int ActualPacketAccessBit = packet_traits<Scalar>::Vectorizable ? PacketAccessBit : 0;
51 static constexpr int FlagMask =
52 ActualDirectAccessBit | ActualLvalueBit | ActualPacketAccessBit | HereditaryBits | LinearAccessBit;
53 static constexpr int BaseFlags = int(evaluator<Xpr>::Flags) | int(Base::Flags);
54 static constexpr int Flags = BaseFlags & FlagMask;
55 static constexpr bool IsRowMajor = Flags & RowMajorBit;
56 static constexpr int RowsAtCompileTime = double_size(Base::RowsAtCompileTime, !IsRowMajor);
57 static constexpr int ColsAtCompileTime = double_size(Base::ColsAtCompileTime, IsRowMajor);
58 static constexpr int SizeAtCompileTime = size_at_compile_time(RowsAtCompileTime, ColsAtCompileTime);
59 static constexpr int MaxRowsAtCompileTime = double_size(Base::MaxRowsAtCompileTime, !IsRowMajor);
60 static constexpr int MaxColsAtCompileTime = double_size(Base::MaxColsAtCompileTime, IsRowMajor);
61 static constexpr int MaxSizeAtCompileTime = size_at_compile_time(MaxRowsAtCompileTime, MaxColsAtCompileTime);
62 static constexpr int OuterStrideAtCompileTime = double_size(outer_stride_at_compile_time<Xpr>::value, true);
63 static constexpr int InnerStrideAtCompileTime = inner_stride_at_compile_time<Xpr>::value;
64};
65
66template <typename Xpr>
67struct evaluator<RealView<Xpr>> : private evaluator<Xpr> {
68 using BaseEvaluator = evaluator<Xpr>;
69 using XprType = RealView<Xpr>;
70 using ExpressionTraits = traits<XprType>;
71 using ComplexScalar = typename ExpressionTraits::ComplexScalar;
72 using Scalar = typename ExpressionTraits::Scalar;
73
74 static constexpr int Flags = ExpressionTraits::Flags;
75 static constexpr int CoeffReadCost = BaseEvaluator::CoeffReadCost;
76 static constexpr int Alignment = BaseEvaluator::Alignment;
77 static constexpr bool IsRowMajor = ExpressionTraits::IsRowMajor;
78 // DenseCoeffsBase::CoeffReturnType is a reference for LvalueBit as well as DirectAccessBit; returning a value
79 // there would dangle.
80 static constexpr bool CoeffByReference = (Flags & (LvalueBit | DirectAccessBit)) != 0;
81
82 using ComplexCoeffReturnType = std::conditional_t<CoeffByReference, const ComplexScalar&, ComplexScalar>;
83 using CoeffReturnType = std::conditional_t<CoeffByReference, const Scalar&, Scalar>;
84
85 EIGEN_DEVICE_FUNC explicit evaluator(XprType realView) : BaseEvaluator(realView.m_xpr) {}
86
87 template <bool Enable = CoeffByReference, std::enable_if_t<!Enable, bool> = true>
88 constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index row, Index col) const {
89 Index r = IsRowMajor ? row : row / 2;
90 Index c = IsRowMajor ? col / 2 : col;
91 bool p = (IsRowMajor ? col : row) & 1;
92 ComplexScalar ccoeff = BaseEvaluator::coeff(r, c);
93 return p ? numext::imag(ccoeff) : numext::real(ccoeff);
94 }
95 template <bool Enable = CoeffByReference, std::enable_if_t<Enable, bool> = true>
96 constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
97 Index r = IsRowMajor ? row : row / 2;
98 Index c = IsRowMajor ? col / 2 : col;
99 Index p = (IsRowMajor ? col : row) & 1;
100 ComplexCoeffReturnType ccoeff = BaseEvaluator::coeff(r, c);
101 return reinterpret_cast<const Scalar(&)[2]>(ccoeff)[p];
102 }
103 template <bool Enable = CoeffByReference, std::enable_if_t<!Enable, bool> = true>
104 constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index index) const {
105 ComplexScalar ccoeff = BaseEvaluator::coeff(index / 2);
106 bool p = index & 1;
107 return p ? numext::imag(ccoeff) : numext::real(ccoeff);
108 }
109 template <bool Enable = CoeffByReference, std::enable_if_t<Enable, bool> = true>
110 constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
111 ComplexCoeffReturnType ccoeff = BaseEvaluator::coeff(index / 2);
112 Index p = index & 1;
113 return reinterpret_cast<const Scalar(&)[2]>(ccoeff)[p];
114 }
115 constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) {
116 Index r = IsRowMajor ? row : row / 2;
117 Index c = IsRowMajor ? col / 2 : col;
118 Index p = (IsRowMajor ? col : row) & 1;
119 ComplexScalar& ccoeffRef = BaseEvaluator::coeffRef(r, c);
120 return reinterpret_cast<Scalar(&)[2]>(ccoeffRef)[p];
121 }
122 constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
123 ComplexScalar& ccoeffRef = BaseEvaluator::coeffRef(index / 2);
124 Index p = index & 1;
125 return reinterpret_cast<Scalar(&)[2]>(ccoeffRef)[p];
126 }
127
128 // If the first index is odd (imaginary), discard the first scalar
129 // in 'result' and assign the missing scalar.
130 // This operation is safe as the real component of the first scalar must exist.
131
132 template <int LoadMode, typename PacketType>
133 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
134 constexpr int RealPacketSize = unpacket_traits<PacketType>::size;
135 using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type;
136 EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value),
137 MISSING COMPATIBLE COMPLEX PACKET TYPE)
138 Index r = IsRowMajor ? row : row / 2;
139 Index c = IsRowMajor ? col / 2 : col;
140 bool p = (IsRowMajor ? col : row) & 1;
141 ComplexPacket cresult = BaseEvaluator::template packet<LoadMode, ComplexPacket>(r, c);
142 PacketType result = preinterpret<PacketType>(cresult);
143 if (p) {
144 Scalar aux[RealPacketSize + 1];
145 pstoreu(aux, result);
146 Index lastr = IsRowMajor ? row : row + RealPacketSize - 1;
147 Index lastc = IsRowMajor ? col + RealPacketSize - 1 : col;
148 aux[RealPacketSize] = coeff(lastr, lastc);
149 result = ploadu<PacketType>(aux + 1);
150 }
151 return result;
152 }
153
154 template <int LoadMode, typename PacketType>
155 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
156 constexpr int RealPacketSize = unpacket_traits<PacketType>::size;
157 using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type;
158 EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value),
159 MISSING COMPATIBLE COMPLEX PACKET TYPE)
160 ComplexPacket cresult = BaseEvaluator::template packet<LoadMode, ComplexPacket>(index / 2);
161 PacketType result = preinterpret<PacketType>(cresult);
162 bool p = index & 1;
163 if (p) {
164 Scalar aux[RealPacketSize + 1];
165 pstoreu(aux, result);
166 aux[RealPacketSize] = coeff(index + RealPacketSize - 1);
167 result = ploadu<PacketType>(aux + 1);
168 }
169 return result;
170 }
171
172 // The requested real packet segment forms the half-open interval [begin, end), where 'end' = 'begin' + 'count'.
173 // In order to access the underlying complex array, even indices must be aligned with the real components
174 // of the complex scalars. 'begin' and 'count' must be modified as follows:
175 // a) 'begin' must be rounded down to the nearest even number; and
176 // b) 'end' must be rounded up to the nearest even number.
177
178 template <int LoadMode, typename PacketType>
179 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
180 constexpr int RealPacketSize = unpacket_traits<PacketType>::size;
181 using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type;
182 EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value),
183 MISSING COMPATIBLE COMPLEX PACKET TYPE)
184 Index actualBegin = numext::round_down(begin, 2);
185 Index actualEnd = numext::round_down(begin + count + 1, 2);
186 Index actualCount = actualEnd - actualBegin;
187 Index r = IsRowMajor ? row : row / 2;
188 Index c = IsRowMajor ? col / 2 : col;
189 ComplexPacket cresult =
190 BaseEvaluator::template packetSegment<LoadMode, ComplexPacket>(r, c, actualBegin / 2, actualCount / 2);
191 PacketType result = preinterpret<PacketType>(cresult);
192 bool p = (IsRowMajor ? col : row) & 1;
193 if (p) {
194 Scalar aux[RealPacketSize + 1] = {};
195 pstoreu(aux, result);
196 Index lastr = IsRowMajor ? row : row + actualEnd - 1;
197 Index lastc = IsRowMajor ? col + actualEnd - 1 : col;
198 aux[actualEnd] = coeff(lastr, lastc);
199 result = ploadu<PacketType>(aux + 1);
200 }
201 return result;
202 }
203
204 template <int LoadMode, typename PacketType>
205 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
206 constexpr int RealPacketSize = unpacket_traits<PacketType>::size;
207 using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type;
208 EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value),
209 MISSING COMPATIBLE COMPLEX PACKET TYPE)
210 Index actualBegin = numext::round_down(begin, 2);
211 Index actualEnd = numext::round_down(begin + count + 1, 2);
212 Index actualCount = actualEnd - actualBegin;
213 ComplexPacket cresult =
214 BaseEvaluator::template packetSegment<LoadMode, ComplexPacket>(index / 2, actualBegin / 2, actualCount / 2);
215 PacketType result = preinterpret<PacketType>(cresult);
216 bool p = index & 1;
217 if (p) {
218 Scalar aux[RealPacketSize + 1] = {};
219 pstoreu(aux, result);
220 aux[actualEnd] = coeff(index + actualEnd - 1);
221 result = ploadu<PacketType>(aux + 1);
222 }
223 return result;
224 }
225};
226
227} // namespace internal
228
229template <typename Xpr>
230class RealView : public internal::dense_xpr_base<RealView<Xpr>>::type {
231 using ExpressionTraits = internal::traits<RealView>;
232 EIGEN_STATIC_ASSERT(NumTraits<typename Xpr::Scalar>::IsComplex, SCALAR MUST BE COMPLEX)
233 public:
234 using Scalar = typename ExpressionTraits::Scalar;
235 using Nested = RealView;
236
237 EIGEN_DEVICE_FUNC explicit RealView(Xpr& xpr) : m_xpr(xpr) {}
238 EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return Xpr::IsRowMajor ? m_xpr.rows() : 2 * m_xpr.rows(); }
239 EIGEN_DEVICE_FUNC constexpr Index cols() const noexcept { return Xpr::IsRowMajor ? 2 * m_xpr.cols() : m_xpr.cols(); }
240 EIGEN_DEVICE_FUNC constexpr Index size() const noexcept { return 2 * m_xpr.size(); }
241 EIGEN_DEVICE_FUNC constexpr Index innerStride() const noexcept { return m_xpr.innerStride(); }
242 EIGEN_DEVICE_FUNC constexpr Index outerStride() const noexcept { return 2 * m_xpr.outerStride(); }
243 EIGEN_DEVICE_FUNC void resize(Index rows, Index cols) {
244 m_xpr.resize(Xpr::IsRowMajor ? rows : rows / 2, Xpr::IsRowMajor ? cols / 2 : cols);
245 }
246 EIGEN_DEVICE_FUNC void resize(Index size) { m_xpr.resize(size / 2); }
247 using ScalarWithConstIfNotLvalue = std::conditional_t<internal::is_lvalue<Xpr>::value, Scalar, const Scalar>;
248 EIGEN_DEVICE_FUNC ScalarWithConstIfNotLvalue* data() {
249 return reinterpret_cast<ScalarWithConstIfNotLvalue*>(m_xpr.data());
250 }
251 EIGEN_DEVICE_FUNC const Scalar* data() const { return reinterpret_cast<const Scalar*>(m_xpr.data()); }
252
253 EIGEN_DEVICE_FUNC RealView(const RealView&) = default;
254
255 EIGEN_DEVICE_FUNC RealView& operator=(const RealView& other);
256
257 template <typename OtherDerived>
258 EIGEN_DEVICE_FUNC RealView& operator=(const RealView<OtherDerived>& other);
259
260 template <typename OtherDerived>
261 EIGEN_DEVICE_FUNC RealView& operator=(const DenseBase<OtherDerived>& other);
262
263 protected:
264 friend struct internal::evaluator<RealView>;
265 Xpr& m_xpr;
266};
267
268template <typename Xpr>
269EIGEN_DEVICE_FUNC RealView<Xpr>& RealView<Xpr>::operator=(const RealView& other) {
270 internal::call_assignment(*this, other);
271 return *this;
272}
273
274template <typename Xpr>
275template <typename OtherDerived>
276EIGEN_DEVICE_FUNC RealView<Xpr>& RealView<Xpr>::operator=(const RealView<OtherDerived>& other) {
277 internal::call_assignment(*this, other);
278 return *this;
279}
280
281template <typename Xpr>
282template <typename OtherDerived>
283EIGEN_DEVICE_FUNC RealView<Xpr>& RealView<Xpr>::operator=(const DenseBase<OtherDerived>& other) {
284 internal::call_assignment(*this, other.derived());
285 return *this;
286}
287
288template <typename Derived>
289EIGEN_DEVICE_FUNC typename DenseBase<Derived>::RealViewReturnType DenseBase<Derived>::realView() {
290 return RealViewReturnType(derived());
291}
292
293template <typename Derived>
294EIGEN_DEVICE_FUNC typename DenseBase<Derived>::ConstRealViewReturnType DenseBase<Derived>::realView() const {
295 return ConstRealViewReturnType(derived());
296}
297
298} // namespace Eigen
299
300#endif // EIGEN_REALVIEW_H
Base class for all dense matrices, vectors, and arrays.
Definition DenseBase.h:45
RealViewReturnType realView()
Definition RealView.h:289
constexpr unsigned int ActualPacketAccessBit
Definition Constants.h:109
constexpr unsigned int PacketAccessBit
Definition Constants.h:98
constexpr unsigned int DirectAccessBit
Definition Constants.h:160
constexpr unsigned int LinearAccessBit
Definition Constants.h:134
constexpr unsigned int LvalueBit
Definition Constants.h:149
constexpr unsigned int RowMajorBit
Definition Constants.h:71