GeneralProduct.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-2011 Gael Guennebaud <gael.guennebaud@inria.fr>
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_GENERAL_PRODUCT_H
12#define EIGEN_GENERAL_PRODUCT_H
13
14namespace Eigen {
15
35template<typename Lhs, typename Rhs, int ProductType = internal::product_type<Lhs,Rhs>::value>
37
38enum {
39 Large = 2,
40 Small = 3
41};
42
43namespace internal {
44
45template<int Rows, int Cols, int Depth> struct product_type_selector;
46
47template<int Size, int MaxSize> struct product_size_category
48{
49 enum { is_large = MaxSize == Dynamic ||
50 Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD,
51 value = is_large ? Large
52 : Size == 1 ? 1
53 : Small
54 };
55};
56
57template<typename Lhs, typename Rhs> struct product_type
58{
59 typedef typename remove_all<Lhs>::type _Lhs;
60 typedef typename remove_all<Rhs>::type _Rhs;
61 enum {
62 MaxRows = _Lhs::MaxRowsAtCompileTime,
63 Rows = _Lhs::RowsAtCompileTime,
64 MaxCols = _Rhs::MaxColsAtCompileTime,
65 Cols = _Rhs::ColsAtCompileTime,
66 MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::MaxColsAtCompileTime,
67 _Rhs::MaxRowsAtCompileTime),
68 Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime,
69 _Rhs::RowsAtCompileTime),
70 LargeThreshold = EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
71 };
72
73 // the splitting into different lines of code here, introducing the _select enums and the typedef below,
74 // is to work around an internal compiler error with gcc 4.1 and 4.2.
75private:
76 enum {
77 rows_select = product_size_category<Rows,MaxRows>::value,
78 cols_select = product_size_category<Cols,MaxCols>::value,
79 depth_select = product_size_category<Depth,MaxDepth>::value
80 };
81 typedef product_type_selector<rows_select, cols_select, depth_select> selector;
82
83public:
84 enum {
85 value = selector::ret
86 };
87#ifdef EIGEN_DEBUG_PRODUCT
88 static void debug()
89 {
90 EIGEN_DEBUG_VAR(Rows);
91 EIGEN_DEBUG_VAR(Cols);
92 EIGEN_DEBUG_VAR(Depth);
93 EIGEN_DEBUG_VAR(rows_select);
94 EIGEN_DEBUG_VAR(cols_select);
95 EIGEN_DEBUG_VAR(depth_select);
96 EIGEN_DEBUG_VAR(value);
97 }
98#endif
99};
100
101
102/* The following allows to select the kind of product at compile time
103 * based on the three dimensions of the product.
104 * This is a compile time mapping from {1,Small,Large}^3 -> {product types} */
105// FIXME I'm not sure the current mapping is the ideal one.
106template<int M, int N> struct product_type_selector<M,N,1> { enum { ret = OuterProduct }; };
107template<int Depth> struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; };
108template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; };
109template<> struct product_type_selector<Small,1, Small> { enum { ret = CoeffBasedProductMode }; };
110template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; };
111template<> struct product_type_selector<Small,Small,Small> { enum { ret = CoeffBasedProductMode }; };
112template<> struct product_type_selector<Small, Small, 1> { enum { ret = LazyCoeffBasedProductMode }; };
113template<> struct product_type_selector<Small, Large, 1> { enum { ret = LazyCoeffBasedProductMode }; };
114template<> struct product_type_selector<Large, Small, 1> { enum { ret = LazyCoeffBasedProductMode }; };
115template<> struct product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; };
116template<> struct product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; };
117template<> struct product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; };
118template<> struct product_type_selector<Large,1, Small> { enum { ret = CoeffBasedProductMode }; };
119template<> struct product_type_selector<Large,1, Large> { enum { ret = GemvProduct }; };
120template<> struct product_type_selector<Small,1, Large> { enum { ret = CoeffBasedProductMode }; };
121template<> struct product_type_selector<Small,Small,Large> { enum { ret = GemmProduct }; };
122template<> struct product_type_selector<Large,Small,Large> { enum { ret = GemmProduct }; };
123template<> struct product_type_selector<Small,Large,Large> { enum { ret = GemmProduct }; };
124template<> struct product_type_selector<Large,Large,Large> { enum { ret = GemmProduct }; };
125template<> struct product_type_selector<Large,Small,Small> { enum { ret = GemmProduct }; };
126template<> struct product_type_selector<Small,Large,Small> { enum { ret = GemmProduct }; };
127template<> struct product_type_selector<Large,Large,Small> { enum { ret = GemmProduct }; };
128
129} // end namespace internal
130
148template<typename Lhs, typename Rhs, int ProductType>
150{
151 // TODO use the nested type to reduce instanciations ????
152// typedef typename internal::nested<Lhs,Rhs::ColsAtCompileTime>::type LhsNested;
153// typedef typename internal::nested<Rhs,Lhs::RowsAtCompileTime>::type RhsNested;
154
155 typedef GeneralProduct<Lhs/*Nested*/, Rhs/*Nested*/, ProductType> Type;
156};
157
158template<typename Lhs, typename Rhs>
159struct ProductReturnType<Lhs,Rhs,CoeffBasedProductMode>
160{
161 typedef typename internal::nested<Lhs, Rhs::ColsAtCompileTime, typename internal::plain_matrix_type<Lhs>::type >::type LhsNested;
162 typedef typename internal::nested<Rhs, Lhs::RowsAtCompileTime, typename internal::plain_matrix_type<Rhs>::type >::type RhsNested;
163 typedef CoeffBasedProduct<LhsNested, RhsNested, EvalBeforeAssigningBit | EvalBeforeNestingBit> Type;
164};
165
166template<typename Lhs, typename Rhs>
167struct ProductReturnType<Lhs,Rhs,LazyCoeffBasedProductMode>
168{
169 typedef typename internal::nested<Lhs, Rhs::ColsAtCompileTime, typename internal::plain_matrix_type<Lhs>::type >::type LhsNested;
170 typedef typename internal::nested<Rhs, Lhs::RowsAtCompileTime, typename internal::plain_matrix_type<Rhs>::type >::type RhsNested;
171 typedef CoeffBasedProduct<LhsNested, RhsNested, NestByRefBit> Type;
172};
173
174// this is a workaround for sun CC
175template<typename Lhs, typename Rhs>
176struct LazyProductReturnType : public ProductReturnType<Lhs,Rhs,LazyCoeffBasedProductMode>
177{};
178
179/***********************************************************************
180* Implementation of Inner Vector Vector Product
181***********************************************************************/
182
183// FIXME : maybe the "inner product" could return a Scalar
184// instead of a 1x1 matrix ??
185// Pro: more natural for the user
186// Cons: this could be a problem if in a meta unrolled algorithm a matrix-matrix
187// product ends up to a row-vector times col-vector product... To tackle this use
188// case, we could have a specialization for Block<MatrixType,1,1> with: operator=(Scalar x);
189
190namespace internal {
191
192template<typename Lhs, typename Rhs>
193struct traits<GeneralProduct<Lhs,Rhs,InnerProduct> >
194 : traits<Matrix<typename scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1> >
195{};
196
197}
198
199template<typename Lhs, typename Rhs>
200class GeneralProduct<Lhs, Rhs, InnerProduct>
201 : internal::no_assignment_operator,
202 public Matrix<typename internal::scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1>
203{
204 typedef Matrix<typename internal::scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1> Base;
205 public:
206 GeneralProduct(const Lhs& lhs, const Rhs& rhs)
207 {
208 EIGEN_STATIC_ASSERT((internal::is_same<typename Lhs::RealScalar, typename Rhs::RealScalar>::value),
209 YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
210
211 Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum();
212 }
213
215 operator const typename Base::Scalar() const {
216 return Base::coeff(0,0);
217 }
218};
219
220/***********************************************************************
221* Implementation of Outer Vector Vector Product
222***********************************************************************/
223
224namespace internal {
225template<int StorageOrder> struct outer_product_selector;
226
227template<typename Lhs, typename Rhs>
228struct traits<GeneralProduct<Lhs,Rhs,OuterProduct> >
229 : traits<ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs> >
230{};
231
232}
233
234template<typename Lhs, typename Rhs>
235class GeneralProduct<Lhs, Rhs, OuterProduct>
236 : public ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs>
237{
238 public:
239 EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct)
240
241 GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
242 {
243 EIGEN_STATIC_ASSERT((internal::is_same<typename Lhs::RealScalar, typename Rhs::RealScalar>::value),
244 YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
245 }
246
247 template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
248 {
249 internal::outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha);
250 }
251};
252
253namespace internal {
254
255template<> struct outer_product_selector<ColMajor> {
256 template<typename ProductType, typename Dest>
257 static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) {
258 typedef typename Dest::Index Index;
259 // FIXME make sure lhs is sequentially stored
260 // FIXME not very good if rhs is real and lhs complex while alpha is real too
261 const Index cols = dest.cols();
262 for (Index j=0; j<cols; ++j)
263 dest.col(j) += (alpha * prod.rhs().coeff(j)) * prod.lhs();
264 }
265};
266
267template<> struct outer_product_selector<RowMajor> {
268 template<typename ProductType, typename Dest>
269 static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) {
270 typedef typename Dest::Index Index;
271 // FIXME make sure rhs is sequentially stored
272 // FIXME not very good if lhs is real and rhs complex while alpha is real too
273 const Index rows = dest.rows();
274 for (Index i=0; i<rows; ++i)
275 dest.row(i) += (alpha * prod.lhs().coeff(i)) * prod.rhs();
276 }
277};
278
279} // end namespace internal
280
281/***********************************************************************
282* Implementation of General Matrix Vector Product
283***********************************************************************/
284
285/* According to the shape/flags of the matrix we have to distinghish 3 different cases:
286 * 1 - the matrix is col-major, BLAS compatible and M is large => call fast BLAS-like colmajor routine
287 * 2 - the matrix is row-major, BLAS compatible and N is large => call fast BLAS-like rowmajor routine
288 * 3 - all other cases are handled using a simple loop along the outer-storage direction.
289 * Therefore we need a lower level meta selector.
290 * Furthermore, if the matrix is the rhs, then the product has to be transposed.
291 */
292namespace internal {
293
294template<typename Lhs, typename Rhs>
295struct traits<GeneralProduct<Lhs,Rhs,GemvProduct> >
296 : traits<ProductBase<GeneralProduct<Lhs,Rhs,GemvProduct>, Lhs, Rhs> >
297{};
298
299template<int Side, int StorageOrder, bool BlasCompatible>
300struct gemv_selector;
301
302} // end namespace internal
303
304template<typename Lhs, typename Rhs>
305class GeneralProduct<Lhs, Rhs, GemvProduct>
306 : public ProductBase<GeneralProduct<Lhs,Rhs,GemvProduct>, Lhs, Rhs>
307{
308 public:
309 EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct)
310
311 typedef typename Lhs::Scalar LhsScalar;
312 typedef typename Rhs::Scalar RhsScalar;
313
314 GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
315 {
316// EIGEN_STATIC_ASSERT((internal::is_same<typename Lhs::Scalar, typename Rhs::Scalar>::value),
317// YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
318 }
319
320 enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight };
321 typedef typename internal::conditional<int(Side)==OnTheRight,_LhsNested,_RhsNested>::type MatrixType;
322
323 template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
324 {
325 eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols());
326 internal::gemv_selector<Side,(int(MatrixType::Flags)&RowMajorBit) ? RowMajor : ColMajor,
327 bool(internal::blas_traits<MatrixType>::HasUsableDirectAccess)>::run(*this, dst, alpha);
328 }
329};
330
331namespace internal {
332
333// The vector is on the left => transposition
334template<int StorageOrder, bool BlasCompatible>
335struct gemv_selector<OnTheLeft,StorageOrder,BlasCompatible>
336{
337 template<typename ProductType, typename Dest>
338 static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
339 {
340 Transpose<Dest> destT(dest);
341 enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor };
342 gemv_selector<OnTheRight,OtherStorageOrder,BlasCompatible>
343 ::run(GeneralProduct<Transpose<const typename ProductType::_RhsNested>,Transpose<const typename ProductType::_LhsNested>, GemvProduct>
344 (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha);
345 }
346};
347
348template<typename Scalar,int Size,int MaxSize,bool Cond> struct gemv_static_vector_if;
349
350template<typename Scalar,int Size,int MaxSize>
351struct gemv_static_vector_if<Scalar,Size,MaxSize,false>
352{
353 EIGEN_STRONG_INLINE Scalar* data() { eigen_internal_assert(false && "should never be called"); return 0; }
354};
355
356template<typename Scalar,int Size>
357struct gemv_static_vector_if<Scalar,Size,Dynamic,true>
358{
359 EIGEN_STRONG_INLINE Scalar* data() { return 0; }
360};
361
362template<typename Scalar,int Size,int MaxSize>
363struct gemv_static_vector_if<Scalar,Size,MaxSize,true>
364{
365 #if EIGEN_ALIGN_STATICALLY
366 internal::plain_array<Scalar,EIGEN_SIZE_MIN_PREFER_FIXED(Size,MaxSize),0> m_data;
367 EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; }
368 #else
369 // Some architectures cannot align on the stack,
370 // => let's manually enforce alignment by allocating more data and return the address of the first aligned element.
371 enum {
372 ForceAlignment = internal::packet_traits<Scalar>::Vectorizable,
373 PacketSize = internal::packet_traits<Scalar>::size
374 };
375 internal::plain_array<Scalar,EIGEN_SIZE_MIN_PREFER_FIXED(Size,MaxSize)+(ForceAlignment?PacketSize:0),0> m_data;
376 EIGEN_STRONG_INLINE Scalar* data() {
377 return ForceAlignment
378 ? reinterpret_cast<Scalar*>((reinterpret_cast<size_t>(m_data.array) & ~(size_t(15))) + 16)
379 : m_data.array;
380 }
381 #endif
382};
383
384template<> struct gemv_selector<OnTheRight,ColMajor,true>
385{
386 template<typename ProductType, typename Dest>
387 static inline void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
388 {
389 typedef typename ProductType::Index Index;
390 typedef typename ProductType::LhsScalar LhsScalar;
391 typedef typename ProductType::RhsScalar RhsScalar;
392 typedef typename ProductType::Scalar ResScalar;
393 typedef typename ProductType::RealScalar RealScalar;
394 typedef typename ProductType::ActualLhsType ActualLhsType;
395 typedef typename ProductType::ActualRhsType ActualRhsType;
396 typedef typename ProductType::LhsBlasTraits LhsBlasTraits;
397 typedef typename ProductType::RhsBlasTraits RhsBlasTraits;
398 typedef Map<Matrix<ResScalar,Dynamic,1>, Aligned> MappedDest;
399
400 ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs());
401 ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs());
402
403 ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs())
404 * RhsBlasTraits::extractScalarFactor(prod.rhs());
405
406 enum {
407 // FIXME find a way to allow an inner stride on the result if packet_traits<Scalar>::size==1
408 // on, the other hand it is good for the cache to pack the vector anyways...
409 EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1,
410 ComplexByReal = (NumTraits<LhsScalar>::IsComplex) && (!NumTraits<RhsScalar>::IsComplex),
411 MightCannotUseDest = (Dest::InnerStrideAtCompileTime!=1) || ComplexByReal
412 };
413
414 gemv_static_vector_if<ResScalar,Dest::SizeAtCompileTime,Dest::MaxSizeAtCompileTime,MightCannotUseDest> static_dest;
415
416 bool alphaIsCompatible = (!ComplexByReal) || (imag(actualAlpha)==RealScalar(0));
417 bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible;
418
419 RhsScalar compatibleAlpha = get_factor<ResScalar,RhsScalar>::run(actualAlpha);
420
421 ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(),
422 evalToDest ? dest.data() : static_dest.data());
423
424 if(!evalToDest)
425 {
426 #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN
427 int size = dest.size();
428 EIGEN_DENSE_STORAGE_CTOR_PLUGIN
429 #endif
430 if(!alphaIsCompatible)
431 {
432 MappedDest(actualDestPtr, dest.size()).setZero();
433 compatibleAlpha = RhsScalar(1);
434 }
435 else
436 MappedDest(actualDestPtr, dest.size()) = dest;
437 }
438
439 general_matrix_vector_product
440 <Index,LhsScalar,ColMajor,LhsBlasTraits::NeedToConjugate,RhsScalar,RhsBlasTraits::NeedToConjugate>::run(
441 actualLhs.rows(), actualLhs.cols(),
442 actualLhs.data(), actualLhs.outerStride(),
443 actualRhs.data(), actualRhs.innerStride(),
444 actualDestPtr, 1,
445 compatibleAlpha);
446
447 if (!evalToDest)
448 {
449 if(!alphaIsCompatible)
450 dest += actualAlpha * MappedDest(actualDestPtr, dest.size());
451 else
452 dest = MappedDest(actualDestPtr, dest.size());
453 }
454 }
455};
456
457template<> struct gemv_selector<OnTheRight,RowMajor,true>
458{
459 template<typename ProductType, typename Dest>
460 static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
461 {
462 typedef typename ProductType::LhsScalar LhsScalar;
463 typedef typename ProductType::RhsScalar RhsScalar;
464 typedef typename ProductType::Scalar ResScalar;
465 typedef typename ProductType::Index Index;
466 typedef typename ProductType::ActualLhsType ActualLhsType;
467 typedef typename ProductType::ActualRhsType ActualRhsType;
468 typedef typename ProductType::_ActualRhsType _ActualRhsType;
469 typedef typename ProductType::LhsBlasTraits LhsBlasTraits;
470 typedef typename ProductType::RhsBlasTraits RhsBlasTraits;
471
472 typename add_const<ActualLhsType>::type actualLhs = LhsBlasTraits::extract(prod.lhs());
473 typename add_const<ActualRhsType>::type actualRhs = RhsBlasTraits::extract(prod.rhs());
474
475 ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs())
476 * RhsBlasTraits::extractScalarFactor(prod.rhs());
477
478 enum {
479 // FIXME find a way to allow an inner stride on the result if packet_traits<Scalar>::size==1
480 // on, the other hand it is good for the cache to pack the vector anyways...
481 DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1
482 };
483
484 gemv_static_vector_if<RhsScalar,_ActualRhsType::SizeAtCompileTime,_ActualRhsType::MaxSizeAtCompileTime,!DirectlyUseRhs> static_rhs;
485
486 ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(),
487 DirectlyUseRhs ? const_cast<RhsScalar*>(actualRhs.data()) : static_rhs.data());
488
489 if(!DirectlyUseRhs)
490 {
491 #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN
492 int size = actualRhs.size();
493 EIGEN_DENSE_STORAGE_CTOR_PLUGIN
494 #endif
495 Map<typename _ActualRhsType::PlainObject>(actualRhsPtr, actualRhs.size()) = actualRhs;
496 }
497
498 general_matrix_vector_product
499 <Index,LhsScalar,RowMajor,LhsBlasTraits::NeedToConjugate,RhsScalar,RhsBlasTraits::NeedToConjugate>::run(
500 actualLhs.rows(), actualLhs.cols(),
501 actualLhs.data(), actualLhs.outerStride(),
502 actualRhsPtr, 1,
503 dest.data(), dest.innerStride(),
504 actualAlpha);
505 }
506};
507
508template<> struct gemv_selector<OnTheRight,ColMajor,false>
509{
510 template<typename ProductType, typename Dest>
511 static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
512 {
513 typedef typename Dest::Index Index;
514 // TODO makes sure dest is sequentially stored in memory, otherwise use a temp
515 const Index size = prod.rhs().rows();
516 for(Index k=0; k<size; ++k)
517 dest += (alpha*prod.rhs().coeff(k)) * prod.lhs().col(k);
518 }
519};
520
521template<> struct gemv_selector<OnTheRight,RowMajor,false>
522{
523 template<typename ProductType, typename Dest>
524 static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
525 {
526 typedef typename Dest::Index Index;
527 // TODO makes sure rhs is sequentially stored in memory, otherwise use a temp
528 const Index rows = prod.rows();
529 for(Index i=0; i<rows; ++i)
530 dest.coeffRef(i) += alpha * (prod.lhs().row(i).cwiseProduct(prod.rhs().transpose())).sum();
531 }
532};
533
534} // end namespace internal
535
536/***************************************************************************
537* Implementation of matrix base methods
538***************************************************************************/
539
546template<typename Derived>
547template<typename OtherDerived>
548inline const typename ProductReturnType<Derived, OtherDerived>::Type
549MatrixBase<Derived>::operator*(const MatrixBase<OtherDerived> &other) const
550{
551 // A note regarding the function declaration: In MSVC, this function will sometimes
552 // not be inlined since DenseStorage is an unwindable object for dynamic
553 // matrices and product types are holding a member to store the result.
554 // Thus it does not help tagging this function with EIGEN_STRONG_INLINE.
555 enum {
556 ProductIsValid = Derived::ColsAtCompileTime==Dynamic
557 || OtherDerived::RowsAtCompileTime==Dynamic
558 || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime),
559 AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime,
560 SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived)
561 };
562 // note to the lost user:
563 // * for a dot product use: v1.dot(v2)
564 // * for a coeff-wise product use: v1.cwiseProduct(v2)
565 EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes),
566 INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS)
567 EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors),
568 INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION)
569 EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT)
570#ifdef EIGEN_DEBUG_PRODUCT
571 internal::product_type<Derived,OtherDerived>::debug();
572#endif
573 return typename ProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived());
574}
575
587template<typename Derived>
588template<typename OtherDerived>
589const typename LazyProductReturnType<Derived,OtherDerived>::Type
590MatrixBase<Derived>::lazyProduct(const MatrixBase<OtherDerived> &other) const
591{
592 enum {
593 ProductIsValid = Derived::ColsAtCompileTime==Dynamic
594 || OtherDerived::RowsAtCompileTime==Dynamic
595 || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime),
596 AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime,
597 SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived)
598 };
599 // note to the lost user:
600 // * for a dot product use: v1.dot(v2)
601 // * for a coeff-wise product use: v1.cwiseProduct(v2)
602 EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes),
603 INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS)
604 EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors),
605 INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION)
606 EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT)
607
608 return typename LazyProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived());
609}
610
611} // end namespace Eigen
612
613#endif // EIGEN_PRODUCT_H
Expression of the product of two general matrices or vectors.
Definition GeneralProduct.h:36
const LazyProductReturnType< Derived, OtherDerived >::Type lazyProduct(const MatrixBase< OtherDerived > &other) const
Definition GeneralProduct.h:590
const ScalarMultipleReturnType operator*(const Scalar &scalar) const
Definition MatrixBase.h:50
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:129
@ RowMajor
Definition Constants.h:259
@ ColMajor
Definition Constants.h:257
@ Aligned
Definition Constants.h:189
@ OnTheLeft
Definition Constants.h:270
@ OnTheRight
Definition Constants.h:272
const unsigned int RowMajorBit
Definition Constants.h:48
Definition LDLT.h:18
Helper class to get the correct and optimized returned type of operator*.
Definition GeneralProduct.h:150