Eigen  5.0.1-dev+60122df6
 
Loading...
Searching...
No Matches
FindCoeff.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
10#ifndef EIGEN_FIND_COEFF_H
11#define EIGEN_FIND_COEFF_H
12
13// IWYU pragma: private
14#include "./InternalHeaderCheck.h"
15
16namespace Eigen {
17
18namespace internal {
19
20template <typename Scalar, int NaNPropagation, bool IsInteger = NumTraits<Scalar>::IsInteger>
21struct max_coeff_functor {
22 EIGEN_DEVICE_FUNC inline bool compareCoeff(const Scalar& incumbent, const Scalar& candidate) const {
23 return candidate > incumbent;
24 }
25 template <typename Packet>
26 EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) const {
27 return pcmp_lt(incumbent, candidate);
28 }
29 template <typename Packet>
30 EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
31 return predux_max(a);
32 }
33};
34
35template <typename Scalar>
36struct max_coeff_functor<Scalar, PropagateNaN, false> {
37 EIGEN_DEVICE_FUNC inline Scalar compareCoeff(const Scalar& incumbent, const Scalar& candidate) {
38 return (candidate > incumbent) || ((candidate != candidate) && (incumbent == incumbent));
39 }
40 template <typename Packet>
41 EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) {
42 return pandnot(pcmp_lt_or_nan(incumbent, candidate), pisnan(incumbent));
43 }
44 template <typename Packet>
45 EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
46 return predux_max<PropagateNaN>(a);
47 }
48};
49
50template <typename Scalar>
51struct max_coeff_functor<Scalar, PropagateNumbers, false> {
52 EIGEN_DEVICE_FUNC inline bool compareCoeff(const Scalar& incumbent, const Scalar& candidate) const {
53 return (candidate > incumbent) || ((candidate == candidate) && (incumbent != incumbent));
54 }
55 template <typename Packet>
56 EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) const {
57 return pandnot(pcmp_lt_or_nan(incumbent, candidate), pisnan(candidate));
58 }
59 template <typename Packet>
60 EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
61 return predux_max<PropagateNumbers>(a);
62 }
63};
64
65template <typename Scalar, int NaNPropagation, bool IsInteger = NumTraits<Scalar>::IsInteger>
66struct min_coeff_functor {
67 EIGEN_DEVICE_FUNC inline bool compareCoeff(const Scalar& incumbent, const Scalar& candidate) const {
68 return candidate < incumbent;
69 }
70 template <typename Packet>
71 EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) const {
72 return pcmp_lt(candidate, incumbent);
73 }
74 template <typename Packet>
75 EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
76 return predux_min(a);
77 }
78};
79
80template <typename Scalar>
81struct min_coeff_functor<Scalar, PropagateNaN, false> {
82 EIGEN_DEVICE_FUNC inline Scalar compareCoeff(const Scalar& incumbent, const Scalar& candidate) {
83 return (candidate < incumbent) || ((candidate != candidate) && (incumbent == incumbent));
84 }
85 template <typename Packet>
86 EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) {
87 return pandnot(pcmp_lt_or_nan(candidate, incumbent), pisnan(incumbent));
88 }
89 template <typename Packet>
90 EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
91 return predux_min<PropagateNaN>(a);
92 }
93};
94
95template <typename Scalar>
96struct min_coeff_functor<Scalar, PropagateNumbers, false> {
97 EIGEN_DEVICE_FUNC inline bool compareCoeff(const Scalar& incumbent, const Scalar& candidate) const {
98 return (candidate < incumbent) || ((candidate == candidate) && (incumbent != incumbent));
99 }
100 template <typename Packet>
101 EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) const {
102 return pandnot(pcmp_lt_or_nan(candidate, incumbent), pisnan(candidate));
103 }
104 template <typename Packet>
105 EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
106 return predux_min<PropagateNumbers>(a);
107 }
108};
109
110template <typename Scalar>
111struct min_max_traits {
112 static constexpr bool PacketAccess = packet_traits<Scalar>::Vectorizable;
113};
114template <typename Scalar, int NaNPropagation>
115struct functor_traits<max_coeff_functor<Scalar, NaNPropagation>> : min_max_traits<Scalar> {};
116template <typename Scalar, int NaNPropagation>
117struct functor_traits<min_coeff_functor<Scalar, NaNPropagation>> : min_max_traits<Scalar> {};
118
119template <typename Evaluator, typename Func, bool Linear, bool Vectorize>
120struct find_coeff_loop;
121template <typename Evaluator, typename Func>
122struct find_coeff_loop<Evaluator, Func, /*Linear*/ false, /*Vectorize*/ false> {
123 using Scalar = typename Evaluator::Scalar;
124 static EIGEN_DEVICE_FUNC inline void run(const Evaluator& eval, Func& func, Scalar& res, Index& outer, Index& inner) {
125 Index outerSize = eval.outerSize();
126 Index innerSize = eval.innerSize();
127
128 /* initialization performed in calling function */
129 /* result = eval.coeff(0, 0); */
130 /* outer = 0; */
131 /* inner = 0; */
132
133 for (Index j = 0; j < outerSize; j++) {
134 for (Index i = 0; i < innerSize; i++) {
135 Scalar xprCoeff = eval.coeffByOuterInner(j, i);
136 bool newRes = func.compareCoeff(res, xprCoeff);
137 if (newRes) {
138 outer = j;
139 inner = i;
140 res = xprCoeff;
141 }
142 }
143 }
144 }
145};
146template <typename Evaluator, typename Func>
147struct find_coeff_loop<Evaluator, Func, /*Linear*/ true, /*Vectorize*/ false> {
148 using Scalar = typename Evaluator::Scalar;
149 static EIGEN_DEVICE_FUNC inline void run(const Evaluator& eval, Func& func, Scalar& res, Index& index) {
150 Index size = eval.size();
151
152 /* initialization performed in calling function */
153 /* result = eval.coeff(0); */
154 /* index = 0; */
155
156 for (Index k = 0; k < size; k++) {
157 Scalar xprCoeff = eval.coeff(k);
158 bool newRes = func.compareCoeff(res, xprCoeff);
159 if (newRes) {
160 index = k;
161 res = xprCoeff;
162 }
163 }
164 }
165};
166template <typename Evaluator, typename Func>
167struct find_coeff_loop<Evaluator, Func, /*Linear*/ false, /*Vectorize*/ true> {
168 using ScalarImpl = find_coeff_loop<Evaluator, Func, false, false>;
169 using Scalar = typename Evaluator::Scalar;
170 using Packet = typename Evaluator::Packet;
171 static constexpr int PacketSize = unpacket_traits<Packet>::size;
172 static EIGEN_DEVICE_FUNC inline void run(const Evaluator& eval, Func& func, Scalar& result, Index& outer,
173 Index& inner) {
174 Index outerSize = eval.outerSize();
175 Index innerSize = eval.innerSize();
176 Index packetEnd = numext::round_down(innerSize, PacketSize);
177
178 /* initialization performed in calling function */
179 /* result = eval.coeff(0, 0); */
180 /* outer = 0; */
181 /* inner = 0; */
182
183 bool checkPacket = false;
184
185 for (Index j = 0; j < outerSize; j++) {
186 Packet resultPacket = pset1<Packet>(result);
187 for (Index i = 0; i < packetEnd; i += PacketSize) {
188 Packet xprPacket = eval.template packetByOuterInner<Unaligned, Packet>(j, i);
189 if (predux_any(func.comparePacket(resultPacket, xprPacket))) {
190 outer = j;
191 inner = i;
192 result = func.predux(xprPacket);
193 resultPacket = pset1<Packet>(result);
194 checkPacket = true;
195 }
196 }
197
198 for (Index i = packetEnd; i < innerSize; i++) {
199 Scalar xprCoeff = eval.coeffByOuterInner(j, i);
200 if (func.compareCoeff(result, xprCoeff)) {
201 outer = j;
202 inner = i;
203 result = xprCoeff;
204 checkPacket = false;
205 }
206 }
207 }
208
209 if (checkPacket) {
210 result = eval.coeffByOuterInner(outer, inner);
211 Index i_end = inner + PacketSize;
212 for (Index i = inner; i < i_end; i++) {
213 Scalar xprCoeff = eval.coeffByOuterInner(outer, i);
214 if (func.compareCoeff(result, xprCoeff)) {
215 inner = i;
216 result = xprCoeff;
217 }
218 }
219 }
220 }
221};
222template <typename Evaluator, typename Func>
223struct find_coeff_loop<Evaluator, Func, /*Linear*/ true, /*Vectorize*/ true> {
224 using ScalarImpl = find_coeff_loop<Evaluator, Func, true, false>;
225 using Scalar = typename Evaluator::Scalar;
226 using Packet = typename Evaluator::Packet;
227 static constexpr int PacketSize = unpacket_traits<Packet>::size;
228 static constexpr int Alignment = Evaluator::Alignment;
229
230 static EIGEN_DEVICE_FUNC inline void run(const Evaluator& eval, Func& func, Scalar& result, Index& index) {
231 Index size = eval.size();
232 Index packetEnd = numext::round_down(size, PacketSize);
233
234 /* initialization performed in calling function */
235 /* result = eval.coeff(0); */
236 /* index = 0; */
237
238 Packet resultPacket = pset1<Packet>(result);
239 bool checkPacket = false;
240
241 for (Index k = 0; k < packetEnd; k += PacketSize) {
242 Packet xprPacket = eval.template packet<Alignment, Packet>(k);
243 if (predux_any(func.comparePacket(resultPacket, xprPacket))) {
244 index = k;
245 result = func.predux(xprPacket);
246 resultPacket = pset1<Packet>(result);
247 checkPacket = true;
248 }
249 }
250
251 for (Index k = packetEnd; k < size; k++) {
252 Scalar xprCoeff = eval.coeff(k);
253 if (func.compareCoeff(result, xprCoeff)) {
254 index = k;
255 result = xprCoeff;
256 checkPacket = false;
257 }
258 }
259
260 if (checkPacket) {
261 result = eval.coeff(index);
262 Index k_end = index + PacketSize;
263 for (Index k = index; k < k_end; k++) {
264 Scalar xprCoeff = eval.coeff(k);
265 if (func.compareCoeff(result, xprCoeff)) {
266 index = k;
267 result = xprCoeff;
268 }
269 }
270 }
271 }
272};
273
274template <typename Derived>
275struct find_coeff_evaluator : public evaluator<Derived> {
276 using Base = evaluator<Derived>;
277 using Scalar = typename Derived::Scalar;
278 using Packet = typename packet_traits<Scalar>::type;
279 static constexpr int Flags = Base::Flags;
280 static constexpr bool IsRowMajor = bool(Flags & RowMajorBit);
281 EIGEN_DEVICE_FUNC inline find_coeff_evaluator(const Derived& xpr) : Base(xpr), m_xpr(xpr) {}
282
283 EIGEN_DEVICE_FUNC inline Scalar coeffByOuterInner(Index outer, Index inner) const {
284 Index row = IsRowMajor ? outer : inner;
285 Index col = IsRowMajor ? inner : outer;
286 return Base::coeff(row, col);
287 }
288 template <int LoadMode, typename PacketType>
289 EIGEN_DEVICE_FUNC inline PacketType packetByOuterInner(Index outer, Index inner) const {
290 Index row = IsRowMajor ? outer : inner;
291 Index col = IsRowMajor ? inner : outer;
292 return Base::template packet<LoadMode, PacketType>(row, col);
293 }
294
295 EIGEN_DEVICE_FUNC inline Index innerSize() const { return m_xpr.innerSize(); }
296 EIGEN_DEVICE_FUNC inline Index outerSize() const { return m_xpr.outerSize(); }
297 EIGEN_DEVICE_FUNC inline Index size() const { return m_xpr.size(); }
298
299 const Derived& m_xpr;
300};
301
302template <typename Derived, typename Func>
303struct find_coeff_impl {
304 using Evaluator = find_coeff_evaluator<Derived>;
305 static constexpr int Flags = Evaluator::Flags;
306 static constexpr int Alignment = Evaluator::Alignment;
307 static constexpr bool IsRowMajor = Derived::IsRowMajor;
308 static constexpr int MaxInnerSizeAtCompileTime =
309 IsRowMajor ? Derived::MaxColsAtCompileTime : Derived::MaxRowsAtCompileTime;
310 static constexpr int MaxSizeAtCompileTime = Derived::MaxSizeAtCompileTime;
311
312 using Scalar = typename Derived::Scalar;
313 using Packet = typename Evaluator::Packet;
314
315 static constexpr int PacketSize = unpacket_traits<Packet>::size;
316 static constexpr bool Linearize = bool(Flags & LinearAccessBit);
317 static constexpr bool DontVectorize =
318 enum_lt_not_dynamic(Linearize ? MaxSizeAtCompileTime : MaxInnerSizeAtCompileTime, PacketSize);
319 static constexpr bool Vectorize =
320 !DontVectorize && bool(Flags & PacketAccessBit) && functor_traits<Func>::PacketAccess;
321
322 using Loop = find_coeff_loop<Evaluator, Func, Linearize, Vectorize>;
323
324 template <bool ForwardLinearAccess = Linearize, std::enable_if_t<!ForwardLinearAccess, bool> = true>
325 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& xpr, Func& func, Scalar& res, Index& outer,
326 Index& inner) {
327 Evaluator eval(xpr);
328 Loop::run(eval, func, res, outer, inner);
329 }
330 template <bool ForwardLinearAccess = Linearize, std::enable_if_t<ForwardLinearAccess, bool> = true>
331 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& xpr, Func& func, Scalar& res, Index& outer,
332 Index& inner) {
333 // where possible, use the linear loop and back-calculate the outer and inner indices
334 Index index = 0;
335 run(xpr, func, res, index);
336 outer = index / xpr.innerSize();
337 inner = index % xpr.innerSize();
338 }
339 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& xpr, Func& func, Scalar& res, Index& index) {
340 Evaluator eval(xpr);
341 Loop::run(eval, func, res, index);
342 }
343};
344
345template <typename Derived, typename IndexType, typename Func>
346EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar findCoeff(const DenseBase<Derived>& mat, Func& func,
347 IndexType* rowPtr, IndexType* colPtr) {
348 eigen_assert(mat.rows() > 0 && mat.cols() > 0 && "you are using an empty matrix");
349 using Scalar = typename DenseBase<Derived>::Scalar;
350 using FindCoeffImpl = internal::find_coeff_impl<Derived, Func>;
351 Index outer = 0;
352 Index inner = 0;
353 Scalar res = mat.coeff(0, 0);
354 FindCoeffImpl::run(mat.derived(), func, res, outer, inner);
355 *rowPtr = internal::convert_index<IndexType>(Derived::IsRowMajor ? outer : inner);
356 if (colPtr) *colPtr = internal::convert_index<IndexType>(Derived::IsRowMajor ? inner : outer);
357 return res;
358}
359
360template <typename Derived, typename IndexType, typename Func>
361EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar findCoeff(const DenseBase<Derived>& mat, Func& func,
362 IndexType* indexPtr) {
363 eigen_assert(mat.size() > 0 && "you are using an empty matrix");
364 EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
365 using Scalar = typename DenseBase<Derived>::Scalar;
366 using FindCoeffImpl = internal::find_coeff_impl<Derived, Func>;
367 Index index = 0;
368 Scalar res = mat.coeff(0);
369 FindCoeffImpl::run(mat.derived(), func, res, index);
370 *indexPtr = internal::convert_index<IndexType>(index);
371 return res;
372}
373
374} // namespace internal
375
389template <typename Derived>
390template <int NaNPropagation, typename IndexType>
391EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar DenseBase<Derived>::minCoeff(IndexType* rowPtr,
392 IndexType* colPtr) const {
393 using Func = internal::min_coeff_functor<Scalar, NaNPropagation>;
394 Func func;
395 return internal::findCoeff(derived(), func, rowPtr, colPtr);
396}
397
411template <typename Derived>
412template <int NaNPropagation, typename IndexType>
413EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar DenseBase<Derived>::minCoeff(IndexType* indexPtr) const {
414 using Func = internal::min_coeff_functor<Scalar, NaNPropagation>;
415 Func func;
416 return internal::findCoeff(derived(), func, indexPtr);
417}
418
432template <typename Derived>
433template <int NaNPropagation, typename IndexType>
434EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar DenseBase<Derived>::maxCoeff(IndexType* rowPtr,
435 IndexType* colPtr) const {
436 using Func = internal::max_coeff_functor<Scalar, NaNPropagation>;
437 Func func;
438 return internal::findCoeff(derived(), func, rowPtr, colPtr);
439}
440
445 * In case \c *this contains NaN, NaNPropagation determines the behavior:
446 * NaNPropagation == PropagateFast : undefined
447 * NaNPropagation == PropagateNaN : result is NaN
448 * NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN
449 * \warning the matrix must be not empty, otherwise an assertion is triggered.
451 * \sa DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(),
452 * DenseBase::maxCoeff()
453 */
454template <typename Derived>
455template <int NaNPropagation, typename IndexType>
456EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar DenseBase<Derived>::maxCoeff(IndexType* indexPtr) const {
457 using Func = internal::max_coeff_functor<Scalar, NaNPropagation>;
458 Func func;
459 return internal::findCoeff(derived(), func, indexPtr);
460}
461
462} // namespace Eigen
463
464#endif // EIGEN_FIND_COEFF_H
internal::traits< Derived >::Scalar minCoeff() const
Definition Redux.h:464
internal::traits< Derived >::Scalar Scalar
Definition DenseBase.h:62
internal::traits< Derived >::Scalar maxCoeff() const
Definition Redux.h:477
@ PropagateNaN
Definition Constants.h:342
@ PropagateNumbers
Definition Constants.h:344
const unsigned int PacketAccessBit
Definition Constants.h:97
const unsigned int LinearAccessBit
Definition Constants.h:133
const unsigned int RowMajorBit
Definition Constants.h:70
Namespace containing all symbols from the Eigen library.
Definition B01_Experimental.dox:1
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition Meta.h:82