compbio
ProductEvaluators.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
5 // Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
6 // Copyright (C) 2011 Jitse Niesen <jitse@maths.leeds.ac.uk>
7 //
8 // This Source Code Form is subject to the terms of the Mozilla
9 // Public License v. 2.0. If a copy of the MPL was not distributed
10 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 
12 
13 #ifndef EIGEN_PRODUCTEVALUATORS_H
14 #define EIGEN_PRODUCTEVALUATORS_H
15 
16 namespace Eigen {
17 
18 namespace internal {
19 
28 template<typename Lhs, typename Rhs, int Options>
29 struct evaluator<Product<Lhs, Rhs, Options> >
30  : public product_evaluator<Product<Lhs, Rhs, Options> >
31 {
34 
35  EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : Base(xpr) {}
36 };
37 
38 // Catch "scalar * ( A * B )" and transform it to "(A*scalar) * B"
39 // TODO we should apply that rule only if that's really helpful
40 template<typename Lhs, typename Rhs, typename Scalar1, typename Scalar2, typename Plain1>
42  const CwiseNullaryOp<internal::scalar_constant_op<Scalar1>, Plain1>,
43  const Product<Lhs, Rhs, DefaultProduct> > >
44 {
45  static const bool value = true;
46 };
47 template<typename Lhs, typename Rhs, typename Scalar1, typename Scalar2, typename Plain1>
49  const CwiseNullaryOp<internal::scalar_constant_op<Scalar1>, Plain1>,
50  const Product<Lhs, Rhs, DefaultProduct> > >
51  : public evaluator<Product<EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar1,Lhs,product), Rhs, DefaultProduct> >
52 {
57 
58  EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr)
59  : Base(xpr.lhs().functor().m_other * xpr.rhs().lhs() * xpr.rhs().rhs())
60  {}
61 };
62 
63 
64 template<typename Lhs, typename Rhs, int DiagIndex>
65 struct evaluator<Diagonal<const Product<Lhs, Rhs, DefaultProduct>, DiagIndex> >
66  : public evaluator<Diagonal<const Product<Lhs, Rhs, LazyProduct>, DiagIndex> >
67 {
70 
71  EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr)
72  : Base(Diagonal<const Product<Lhs, Rhs, LazyProduct>, DiagIndex>(
73  Product<Lhs, Rhs, LazyProduct>(xpr.nestedExpression().lhs(), xpr.nestedExpression().rhs()),
74  xpr.index() ))
75  {}
76 };
77 
78 
79 // Helper class to perform a matrix product with the destination at hand.
80 // Depending on the sizes of the factors, there are different evaluation strategies
81 // as controlled by internal::product_type.
82 template< typename Lhs, typename Rhs,
83  typename LhsShape = typename evaluator_traits<Lhs>::Shape,
84  typename RhsShape = typename evaluator_traits<Rhs>::Shape,
87 
88 template<typename Lhs, typename Rhs>
89 struct evaluator_assume_aliasing<Product<Lhs, Rhs, DefaultProduct> > {
90  static const bool value = true;
91 };
92 
93 // This is the default evaluator implementation for products:
94 // It creates a temporary and call generic_product_impl
95 template<typename Lhs, typename Rhs, int Options, int ProductTag, typename LhsShape, typename RhsShape>
96 struct product_evaluator<Product<Lhs, Rhs, Options>, ProductTag, LhsShape, RhsShape>
97  : public evaluator<typename Product<Lhs, Rhs, Options>::PlainObject>
98 {
100  typedef typename XprType::PlainObject PlainObject;
102  enum {
103  Flags = Base::Flags | EvalBeforeNestingBit
104  };
105 
106  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
107  explicit product_evaluator(const XprType& xpr)
108  : m_result(xpr.rows(), xpr.cols())
109  {
110  ::new (static_cast<Base*>(this)) Base(m_result);
111 
112 // FIXME shall we handle nested_eval here?,
113 // if so, then we must take care at removing the call to nested_eval in the specializations (e.g., in permutation_matrix_product, transposition_matrix_product, etc.)
114 // typedef typename internal::nested_eval<Lhs,Rhs::ColsAtCompileTime>::type LhsNested;
115 // typedef typename internal::nested_eval<Rhs,Lhs::RowsAtCompileTime>::type RhsNested;
116 // typedef typename internal::remove_all<LhsNested>::type LhsNestedCleaned;
117 // typedef typename internal::remove_all<RhsNested>::type RhsNestedCleaned;
118 //
119 // const LhsNested lhs(xpr.lhs());
120 // const RhsNested rhs(xpr.rhs());
121 //
122 // generic_product_impl<LhsNestedCleaned, RhsNestedCleaned>::evalTo(m_result, lhs, rhs);
123 
125  }
126 
127 protected:
128  PlainObject m_result;
129 };
130 
131 // The following three shortcuts are enabled only if the scalar types match excatly.
132 // TODO: we could enable them for different scalar types when the product is not vectorized.
133 
134 // Dense = Product
135 template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar>
136 struct Assignment<DstXprType, Product<Lhs,Rhs,Options>, internal::assign_op<Scalar,Scalar>, Dense2Dense,
137  typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type>
138 {
140  static EIGEN_STRONG_INLINE
141  void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<Scalar,Scalar> &)
142  {
143  Index dstRows = src.rows();
144  Index dstCols = src.cols();
145  if((dst.rows()!=dstRows) || (dst.cols()!=dstCols))
146  dst.resize(dstRows, dstCols);
147  // FIXME shall we handle nested_eval here?
148  generic_product_impl<Lhs, Rhs>::evalTo(dst, src.lhs(), src.rhs());
149  }
150 };
151 
152 // Dense += Product
153 template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar>
154 struct Assignment<DstXprType, Product<Lhs,Rhs,Options>, internal::add_assign_op<Scalar,Scalar>, Dense2Dense,
155  typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type>
156 {
158  static EIGEN_STRONG_INLINE
159  void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op<Scalar,Scalar> &)
160  {
161  Index dstRows = src.rows();
162  Index dstCols = src.cols();
163  if((dst.rows()!=dstRows) || (dst.cols()!=dstCols))
164  dst.resize(dstRows, dstCols);
165  // FIXME shall we handle nested_eval here?
166  generic_product_impl<Lhs, Rhs>::addTo(dst, src.lhs(), src.rhs());
167  }
168 };
169 
170 // Dense -= Product
171 template< typename DstXprType, typename Lhs, typename Rhs, int Options, typename Scalar>
172 struct Assignment<DstXprType, Product<Lhs,Rhs,Options>, internal::sub_assign_op<Scalar,Scalar>, Dense2Dense,
173  typename enable_if<(Options==DefaultProduct || Options==AliasFreeProduct)>::type>
174 {
176  static EIGEN_STRONG_INLINE
177  void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op<Scalar,Scalar> &)
178  {
179  Index dstRows = src.rows();
180  Index dstCols = src.cols();
181  if((dst.rows()!=dstRows) || (dst.cols()!=dstCols))
182  dst.resize(dstRows, dstCols);
183  // FIXME shall we handle nested_eval here?
184  generic_product_impl<Lhs, Rhs>::subTo(dst, src.lhs(), src.rhs());
185  }
186 };
187 
188 
189 // Dense ?= scalar * Product
190 // TODO we should apply that rule if that's really helpful
191 // for instance, this is not good for inner products
192 template< typename DstXprType, typename Lhs, typename Rhs, typename AssignFunc, typename Scalar, typename ScalarBis, typename Plain>
193 struct Assignment<DstXprType, CwiseBinaryOp<internal::scalar_product_op<ScalarBis,Scalar>, const CwiseNullaryOp<internal::scalar_constant_op<ScalarBis>,Plain>,
194  const Product<Lhs,Rhs,DefaultProduct> >, AssignFunc, Dense2Dense>
195 {
199  static EIGEN_STRONG_INLINE
200  void run(DstXprType &dst, const SrcXprType &src, const AssignFunc& func)
201  {
202  call_assignment_no_alias(dst, (src.lhs().functor().m_other * src.rhs().lhs())*src.rhs().rhs(), func);
203  }
204 };
205 
206 //----------------------------------------
207 // Catch "Dense ?= xpr + Product<>" expression to save one temporary
208 // FIXME we could probably enable these rules for any product, i.e., not only Dense and DefaultProduct
209 
210 template<typename OtherXpr, typename Lhs, typename Rhs>
211 struct evaluator_assume_aliasing<CwiseBinaryOp<internal::scalar_sum_op<typename OtherXpr::Scalar,typename Product<Lhs,Rhs,DefaultProduct>::Scalar>, const OtherXpr,
212  const Product<Lhs,Rhs,DefaultProduct> >, DenseShape > {
213  static const bool value = true;
214 };
215 
216 template<typename DstXprType, typename OtherXpr, typename ProductType, typename Func1, typename Func2>
218 {
219  template<typename SrcXprType, typename InitialFunc>
220  static EIGEN_STRONG_INLINE
221  void run(DstXprType &dst, const SrcXprType &src, const InitialFunc& /*func*/)
222  {
223  call_assignment_no_alias(dst, src.lhs(), Func1());
224  call_assignment_no_alias(dst, src.rhs(), Func2());
225  }
226 };
227 
228 #define EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(ASSIGN_OP,BINOP,ASSIGN_OP2) \
229  template< typename DstXprType, typename OtherXpr, typename Lhs, typename Rhs, typename DstScalar, typename SrcScalar, typename OtherScalar,typename ProdScalar> \
230  struct Assignment<DstXprType, CwiseBinaryOp<internal::BINOP<OtherScalar,ProdScalar>, const OtherXpr, \
231  const Product<Lhs,Rhs,DefaultProduct> >, internal::ASSIGN_OP<DstScalar,SrcScalar>, Dense2Dense> \
232  : assignment_from_xpr_op_product<DstXprType, OtherXpr, Product<Lhs,Rhs,DefaultProduct>, internal::ASSIGN_OP<DstScalar,OtherScalar>, internal::ASSIGN_OP2<DstScalar,ProdScalar> > \
233  {}
234 
235 EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(assign_op, scalar_sum_op,add_assign_op);
236 EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(add_assign_op,scalar_sum_op,add_assign_op);
237 EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(sub_assign_op,scalar_sum_op,sub_assign_op);
238 
239 EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(assign_op, scalar_difference_op,sub_assign_op);
240 EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(add_assign_op,scalar_difference_op,sub_assign_op);
241 EIGEN_CATCH_ASSIGN_XPR_OP_PRODUCT(sub_assign_op,scalar_difference_op,add_assign_op);
242 
243 //----------------------------------------
244 
245 template<typename Lhs, typename Rhs>
246 struct generic_product_impl<Lhs,Rhs,DenseShape,DenseShape,InnerProduct>
247 {
248  template<typename Dst>
249  static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
250  {
251  dst.coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum();
252  }
253 
254  template<typename Dst>
255  static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
256  {
257  dst.coeffRef(0,0) += (lhs.transpose().cwiseProduct(rhs)).sum();
258  }
259 
260  template<typename Dst>
261  static void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
262  { dst.coeffRef(0,0) -= (lhs.transpose().cwiseProduct(rhs)).sum(); }
263 };
264 
265 
266 /***********************************************************************
267 * Implementation of outer dense * dense vector product
268 ***********************************************************************/
269 
270 // Column major result
271 template<typename Dst, typename Lhs, typename Rhs, typename Func>
272 void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const false_type&)
273 {
274  evaluator<Rhs> rhsEval(rhs);
275  typename nested_eval<Lhs,Rhs::SizeAtCompileTime>::type actual_lhs(lhs);
276  // FIXME if cols is large enough, then it might be useful to make sure that lhs is sequentially stored
277  // FIXME not very good if rhs is real and lhs complex while alpha is real too
278  const Index cols = dst.cols();
279  for (Index j=0; j<cols; ++j)
280  func(dst.col(j), rhsEval.coeff(Index(0),j) * actual_lhs);
281 }
282 
283 // Row major result
284 template<typename Dst, typename Lhs, typename Rhs, typename Func>
285 void outer_product_selector_run(Dst& dst, const Lhs &lhs, const Rhs &rhs, const Func& func, const true_type&)
286 {
287  evaluator<Lhs> lhsEval(lhs);
288  typename nested_eval<Rhs,Lhs::SizeAtCompileTime>::type actual_rhs(rhs);
289  // FIXME if rows is large enough, then it might be useful to make sure that rhs is sequentially stored
290  // FIXME not very good if lhs is real and rhs complex while alpha is real too
291  const Index rows = dst.rows();
292  for (Index i=0; i<rows; ++i)
293  func(dst.row(i), lhsEval.coeff(i,Index(0)) * actual_rhs);
294 }
295 
296 template<typename Lhs, typename Rhs>
297 struct generic_product_impl<Lhs,Rhs,DenseShape,DenseShape,OuterProduct>
298 {
299  template<typename T> struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {};
300  typedef typename Product<Lhs,Rhs>::Scalar Scalar;
301 
302  // TODO it would be nice to be able to exploit our *_assign_op functors for that purpose
303  struct set { template<typename Dst, typename Src> void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() = src; } };
304  struct add { template<typename Dst, typename Src> void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() += src; } };
305  struct sub { template<typename Dst, typename Src> void operator()(const Dst& dst, const Src& src) const { dst.const_cast_derived() -= src; } };
306  struct adds {
307  Scalar m_scale;
308  explicit adds(const Scalar& s) : m_scale(s) {}
309  template<typename Dst, typename Src> void operator()(const Dst& dst, const Src& src) const {
310  dst.const_cast_derived() += m_scale * src;
311  }
312  };
313 
314  template<typename Dst>
315  static inline void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
316  {
317  internal::outer_product_selector_run(dst, lhs, rhs, set(), is_row_major<Dst>());
318  }
319 
320  template<typename Dst>
321  static inline void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
322  {
323  internal::outer_product_selector_run(dst, lhs, rhs, add(), is_row_major<Dst>());
324  }
325 
326  template<typename Dst>
327  static inline void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
328  {
329  internal::outer_product_selector_run(dst, lhs, rhs, sub(), is_row_major<Dst>());
330  }
331 
332  template<typename Dst>
333  static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha)
334  {
335  internal::outer_product_selector_run(dst, lhs, rhs, adds(alpha), is_row_major<Dst>());
336  }
337 
338 };
339 
340 
341 // This base class provides default implementations for evalTo, addTo, subTo, in terms of scaleAndAddTo
342 template<typename Lhs, typename Rhs, typename Derived>
344 {
345  typedef typename Product<Lhs,Rhs>::Scalar Scalar;
346 
347  template<typename Dst>
348  static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
349  { dst.setZero(); scaleAndAddTo(dst, lhs, rhs, Scalar(1)); }
350 
351  template<typename Dst>
352  static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
353  { scaleAndAddTo(dst,lhs, rhs, Scalar(1)); }
354 
355  template<typename Dst>
356  static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
357  { scaleAndAddTo(dst, lhs, rhs, Scalar(-1)); }
358 
359  template<typename Dst>
360  static EIGEN_STRONG_INLINE void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha)
361  { Derived::scaleAndAddTo(dst,lhs,rhs,alpha); }
362 
363 };
364 
365 template<typename Lhs, typename Rhs>
366 struct generic_product_impl<Lhs,Rhs,DenseShape,DenseShape,GemvProduct>
367  : generic_product_impl_base<Lhs,Rhs,generic_product_impl<Lhs,Rhs,DenseShape,DenseShape,GemvProduct> >
368 {
369  typedef typename nested_eval<Lhs,1>::type LhsNested;
370  typedef typename nested_eval<Rhs,1>::type RhsNested;
371  typedef typename Product<Lhs,Rhs>::Scalar Scalar;
372  enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight };
374 
375  template<typename Dest>
376  static EIGEN_STRONG_INLINE void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha)
377  {
378  LhsNested actual_lhs(lhs);
379  RhsNested actual_rhs(rhs);
380 
382  (int(MatrixType::Flags)&RowMajorBit) ? RowMajor : ColMajor,
384  >::run(actual_lhs, actual_rhs, dst, alpha);
385  }
386 };
387 
388 template<typename Lhs, typename Rhs>
389 struct generic_product_impl<Lhs,Rhs,DenseShape,DenseShape,CoeffBasedProductMode>
390 {
391  typedef typename Product<Lhs,Rhs>::Scalar Scalar;
392 
393  template<typename Dst>
394  static EIGEN_STRONG_INLINE void evalTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
395  {
396  // Same as: dst.noalias() = lhs.lazyProduct(rhs);
397  // but easier on the compiler side
398  call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::assign_op<typename Dst::Scalar,Scalar>());
399  }
400 
401  template<typename Dst>
402  static EIGEN_STRONG_INLINE void addTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
403  {
404  // dst.noalias() += lhs.lazyProduct(rhs);
405  call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::add_assign_op<typename Dst::Scalar,Scalar>());
406  }
407 
408  template<typename Dst>
409  static EIGEN_STRONG_INLINE void subTo(Dst& dst, const Lhs& lhs, const Rhs& rhs)
410  {
411  // dst.noalias() -= lhs.lazyProduct(rhs);
412  call_assignment_no_alias(dst, lhs.lazyProduct(rhs), internal::sub_assign_op<typename Dst::Scalar,Scalar>());
413  }
414 
415 // template<typename Dst>
416 // static inline void scaleAndAddTo(Dst& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha)
417 // { dst.noalias() += alpha * lhs.lazyProduct(rhs); }
418 };
419 
420 // This specialization enforces the use of a coefficient-based evaluation strategy
421 template<typename Lhs, typename Rhs>
422 struct generic_product_impl<Lhs,Rhs,DenseShape,DenseShape,LazyCoeffBasedProductMode>
423  : generic_product_impl<Lhs,Rhs,DenseShape,DenseShape,CoeffBasedProductMode> {};
424 
425 // Case 2: Evaluate coeff by coeff
426 //
427 // This is mostly taken from CoeffBasedProduct.h
428 // The main difference is that we add an extra argument to the etor_product_*_impl::run() function
429 // for the inner dimension of the product, because evaluator object do not know their size.
430 
431 template<int Traversal, int UnrollingIndex, typename Lhs, typename Rhs, typename RetScalar>
433 
434 template<int StorageOrder, int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, int LoadMode>
436 
437 template<typename Lhs, typename Rhs, int ProductTag>
438 struct product_evaluator<Product<Lhs, Rhs, LazyProduct>, ProductTag, DenseShape, DenseShape>
439  : evaluator_base<Product<Lhs, Rhs, LazyProduct> >
440 {
442  typedef typename XprType::Scalar Scalar;
443  typedef typename XprType::CoeffReturnType CoeffReturnType;
444 
445  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
446  explicit product_evaluator(const XprType& xpr)
447  : m_lhs(xpr.lhs()),
448  m_rhs(xpr.rhs()),
449  m_lhsImpl(m_lhs), // FIXME the creation of the evaluator objects should result in a no-op, but check that!
450  m_rhsImpl(m_rhs), // Moreover, they are only useful for the packet path, so we could completely disable them when not needed,
451  // or perhaps declare them on the fly on the packet method... We have experiment to check what's best.
452  m_innerDim(xpr.lhs().cols())
453  {
454  EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits<Scalar>::MulCost);
455  EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits<Scalar>::AddCost);
456  EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
457 #if 0
458  std::cerr << "LhsOuterStrideBytes= " << LhsOuterStrideBytes << "\n";
459  std::cerr << "RhsOuterStrideBytes= " << RhsOuterStrideBytes << "\n";
460  std::cerr << "LhsAlignment= " << LhsAlignment << "\n";
461  std::cerr << "RhsAlignment= " << RhsAlignment << "\n";
462  std::cerr << "CanVectorizeLhs= " << CanVectorizeLhs << "\n";
463  std::cerr << "CanVectorizeRhs= " << CanVectorizeRhs << "\n";
464  std::cerr << "CanVectorizeInner= " << CanVectorizeInner << "\n";
465  std::cerr << "EvalToRowMajor= " << EvalToRowMajor << "\n";
466  std::cerr << "Alignment= " << Alignment << "\n";
467  std::cerr << "Flags= " << Flags << "\n";
468 #endif
469  }
470 
471  // Everything below here is taken from CoeffBasedProduct.h
472 
475 
478 
481 
482  enum {
483  RowsAtCompileTime = LhsNestedCleaned::RowsAtCompileTime,
484  ColsAtCompileTime = RhsNestedCleaned::ColsAtCompileTime,
485  InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(LhsNestedCleaned::ColsAtCompileTime, RhsNestedCleaned::RowsAtCompileTime),
486  MaxRowsAtCompileTime = LhsNestedCleaned::MaxRowsAtCompileTime,
487  MaxColsAtCompileTime = RhsNestedCleaned::MaxColsAtCompileTime
488  };
489 
490  typedef typename find_best_packet<Scalar,RowsAtCompileTime>::type LhsVecPacketType;
491  typedef typename find_best_packet<Scalar,ColsAtCompileTime>::type RhsVecPacketType;
492 
493  enum {
494 
495  LhsCoeffReadCost = LhsEtorType::CoeffReadCost,
496  RhsCoeffReadCost = RhsEtorType::CoeffReadCost,
497  CoeffReadCost = InnerSize==0 ? NumTraits<Scalar>::ReadCost
498  : InnerSize == Dynamic ? HugeCost
499  : InnerSize * (NumTraits<Scalar>::MulCost + LhsCoeffReadCost + RhsCoeffReadCost)
500  + (InnerSize - 1) * NumTraits<Scalar>::AddCost,
501 
502  Unroll = CoeffReadCost <= EIGEN_UNROLLING_LIMIT,
503 
504  LhsFlags = LhsEtorType::Flags,
505  RhsFlags = RhsEtorType::Flags,
506 
507  LhsRowMajor = LhsFlags & RowMajorBit,
508  RhsRowMajor = RhsFlags & RowMajorBit,
509 
510  LhsVecPacketSize = unpacket_traits<LhsVecPacketType>::size,
511  RhsVecPacketSize = unpacket_traits<RhsVecPacketType>::size,
512 
513  // Here, we don't care about alignment larger than the usable packet size.
514  LhsAlignment = EIGEN_PLAIN_ENUM_MIN(LhsEtorType::Alignment,LhsVecPacketSize*int(sizeof(typename LhsNestedCleaned::Scalar))),
515  RhsAlignment = EIGEN_PLAIN_ENUM_MIN(RhsEtorType::Alignment,RhsVecPacketSize*int(sizeof(typename RhsNestedCleaned::Scalar))),
516 
518 
519  CanVectorizeRhs = bool(RhsRowMajor) && (RhsFlags & PacketAccessBit) && (ColsAtCompileTime!=1),
520  CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit) && (RowsAtCompileTime!=1),
521 
522  EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1
523  : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0
524  : (bool(RhsRowMajor) && !CanVectorizeLhs),
525 
526  Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & ~RowMajorBit)
527  | (EvalToRowMajor ? RowMajorBit : 0)
528  // TODO enable vectorization for mixed types
529  | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0)
530  | (XprType::IsVectorAtCompileTime ? LinearAccessBit : 0),
531 
532  LhsOuterStrideBytes = int(LhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename LhsNestedCleaned::Scalar)),
533  RhsOuterStrideBytes = int(RhsNestedCleaned::OuterStrideAtCompileTime) * int(sizeof(typename RhsNestedCleaned::Scalar)),
534 
535  Alignment = bool(CanVectorizeLhs) ? (LhsOuterStrideBytes<=0 || (int(LhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,LhsAlignment))!=0 ? 0 : LhsAlignment)
536  : bool(CanVectorizeRhs) ? (RhsOuterStrideBytes<=0 || (int(RhsOuterStrideBytes) % EIGEN_PLAIN_ENUM_MAX(1,RhsAlignment))!=0 ? 0 : RhsAlignment)
537  : 0,
538 
539  /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside
540  * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner
541  * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect
542  * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI.
543  */
544  CanVectorizeInner = SameType
545  && LhsRowMajor
546  && (!RhsRowMajor)
547  && (LhsFlags & RhsFlags & ActualPacketAccessBit)
548  && (InnerSize % packet_traits<Scalar>::size == 0)
549  };
550 
551  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index row, Index col) const
552  {
553  return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum();
554  }
555 
556  /* Allow index-based non-packet access. It is impossible though to allow index-based packed access,
557  * which is why we don't set the LinearAccessBit.
558  * TODO: this seems possible when the result is a vector
559  */
560  EIGEN_DEVICE_FUNC const CoeffReturnType coeff(Index index) const
561  {
562  const Index row = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? 0 : index;
563  const Index col = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? index : 0;
564  return (m_lhs.row(row).transpose().cwiseProduct( m_rhs.col(col) )).sum();
565  }
566 
567  template<int LoadMode, typename PacketType>
568  const PacketType packet(Index row, Index col) const
569  {
570  PacketType res;
571  typedef etor_product_packet_impl<bool(int(Flags)&RowMajorBit) ? RowMajor : ColMajor,
572  Unroll ? int(InnerSize) : Dynamic,
573  LhsEtorType, RhsEtorType, PacketType, LoadMode> PacketImpl;
574  PacketImpl::run(row, col, m_lhsImpl, m_rhsImpl, m_innerDim, res);
575  return res;
576  }
577 
578  template<int LoadMode, typename PacketType>
579  const PacketType packet(Index index) const
580  {
581  const Index row = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? 0 : index;
582  const Index col = (RowsAtCompileTime == 1 || MaxRowsAtCompileTime==1) ? index : 0;
583  return packet<LoadMode,PacketType>(row,col);
584  }
585 
586 protected:
589 
590  LhsEtorType m_lhsImpl;
591  RhsEtorType m_rhsImpl;
592 
593  // TODO: Get rid of m_innerDim if known at compile time
594  Index m_innerDim;
595 };
596 
597 template<typename Lhs, typename Rhs>
598 struct product_evaluator<Product<Lhs, Rhs, DefaultProduct>, LazyCoeffBasedProductMode, DenseShape, DenseShape>
599  : product_evaluator<Product<Lhs, Rhs, LazyProduct>, CoeffBasedProductMode, DenseShape, DenseShape>
600 {
604  enum {
605  Flags = Base::Flags | EvalBeforeNestingBit
606  };
607  EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr)
608  : Base(BaseProduct(xpr.lhs(),xpr.rhs()))
609  {}
610 };
611 
612 /****************************************
613 *** Coeff based product, Packet path ***
614 ****************************************/
615 
616 template<int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, int LoadMode>
617 struct etor_product_packet_impl<RowMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode>
618 {
619  static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res)
620  {
622  res = pmadd(pset1<Packet>(lhs.coeff(row, Index(UnrollingIndex-1))), rhs.template packet<LoadMode,Packet>(Index(UnrollingIndex-1), col), res);
623  }
624 };
625 
626 template<int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, int LoadMode>
627 struct etor_product_packet_impl<ColMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode>
628 {
629  static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet &res)
630  {
632  res = pmadd(lhs.template packet<LoadMode,Packet>(row, Index(UnrollingIndex-1)), pset1<Packet>(rhs.coeff(Index(UnrollingIndex-1), col)), res);
633  }
634 };
635 
636 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
637 struct etor_product_packet_impl<RowMajor, 1, Lhs, Rhs, Packet, LoadMode>
638 {
639  static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res)
640  {
641  res = pmul(pset1<Packet>(lhs.coeff(row, Index(0))),rhs.template packet<LoadMode,Packet>(Index(0), col));
642  }
643 };
644 
645 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
646 struct etor_product_packet_impl<ColMajor, 1, Lhs, Rhs, Packet, LoadMode>
647 {
648  static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index /*innerDim*/, Packet &res)
649  {
650  res = pmul(lhs.template packet<LoadMode,Packet>(row, Index(0)), pset1<Packet>(rhs.coeff(Index(0), col)));
651  }
652 };
653 
654 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
655 struct etor_product_packet_impl<RowMajor, 0, Lhs, Rhs, Packet, LoadMode>
656 {
657  static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res)
658  {
659  res = pset1<Packet>(typename unpacket_traits<Packet>::type(0));
660  }
661 };
662 
663 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
664 struct etor_product_packet_impl<ColMajor, 0, Lhs, Rhs, Packet, LoadMode>
665 {
666  static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Index /*innerDim*/, Packet &res)
667  {
668  res = pset1<Packet>(typename unpacket_traits<Packet>::type(0));
669  }
670 };
671 
672 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
673 struct etor_product_packet_impl<RowMajor, Dynamic, Lhs, Rhs, Packet, LoadMode>
674 {
675  static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res)
676  {
677  res = pset1<Packet>(typename unpacket_traits<Packet>::type(0));
678  for(Index i = 0; i < innerDim; ++i)
679  res = pmadd(pset1<Packet>(lhs.coeff(row, i)), rhs.template packet<LoadMode,Packet>(i, col), res);
680  }
681 };
682 
683 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
684 struct etor_product_packet_impl<ColMajor, Dynamic, Lhs, Rhs, Packet, LoadMode>
685 {
686  static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Index innerDim, Packet& res)
687  {
688  res = pset1<Packet>(typename unpacket_traits<Packet>::type(0));
689  for(Index i = 0; i < innerDim; ++i)
690  res = pmadd(lhs.template packet<LoadMode,Packet>(row, i), pset1<Packet>(rhs.coeff(i, col)), res);
691  }
692 };
693 
694 
695 /***************************************************************************
696 * Triangular products
697 ***************************************************************************/
698 template<int Mode, bool LhsIsTriangular,
699  typename Lhs, bool LhsIsVector,
700  typename Rhs, bool RhsIsVector>
702 
703 template<typename Lhs, typename Rhs, int ProductTag>
705  : generic_product_impl_base<Lhs,Rhs,generic_product_impl<Lhs,Rhs,TriangularShape,DenseShape,ProductTag> >
706 {
707  typedef typename Product<Lhs,Rhs>::Scalar Scalar;
708 
709  template<typename Dest>
710  static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha)
711  {
713  ::run(dst, lhs.nestedExpression(), rhs, alpha);
714  }
715 };
716 
717 template<typename Lhs, typename Rhs, int ProductTag>
719 : generic_product_impl_base<Lhs,Rhs,generic_product_impl<Lhs,Rhs,DenseShape,TriangularShape,ProductTag> >
720 {
721  typedef typename Product<Lhs,Rhs>::Scalar Scalar;
722 
723  template<typename Dest>
724  static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha)
725  {
727  }
728 };
729 
730 
731 /***************************************************************************
732 * SelfAdjoint products
733 ***************************************************************************/
734 template <typename Lhs, int LhsMode, bool LhsIsVector,
735  typename Rhs, int RhsMode, bool RhsIsVector>
737 
738 template<typename Lhs, typename Rhs, int ProductTag>
740  : generic_product_impl_base<Lhs,Rhs,generic_product_impl<Lhs,Rhs,SelfAdjointShape,DenseShape,ProductTag> >
741 {
742  typedef typename Product<Lhs,Rhs>::Scalar Scalar;
743 
744  template<typename Dest>
745  static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha)
746  {
748  }
749 };
750 
751 template<typename Lhs, typename Rhs, int ProductTag>
753 : generic_product_impl_base<Lhs,Rhs,generic_product_impl<Lhs,Rhs,DenseShape,SelfAdjointShape,ProductTag> >
754 {
755  typedef typename Product<Lhs,Rhs>::Scalar Scalar;
756 
757  template<typename Dest>
758  static void scaleAndAddTo(Dest& dst, const Lhs& lhs, const Rhs& rhs, const Scalar& alpha)
759  {
761  }
762 };
763 
764 
765 /***************************************************************************
766 * Diagonal products
767 ***************************************************************************/
768 
769 template<typename MatrixType, typename DiagonalType, typename Derived, int ProductOrder>
771  : evaluator_base<Derived>
772 {
774 public:
775  enum {
777 
778  MatrixFlags = evaluator<MatrixType>::Flags,
779  DiagFlags = evaluator<DiagonalType>::Flags,
780  _StorageOrder = MatrixFlags & RowMajorBit ? RowMajor : ColMajor,
781  _ScalarAccessOnDiag = !((int(_StorageOrder) == ColMajor && int(ProductOrder) == OnTheLeft)
782  ||(int(_StorageOrder) == RowMajor && int(ProductOrder) == OnTheRight)),
784  // FIXME currently we need same types, but in the future the next rule should be the one
785  //_Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && ((!_PacketOnDiag) || (_SameTypes && bool(int(DiagFlags)&PacketAccessBit))),
786  _Vectorizable = bool(int(MatrixFlags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagFlags)&PacketAccessBit))),
787  _LinearAccessMask = (MatrixType::RowsAtCompileTime==1 || MatrixType::ColsAtCompileTime==1) ? LinearAccessBit : 0,
788  Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixFlags)) | (_Vectorizable ? PacketAccessBit : 0),
790  };
791 
792  diagonal_product_evaluator_base(const MatrixType &mat, const DiagonalType &diag)
793  : m_diagImpl(diag), m_matImpl(mat)
794  {
795  EIGEN_INTERNAL_CHECK_COST_VALUE(NumTraits<Scalar>::MulCost);
796  EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
797  }
798 
799  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index idx) const
800  {
801  return m_diagImpl.coeff(idx) * m_matImpl.coeff(idx);
802  }
803 
804 protected:
805  template<int LoadMode,typename PacketType>
806  EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::true_type) const
807  {
808  return internal::pmul(m_matImpl.template packet<LoadMode,PacketType>(row, col),
809  internal::pset1<PacketType>(m_diagImpl.coeff(id)));
810  }
811 
812  template<int LoadMode,typename PacketType>
813  EIGEN_STRONG_INLINE PacketType packet_impl(Index row, Index col, Index id, internal::false_type) const
814  {
815  enum {
816  InnerSize = (MatrixType::Flags & RowMajorBit) ? MatrixType::ColsAtCompileTime : MatrixType::RowsAtCompileTime,
817  DiagonalPacketLoadMode = EIGEN_PLAIN_ENUM_MIN(LoadMode,((InnerSize%16) == 0) ? int(Aligned16) : int(evaluator<DiagonalType>::Alignment)) // FIXME hardcoded 16!!
818  };
819  return internal::pmul(m_matImpl.template packet<LoadMode,PacketType>(row, col),
820  m_diagImpl.template packet<DiagonalPacketLoadMode,PacketType>(id));
821  }
822 
823  evaluator<DiagonalType> m_diagImpl;
824  evaluator<MatrixType> m_matImpl;
825 };
826 
827 // diagonal * dense
828 template<typename Lhs, typename Rhs, int ProductKind, int ProductTag>
829 struct product_evaluator<Product<Lhs, Rhs, ProductKind>, ProductTag, DiagonalShape, DenseShape>
830  : diagonal_product_evaluator_base<Rhs, typename Lhs::DiagonalVectorType, Product<Lhs, Rhs, LazyProduct>, OnTheLeft>
831 {
833  using Base::m_diagImpl;
834  using Base::m_matImpl;
835  using Base::coeff;
836  typedef typename Base::Scalar Scalar;
837 
839  typedef typename XprType::PlainObject PlainObject;
840 
841  enum {
842  StorageOrder = int(Rhs::Flags) & RowMajorBit ? RowMajor : ColMajor
843  };
844 
845  EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr)
846  : Base(xpr.rhs(), xpr.lhs().diagonal())
847  {
848  }
849 
850  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const
851  {
852  return m_diagImpl.coeff(row) * m_matImpl.coeff(row, col);
853  }
854 
855 #ifndef __CUDACC__
856  template<int LoadMode,typename PacketType>
857  EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const
858  {
859  // FIXME: NVCC used to complain about the template keyword, but we have to check whether this is still the case.
860  // See also similar calls below.
861  return this->template packet_impl<LoadMode,PacketType>(row,col, row,
863  }
864 
865  template<int LoadMode,typename PacketType>
866  EIGEN_STRONG_INLINE PacketType packet(Index idx) const
867  {
868  return packet<LoadMode,PacketType>(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx);
869  }
870 #endif
871 };
872 
873 // dense * diagonal
874 template<typename Lhs, typename Rhs, int ProductKind, int ProductTag>
877 {
879  using Base::m_diagImpl;
880  using Base::m_matImpl;
881  using Base::coeff;
882  typedef typename Base::Scalar Scalar;
883 
885  typedef typename XprType::PlainObject PlainObject;
886 
887  enum { StorageOrder = int(Lhs::Flags) & RowMajorBit ? RowMajor : ColMajor };
888 
889  EIGEN_DEVICE_FUNC explicit product_evaluator(const XprType& xpr)
890  : Base(xpr.lhs(), xpr.rhs().diagonal())
891  {
892  }
893 
894  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const
895  {
896  return m_matImpl.coeff(row, col) * m_diagImpl.coeff(col);
897  }
898 
899 #ifndef __CUDACC__
900  template<int LoadMode,typename PacketType>
901  EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const
902  {
903  return this->template packet_impl<LoadMode,PacketType>(row,col, col,
905  }
906 
907  template<int LoadMode,typename PacketType>
908  EIGEN_STRONG_INLINE PacketType packet(Index idx) const
909  {
910  return packet<LoadMode,PacketType>(int(StorageOrder)==ColMajor?idx:0,int(StorageOrder)==ColMajor?0:idx);
911  }
912 #endif
913 };
914 
915 /***************************************************************************
916 * Products with permutation matrices
917 ***************************************************************************/
918 
924 template<typename ExpressionType, int Side, bool Transposed, typename ExpressionShape>
926 
927 template<typename ExpressionType, int Side, bool Transposed>
929 {
932 
933  template<typename Dest, typename PermutationType>
934  static inline void run(Dest& dst, const PermutationType& perm, const ExpressionType& xpr)
935  {
936  MatrixType mat(xpr);
937  const Index n = Side==OnTheLeft ? mat.rows() : mat.cols();
938  // FIXME we need an is_same for expression that is not sensitive to constness. For instance
939  // is_same_xpr<Block<const Matrix>, Block<Matrix> >::value should be true.
940  //if(is_same<MatrixTypeCleaned,Dest>::value && extract_data(dst) == extract_data(mat))
941  if(is_same_dense(dst, mat))
942  {
943  // apply the permutation inplace
945  mask.fill(false);
946  Index r = 0;
947  while(r < perm.size())
948  {
949  // search for the next seed
950  while(r<perm.size() && mask[r]) r++;
951  if(r>=perm.size())
952  break;
953  // we got one, let's follow it until we are back to the seed
954  Index k0 = r++;
955  Index kPrev = k0;
956  mask.coeffRef(k0) = true;
957  for(Index k=perm.indices().coeff(k0); k!=k0; k=perm.indices().coeff(k))
958  {
961  (dst,((Side==OnTheLeft) ^ Transposed) ? k0 : kPrev));
962 
963  mask.coeffRef(k) = true;
964  kPrev = k;
965  }
966  }
967  }
968  else
969  {
970  for(Index i = 0; i < n; ++i)
971  {
973  (dst, ((Side==OnTheLeft) ^ Transposed) ? perm.indices().coeff(i) : i)
974 
975  =
976 
978  (mat, ((Side==OnTheRight) ^ Transposed) ? perm.indices().coeff(i) : i);
979  }
980  }
981  }
982 };
983 
984 template<typename Lhs, typename Rhs, int ProductTag, typename MatrixShape>
986 {
987  template<typename Dest>
988  static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs)
989  {
991  }
992 };
993 
994 template<typename Lhs, typename Rhs, int ProductTag, typename MatrixShape>
996 {
997  template<typename Dest>
998  static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs)
999  {
1001  }
1002 };
1003 
1004 template<typename Lhs, typename Rhs, int ProductTag, typename MatrixShape>
1005 struct generic_product_impl<Inverse<Lhs>, Rhs, PermutationShape, MatrixShape, ProductTag>
1006 {
1007  template<typename Dest>
1008  static void evalTo(Dest& dst, const Inverse<Lhs>& lhs, const Rhs& rhs)
1009  {
1011  }
1012 };
1013 
1014 template<typename Lhs, typename Rhs, int ProductTag, typename MatrixShape>
1015 struct generic_product_impl<Lhs, Inverse<Rhs>, MatrixShape, PermutationShape, ProductTag>
1016 {
1017  template<typename Dest>
1018  static void evalTo(Dest& dst, const Lhs& lhs, const Inverse<Rhs>& rhs)
1019  {
1021  }
1022 };
1023 
1024 
1025 /***************************************************************************
1026 * Products with transpositions matrices
1027 ***************************************************************************/
1028 
1029 // FIXME could we unify Transpositions and Permutation into a single "shape"??
1030 
1035 template<typename ExpressionType, int Side, bool Transposed, typename ExpressionShape>
1037 {
1040 
1041  template<typename Dest, typename TranspositionType>
1042  static inline void run(Dest& dst, const TranspositionType& tr, const ExpressionType& xpr)
1043  {
1044  MatrixType mat(xpr);
1045  typedef typename TranspositionType::StorageIndex StorageIndex;
1046  const Index size = tr.size();
1047  StorageIndex j = 0;
1048 
1049  if(!is_same_dense(dst,mat))
1050  dst = mat;
1051 
1052  for(Index k=(Transposed?size-1:0) ; Transposed?k>=0:k<size ; Transposed?--k:++k)
1053  if(Index(j=tr.coeff(k))!=k)
1054  {
1055  if(Side==OnTheLeft) dst.row(k).swap(dst.row(j));
1056  else if(Side==OnTheRight) dst.col(k).swap(dst.col(j));
1057  }
1058  }
1059 };
1060 
1061 template<typename Lhs, typename Rhs, int ProductTag, typename MatrixShape>
1062 struct generic_product_impl<Lhs, Rhs, TranspositionsShape, MatrixShape, ProductTag>
1063 {
1064  template<typename Dest>
1065  static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs)
1066  {
1068  }
1069 };
1070 
1071 template<typename Lhs, typename Rhs, int ProductTag, typename MatrixShape>
1072 struct generic_product_impl<Lhs, Rhs, MatrixShape, TranspositionsShape, ProductTag>
1073 {
1074  template<typename Dest>
1075  static void evalTo(Dest& dst, const Lhs& lhs, const Rhs& rhs)
1076  {
1078  }
1079 };
1080 
1081 
1082 template<typename Lhs, typename Rhs, int ProductTag, typename MatrixShape>
1083 struct generic_product_impl<Transpose<Lhs>, Rhs, TranspositionsShape, MatrixShape, ProductTag>
1084 {
1085  template<typename Dest>
1086  static void evalTo(Dest& dst, const Transpose<Lhs>& lhs, const Rhs& rhs)
1087  {
1089  }
1090 };
1091 
1092 template<typename Lhs, typename Rhs, int ProductTag, typename MatrixShape>
1093 struct generic_product_impl<Lhs, Transpose<Rhs>, MatrixShape, TranspositionsShape, ProductTag>
1094 {
1095  template<typename Dest>
1096  static void evalTo(Dest& dst, const Lhs& lhs, const Transpose<Rhs>& rhs)
1097  {
1099  }
1100 };
1101 
1102 } // end namespace internal
1103 
1104 } // end namespace Eigen
1105 
1106 #endif // EIGEN_PRODUCT_EVALUATORS_H
Generic expression of a matrix where all coefficients are defined by a functor.
Definition: CwiseNullaryOp.h:60
Definition: BlasUtil.h:269
Storage order is column major (see TopicStorageOrders).
Definition: Constants.h:320
const int HugeCost
This value means that the cost to evaluate an expression coefficient is either very expensive or cann...
Definition: Constants.h:39
Expression of the product of two arbitrary matrices or vectors.
Definition: Product.h:71
Definition: ForwardDeclarations.h:162
Apply transformation on the right.
Definition: Constants.h:335
Data pointer is aligned on a 16 bytes boundary.
Definition: Constants.h:230
Definition: Meta.h:55
Definition: XprHelper.h:158
Definition: AssignmentFunctors.h:67
Definition: Meta.h:63
Expression of the transpose of a matrix.
Definition: Transpose.h:52
Definition: BinaryFunctors.h:32
Definition: CoreEvaluators.h:90
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:85
Holds information about the various numeric (i.e.
Definition: NumTraits.h:150
Definition: Meta.h:58
const unsigned int RowMajorBit
for a matrix, this means that the storage order is row-major.
Definition: Constants.h:61
Definition: Constants.h:512
Definition: ProductEvaluators.h:343
const unsigned int PacketAccessBit
Short version: means the expression might be vectorized.
Definition: Constants.h:89
EIGEN_DEVICE_FUNC const _RhsNested & rhs() const
Definition: CwiseBinaryOp.h:135
EIGEN_DEVICE_FUNC const internal::remove_all< MatrixTypeNested >::type & nestedExpression() const
Definition: Transpose.h:74
Definition: ProductEvaluators.h:1036
Definition: AssignmentFunctors.h:21
Definition: AssignEvaluator.h:753
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar & coeffRef(Index rowId, Index colId)
This is an overloaded version of DenseCoeffsBase<Derived,WriteAccessors>::coeffRef(Index,Index) const provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts.
Definition: PlainObjectBase.h:177
Definition: AssignEvaluator.h:743
Definition: CoreEvaluators.h:109
Expression of the inverse of another expression.
Definition: Inverse.h:43
Definition: GenericPacketMath.h:96
Definition: BinaryFunctors.h:76
Generic expression where a coefficient-wise binary operator is applied to two expressions.
Definition: CwiseBinaryOp.h:77
Definition: ProductEvaluators.h:217
Definition: ProductEvaluators.h:925
Definition: ProductEvaluators.h:86
Definition: GeneralProduct.h:36
Definition: Constants.h:518
Definition: Constants.h:515
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:33
Apply transformation on the left.
Definition: Constants.h:333
Definition: ProductEvaluators.h:770
Definition: ProductEvaluators.h:701
Definition: ProductEvaluators.h:435
Definition: Meta.h:162
Definition: benchGeometry.cpp:23
Definition: PacketMath.h:48
Definition: BandTriangularSolver.h:13
Expression of a fixed-size or dynamic-size block.
Definition: Block.h:103
Definition: CoreEvaluators.h:84
Definition: BinaryFunctors.h:329
Storage order is row major (see TopicStorageOrders).
Definition: Constants.h:322
Definition: Meta.h:78
Definition: GeneralProduct.h:140
Definition: ProductEvaluators.h:432
Definition: ProductEvaluators.h:736
Determines whether the given binary operation of two numeric types is allowed and what the scalar ret...
Definition: XprHelper.h:757
Definition: AssignmentFunctors.h:46
Definition: Constants.h:517
Expression of a diagonal/subdiagonal/superdiagonal in a matrix.
Definition: Diagonal.h:63
const int Dynamic
This value means that a positive quantity (e.g., a size) is not known at compile-time, and that instead the value is stored in some runtime variable.
Definition: Constants.h:21
const unsigned int EvalBeforeNestingBit
means the expression should be evaluated by the calling expression
Definition: Constants.h:65
Generic expression where a coefficient-wise unary operator is applied to an expression.
Definition: CwiseUnaryOp.h:55
Definition: TensorMeta.h:50
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:178
Definition: Meta.h:54
const unsigned int LinearAccessBit
Short version: means the expression can be seen as 1D vector.
Definition: Constants.h:125
EIGEN_DEVICE_FUNC const _LhsNested & lhs() const
Definition: CwiseBinaryOp.h:132
Definition: Constants.h:520
Definition: Constants.h:519