$darkmode
Eigen  5.0.1-dev
XprHelper.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
5 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11 #ifndef EIGEN_XPRHELPER_H
12 #define EIGEN_XPRHELPER_H
13 
14 // IWYU pragma: private
15 #include "../InternalHeaderCheck.h"
16 
17 namespace Eigen {
18 
19 namespace internal {
20 
21 // useful for unsigned / signed integer comparisons when idx is intended to be non-negative
22 template <typename IndexType>
23 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename make_unsigned<IndexType>::type returnUnsignedIndexValue(
24  const IndexType& idx) {
25  EIGEN_STATIC_ASSERT((NumTraits<IndexType>::IsInteger), THIS FUNCTION IS FOR INTEGER TYPES)
26  eigen_internal_assert(idx >= 0 && "Index value is negative and target type is unsigned");
27  using UnsignedType = typename make_unsigned<IndexType>::type;
28  return static_cast<UnsignedType>(idx);
29 }
30 
31 template <typename IndexDest, typename IndexSrc, bool IndexDestIsInteger = NumTraits<IndexDest>::IsInteger,
32  bool IndexDestIsSigned = NumTraits<IndexDest>::IsSigned,
33  bool IndexSrcIsInteger = NumTraits<IndexSrc>::IsInteger,
34  bool IndexSrcIsSigned = NumTraits<IndexSrc>::IsSigned>
35 struct convert_index_impl {
36  static inline EIGEN_DEVICE_FUNC IndexDest run(const IndexSrc& idx) {
37  eigen_internal_assert(idx <= NumTraits<IndexDest>::highest() && "Index value is too big for target type");
38  return static_cast<IndexDest>(idx);
39  }
40 };
41 template <typename IndexDest, typename IndexSrc>
42 struct convert_index_impl<IndexDest, IndexSrc, true, true, true, false> {
43  // IndexDest is a signed integer
44  // IndexSrc is an unsigned integer
45  static inline EIGEN_DEVICE_FUNC IndexDest run(const IndexSrc& idx) {
46  eigen_internal_assert(idx <= returnUnsignedIndexValue(NumTraits<IndexDest>::highest()) &&
47  "Index value is too big for target type");
48  return static_cast<IndexDest>(idx);
49  }
50 };
51 template <typename IndexDest, typename IndexSrc>
52 struct convert_index_impl<IndexDest, IndexSrc, true, false, true, true> {
53  // IndexDest is an unsigned integer
54  // IndexSrc is a signed integer
55  static inline EIGEN_DEVICE_FUNC IndexDest run(const IndexSrc& idx) {
56  eigen_internal_assert(returnUnsignedIndexValue(idx) <= NumTraits<IndexDest>::highest() &&
57  "Index value is too big for target type");
58  return static_cast<IndexDest>(idx);
59  }
60 };
61 
62 template <typename IndexDest, typename IndexSrc>
63 EIGEN_DEVICE_FUNC inline IndexDest convert_index(const IndexSrc& idx) {
64  return convert_index_impl<IndexDest, IndexSrc>::run(idx);
65 }
66 
67 // true if T can be considered as an integral index (i.e., and integral type or enum)
68 template <typename T>
69 struct is_valid_index_type {
70  enum { value = internal::is_integral<T>::value || std::is_enum<T>::value };
71 };
72 
73 // true if both types are not valid index types
74 template <typename RowIndices, typename ColIndices>
75 struct valid_indexed_view_overload {
76  enum {
77  value = !(internal::is_valid_index_type<RowIndices>::value && internal::is_valid_index_type<ColIndices>::value)
78  };
79 };
80 
81 // promote_scalar_arg is an helper used in operation between an expression and a scalar, like:
82 // expression * scalar
83 // Its role is to determine how the type T of the scalar operand should be promoted given the scalar type ExprScalar of
84 // the given expression. The IsSupported template parameter must be provided by the caller as:
85 // internal::has_ReturnType<ScalarBinaryOpTraits<ExprScalar,T,op> >::value using the proper order for ExprScalar and T.
86 // Then the logic is as follows:
87 // - if the operation is natively supported as defined by IsSupported, then the scalar type is not promoted, and T is
88 // returned.
89 // - otherwise, NumTraits<ExprScalar>::Literal is returned if T is implicitly convertible to
90 // NumTraits<ExprScalar>::Literal AND that this does not imply a float to integer conversion.
91 // - otherwise, ExprScalar is returned if T is implicitly convertible to ExprScalar AND that this does not imply a
92 // float to integer conversion.
93 // - In all other cases, the promoted type is not defined, and the respective operation is thus invalid and not
94 // available (SFINAE).
95 template <typename ExprScalar, typename T, bool IsSupported>
96 struct promote_scalar_arg;
97 
98 template <typename S, typename T>
99 struct promote_scalar_arg<S, T, true> {
100  typedef T type;
101 };
102 
103 // Recursively check safe conversion to PromotedType, and then ExprScalar if they are different.
104 template <typename ExprScalar, typename T, typename PromotedType,
105  bool ConvertibleToLiteral = internal::is_convertible<T, PromotedType>::value,
106  bool IsSafe = NumTraits<T>::IsInteger || !NumTraits<PromotedType>::IsInteger>
107 struct promote_scalar_arg_unsupported;
108 
109 // Start recursion with NumTraits<ExprScalar>::Literal
110 template <typename S, typename T>
111 struct promote_scalar_arg<S, T, false> : promote_scalar_arg_unsupported<S, T, typename NumTraits<S>::Literal> {};
112 
113 // We found a match!
114 template <typename S, typename T, typename PromotedType>
115 struct promote_scalar_arg_unsupported<S, T, PromotedType, true, true> {
116  typedef PromotedType type;
117 };
118 
119 // No match, but no real-to-integer issues, and ExprScalar and current PromotedType are different,
120 // so let's try to promote to ExprScalar
121 template <typename ExprScalar, typename T, typename PromotedType>
122 struct promote_scalar_arg_unsupported<ExprScalar, T, PromotedType, false, true>
123  : promote_scalar_arg_unsupported<ExprScalar, T, ExprScalar> {};
124 
125 // Unsafe real-to-integer, let's stop.
126 template <typename S, typename T, typename PromotedType, bool ConvertibleToLiteral>
127 struct promote_scalar_arg_unsupported<S, T, PromotedType, ConvertibleToLiteral, false> {};
128 
129 // T is not even convertible to ExprScalar, let's stop.
130 template <typename S, typename T>
131 struct promote_scalar_arg_unsupported<S, T, S, false, true> {};
132 
133 // classes inheriting no_assignment_operator don't generate a default operator=.
134 class no_assignment_operator {
135  private:
136  no_assignment_operator& operator=(const no_assignment_operator&);
137 
138  protected:
139  EIGEN_DEFAULT_COPY_CONSTRUCTOR(no_assignment_operator)
140  EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(no_assignment_operator)
141 };
142 
144 template <typename I1, typename I2>
145 struct promote_index_type {
146  typedef std::conditional_t<(sizeof(I1) < sizeof(I2)), I2, I1> type;
147 };
148 
153 template <typename T, int Value>
154 class variable_if_dynamic {
155  public:
156  EIGEN_DEFAULT_EMPTY_CONSTRUCTOR_AND_DESTRUCTOR(variable_if_dynamic)
157  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamic(T v) {
158  EIGEN_ONLY_USED_FOR_DEBUG(v);
159  eigen_assert(v == T(Value));
160  }
161  EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE constexpr T value() { return T(Value); }
162  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr operator T() const { return T(Value); }
163  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T v) const {
164  EIGEN_ONLY_USED_FOR_DEBUG(v);
165  eigen_assert(v == T(Value));
166  }
167 };
168 
169 template <typename T>
170 class variable_if_dynamic<T, Dynamic> {
171  T m_value;
172 
173  public:
174  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamic(T value = 0) noexcept : m_value(value) {}
175  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T value() const { return m_value; }
176  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE operator T() const { return m_value; }
177  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T value) { m_value = value; }
178 };
179 
182 template <typename T, int Value>
183 class variable_if_dynamicindex {
184  public:
185  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamicindex(T v) {
186  EIGEN_ONLY_USED_FOR_DEBUG(v);
187  eigen_assert(v == T(Value));
188  }
189  EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE constexpr T value() { return T(Value); }
190  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T) {}
191 };
192 
193 template <typename T>
194 class variable_if_dynamicindex<T, DynamicIndex> {
195  T m_value;
196  EIGEN_DEVICE_FUNC variable_if_dynamicindex() { eigen_assert(false); }
197 
198  public:
199  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit variable_if_dynamicindex(T value) : m_value(value) {}
200  EIGEN_DEVICE_FUNC T EIGEN_STRONG_INLINE value() const { return m_value; }
201  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void setValue(T value) { m_value = value; }
202 };
203 
204 template <typename T>
205 struct functor_traits {
206  enum { Cost = 10, PacketAccess = false, IsRepeatable = false };
207 };
208 
209 // estimates the cost of lazily evaluating a generic functor by unwinding the expression
210 template <typename Xpr>
211 struct nested_functor_cost {
212  static constexpr Index Cost = static_cast<Index>(functor_traits<Xpr>::Cost);
213 };
214 
215 template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
216 struct nested_functor_cost<Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>> {
217  static constexpr Index Cost = 1;
218 };
219 
220 template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
221 struct nested_functor_cost<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols>> {
222  static constexpr Index Cost = 1;
223 };
224 
225 // TODO: assign a cost to the stride type?
226 template <typename PlainObjectType, int MapOptions, typename StrideType>
227 struct nested_functor_cost<Map<PlainObjectType, MapOptions, StrideType>> : nested_functor_cost<PlainObjectType> {};
228 
229 template <typename Func, typename Xpr>
230 struct nested_functor_cost<CwiseUnaryOp<Func, Xpr>> {
231  using XprCleaned = remove_all_t<Xpr>;
232  using FuncCleaned = remove_all_t<Func>;
233  static constexpr Index Cost = nested_functor_cost<FuncCleaned>::Cost + nested_functor_cost<XprCleaned>::Cost;
234 };
235 
236 template <typename Func, typename Xpr>
237 struct nested_functor_cost<CwiseNullaryOp<Func, Xpr>> {
238  using XprCleaned = remove_all_t<Xpr>;
239  using FuncCleaned = remove_all_t<Func>;
240  static constexpr Index Cost = nested_functor_cost<FuncCleaned>::Cost + nested_functor_cost<XprCleaned>::Cost;
241 };
242 
243 template <typename Func, typename LhsXpr, typename RhsXpr>
244 struct nested_functor_cost<CwiseBinaryOp<Func, LhsXpr, RhsXpr>> {
245  using LhsXprCleaned = remove_all_t<LhsXpr>;
246  using RhsXprCleaned = remove_all_t<RhsXpr>;
247  using FuncCleaned = remove_all_t<Func>;
248  static constexpr Index Cost = nested_functor_cost<FuncCleaned>::Cost + nested_functor_cost<LhsXprCleaned>::Cost +
249  nested_functor_cost<RhsXprCleaned>::Cost;
250 };
251 
252 template <typename Func, typename LhsXpr, typename MidXpr, typename RhsXpr>
253 struct nested_functor_cost<CwiseTernaryOp<Func, LhsXpr, MidXpr, RhsXpr>> {
254  using LhsXprCleaned = remove_all_t<LhsXpr>;
255  using MidXprCleaned = remove_all_t<MidXpr>;
256  using RhsXprCleaned = remove_all_t<RhsXpr>;
257  using FuncCleaned = remove_all_t<Func>;
258  static constexpr Index Cost = nested_functor_cost<FuncCleaned>::Cost + nested_functor_cost<LhsXprCleaned>::Cost +
259  nested_functor_cost<MidXprCleaned>::Cost + nested_functor_cost<RhsXprCleaned>::Cost;
260 };
261 
262 template <typename Xpr>
263 struct functor_cost {
264  static constexpr Index Cost = plain_enum_max(nested_functor_cost<Xpr>::Cost, 1);
265 };
266 
267 template <typename T>
268 struct packet_traits;
269 
270 template <typename T>
271 struct unpacket_traits;
272 
273 template <int Size, typename PacketType,
274  bool Stop = Size == Dynamic || (Size % unpacket_traits<PacketType>::size) == 0 ||
275  is_same<PacketType, typename unpacket_traits<PacketType>::half>::value>
276 struct find_best_packet_helper;
277 
278 template <int Size, typename PacketType>
279 struct find_best_packet_helper<Size, PacketType, true> {
280  typedef PacketType type;
281 };
282 
283 template <int Size, typename PacketType>
284 struct find_best_packet_helper<Size, PacketType, false> {
285  typedef typename find_best_packet_helper<Size, typename unpacket_traits<PacketType>::half>::type type;
286 };
287 
288 template <typename T, int Size>
289 struct find_best_packet {
290  typedef typename find_best_packet_helper<Size, typename packet_traits<T>::type>::type type;
291 };
292 
293 template <int Size, typename PacketType,
294  bool Stop = (Size == unpacket_traits<PacketType>::size) ||
295  is_same<PacketType, typename unpacket_traits<PacketType>::half>::value>
296 struct find_packet_by_size_helper;
297 template <int Size, typename PacketType>
298 struct find_packet_by_size_helper<Size, PacketType, true> {
299  using type = PacketType;
300 };
301 template <int Size, typename PacketType>
302 struct find_packet_by_size_helper<Size, PacketType, false> {
303  using type = typename find_packet_by_size_helper<Size, typename unpacket_traits<PacketType>::half>::type;
304 };
305 
306 template <typename T, int Size>
307 struct find_packet_by_size {
308  using type = typename find_packet_by_size_helper<Size, typename packet_traits<T>::type>::type;
309  static constexpr bool value = (Size == unpacket_traits<type>::size);
310 };
311 template <typename T>
312 struct find_packet_by_size<T, 1> {
313  using type = typename unpacket_traits<T>::type;
314  static constexpr bool value = (unpacket_traits<type>::size == 1);
315 };
316 
317 #if EIGEN_MAX_STATIC_ALIGN_BYTES > 0
318 constexpr int compute_default_alignment_helper(int ArrayBytes, int AlignmentBytes) {
319  if ((ArrayBytes % AlignmentBytes) == 0) {
320  return AlignmentBytes;
321  } else if (EIGEN_MIN_ALIGN_BYTES < AlignmentBytes) {
322  return compute_default_alignment_helper(ArrayBytes, AlignmentBytes / 2);
323  } else {
324  return 0;
325  }
326 }
327 #else
328 // If static alignment is disabled, no need to bother.
329 // This also avoids a division by zero
330 constexpr int compute_default_alignment_helper(int ArrayBytes, int AlignmentBytes) {
331  EIGEN_UNUSED_VARIABLE(ArrayBytes);
332  EIGEN_UNUSED_VARIABLE(AlignmentBytes);
333  return 0;
334 }
335 #endif
336 
337 template <typename T, int Size>
338 struct compute_default_alignment {
339  enum { value = compute_default_alignment_helper(Size * sizeof(T), EIGEN_MAX_STATIC_ALIGN_BYTES) };
340 };
341 
342 template <typename T>
343 struct compute_default_alignment<T, Dynamic> {
344  enum { value = EIGEN_MAX_ALIGN_BYTES };
345 };
346 
347 template <typename Scalar_, int Rows_, int Cols_,
348  int Options_ = AutoAlign | ((Rows_ == 1 && Cols_ != 1) ? RowMajor
349  : (Cols_ == 1 && Rows_ != 1) ? ColMajor
350  : EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION),
351  int MaxRows_ = Rows_, int MaxCols_ = Cols_>
352 class make_proper_matrix_type {
353  enum {
354  IsColVector = Cols_ == 1 && Rows_ != 1,
355  IsRowVector = Rows_ == 1 && Cols_ != 1,
356  Options = IsColVector ? (Options_ | ColMajor) & ~RowMajor
357  : IsRowVector ? (Options_ | RowMajor) & ~ColMajor
358  : Options_
359  };
360 
361  public:
362  typedef Matrix<Scalar_, Rows_, Cols_, Options, MaxRows_, MaxCols_> type;
363 };
364 
365 constexpr unsigned compute_matrix_flags(int Options) {
366  unsigned row_major_bit = Options & RowMajor ? RowMajorBit : 0;
367  // FIXME currently we still have to handle DirectAccessBit at the expression level to handle DenseCoeffsBase<>
368  // and then propagate this information to the evaluator's flags.
369  // However, I (Gael) think that DirectAccessBit should only matter at the evaluation stage.
370  return DirectAccessBit | LvalueBit | NestByRefBit | row_major_bit;
371 }
372 
373 constexpr int size_at_compile_time(int rows, int cols) {
374  if (rows == 0 || cols == 0) return 0;
375  if (rows == Dynamic || cols == Dynamic) return Dynamic;
376  return rows * cols;
377 }
378 
379 template <typename XprType>
380 struct size_of_xpr_at_compile_time {
381  enum { ret = size_at_compile_time(traits<XprType>::RowsAtCompileTime, traits<XprType>::ColsAtCompileTime) };
382 };
383 
384 /* plain_matrix_type : the difference from eval is that plain_matrix_type is always a plain matrix type,
385  * whereas eval is a const reference in the case of a matrix
386  */
387 
388 template <typename T, typename StorageKind = typename traits<T>::StorageKind>
389 struct plain_matrix_type;
390 template <typename T, typename BaseClassType, int Flags>
391 struct plain_matrix_type_dense;
392 template <typename T>
393 struct plain_matrix_type<T, Dense> {
394  typedef typename plain_matrix_type_dense<T, typename traits<T>::XprKind, traits<T>::Flags>::type type;
395 };
396 template <typename T>
397 struct plain_matrix_type<T, DiagonalShape> {
398  typedef typename T::PlainObject type;
399 };
400 
401 template <typename T>
402 struct plain_matrix_type<T, SkewSymmetricShape> {
403  typedef typename T::PlainObject type;
404 };
405 
406 template <typename T, int Flags>
407 struct plain_matrix_type_dense<T, MatrixXpr, Flags> {
408  typedef Matrix<typename traits<T>::Scalar, traits<T>::RowsAtCompileTime, traits<T>::ColsAtCompileTime,
409  AutoAlign | (Flags & RowMajorBit ? RowMajor : ColMajor), traits<T>::MaxRowsAtCompileTime,
410  traits<T>::MaxColsAtCompileTime>
411  type;
412 };
413 
414 template <typename T, int Flags>
415 struct plain_matrix_type_dense<T, ArrayXpr, Flags> {
416  typedef Array<typename traits<T>::Scalar, traits<T>::RowsAtCompileTime, traits<T>::ColsAtCompileTime,
417  AutoAlign | (Flags & RowMajorBit ? RowMajor : ColMajor), traits<T>::MaxRowsAtCompileTime,
418  traits<T>::MaxColsAtCompileTime>
419  type;
420 };
421 
422 /* eval : the return type of eval(). For matrices, this is just a const reference
423  * in order to avoid a useless copy
424  */
425 
426 template <typename T, typename StorageKind = typename traits<T>::StorageKind>
427 struct eval;
428 
429 template <typename T>
430 struct eval<T, Dense> {
431  typedef typename plain_matrix_type<T>::type type;
432  // typedef typename T::PlainObject type;
433  // typedef T::Matrix<typename traits<T>::Scalar,
434  // traits<T>::RowsAtCompileTime,
435  // traits<T>::ColsAtCompileTime,
436  // AutoAlign | (traits<T>::Flags&RowMajorBit ? RowMajor : ColMajor),
437  // traits<T>::MaxRowsAtCompileTime,
438  // traits<T>::MaxColsAtCompileTime
439  // > type;
440 };
441 
442 template <typename T>
443 struct eval<T, DiagonalShape> {
444  typedef typename plain_matrix_type<T>::type type;
445 };
446 
447 template <typename T>
448 struct eval<T, SkewSymmetricShape> {
449  typedef typename plain_matrix_type<T>::type type;
450 };
451 
452 // for matrices, no need to evaluate, just use a const reference to avoid a useless copy
453 template <typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
454 struct eval<Matrix<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>, Dense> {
455  typedef const Matrix<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>& type;
456 };
457 
458 template <typename Scalar_, int Rows_, int Cols_, int Options_, int MaxRows_, int MaxCols_>
459 struct eval<Array<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>, Dense> {
460  typedef const Array<Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_>& type;
461 };
462 
463 /* similar to plain_matrix_type, but using the evaluator's Flags */
464 template <typename T, typename StorageKind = typename traits<T>::StorageKind>
465 struct plain_object_eval;
466 
467 template <typename T>
468 struct plain_object_eval<T, Dense> {
469  typedef typename plain_matrix_type_dense<T, typename traits<T>::XprKind, evaluator<T>::Flags>::type type;
470 };
471 
472 /* plain_matrix_type_column_major : same as plain_matrix_type but guaranteed to be column-major
473  */
474 template <typename T>
475 struct plain_matrix_type_column_major {
476  enum {
477  Rows = traits<T>::RowsAtCompileTime,
478  Cols = traits<T>::ColsAtCompileTime,
479  MaxRows = traits<T>::MaxRowsAtCompileTime,
480  MaxCols = traits<T>::MaxColsAtCompileTime
481  };
482  typedef Matrix<typename traits<T>::Scalar, Rows, Cols, (MaxRows == 1 && MaxCols != 1) ? RowMajor : ColMajor, MaxRows,
483  MaxCols>
484  type;
485 };
486 
487 /* plain_matrix_type_row_major : same as plain_matrix_type but guaranteed to be row-major
488  */
489 template <typename T>
490 struct plain_matrix_type_row_major {
491  enum {
492  Rows = traits<T>::RowsAtCompileTime,
493  Cols = traits<T>::ColsAtCompileTime,
494  MaxRows = traits<T>::MaxRowsAtCompileTime,
495  MaxCols = traits<T>::MaxColsAtCompileTime
496  };
497  typedef Matrix<typename traits<T>::Scalar, Rows, Cols, (MaxCols == 1 && MaxRows != 1) ? ColMajor : RowMajor, MaxRows,
498  MaxCols>
499  type;
500 };
501 
505 template <typename T>
506 struct ref_selector {
507  typedef std::conditional_t<bool(traits<T>::Flags& NestByRefBit), T const&, const T> type;
508 
509  typedef std::conditional_t<bool(traits<T>::Flags& NestByRefBit), T&, T> non_const_type;
510 };
511 
513 template <typename T1, typename T2>
514 struct transfer_constness {
515  typedef std::conditional_t<bool(internal::is_const<T1>::value), add_const_on_value_type_t<T2>, T2> type;
516 };
517 
518 // However, we still need a mechanism to detect whether an expression which is evaluated multiple time
519 // has to be evaluated into a temporary.
520 // That's the purpose of this new nested_eval helper:
532 template <typename T, int n, typename PlainObject = typename plain_object_eval<T>::type>
533 struct nested_eval {
534  enum {
535  ScalarReadCost = NumTraits<typename traits<T>::Scalar>::ReadCost,
536  CoeffReadCost =
537  evaluator<T>::CoeffReadCost, // NOTE What if an evaluator evaluate itself into a temporary?
538  // Then CoeffReadCost will be small (e.g., 1) but we still have to evaluate,
539  // especially if n>1. This situation is already taken care by the
540  // EvalBeforeNestingBit flag, which is turned ON for all evaluator creating a
541  // temporary. This flag is then propagated by the parent evaluators. Another
542  // solution could be to count the number of temps?
543  NAsInteger = n == Dynamic ? HugeCost : n,
544  CostEval = (NAsInteger + 1) * ScalarReadCost + CoeffReadCost,
545  CostNoEval = int(NAsInteger) * int(CoeffReadCost),
546  Evaluate = (int(evaluator<T>::Flags) & EvalBeforeNestingBit) || (int(CostEval) < int(CostNoEval))
547  };
548 
549  typedef std::conditional_t<Evaluate, PlainObject, typename ref_selector<T>::type> type;
550 };
551 
552 template <typename T>
553 EIGEN_DEVICE_FUNC inline T* const_cast_ptr(const T* ptr) {
554  return const_cast<T*>(ptr);
555 }
556 
557 template <typename Derived, typename XprKind = typename traits<Derived>::XprKind>
558 struct dense_xpr_base {
559  /* dense_xpr_base should only ever be used on dense expressions, thus falling either into the MatrixXpr or into the
560  * ArrayXpr cases */
561 };
562 
563 template <typename Derived>
564 struct dense_xpr_base<Derived, MatrixXpr> {
565  typedef MatrixBase<Derived> type;
566 };
567 
568 template <typename Derived>
569 struct dense_xpr_base<Derived, ArrayXpr> {
570  typedef ArrayBase<Derived> type;
571 };
572 
573 template <typename Derived, typename XprKind = typename traits<Derived>::XprKind,
574  typename StorageKind = typename traits<Derived>::StorageKind>
575 struct generic_xpr_base;
576 
577 template <typename Derived, typename XprKind>
578 struct generic_xpr_base<Derived, XprKind, Dense> {
579  typedef typename dense_xpr_base<Derived, XprKind>::type type;
580 };
581 
582 template <typename XprType, typename CastType>
583 struct cast_return_type {
584  typedef typename XprType::Scalar CurrentScalarType;
585  typedef remove_all_t<CastType> CastType_;
586  typedef typename CastType_::Scalar NewScalarType;
587  typedef std::conditional_t<is_same<CurrentScalarType, NewScalarType>::value, const XprType&, CastType> type;
588 };
589 
590 template <typename A, typename B>
591 struct promote_storage_type;
592 
593 template <typename A>
594 struct promote_storage_type<A, A> {
595  typedef A ret;
596 };
597 template <typename A>
598 struct promote_storage_type<A, const A> {
599  typedef A ret;
600 };
601 template <typename A>
602 struct promote_storage_type<const A, A> {
603  typedef A ret;
604 };
605 
619 template <typename A, typename B, typename Functor>
620 struct cwise_promote_storage_type;
621 
622 template <typename A, typename Functor>
623 struct cwise_promote_storage_type<A, A, Functor> {
624  typedef A ret;
625 };
626 template <typename Functor>
627 struct cwise_promote_storage_type<Dense, Dense, Functor> {
628  typedef Dense ret;
629 };
630 template <typename A, typename Functor>
631 struct cwise_promote_storage_type<A, Dense, Functor> {
632  typedef Dense ret;
633 };
634 template <typename B, typename Functor>
635 struct cwise_promote_storage_type<Dense, B, Functor> {
636  typedef Dense ret;
637 };
638 template <typename Functor>
639 struct cwise_promote_storage_type<Sparse, Dense, Functor> {
640  typedef Sparse ret;
641 };
642 template <typename Functor>
643 struct cwise_promote_storage_type<Dense, Sparse, Functor> {
644  typedef Sparse ret;
645 };
646 
647 template <typename LhsKind, typename RhsKind, int LhsOrder, int RhsOrder>
648 struct cwise_promote_storage_order {
649  enum { value = LhsOrder };
650 };
651 
652 template <typename LhsKind, int LhsOrder, int RhsOrder>
653 struct cwise_promote_storage_order<LhsKind, Sparse, LhsOrder, RhsOrder> {
654  enum { value = RhsOrder };
655 };
656 template <typename RhsKind, int LhsOrder, int RhsOrder>
657 struct cwise_promote_storage_order<Sparse, RhsKind, LhsOrder, RhsOrder> {
658  enum { value = LhsOrder };
659 };
660 template <int Order>
661 struct cwise_promote_storage_order<Sparse, Sparse, Order, Order> {
662  enum { value = Order };
663 };
664 
679 template <typename A, typename B, int ProductTag>
680 struct product_promote_storage_type;
681 
682 template <typename A, int ProductTag>
683 struct product_promote_storage_type<A, A, ProductTag> {
684  typedef A ret;
685 };
686 template <int ProductTag>
687 struct product_promote_storage_type<Dense, Dense, ProductTag> {
688  typedef Dense ret;
689 };
690 template <typename A, int ProductTag>
691 struct product_promote_storage_type<A, Dense, ProductTag> {
692  typedef Dense ret;
693 };
694 template <typename B, int ProductTag>
695 struct product_promote_storage_type<Dense, B, ProductTag> {
696  typedef Dense ret;
697 };
698 
699 template <typename A, int ProductTag>
700 struct product_promote_storage_type<A, DiagonalShape, ProductTag> {
701  typedef A ret;
702 };
703 template <typename B, int ProductTag>
704 struct product_promote_storage_type<DiagonalShape, B, ProductTag> {
705  typedef B ret;
706 };
707 template <int ProductTag>
708 struct product_promote_storage_type<Dense, DiagonalShape, ProductTag> {
709  typedef Dense ret;
710 };
711 template <int ProductTag>
712 struct product_promote_storage_type<DiagonalShape, Dense, ProductTag> {
713  typedef Dense ret;
714 };
715 
716 template <typename A, int ProductTag>
717 struct product_promote_storage_type<A, SkewSymmetricShape, ProductTag> {
718  typedef A ret;
719 };
720 template <typename B, int ProductTag>
721 struct product_promote_storage_type<SkewSymmetricShape, B, ProductTag> {
722  typedef B ret;
723 };
724 template <int ProductTag>
725 struct product_promote_storage_type<Dense, SkewSymmetricShape, ProductTag> {
726  typedef Dense ret;
727 };
728 template <int ProductTag>
729 struct product_promote_storage_type<SkewSymmetricShape, Dense, ProductTag> {
730  typedef Dense ret;
731 };
732 template <int ProductTag>
733 struct product_promote_storage_type<SkewSymmetricShape, SkewSymmetricShape, ProductTag> {
734  typedef Dense ret;
735 };
736 
737 template <typename A, int ProductTag>
738 struct product_promote_storage_type<A, PermutationStorage, ProductTag> {
739  typedef A ret;
740 };
741 template <typename B, int ProductTag>
742 struct product_promote_storage_type<PermutationStorage, B, ProductTag> {
743  typedef B ret;
744 };
745 template <int ProductTag>
746 struct product_promote_storage_type<Dense, PermutationStorage, ProductTag> {
747  typedef Dense ret;
748 };
749 template <int ProductTag>
750 struct product_promote_storage_type<PermutationStorage, Dense, ProductTag> {
751  typedef Dense ret;
752 };
753 
757 template <typename ExpressionType, typename Scalar = typename ExpressionType::Scalar>
758 struct plain_row_type {
759  typedef Matrix<Scalar, 1, ExpressionType::ColsAtCompileTime,
760  int(ExpressionType::PlainObject::Options) | int(RowMajor), 1, ExpressionType::MaxColsAtCompileTime>
761  MatrixRowType;
762  typedef Array<Scalar, 1, ExpressionType::ColsAtCompileTime, int(ExpressionType::PlainObject::Options) | int(RowMajor),
763  1, ExpressionType::MaxColsAtCompileTime>
764  ArrayRowType;
765 
766  typedef std::conditional_t<is_same<typename traits<ExpressionType>::XprKind, MatrixXpr>::value, MatrixRowType,
767  ArrayRowType>
768  type;
769 };
770 
771 template <typename ExpressionType, typename Scalar = typename ExpressionType::Scalar>
772 struct plain_col_type {
773  typedef Matrix<Scalar, ExpressionType::RowsAtCompileTime, 1, ExpressionType::PlainObject::Options & ~RowMajor,
774  ExpressionType::MaxRowsAtCompileTime, 1>
775  MatrixColType;
776  typedef Array<Scalar, ExpressionType::RowsAtCompileTime, 1, ExpressionType::PlainObject::Options & ~RowMajor,
777  ExpressionType::MaxRowsAtCompileTime, 1>
778  ArrayColType;
779 
780  typedef std::conditional_t<is_same<typename traits<ExpressionType>::XprKind, MatrixXpr>::value, MatrixColType,
781  ArrayColType>
782  type;
783 };
784 
785 template <typename ExpressionType, typename Scalar = typename ExpressionType::Scalar>
786 struct plain_diag_type {
787  enum {
788  diag_size = internal::min_size_prefer_dynamic(ExpressionType::RowsAtCompileTime, ExpressionType::ColsAtCompileTime),
789  max_diag_size = min_size_prefer_fixed(ExpressionType::MaxRowsAtCompileTime, ExpressionType::MaxColsAtCompileTime)
790  };
791  typedef Matrix<Scalar, diag_size, 1, ExpressionType::PlainObject::Options & ~RowMajor, max_diag_size, 1>
792  MatrixDiagType;
793  typedef Array<Scalar, diag_size, 1, ExpressionType::PlainObject::Options & ~RowMajor, max_diag_size, 1> ArrayDiagType;
794 
795  typedef std::conditional_t<is_same<typename traits<ExpressionType>::XprKind, MatrixXpr>::value, MatrixDiagType,
796  ArrayDiagType>
797  type;
798 };
799 
800 template <typename Expr, typename Scalar = typename Expr::Scalar>
801 struct plain_constant_type {
802  enum { Options = (traits<Expr>::Flags & RowMajorBit) ? RowMajor : 0 };
803 
804  typedef Array<Scalar, traits<Expr>::RowsAtCompileTime, traits<Expr>::ColsAtCompileTime, Options,
805  traits<Expr>::MaxRowsAtCompileTime, traits<Expr>::MaxColsAtCompileTime>
806  array_type;
807 
808  typedef Matrix<Scalar, traits<Expr>::RowsAtCompileTime, traits<Expr>::ColsAtCompileTime, Options,
809  traits<Expr>::MaxRowsAtCompileTime, traits<Expr>::MaxColsAtCompileTime>
810  matrix_type;
811 
812  typedef CwiseNullaryOp<
813  scalar_constant_op<Scalar>,
814  const std::conditional_t<is_same<typename traits<Expr>::XprKind, MatrixXpr>::value, matrix_type, array_type>>
815  type;
816 };
817 
818 template <typename ExpressionType>
819 struct is_lvalue {
820  enum { value = (!bool(is_const<ExpressionType>::value)) && bool(traits<ExpressionType>::Flags & LvalueBit) };
821 };
822 
823 template <typename T>
824 struct is_diagonal {
825  enum { ret = false };
826 };
827 
828 template <typename T>
829 struct is_diagonal<DiagonalBase<T>> {
830  enum { ret = true };
831 };
832 
833 template <typename T>
834 struct is_diagonal<DiagonalWrapper<T>> {
835  enum { ret = true };
836 };
837 
838 template <typename T, int S>
839 struct is_diagonal<DiagonalMatrix<T, S>> {
840  enum { ret = true };
841 };
842 
843 template <typename T>
844 struct is_identity {
845  enum { value = false };
846 };
847 
848 template <typename T>
849 struct is_identity<CwiseNullaryOp<internal::scalar_identity_op<typename T::Scalar>, T>> {
850  enum { value = true };
851 };
852 
853 template <typename S1, typename S2>
854 struct glue_shapes;
855 template <>
856 struct glue_shapes<DenseShape, TriangularShape> {
857  typedef TriangularShape type;
858 };
859 
860 template <typename T1, typename T2>
861 struct possibly_same_dense {
862  enum {
863  value = has_direct_access<T1>::ret && has_direct_access<T2>::ret &&
864  is_same<typename T1::Scalar, typename T2::Scalar>::value
865  };
866 };
867 
868 template <typename T1, typename T2>
869 EIGEN_DEVICE_FUNC bool is_same_dense(const T1& mat1, const T2& mat2,
870  std::enable_if_t<possibly_same_dense<T1, T2>::value>* = 0) {
871  return (mat1.data() == mat2.data()) && (mat1.innerStride() == mat2.innerStride()) &&
872  (mat1.outerStride() == mat2.outerStride());
873 }
874 
875 template <typename T1, typename T2>
876 EIGEN_DEVICE_FUNC bool is_same_dense(const T1&, const T2&, std::enable_if_t<!possibly_same_dense<T1, T2>::value>* = 0) {
877  return false;
878 }
879 
880 // Internal helper defining the cost of a scalar division for the type T.
881 // The default heuristic can be specialized for each scalar type and architecture.
882 template <typename T, bool Vectorized = false, typename EnableIf = void>
883 struct scalar_div_cost {
884  enum { value = 8 * NumTraits<T>::MulCost };
885 };
886 
887 template <typename T, bool Vectorized>
888 struct scalar_div_cost<T, Vectorized, std::enable_if_t<NumTraits<T>::IsComplex>> {
889  using RealScalar = typename NumTraits<T>::Real;
890  enum {
891  value =
892  2 * scalar_div_cost<RealScalar>::value + 6 * NumTraits<RealScalar>::MulCost + 3 * NumTraits<RealScalar>::AddCost
893  };
894 };
895 
896 template <bool Vectorized>
897 struct scalar_div_cost<signed long, Vectorized, std::conditional_t<sizeof(long) == 8, void, false_type>> {
898  enum { value = 24 };
899 };
900 template <bool Vectorized>
901 struct scalar_div_cost<unsigned long, Vectorized, std::conditional_t<sizeof(long) == 8, void, false_type>> {
902  enum { value = 21 };
903 };
904 
905 #ifdef EIGEN_DEBUG_ASSIGN
906 std::string demangle_traversal(int t) {
907  if (t == DefaultTraversal) return "DefaultTraversal";
908  if (t == LinearTraversal) return "LinearTraversal";
909  if (t == InnerVectorizedTraversal) return "InnerVectorizedTraversal";
910  if (t == LinearVectorizedTraversal) return "LinearVectorizedTraversal";
911  if (t == SliceVectorizedTraversal) return "SliceVectorizedTraversal";
912  return "?";
913 }
914 std::string demangle_unrolling(int t) {
915  if (t == NoUnrolling) return "NoUnrolling";
916  if (t == InnerUnrolling) return "InnerUnrolling";
917  if (t == CompleteUnrolling) return "CompleteUnrolling";
918  return "?";
919 }
920 std::string demangle_flags(int f) {
921  std::string res;
922  if (f & RowMajorBit) res += " | RowMajor";
923  if (f & PacketAccessBit) res += " | Packet";
924  if (f & LinearAccessBit) res += " | Linear";
925  if (f & LvalueBit) res += " | Lvalue";
926  if (f & DirectAccessBit) res += " | Direct";
927  if (f & NestByRefBit) res += " | NestByRef";
928  if (f & NoPreferredStorageOrderBit) res += " | NoPreferredStorageOrderBit";
929 
930  return res;
931 }
932 #endif
933 
934 template <typename XprType>
935 struct is_block_xpr : std::false_type {};
936 
937 template <typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
938 struct is_block_xpr<Block<XprType, BlockRows, BlockCols, InnerPanel>> : std::true_type {};
939 
940 template <typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
941 struct is_block_xpr<const Block<XprType, BlockRows, BlockCols, InnerPanel>> : std::true_type {};
942 
943 // Helper utility for constructing non-recursive block expressions.
944 template <typename XprType>
945 struct block_xpr_helper {
946  using BaseType = XprType;
947 
948  // For regular block expressions, simply forward along the InnerPanel argument,
949  // which is set when calling row/column expressions.
950  static constexpr bool is_inner_panel(bool inner_panel) { return inner_panel; }
951 
952  // Only enable non-const base function if XprType is not const (otherwise we get a duplicate definition).
953  template <typename T = XprType, typename EnableIf = std::enable_if_t<!std::is_const<T>::value>>
954  static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE BaseType& base(XprType& xpr) {
955  return xpr;
956  }
957  static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const BaseType& base(const XprType& xpr) { return xpr; }
958  static constexpr EIGEN_ALWAYS_INLINE Index row(const XprType& /*xpr*/, Index r) { return r; }
959  static constexpr EIGEN_ALWAYS_INLINE Index col(const XprType& /*xpr*/, Index c) { return c; }
960 };
961 
962 template <typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
963 struct block_xpr_helper<Block<XprType, BlockRows, BlockCols, InnerPanel>> {
964  using BlockXprType = Block<XprType, BlockRows, BlockCols, InnerPanel>;
965  // Recursive helper in case of explicit block-of-block expression.
966  using NestedXprHelper = block_xpr_helper<XprType>;
967  using BaseType = typename NestedXprHelper::BaseType;
968 
969  // For block-of-block expressions, we need to combine the InnerPannel trait
970  // with that of the block subexpression.
971  static constexpr bool is_inner_panel(bool inner_panel) { return InnerPanel && inner_panel; }
972 
973  // Only enable non-const base function if XprType is not const (otherwise we get a duplicates definition).
974  template <typename T = XprType, typename EnableIf = std::enable_if_t<!std::is_const<T>::value>>
975  static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE BaseType& base(BlockXprType& xpr) {
976  return NestedXprHelper::base(xpr.nestedExpression());
977  }
978  static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const BaseType& base(const BlockXprType& xpr) {
979  return NestedXprHelper::base(xpr.nestedExpression());
980  }
981  static constexpr EIGEN_ALWAYS_INLINE Index row(const BlockXprType& xpr, Index r) {
982  return xpr.startRow() + NestedXprHelper::row(xpr.nestedExpression(), r);
983  }
984  static constexpr EIGEN_ALWAYS_INLINE Index col(const BlockXprType& xpr, Index c) {
985  return xpr.startCol() + NestedXprHelper::col(xpr.nestedExpression(), c);
986  }
987 };
988 
989 template <typename XprType, int BlockRows, int BlockCols, bool InnerPanel>
990 struct block_xpr_helper<const Block<XprType, BlockRows, BlockCols, InnerPanel>>
991  : block_xpr_helper<Block<XprType, BlockRows, BlockCols, InnerPanel>> {};
992 
993 template <typename XprType>
994 struct is_matrix_base_xpr : std::is_base_of<MatrixBase<remove_all_t<XprType>>, remove_all_t<XprType>> {};
995 
996 template <typename XprType>
997 struct is_permutation_base_xpr : std::is_base_of<PermutationBase<remove_all_t<XprType>>, remove_all_t<XprType>> {};
998 
999 } // end namespace internal
1000 
1041 template <typename ScalarA, typename ScalarB, typename BinaryOp = internal::scalar_product_op<ScalarA, ScalarB>>
1043 #ifndef EIGEN_PARSED_BY_DOXYGEN
1044  // for backward compatibility, use the hints given by the (deprecated) internal::scalar_product_traits class.
1045  : internal::scalar_product_traits<ScalarA, ScalarB>
1046 #endif // EIGEN_PARSED_BY_DOXYGEN
1047 {
1048 };
1049 
1050 template <typename T, typename BinaryOp>
1051 struct ScalarBinaryOpTraits<T, T, BinaryOp> {
1052  typedef T ReturnType;
1053 };
1054 
1055 template <typename T, typename BinaryOp>
1056 struct ScalarBinaryOpTraits<T, typename NumTraits<std::enable_if_t<NumTraits<T>::IsComplex, T>>::Real, BinaryOp> {
1057  typedef T ReturnType;
1058 };
1059 template <typename T, typename BinaryOp>
1060 struct ScalarBinaryOpTraits<typename NumTraits<std::enable_if_t<NumTraits<T>::IsComplex, T>>::Real, T, BinaryOp> {
1061  typedef T ReturnType;
1062 };
1063 
1064 // For Matrix * Permutation
1065 template <typename T, typename BinaryOp>
1066 struct ScalarBinaryOpTraits<T, void, BinaryOp> {
1067  typedef T ReturnType;
1068 };
1069 
1070 // For Permutation * Matrix
1071 template <typename T, typename BinaryOp>
1072 struct ScalarBinaryOpTraits<void, T, BinaryOp> {
1073  typedef T ReturnType;
1074 };
1075 
1076 // for Permutation*Permutation
1077 template <typename BinaryOp>
1078 struct ScalarBinaryOpTraits<void, void, BinaryOp> {
1079  typedef void ReturnType;
1080 };
1081 
1082 // We require Lhs and Rhs to have "compatible" scalar types.
1083 // It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized
1084 // paths. So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user
1085 // tries to add together a float matrix and a double matrix.
1086 #define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP, LHS, RHS) \
1087  EIGEN_STATIC_ASSERT( \
1088  (Eigen::internal::has_ReturnType<ScalarBinaryOpTraits<LHS, RHS, BINOP>>::value), \
1089  YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
1090 
1091 } // end namespace Eigen
1092 
1093 #endif // EIGEN_XPRHELPER_H
Definition: Constants.h:318
const int HugeCost
Definition: Constants.h:48
const unsigned int DirectAccessBit
Definition: Constants.h:159
const unsigned int LvalueBit
Definition: Constants.h:148
Namespace containing all symbols from the Eigen library.
Definition: B01_Experimental.dox:1
const int DynamicIndex
Definition: Constants.h:30
Definition: BFloat16.h:231
const unsigned int RowMajorBit
Definition: Constants.h:70
const unsigned int PacketAccessBit
Definition: Constants.h:97
Definition: Constants.h:322
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
Definition: Constants.h:320
Determines whether the given binary operation of two numeric types is allowed and what the scalar ret...
Definition: XprHelper.h:1042
const int Dynamic
Definition: Constants.h:25
const unsigned int EvalBeforeNestingBit
Definition: Constants.h:74
const unsigned int LinearAccessBit
Definition: Constants.h:133
const unsigned int NoPreferredStorageOrderBit
Definition: Constants.h:182