$darkmode
Eigen  5.0.1-dev
Product.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
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_PRODUCT_H
11 #define EIGEN_PRODUCT_H
12 
13 // IWYU pragma: private
14 #include "./InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
18 template <typename Lhs, typename Rhs, int Option, typename StorageKind>
19 class ProductImpl;
20 
21 namespace internal {
22 
23 template <typename Lhs, typename Rhs, int Option>
24 struct traits<Product<Lhs, Rhs, Option>> {
25  typedef remove_all_t<Lhs> LhsCleaned;
26  typedef remove_all_t<Rhs> RhsCleaned;
27  typedef traits<LhsCleaned> LhsTraits;
28  typedef traits<RhsCleaned> RhsTraits;
29 
30  typedef MatrixXpr XprKind;
31 
32  typedef typename ScalarBinaryOpTraits<typename traits<LhsCleaned>::Scalar,
33  typename traits<RhsCleaned>::Scalar>::ReturnType Scalar;
34  typedef typename product_promote_storage_type<typename LhsTraits::StorageKind, typename RhsTraits::StorageKind,
35  internal::product_type<Lhs, Rhs>::ret>::ret StorageKind;
36  typedef typename promote_index_type<typename LhsTraits::StorageIndex, typename RhsTraits::StorageIndex>::type
37  StorageIndex;
38 
39  enum {
40  RowsAtCompileTime = LhsTraits::RowsAtCompileTime,
41  ColsAtCompileTime = RhsTraits::ColsAtCompileTime,
42  MaxRowsAtCompileTime = LhsTraits::MaxRowsAtCompileTime,
43  MaxColsAtCompileTime = RhsTraits::MaxColsAtCompileTime,
44 
45  // FIXME: only needed by GeneralMatrixMatrixTriangular
46  InnerSize = min_size_prefer_fixed(LhsTraits::ColsAtCompileTime, RhsTraits::RowsAtCompileTime),
47 
48  // The storage order is somewhat arbitrary here. The correct one will be determined through the evaluator.
49  Flags = (MaxRowsAtCompileTime == 1 && MaxColsAtCompileTime != 1) ? RowMajorBit
50  : (MaxColsAtCompileTime == 1 && MaxRowsAtCompileTime != 1) ? 0
51  : (((LhsTraits::Flags & NoPreferredStorageOrderBit) && (RhsTraits::Flags & RowMajorBit)) ||
52  ((RhsTraits::Flags & NoPreferredStorageOrderBit) && (LhsTraits::Flags & RowMajorBit)))
53  ? RowMajorBit
55  };
56 };
57 
58 struct TransposeProductEnum {
59  // convenience enumerations to specialize transposed products
60  enum : int {
61  Default = 0x00,
62  Matrix = 0x01,
63  Permutation = 0x02,
64  MatrixMatrix = (Matrix << 8) | Matrix,
65  MatrixPermutation = (Matrix << 8) | Permutation,
66  PermutationMatrix = (Permutation << 8) | Matrix
67  };
68 };
69 template <typename Xpr>
70 struct TransposeKind {
71  static constexpr int Kind = is_matrix_base_xpr<Xpr>::value ? TransposeProductEnum::Matrix
72  : is_permutation_base_xpr<Xpr>::value ? TransposeProductEnum::Permutation
73  : TransposeProductEnum::Default;
74 };
75 
76 template <typename Lhs, typename Rhs>
77 struct TransposeProductKind {
78  static constexpr int Kind = (TransposeKind<Lhs>::Kind << 8) | TransposeKind<Rhs>::Kind;
79 };
80 
81 template <typename Lhs, typename Rhs, int Option, int Kind = TransposeProductKind<Lhs, Rhs>::Kind>
82 struct product_transpose_helper {
83  // by default, don't optimize the transposed product
84  using Derived = Product<Lhs, Rhs, Option>;
85  using Scalar = typename Derived::Scalar;
86  using TransposeType = Transpose<const Derived>;
87  using ConjugateTransposeType = CwiseUnaryOp<scalar_conjugate_op<Scalar>, TransposeType>;
88  using AdjointType = std::conditional_t<NumTraits<Scalar>::IsComplex, ConjugateTransposeType, TransposeType>;
89 
90  // return (lhs * rhs)^T
91  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TransposeType run_transpose(const Derived& derived) {
92  return TransposeType(derived);
93  }
94  // return (lhs * rhs)^H
95  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AdjointType run_adjoint(const Derived& derived) {
96  return AdjointType(TransposeType(derived));
97  }
98 };
99 
100 template <typename Lhs, typename Rhs, int Option>
101 struct product_transpose_helper<Lhs, Rhs, Option, TransposeProductEnum::MatrixMatrix> {
102  // expand the transposed matrix-matrix product
103  using Derived = Product<Lhs, Rhs, Option>;
104 
105  using LhsScalar = typename traits<Lhs>::Scalar;
106  using LhsTransposeType = typename DenseBase<Lhs>::ConstTransposeReturnType;
107  using LhsConjugateTransposeType = CwiseUnaryOp<scalar_conjugate_op<LhsScalar>, LhsTransposeType>;
108  using LhsAdjointType =
109  std::conditional_t<NumTraits<LhsScalar>::IsComplex, LhsConjugateTransposeType, LhsTransposeType>;
110 
111  using RhsScalar = typename traits<Rhs>::Scalar;
112  using RhsTransposeType = typename DenseBase<Rhs>::ConstTransposeReturnType;
113  using RhsConjugateTransposeType = CwiseUnaryOp<scalar_conjugate_op<RhsScalar>, RhsTransposeType>;
114  using RhsAdjointType =
115  std::conditional_t<NumTraits<RhsScalar>::IsComplex, RhsConjugateTransposeType, RhsTransposeType>;
116 
117  using TransposeType = Product<RhsTransposeType, LhsTransposeType, Option>;
118  using AdjointType = Product<RhsAdjointType, LhsAdjointType, Option>;
119 
120  // return rhs^T * lhs^T
121  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TransposeType run_transpose(const Derived& derived) {
122  return TransposeType(RhsTransposeType(derived.rhs()), LhsTransposeType(derived.lhs()));
123  }
124  // return rhs^H * lhs^H
125  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AdjointType run_adjoint(const Derived& derived) {
126  return AdjointType(RhsAdjointType(RhsTransposeType(derived.rhs())),
127  LhsAdjointType(LhsTransposeType(derived.lhs())));
128  }
129 };
130 template <typename Lhs, typename Rhs, int Option>
131 struct product_transpose_helper<Lhs, Rhs, Option, TransposeProductEnum::PermutationMatrix> {
132  // expand the transposed permutation-matrix product
133  using Derived = Product<Lhs, Rhs, Option>;
134 
135  using LhsInverseType = typename PermutationBase<Lhs>::InverseReturnType;
136 
137  using RhsScalar = typename traits<Rhs>::Scalar;
138  using RhsTransposeType = typename DenseBase<Rhs>::ConstTransposeReturnType;
139  using RhsConjugateTransposeType = CwiseUnaryOp<scalar_conjugate_op<RhsScalar>, RhsTransposeType>;
140  using RhsAdjointType =
141  std::conditional_t<NumTraits<RhsScalar>::IsComplex, RhsConjugateTransposeType, RhsTransposeType>;
142 
143  using TransposeType = Product<RhsTransposeType, LhsInverseType, Option>;
144  using AdjointType = Product<RhsAdjointType, LhsInverseType, Option>;
145 
146  // return rhs^T * lhs^-1
147  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TransposeType run_transpose(const Derived& derived) {
148  return TransposeType(RhsTransposeType(derived.rhs()), LhsInverseType(derived.lhs()));
149  }
150  // return rhs^H * lhs^-1
151  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AdjointType run_adjoint(const Derived& derived) {
152  return AdjointType(RhsAdjointType(RhsTransposeType(derived.rhs())), LhsInverseType(derived.lhs()));
153  }
154 };
155 template <typename Lhs, typename Rhs, int Option>
156 struct product_transpose_helper<Lhs, Rhs, Option, TransposeProductEnum::MatrixPermutation> {
157  // expand the transposed matrix-permutation product
158  using Derived = Product<Lhs, Rhs, Option>;
159 
160  using LhsScalar = typename traits<Lhs>::Scalar;
161  using LhsTransposeType = typename DenseBase<Lhs>::ConstTransposeReturnType;
162  using LhsConjugateTransposeType = CwiseUnaryOp<scalar_conjugate_op<LhsScalar>, LhsTransposeType>;
163  using LhsAdjointType =
164  std::conditional_t<NumTraits<LhsScalar>::IsComplex, LhsConjugateTransposeType, LhsTransposeType>;
165 
166  using RhsInverseType = typename PermutationBase<Rhs>::InverseReturnType;
167 
168  using TransposeType = Product<RhsInverseType, LhsTransposeType, Option>;
169  using AdjointType = Product<RhsInverseType, LhsAdjointType, Option>;
170 
171  // return rhs^-1 * lhs^T
172  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TransposeType run_transpose(const Derived& derived) {
173  return TransposeType(RhsInverseType(derived.rhs()), LhsTransposeType(derived.lhs()));
174  }
175  // return rhs^-1 * lhs^H
176  static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AdjointType run_adjoint(const Derived& derived) {
177  return AdjointType(RhsInverseType(derived.rhs()), LhsAdjointType(LhsTransposeType(derived.lhs())));
178  }
179 };
180 
181 } // end namespace internal
182 
197 template <typename Lhs_, typename Rhs_, int Option>
198 class Product
199  : public ProductImpl<Lhs_, Rhs_, Option,
200  typename internal::product_promote_storage_type<
201  typename internal::traits<Lhs_>::StorageKind, typename internal::traits<Rhs_>::StorageKind,
202  internal::product_type<Lhs_, Rhs_>::ret>::ret> {
203  public:
204  typedef Lhs_ Lhs;
205  typedef Rhs_ Rhs;
206 
207  typedef
208  typename ProductImpl<Lhs, Rhs, Option,
209  typename internal::product_promote_storage_type<
210  typename internal::traits<Lhs>::StorageKind, typename internal::traits<Rhs>::StorageKind,
211  internal::product_type<Lhs, Rhs>::ret>::ret>::Base Base;
212  EIGEN_GENERIC_PUBLIC_INTERFACE(Product)
213 
214  typedef typename internal::ref_selector<Lhs>::type LhsNested;
215  typedef typename internal::ref_selector<Rhs>::type RhsNested;
216  typedef internal::remove_all_t<LhsNested> LhsNestedCleaned;
217  typedef internal::remove_all_t<RhsNested> RhsNestedCleaned;
218 
219  using TransposeReturnType = typename internal::product_transpose_helper<Lhs, Rhs, Option>::TransposeType;
220  using AdjointReturnType = typename internal::product_transpose_helper<Lhs, Rhs, Option>::AdjointType;
221 
222  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Product(const Lhs& lhs, const Rhs& rhs) : m_lhs(lhs), m_rhs(rhs) {
223  eigen_assert(lhs.cols() == rhs.rows() && "invalid matrix product" &&
224  "if you wanted a coeff-wise or a dot product use the respective explicit functions");
225  }
226 
227  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Index rows() const noexcept { return m_lhs.rows(); }
228  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Index cols() const noexcept { return m_rhs.cols(); }
229 
230  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const LhsNestedCleaned& lhs() const { return m_lhs; }
231  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const RhsNestedCleaned& rhs() const { return m_rhs; }
232 
233  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TransposeReturnType transpose() const {
234  return internal::product_transpose_helper<Lhs, Rhs, Option>::run_transpose(*this);
235  }
236  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AdjointReturnType adjoint() const {
237  return internal::product_transpose_helper<Lhs, Rhs, Option>::run_adjoint(*this);
238  }
239 
240  protected:
241  LhsNested m_lhs;
242  RhsNested m_rhs;
243 };
244 
245 namespace internal {
246 
247 template <typename Lhs, typename Rhs, int Option, int ProductTag = internal::product_type<Lhs, Rhs>::ret>
248 class dense_product_base : public internal::dense_xpr_base<Product<Lhs, Rhs, Option>>::type {};
249 
251 template <typename Lhs, typename Rhs, int Option>
252 class dense_product_base<Lhs, Rhs, Option, InnerProduct>
253  : public internal::dense_xpr_base<Product<Lhs, Rhs, Option>>::type {
255  typedef typename internal::dense_xpr_base<ProductXpr>::type Base;
256 
257  public:
258  using Base::derived;
259  typedef typename Base::Scalar Scalar;
260 
261  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE operator const Scalar() const {
262  return internal::evaluator<ProductXpr>(derived()).coeff(0, 0);
263  }
264 };
265 
266 } // namespace internal
267 
268 // Generic API dispatcher
269 template <typename Lhs, typename Rhs, int Option, typename StorageKind>
270 class ProductImpl : public internal::generic_xpr_base<Product<Lhs, Rhs, Option>, MatrixXpr, StorageKind>::type {
271  public:
272  typedef typename internal::generic_xpr_base<Product<Lhs, Rhs, Option>, MatrixXpr, StorageKind>::type Base;
273 };
274 
275 template <typename Lhs, typename Rhs, int Option>
276 class ProductImpl<Lhs, Rhs, Option, Dense> : public internal::dense_product_base<Lhs, Rhs, Option> {
277  typedef Product<Lhs, Rhs, Option> Derived;
278 
279  public:
280  typedef typename internal::dense_product_base<Lhs, Rhs, Option> Base;
281  EIGEN_DENSE_PUBLIC_INTERFACE(Derived)
282  protected:
283  enum {
284  IsOneByOne = (RowsAtCompileTime == 1 || RowsAtCompileTime == Dynamic) &&
285  (ColsAtCompileTime == 1 || ColsAtCompileTime == Dynamic),
286  EnableCoeff = IsOneByOne || Option == LazyProduct
287  };
288 
289  public:
290  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index row, Index col) const {
291  EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS);
292  eigen_assert((Option == LazyProduct) || (this->rows() == 1 && this->cols() == 1));
293 
294  return internal::evaluator<Derived>(derived()).coeff(row, col);
295  }
296 
297  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index i) const {
298  EIGEN_STATIC_ASSERT(EnableCoeff, THIS_METHOD_IS_ONLY_FOR_INNER_OR_LAZY_PRODUCTS);
299  eigen_assert((Option == LazyProduct) || (this->rows() == 1 && this->cols() == 1));
300 
301  return internal::evaluator<Derived>(derived()).coeff(i);
302  }
303 };
304 
305 } // end namespace Eigen
306 
307 #endif // EIGEN_PRODUCT_H
Expression of the product of two arbitrary matrices or vectors.
Definition: Product.h:198
Expression of the transpose of a matrix.
Definition: Transpose.h:56
Namespace containing all symbols from the Eigen library.
Definition: B01_Experimental.dox:1
const unsigned int RowMajorBit
Definition: Constants.h:70
Definition: Constants.h:534
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
const int Dynamic
Definition: Constants.h:25
const unsigned int NoPreferredStorageOrderBit
Definition: Constants.h:182