~choreonoid/choreonoid/debian

« back to all changes in this revision

Viewing changes to thirdparty/eigen3/Eigen/src/Core/Product.h

  • Committer: Thomas Moulard
  • Date: 2012-10-23 12:43:24 UTC
  • Revision ID: git-v1:351cf736ad49bc7a9a7b9767dee760a013517a5d
Tags: upstream/1.1.0
ImportedĀ UpstreamĀ versionĀ 1.1.0

Show diffs side-by-side

added added

removed removed

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