00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifndef EIGEN_PRODUCT_H
00027 #define EIGEN_PRODUCT_H
00028
00048 template<typename Lhs, typename Rhs, int ProductType = internal::product_type<Lhs,Rhs>::value>
00049 class GeneralProduct;
00050
00051 enum {
00052 Large = 2,
00053 Small = 3
00054 };
00055
00056 namespace internal {
00057
00058 template<int Rows, int Cols, int Depth> struct product_type_selector;
00059
00060 template<int Size, int MaxSize> struct product_size_category
00061 {
00062 enum { is_large = MaxSize == Dynamic ||
00063 Size >= EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD,
00064 value = is_large ? Large
00065 : Size == 1 ? 1
00066 : Small
00067 };
00068 };
00069
00070 template<typename Lhs, typename Rhs> struct product_type
00071 {
00072 typedef typename remove_all<Lhs>::type _Lhs;
00073 typedef typename remove_all<Rhs>::type _Rhs;
00074 enum {
00075 MaxRows = _Lhs::MaxRowsAtCompileTime,
00076 Rows = _Lhs::RowsAtCompileTime,
00077 MaxCols = _Rhs::MaxColsAtCompileTime,
00078 Cols = _Rhs::ColsAtCompileTime,
00079 MaxDepth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::MaxColsAtCompileTime,
00080 _Rhs::MaxRowsAtCompileTime),
00081 Depth = EIGEN_SIZE_MIN_PREFER_FIXED(_Lhs::ColsAtCompileTime,
00082 _Rhs::RowsAtCompileTime),
00083 LargeThreshold = EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
00084 };
00085
00086
00087
00088 private:
00089 enum {
00090 rows_select = product_size_category<Rows,MaxRows>::value,
00091 cols_select = product_size_category<Cols,MaxCols>::value,
00092 depth_select = product_size_category<Depth,MaxDepth>::value
00093 };
00094 typedef product_type_selector<rows_select, cols_select, depth_select> selector;
00095
00096 public:
00097 enum {
00098 value = selector::ret
00099 };
00100 #ifdef EIGEN_DEBUG_PRODUCT
00101 static void debug()
00102 {
00103 EIGEN_DEBUG_VAR(Rows);
00104 EIGEN_DEBUG_VAR(Cols);
00105 EIGEN_DEBUG_VAR(Depth);
00106 EIGEN_DEBUG_VAR(rows_select);
00107 EIGEN_DEBUG_VAR(cols_select);
00108 EIGEN_DEBUG_VAR(depth_select);
00109 EIGEN_DEBUG_VAR(value);
00110 }
00111 #endif
00112 };
00113
00114
00115
00116
00117
00118
00119 template<int M, int N> struct product_type_selector<M,N,1> { enum { ret = OuterProduct }; };
00120 template<int Depth> struct product_type_selector<1, 1, Depth> { enum { ret = InnerProduct }; };
00121 template<> struct product_type_selector<1, 1, 1> { enum { ret = InnerProduct }; };
00122 template<> struct product_type_selector<Small,1, Small> { enum { ret = CoeffBasedProductMode }; };
00123 template<> struct product_type_selector<1, Small,Small> { enum { ret = CoeffBasedProductMode }; };
00124 template<> struct product_type_selector<Small,Small,Small> { enum { ret = CoeffBasedProductMode }; };
00125 template<> struct product_type_selector<Small, Small, 1> { enum { ret = LazyCoeffBasedProductMode }; };
00126 template<> struct product_type_selector<Small, Large, 1> { enum { ret = LazyCoeffBasedProductMode }; };
00127 template<> struct product_type_selector<Large, Small, 1> { enum { ret = LazyCoeffBasedProductMode }; };
00128 template<> struct product_type_selector<1, Large,Small> { enum { ret = CoeffBasedProductMode }; };
00129 template<> struct product_type_selector<1, Large,Large> { enum { ret = GemvProduct }; };
00130 template<> struct product_type_selector<1, Small,Large> { enum { ret = CoeffBasedProductMode }; };
00131 template<> struct product_type_selector<Large,1, Small> { enum { ret = CoeffBasedProductMode }; };
00132 template<> struct product_type_selector<Large,1, Large> { enum { ret = GemvProduct }; };
00133 template<> struct product_type_selector<Small,1, Large> { enum { ret = CoeffBasedProductMode }; };
00134 template<> struct product_type_selector<Small,Small,Large> { enum { ret = GemmProduct }; };
00135 template<> struct product_type_selector<Large,Small,Large> { enum { ret = GemmProduct }; };
00136 template<> struct product_type_selector<Small,Large,Large> { enum { ret = GemmProduct }; };
00137 template<> struct product_type_selector<Large,Large,Large> { enum { ret = GemmProduct }; };
00138 template<> struct product_type_selector<Large,Small,Small> { enum { ret = GemmProduct }; };
00139 template<> struct product_type_selector<Small,Large,Small> { enum { ret = GemmProduct }; };
00140 template<> struct product_type_selector<Large,Large,Small> { enum { ret = GemmProduct }; };
00141
00142 }
00143
00161 template<typename Lhs, typename Rhs, int ProductType>
00162 struct ProductReturnType
00163 {
00164
00165
00166
00167
00168 typedef GeneralProduct<Lhs, Rhs, ProductType> Type;
00169 };
00170
00171 template<typename Lhs, typename Rhs>
00172 struct ProductReturnType<Lhs,Rhs,CoeffBasedProductMode>
00173 {
00174 typedef typename internal::nested<Lhs, Rhs::ColsAtCompileTime, typename internal::plain_matrix_type<Lhs>::type >::type LhsNested;
00175 typedef typename internal::nested<Rhs, Lhs::RowsAtCompileTime, typename internal::plain_matrix_type<Rhs>::type >::type RhsNested;
00176 typedef CoeffBasedProduct<LhsNested, RhsNested, EvalBeforeAssigningBit | EvalBeforeNestingBit> Type;
00177 };
00178
00179 template<typename Lhs, typename Rhs>
00180 struct ProductReturnType<Lhs,Rhs,LazyCoeffBasedProductMode>
00181 {
00182 typedef typename internal::nested<Lhs, Rhs::ColsAtCompileTime, typename internal::plain_matrix_type<Lhs>::type >::type LhsNested;
00183 typedef typename internal::nested<Rhs, Lhs::RowsAtCompileTime, typename internal::plain_matrix_type<Rhs>::type >::type RhsNested;
00184 typedef CoeffBasedProduct<LhsNested, RhsNested, NestByRefBit> Type;
00185 };
00186
00187
00188 template<typename Lhs, typename Rhs>
00189 struct LazyProductReturnType : public ProductReturnType<Lhs,Rhs,LazyCoeffBasedProductMode>
00190 {};
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 namespace internal {
00204
00205 template<typename Lhs, typename Rhs>
00206 struct traits<GeneralProduct<Lhs,Rhs,InnerProduct> >
00207 : traits<Matrix<typename scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1> >
00208 {};
00209
00210 }
00211
00212 template<typename Lhs, typename Rhs>
00213 class GeneralProduct<Lhs, Rhs, InnerProduct>
00214 : internal::no_assignment_operator,
00215 public Matrix<typename internal::scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1>
00216 {
00217 typedef Matrix<typename internal::scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType,1,1> Base;
00218 public:
00219 GeneralProduct(const Lhs& lhs, const Rhs& rhs)
00220 {
00221 EIGEN_STATIC_ASSERT((internal::is_same<typename Lhs::RealScalar, typename Rhs::RealScalar>::value),
00222 YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
00223
00224 Base::coeffRef(0,0) = (lhs.transpose().cwiseProduct(rhs)).sum();
00225 }
00226
00228 operator const typename Base::Scalar() const {
00229 return Base::coeff(0,0);
00230 }
00231 };
00232
00233
00234
00235
00236
00237 namespace internal {
00238 template<int StorageOrder> struct outer_product_selector;
00239
00240 template<typename Lhs, typename Rhs>
00241 struct traits<GeneralProduct<Lhs,Rhs,OuterProduct> >
00242 : traits<ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs> >
00243 {};
00244
00245 }
00246
00247 template<typename Lhs, typename Rhs>
00248 class GeneralProduct<Lhs, Rhs, OuterProduct>
00249 : public ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs>
00250 {
00251 public:
00252 EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct)
00253
00254 GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
00255 {
00256 EIGEN_STATIC_ASSERT((internal::is_same<typename Lhs::RealScalar, typename Rhs::RealScalar>::value),
00257 YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
00258 }
00259
00260 template<typename Dest> void scaleAndAddTo(Dest& dest, Scalar alpha) const
00261 {
00262 internal::outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha);
00263 }
00264 };
00265
00266 namespace internal {
00267
00268 template<> struct outer_product_selector<ColMajor> {
00269 template<typename ProductType, typename Dest>
00270 static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) {
00271 typedef typename Dest::Index Index;
00272
00273
00274 const Index cols = dest.cols();
00275 for (Index j=0; j<cols; ++j)
00276 dest.col(j) += (alpha * prod.rhs().coeff(j)) * prod.lhs();
00277 }
00278 };
00279
00280 template<> struct outer_product_selector<RowMajor> {
00281 template<typename ProductType, typename Dest>
00282 static EIGEN_DONT_INLINE void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha) {
00283 typedef typename Dest::Index Index;
00284
00285
00286 const Index rows = dest.rows();
00287 for (Index i=0; i<rows; ++i)
00288 dest.row(i) += (alpha * prod.lhs().coeff(i)) * prod.rhs();
00289 }
00290 };
00291
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 namespace internal {
00306
00307 template<typename Lhs, typename Rhs>
00308 struct traits<GeneralProduct<Lhs,Rhs,GemvProduct> >
00309 : traits<ProductBase<GeneralProduct<Lhs,Rhs,GemvProduct>, Lhs, Rhs> >
00310 {};
00311
00312 template<int Side, int StorageOrder, bool BlasCompatible>
00313 struct gemv_selector;
00314
00315 }
00316
00317 template<typename Lhs, typename Rhs>
00318 class GeneralProduct<Lhs, Rhs, GemvProduct>
00319 : public ProductBase<GeneralProduct<Lhs,Rhs,GemvProduct>, Lhs, Rhs>
00320 {
00321 public:
00322 EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct)
00323
00324 typedef typename Lhs::Scalar LhsScalar;
00325 typedef typename Rhs::Scalar RhsScalar;
00326
00327 GeneralProduct(const Lhs& lhs, const Rhs& rhs) : Base(lhs,rhs)
00328 {
00329
00330
00331 }
00332
00333 enum { Side = Lhs::IsVectorAtCompileTime ? OnTheLeft : OnTheRight };
00334 typedef typename internal::conditional<int(Side)==OnTheRight,_LhsNested,_RhsNested>::type MatrixType;
00335
00336 template<typename Dest> void scaleAndAddTo(Dest& dst, Scalar alpha) const
00337 {
00338 eigen_assert(m_lhs.rows() == dst.rows() && m_rhs.cols() == dst.cols());
00339 internal::gemv_selector<Side,(int(MatrixType::Flags)&RowMajorBit) ? RowMajor : ColMajor,
00340 bool(internal::blas_traits<MatrixType>::HasUsableDirectAccess)>::run(*this, dst, alpha);
00341 }
00342 };
00343
00344 namespace internal {
00345
00346
00347 template<int StorageOrder, bool BlasCompatible>
00348 struct gemv_selector<OnTheLeft,StorageOrder,BlasCompatible>
00349 {
00350 template<typename ProductType, typename Dest>
00351 static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
00352 {
00353 Transpose<Dest> destT(dest);
00354 enum { OtherStorageOrder = StorageOrder == RowMajor ? ColMajor : RowMajor };
00355 gemv_selector<OnTheRight,OtherStorageOrder,BlasCompatible>
00356 ::run(GeneralProduct<Transpose<const typename ProductType::_RhsNested>,Transpose<const typename ProductType::_LhsNested>, GemvProduct>
00357 (prod.rhs().transpose(), prod.lhs().transpose()), destT, alpha);
00358 }
00359 };
00360
00361 template<typename Scalar,int Size,int MaxSize,bool Cond> struct gemv_static_vector_if;
00362
00363 template<typename Scalar,int Size,int MaxSize>
00364 struct gemv_static_vector_if<Scalar,Size,MaxSize,false>
00365 {
00366 EIGEN_STRONG_INLINE Scalar* data() { eigen_internal_assert(false && "should never be called"); return 0; }
00367 };
00368
00369 template<typename Scalar,int Size>
00370 struct gemv_static_vector_if<Scalar,Size,Dynamic,true>
00371 {
00372 EIGEN_STRONG_INLINE Scalar* data() { return 0; }
00373 };
00374
00375 template<typename Scalar,int Size,int MaxSize>
00376 struct gemv_static_vector_if<Scalar,Size,MaxSize,true>
00377 {
00378 #if EIGEN_ALIGN_STATICALLY
00379 internal::plain_array<Scalar,EIGEN_SIZE_MIN_PREFER_FIXED(Size,MaxSize),0> m_data;
00380 EIGEN_STRONG_INLINE Scalar* data() { return m_data.array; }
00381 #else
00382
00383
00384 enum {
00385 ForceAlignment = internal::packet_traits<Scalar>::Vectorizable,
00386 PacketSize = internal::packet_traits<Scalar>::size
00387 };
00388 internal::plain_array<Scalar,EIGEN_SIZE_MIN_PREFER_FIXED(Size,MaxSize)+(ForceAlignment?PacketSize:0),0> m_data;
00389 EIGEN_STRONG_INLINE Scalar* data() {
00390 return ForceAlignment
00391 ? reinterpret_cast<Scalar*>((reinterpret_cast<size_t>(m_data.array) & ~(size_t(15))) + 16)
00392 : m_data.array;
00393 }
00394 #endif
00395 };
00396
00397 template<> struct gemv_selector<OnTheRight,ColMajor,true>
00398 {
00399 template<typename ProductType, typename Dest>
00400 static inline void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
00401 {
00402 typedef typename ProductType::Index Index;
00403 typedef typename ProductType::LhsScalar LhsScalar;
00404 typedef typename ProductType::RhsScalar RhsScalar;
00405 typedef typename ProductType::Scalar ResScalar;
00406 typedef typename ProductType::RealScalar RealScalar;
00407 typedef typename ProductType::ActualLhsType ActualLhsType;
00408 typedef typename ProductType::ActualRhsType ActualRhsType;
00409 typedef typename ProductType::LhsBlasTraits LhsBlasTraits;
00410 typedef typename ProductType::RhsBlasTraits RhsBlasTraits;
00411 typedef Map<Matrix<ResScalar,Dynamic,1>, Aligned> MappedDest;
00412
00413 const ActualLhsType actualLhs = LhsBlasTraits::extract(prod.lhs());
00414 const ActualRhsType actualRhs = RhsBlasTraits::extract(prod.rhs());
00415
00416 ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs())
00417 * RhsBlasTraits::extractScalarFactor(prod.rhs());
00418
00419 enum {
00420
00421
00422 EvalToDestAtCompileTime = Dest::InnerStrideAtCompileTime==1,
00423 ComplexByReal = (NumTraits<LhsScalar>::IsComplex) && (!NumTraits<RhsScalar>::IsComplex),
00424 MightCannotUseDest = (Dest::InnerStrideAtCompileTime!=1) || ComplexByReal
00425 };
00426
00427 gemv_static_vector_if<ResScalar,Dest::SizeAtCompileTime,Dest::MaxSizeAtCompileTime,MightCannotUseDest> static_dest;
00428
00429
00430 bool alphaIsCompatible = (!ComplexByReal) ? true : (imag(actualAlpha)==RealScalar(0));
00431 bool evalToDest = EvalToDestAtCompileTime && alphaIsCompatible;
00432
00433 RhsScalar compatibleAlpha = get_factor<ResScalar,RhsScalar>::run(actualAlpha);
00434
00435 ei_declare_aligned_stack_constructed_variable(ResScalar,actualDestPtr,dest.size(),
00436 evalToDest ? dest.data() : static_dest.data());
00437
00438 if(!evalToDest)
00439 {
00440 #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN
00441 int size = dest.size();
00442 EIGEN_DENSE_STORAGE_CTOR_PLUGIN
00443 #endif
00444 if(!alphaIsCompatible)
00445 {
00446 MappedDest(actualDestPtr, dest.size()).setZero();
00447 compatibleAlpha = RhsScalar(1);
00448 }
00449 else
00450 MappedDest(actualDestPtr, dest.size()) = dest;
00451 }
00452
00453 general_matrix_vector_product
00454 <Index,LhsScalar,ColMajor,LhsBlasTraits::NeedToConjugate,RhsScalar,RhsBlasTraits::NeedToConjugate>::run(
00455 actualLhs.rows(), actualLhs.cols(),
00456 &actualLhs.coeffRef(0,0), actualLhs.outerStride(),
00457 actualRhs.data(), actualRhs.innerStride(),
00458 actualDestPtr, 1,
00459 compatibleAlpha);
00460
00461 if (!evalToDest)
00462 {
00463 if(!alphaIsCompatible)
00464 dest += actualAlpha * MappedDest(actualDestPtr, dest.size());
00465 else
00466 dest = MappedDest(actualDestPtr, dest.size());
00467 }
00468 }
00469 };
00470
00471 template<> struct gemv_selector<OnTheRight,RowMajor,true>
00472 {
00473 template<typename ProductType, typename Dest>
00474 static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
00475 {
00476 typedef typename ProductType::LhsScalar LhsScalar;
00477 typedef typename ProductType::RhsScalar RhsScalar;
00478 typedef typename ProductType::Scalar ResScalar;
00479 typedef typename ProductType::Index Index;
00480 typedef typename ProductType::ActualLhsType ActualLhsType;
00481 typedef typename ProductType::ActualRhsType ActualRhsType;
00482 typedef typename ProductType::_ActualRhsType _ActualRhsType;
00483 typedef typename ProductType::LhsBlasTraits LhsBlasTraits;
00484 typedef typename ProductType::RhsBlasTraits RhsBlasTraits;
00485
00486 typename add_const<ActualLhsType>::type actualLhs = LhsBlasTraits::extract(prod.lhs());
00487 typename add_const<ActualRhsType>::type actualRhs = RhsBlasTraits::extract(prod.rhs());
00488
00489 ResScalar actualAlpha = alpha * LhsBlasTraits::extractScalarFactor(prod.lhs())
00490 * RhsBlasTraits::extractScalarFactor(prod.rhs());
00491
00492 enum {
00493
00494
00495 DirectlyUseRhs = _ActualRhsType::InnerStrideAtCompileTime==1
00496 };
00497
00498 gemv_static_vector_if<RhsScalar,_ActualRhsType::SizeAtCompileTime,_ActualRhsType::MaxSizeAtCompileTime,!DirectlyUseRhs> static_rhs;
00499
00500 ei_declare_aligned_stack_constructed_variable(RhsScalar,actualRhsPtr,actualRhs.size(),
00501 DirectlyUseRhs ? const_cast<RhsScalar*>(actualRhs.data()) : static_rhs.data());
00502
00503 if(!DirectlyUseRhs)
00504 {
00505 #ifdef EIGEN_DENSE_STORAGE_CTOR_PLUGIN
00506 int size = actualRhs.size();
00507 EIGEN_DENSE_STORAGE_CTOR_PLUGIN
00508 #endif
00509 Map<typename _ActualRhsType::PlainObject>(actualRhsPtr, actualRhs.size()) = actualRhs;
00510 }
00511
00512 general_matrix_vector_product
00513 <Index,LhsScalar,RowMajor,LhsBlasTraits::NeedToConjugate,RhsScalar,RhsBlasTraits::NeedToConjugate>::run(
00514 actualLhs.rows(), actualLhs.cols(),
00515 &actualLhs.coeffRef(0,0), actualLhs.outerStride(),
00516 actualRhsPtr, 1,
00517 &dest.coeffRef(0,0), dest.innerStride(),
00518 actualAlpha);
00519 }
00520 };
00521
00522 template<> struct gemv_selector<OnTheRight,ColMajor,false>
00523 {
00524 template<typename ProductType, typename Dest>
00525 static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
00526 {
00527 typedef typename Dest::Index Index;
00528
00529 const Index size = prod.rhs().rows();
00530 for(Index k=0; k<size; ++k)
00531 dest += (alpha*prod.rhs().coeff(k)) * prod.lhs().col(k);
00532 }
00533 };
00534
00535 template<> struct gemv_selector<OnTheRight,RowMajor,false>
00536 {
00537 template<typename ProductType, typename Dest>
00538 static void run(const ProductType& prod, Dest& dest, typename ProductType::Scalar alpha)
00539 {
00540 typedef typename Dest::Index Index;
00541
00542 const Index rows = prod.rows();
00543 for(Index i=0; i<rows; ++i)
00544 dest.coeffRef(i) += alpha * (prod.lhs().row(i).cwiseProduct(prod.rhs().transpose())).sum();
00545 }
00546 };
00547
00548 }
00549
00550
00551
00552
00553
00560 template<typename Derived>
00561 template<typename OtherDerived>
00562 inline const typename ProductReturnType<Derived,OtherDerived>::Type
00563 MatrixBase<Derived>::operator*(const MatrixBase<OtherDerived> &other) const
00564 {
00565
00566
00567
00568
00569 enum {
00570 ProductIsValid = Derived::ColsAtCompileTime==Dynamic
00571 || OtherDerived::RowsAtCompileTime==Dynamic
00572 || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime),
00573 AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime,
00574 SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived)
00575 };
00576
00577
00578
00579 EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes),
00580 INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS)
00581 EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors),
00582 INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION)
00583 EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT)
00584 #ifdef EIGEN_DEBUG_PRODUCT
00585 internal::product_type<Derived,OtherDerived>::debug();
00586 #endif
00587 return typename ProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived());
00588 }
00589
00601 template<typename Derived>
00602 template<typename OtherDerived>
00603 const typename LazyProductReturnType<Derived,OtherDerived>::Type
00604 MatrixBase<Derived>::lazyProduct(const MatrixBase<OtherDerived> &other) const
00605 {
00606 enum {
00607 ProductIsValid = Derived::ColsAtCompileTime==Dynamic
00608 || OtherDerived::RowsAtCompileTime==Dynamic
00609 || int(Derived::ColsAtCompileTime)==int(OtherDerived::RowsAtCompileTime),
00610 AreVectors = Derived::IsVectorAtCompileTime && OtherDerived::IsVectorAtCompileTime,
00611 SameSizes = EIGEN_PREDICATE_SAME_MATRIX_SIZE(Derived,OtherDerived)
00612 };
00613
00614
00615
00616 EIGEN_STATIC_ASSERT(ProductIsValid || !(AreVectors && SameSizes),
00617 INVALID_VECTOR_VECTOR_PRODUCT__IF_YOU_WANTED_A_DOT_OR_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTIONS)
00618 EIGEN_STATIC_ASSERT(ProductIsValid || !(SameSizes && !AreVectors),
00619 INVALID_MATRIX_PRODUCT__IF_YOU_WANTED_A_COEFF_WISE_PRODUCT_YOU_MUST_USE_THE_EXPLICIT_FUNCTION)
00620 EIGEN_STATIC_ASSERT(ProductIsValid || SameSizes, INVALID_MATRIX_PRODUCT)
00621
00622 return typename LazyProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived());
00623 }
00624
00625 #endif // EIGEN_PRODUCT_H