CoeffBasedProduct.h
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
00005 // Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr>
00006 //
00007 // This Source Code Form is subject to the terms of the Mozilla
00008 // Public License v. 2.0. If a copy of the MPL was not distributed
00009 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00010 
00011 #ifndef EIGEN_COEFFBASED_PRODUCT_H
00012 #define EIGEN_COEFFBASED_PRODUCT_H
00013 
00014 namespace Eigen { 
00015 
00016 namespace internal {
00017 
00018 /*********************************************************************************
00019 *  Coefficient based product implementation.
00020 *  It is designed for the following use cases:
00021 *  - small fixed sizes
00022 *  - lazy products
00023 *********************************************************************************/
00024 
00025 /* Since the all the dimensions of the product are small, here we can rely
00026  * on the generic Assign mechanism to evaluate the product per coeff (or packet).
00027  *
00028  * Note that here the inner-loops should always be unrolled.
00029  */
00030 
00031 template<int Traversal, int UnrollingIndex, typename Lhs, typename Rhs, typename RetScalar>
00032 struct product_coeff_impl;
00033 
00034 template<int StorageOrder, int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, int LoadMode>
00035 struct product_packet_impl;
00036 
00037 template<typename LhsNested, typename RhsNested, int NestingFlags>
00038 struct traits<CoeffBasedProduct<LhsNested,RhsNested,NestingFlags> >
00039 {
00040   typedef MatrixXpr XprKind;
00041   typedef typename remove_all<LhsNested>::type _LhsNested;
00042   typedef typename remove_all<RhsNested>::type _RhsNested;
00043   typedef typename scalar_product_traits<typename _LhsNested::Scalar, typename _RhsNested::Scalar>::ReturnType Scalar;
00044   typedef typename promote_storage_type<typename traits<_LhsNested>::StorageKind,
00045                                            typename traits<_RhsNested>::StorageKind>::ret StorageKind;
00046   typedef typename promote_index_type<typename traits<_LhsNested>::Index,
00047                                          typename traits<_RhsNested>::Index>::type Index;
00048 
00049   enum {
00050       LhsCoeffReadCost = _LhsNested::CoeffReadCost,
00051       RhsCoeffReadCost = _RhsNested::CoeffReadCost,
00052       LhsFlags = _LhsNested::Flags,
00053       RhsFlags = _RhsNested::Flags,
00054 
00055       RowsAtCompileTime = _LhsNested::RowsAtCompileTime,
00056       ColsAtCompileTime = _RhsNested::ColsAtCompileTime,
00057       InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(_LhsNested::ColsAtCompileTime, _RhsNested::RowsAtCompileTime),
00058 
00059       MaxRowsAtCompileTime = _LhsNested::MaxRowsAtCompileTime,
00060       MaxColsAtCompileTime = _RhsNested::MaxColsAtCompileTime,
00061 
00062       LhsRowMajor = LhsFlags & RowMajorBit,
00063       RhsRowMajor = RhsFlags & RowMajorBit,
00064 
00065       SameType = is_same<typename _LhsNested::Scalar,typename _RhsNested::Scalar>::value,
00066 
00067       CanVectorizeRhs = RhsRowMajor && (RhsFlags & PacketAccessBit)
00068                       && (ColsAtCompileTime == Dynamic
00069                           || ( (ColsAtCompileTime % packet_traits<Scalar>::size) == 0
00070                               && (RhsFlags&AlignedBit)
00071                              )
00072                          ),
00073 
00074       CanVectorizeLhs = (!LhsRowMajor) && (LhsFlags & PacketAccessBit)
00075                       && (RowsAtCompileTime == Dynamic
00076                           || ( (RowsAtCompileTime % packet_traits<Scalar>::size) == 0
00077                               && (LhsFlags&AlignedBit)
00078                              )
00079                          ),
00080 
00081       EvalToRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1
00082                      : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0
00083                      : (RhsRowMajor && !CanVectorizeLhs),
00084 
00085       Flags = ((unsigned int)(LhsFlags | RhsFlags) & HereditaryBits & ~RowMajorBit)
00086             | (EvalToRowMajor ? RowMajorBit : 0)
00087             | NestingFlags
00088             | (LhsFlags & RhsFlags & AlignedBit)
00089             // TODO enable vectorization for mixed types
00090             | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0),
00091 
00092       CoeffReadCost = InnerSize == Dynamic ? Dynamic
00093                     : InnerSize == 0 ? 0
00094                     : InnerSize * (NumTraits<Scalar>::MulCost + LhsCoeffReadCost + RhsCoeffReadCost)
00095                       + (InnerSize - 1) * NumTraits<Scalar>::AddCost,
00096 
00097       /* CanVectorizeInner deserves special explanation. It does not affect the product flags. It is not used outside
00098       * of Product. If the Product itself is not a packet-access expression, there is still a chance that the inner
00099       * loop of the product might be vectorized. This is the meaning of CanVectorizeInner. Since it doesn't affect
00100       * the Flags, it is safe to make this value depend on ActualPacketAccessBit, that doesn't affect the ABI.
00101       */
00102       CanVectorizeInner =    SameType
00103                           && LhsRowMajor
00104                           && (!RhsRowMajor)
00105                           && (LhsFlags & RhsFlags & ActualPacketAccessBit)
00106                           && (LhsFlags & RhsFlags & AlignedBit)
00107                           && (InnerSize % packet_traits<Scalar>::size == 0)
00108     };
00109 };
00110 
00111 } // end namespace internal
00112 
00113 template<typename LhsNested, typename RhsNested, int NestingFlags>
00114 class CoeffBasedProduct
00115   : internal::no_assignment_operator,
00116     public MatrixBase<CoeffBasedProduct<LhsNested, RhsNested, NestingFlags> >
00117 {
00118   public:
00119 
00120     typedef MatrixBase<CoeffBasedProduct> Base;
00121     EIGEN_DENSE_PUBLIC_INTERFACE(CoeffBasedProduct)
00122     typedef typename Base::PlainObject PlainObject;
00123 
00124   private:
00125 
00126     typedef typename internal::traits<CoeffBasedProduct>::_LhsNested _LhsNested;
00127     typedef typename internal::traits<CoeffBasedProduct>::_RhsNested _RhsNested;
00128 
00129     enum {
00130       PacketSize = internal::packet_traits<Scalar>::size,
00131       InnerSize  = internal::traits<CoeffBasedProduct>::InnerSize,
00132       Unroll = CoeffReadCost != Dynamic && CoeffReadCost <= EIGEN_UNROLLING_LIMIT,
00133       CanVectorizeInner = internal::traits<CoeffBasedProduct>::CanVectorizeInner
00134     };
00135 
00136     typedef internal::product_coeff_impl<CanVectorizeInner ? InnerVectorizedTraversal : DefaultTraversal,
00137                                    Unroll ? InnerSize : Dynamic,
00138                                    _LhsNested, _RhsNested, Scalar> ScalarCoeffImpl;
00139 
00140     typedef CoeffBasedProduct<LhsNested,RhsNested,NestByRefBit> LazyCoeffBasedProductType;
00141 
00142   public:
00143 
00144     inline CoeffBasedProduct(const CoeffBasedProduct& other)
00145       : Base(), m_lhs(other.m_lhs), m_rhs(other.m_rhs)
00146     {}
00147 
00148     template<typename Lhs, typename Rhs>
00149     inline CoeffBasedProduct(const Lhs& lhs, const Rhs& rhs)
00150       : m_lhs(lhs), m_rhs(rhs)
00151     {
00152       // we don't allow taking products of matrices of different real types, as that wouldn't be vectorizable.
00153       // We still allow to mix T and complex<T>.
00154       EIGEN_STATIC_ASSERT((internal::scalar_product_traits<typename Lhs::RealScalar, typename Rhs::RealScalar>::Defined),
00155         YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
00156       eigen_assert(lhs.cols() == rhs.rows()
00157         && "invalid matrix product"
00158         && "if you wanted a coeff-wise or a dot product use the respective explicit functions");
00159     }
00160 
00161     EIGEN_STRONG_INLINE Index rows() const { return m_lhs.rows(); }
00162     EIGEN_STRONG_INLINE Index cols() const { return m_rhs.cols(); }
00163 
00164     EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const
00165     {
00166       Scalar res;
00167       ScalarCoeffImpl::run(row, col, m_lhs, m_rhs, res);
00168       return res;
00169     }
00170 
00171     /* Allow index-based non-packet access. It is impossible though to allow index-based packed access,
00172      * which is why we don't set the LinearAccessBit.
00173      */
00174     EIGEN_STRONG_INLINE const Scalar coeff(Index index) const
00175     {
00176       Scalar res;
00177       const Index row = RowsAtCompileTime == 1 ? 0 : index;
00178       const Index col = RowsAtCompileTime == 1 ? index : 0;
00179       ScalarCoeffImpl::run(row, col, m_lhs, m_rhs, res);
00180       return res;
00181     }
00182 
00183     template<int LoadMode>
00184     EIGEN_STRONG_INLINE const PacketScalar packet(Index row, Index col) const
00185     {
00186       PacketScalar res;
00187       internal::product_packet_impl<Flags&RowMajorBit ? RowMajor : ColMajor,
00188                               Unroll ? InnerSize : Dynamic,
00189                               _LhsNested, _RhsNested, PacketScalar, LoadMode>
00190         ::run(row, col, m_lhs, m_rhs, res);
00191       return res;
00192     }
00193 
00194     // Implicit conversion to the nested type (trigger the evaluation of the product)
00195     EIGEN_STRONG_INLINE operator const PlainObject& () const
00196     {
00197       m_result.lazyAssign(*this);
00198       return m_result;
00199     }
00200 
00201     const _LhsNested& lhs() const { return m_lhs; }
00202     const _RhsNested& rhs() const { return m_rhs; }
00203 
00204     const Diagonal<const LazyCoeffBasedProductType,0> diagonal() const
00205     { return reinterpret_cast<const LazyCoeffBasedProductType&>(*this); }
00206 
00207     template<int DiagonalIndex>
00208     const Diagonal<const LazyCoeffBasedProductType,DiagonalIndex> diagonal() const
00209     { return reinterpret_cast<const LazyCoeffBasedProductType&>(*this); }
00210 
00211     const Diagonal<const LazyCoeffBasedProductType,Dynamic> diagonal(Index index) const
00212     { return reinterpret_cast<const LazyCoeffBasedProductType&>(*this).diagonal(index); }
00213 
00214   protected:
00215     typename internal::add_const_on_value_type<LhsNested>::type m_lhs;
00216     typename internal::add_const_on_value_type<RhsNested>::type m_rhs;
00217 
00218     mutable PlainObject m_result;
00219 };
00220 
00221 namespace internal {
00222 
00223 // here we need to overload the nested rule for products
00224 // such that the nested type is a const reference to a plain matrix
00225 template<typename Lhs, typename Rhs, int N, typename PlainObject>
00226 struct nested<CoeffBasedProduct<Lhs,Rhs,EvalBeforeNestingBit|EvalBeforeAssigningBit>, N, PlainObject>
00227 {
00228   typedef PlainObject const& type;
00229 };
00230 
00231 /***************************************************************************
00232 * Normal product .coeff() implementation (with meta-unrolling)
00233 ***************************************************************************/
00234 
00235 /**************************************
00236 *** Scalar path  - no vectorization ***
00237 **************************************/
00238 
00239 template<int UnrollingIndex, typename Lhs, typename Rhs, typename RetScalar>
00240 struct product_coeff_impl<DefaultTraversal, UnrollingIndex, Lhs, Rhs, RetScalar>
00241 {
00242   typedef typename Lhs::Index Index;
00243   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res)
00244   {
00245     product_coeff_impl<DefaultTraversal, UnrollingIndex-1, Lhs, Rhs, RetScalar>::run(row, col, lhs, rhs, res);
00246     res += lhs.coeff(row, UnrollingIndex-1) * rhs.coeff(UnrollingIndex-1, col);
00247   }
00248 };
00249 
00250 template<typename Lhs, typename Rhs, typename RetScalar>
00251 struct product_coeff_impl<DefaultTraversal, 1, Lhs, Rhs, RetScalar>
00252 {
00253   typedef typename Lhs::Index Index;
00254   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res)
00255   {
00256     res = lhs.coeff(row, 0) * rhs.coeff(0, col);
00257   }
00258 };
00259 
00260 template<typename Lhs, typename Rhs, typename RetScalar>
00261 struct product_coeff_impl<DefaultTraversal, 0, Lhs, Rhs, RetScalar>
00262 {
00263   typedef typename Lhs::Index Index;
00264   static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, RetScalar &res)
00265   {
00266     res = RetScalar(0);
00267   }
00268 };
00269 
00270 template<typename Lhs, typename Rhs, typename RetScalar>
00271 struct product_coeff_impl<DefaultTraversal, Dynamic, Lhs, Rhs, RetScalar>
00272 {
00273   typedef typename Lhs::Index Index;
00274   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar& res)
00275   {
00276     res = (lhs.row(row).transpose().cwiseProduct( rhs.col(col) )).sum();
00277   }
00278 };
00279 
00280 /*******************************************
00281 *** Scalar path with inner vectorization ***
00282 *******************************************/
00283 
00284 template<int UnrollingIndex, typename Lhs, typename Rhs, typename Packet>
00285 struct product_coeff_vectorized_unroller
00286 {
00287   typedef typename Lhs::Index Index;
00288   enum { PacketSize = packet_traits<typename Lhs::Scalar>::size };
00289   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::PacketScalar &pres)
00290   {
00291     product_coeff_vectorized_unroller<UnrollingIndex-PacketSize, Lhs, Rhs, Packet>::run(row, col, lhs, rhs, pres);
00292     pres = padd(pres, pmul( lhs.template packet<Aligned>(row, UnrollingIndex) , rhs.template packet<Aligned>(UnrollingIndex, col) ));
00293   }
00294 };
00295 
00296 template<typename Lhs, typename Rhs, typename Packet>
00297 struct product_coeff_vectorized_unroller<0, Lhs, Rhs, Packet>
00298 {
00299   typedef typename Lhs::Index Index;
00300   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::PacketScalar &pres)
00301   {
00302     pres = pmul(lhs.template packet<Aligned>(row, 0) , rhs.template packet<Aligned>(0, col));
00303   }
00304 };
00305 
00306 template<typename Lhs, typename Rhs, typename RetScalar>
00307 struct product_coeff_impl<InnerVectorizedTraversal, 0, Lhs, Rhs, RetScalar>
00308 {
00309   typedef typename Lhs::Index Index;
00310   static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, RetScalar &res)
00311   {
00312     res = 0;
00313   }
00314 };
00315 
00316 template<int UnrollingIndex, typename Lhs, typename Rhs, typename RetScalar>
00317 struct product_coeff_impl<InnerVectorizedTraversal, UnrollingIndex, Lhs, Rhs, RetScalar>
00318 {
00319   typedef typename Lhs::PacketScalar Packet;
00320   typedef typename Lhs::Index Index;
00321   enum { PacketSize = packet_traits<typename Lhs::Scalar>::size };
00322   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res)
00323   {
00324     Packet pres;
00325     product_coeff_vectorized_unroller<UnrollingIndex-PacketSize, Lhs, Rhs, Packet>::run(row, col, lhs, rhs, pres);
00326     res = predux(pres);
00327   }
00328 };
00329 
00330 template<typename Lhs, typename Rhs, int LhsRows = Lhs::RowsAtCompileTime, int RhsCols = Rhs::ColsAtCompileTime>
00331 struct product_coeff_vectorized_dyn_selector
00332 {
00333   typedef typename Lhs::Index Index;
00334   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res)
00335   {
00336     res = lhs.row(row).transpose().cwiseProduct(rhs.col(col)).sum();
00337   }
00338 };
00339 
00340 // NOTE the 3 following specializations are because taking .col(0) on a vector is a bit slower
00341 // NOTE maybe they are now useless since we have a specialization for Block<Matrix>
00342 template<typename Lhs, typename Rhs, int RhsCols>
00343 struct product_coeff_vectorized_dyn_selector<Lhs,Rhs,1,RhsCols>
00344 {
00345   typedef typename Lhs::Index Index;
00346   static EIGEN_STRONG_INLINE void run(Index /*row*/, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res)
00347   {
00348     res = lhs.transpose().cwiseProduct(rhs.col(col)).sum();
00349   }
00350 };
00351 
00352 template<typename Lhs, typename Rhs, int LhsRows>
00353 struct product_coeff_vectorized_dyn_selector<Lhs,Rhs,LhsRows,1>
00354 {
00355   typedef typename Lhs::Index Index;
00356   static EIGEN_STRONG_INLINE void run(Index row, Index /*col*/, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res)
00357   {
00358     res = lhs.row(row).transpose().cwiseProduct(rhs).sum();
00359   }
00360 };
00361 
00362 template<typename Lhs, typename Rhs>
00363 struct product_coeff_vectorized_dyn_selector<Lhs,Rhs,1,1>
00364 {
00365   typedef typename Lhs::Index Index;
00366   static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res)
00367   {
00368     res = lhs.transpose().cwiseProduct(rhs).sum();
00369   }
00370 };
00371 
00372 template<typename Lhs, typename Rhs, typename RetScalar>
00373 struct product_coeff_impl<InnerVectorizedTraversal, Dynamic, Lhs, Rhs, RetScalar>
00374 {
00375   typedef typename Lhs::Index Index;
00376   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, typename Lhs::Scalar &res)
00377   {
00378     product_coeff_vectorized_dyn_selector<Lhs,Rhs>::run(row, col, lhs, rhs, res);
00379   }
00380 };
00381 
00382 /*******************
00383 *** Packet path  ***
00384 *******************/
00385 
00386 template<int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, int LoadMode>
00387 struct product_packet_impl<RowMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode>
00388 {
00389   typedef typename Lhs::Index Index;
00390   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res)
00391   {
00392     product_packet_impl<RowMajor, UnrollingIndex-1, Lhs, Rhs, Packet, LoadMode>::run(row, col, lhs, rhs, res);
00393     res =  pmadd(pset1<Packet>(lhs.coeff(row, UnrollingIndex-1)), rhs.template packet<LoadMode>(UnrollingIndex-1, col), res);
00394   }
00395 };
00396 
00397 template<int UnrollingIndex, typename Lhs, typename Rhs, typename Packet, int LoadMode>
00398 struct product_packet_impl<ColMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode>
00399 {
00400   typedef typename Lhs::Index Index;
00401   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res)
00402   {
00403     product_packet_impl<ColMajor, UnrollingIndex-1, Lhs, Rhs, Packet, LoadMode>::run(row, col, lhs, rhs, res);
00404     res =  pmadd(lhs.template packet<LoadMode>(row, UnrollingIndex-1), pset1<Packet>(rhs.coeff(UnrollingIndex-1, col)), res);
00405   }
00406 };
00407 
00408 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
00409 struct product_packet_impl<RowMajor, 1, Lhs, Rhs, Packet, LoadMode>
00410 {
00411   typedef typename Lhs::Index Index;
00412   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res)
00413   {
00414     res = pmul(pset1<Packet>(lhs.coeff(row, 0)),rhs.template packet<LoadMode>(0, col));
00415   }
00416 };
00417 
00418 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
00419 struct product_packet_impl<ColMajor, 1, Lhs, Rhs, Packet, LoadMode>
00420 {
00421   typedef typename Lhs::Index Index;
00422   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res)
00423   {
00424     res = pmul(lhs.template packet<LoadMode>(row, 0), pset1<Packet>(rhs.coeff(0, col)));
00425   }
00426 };
00427 
00428 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
00429 struct product_packet_impl<RowMajor, 0, Lhs, Rhs, Packet, LoadMode>
00430 {
00431   typedef typename Lhs::Index Index;
00432   static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Packet &res)
00433   {
00434     res = pset1<Packet>(0);
00435   }
00436 };
00437 
00438 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
00439 struct product_packet_impl<ColMajor, 0, Lhs, Rhs, Packet, LoadMode>
00440 {
00441   typedef typename Lhs::Index Index;
00442   static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Packet &res)
00443   {
00444     res = pset1<Packet>(0);
00445   }
00446 };
00447 
00448 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
00449 struct product_packet_impl<RowMajor, Dynamic, Lhs, Rhs, Packet, LoadMode>
00450 {
00451   typedef typename Lhs::Index Index;
00452   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res)
00453   {
00454     res = pset1<Packet>(0);
00455     for(Index i = 0; i < lhs.cols(); ++i)
00456       res =  pmadd(pset1<Packet>(lhs.coeff(row, i)), rhs.template packet<LoadMode>(i, col), res);
00457   }
00458 };
00459 
00460 template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
00461 struct product_packet_impl<ColMajor, Dynamic, Lhs, Rhs, Packet, LoadMode>
00462 {
00463   typedef typename Lhs::Index Index;
00464   static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res)
00465   {
00466     res = pset1<Packet>(0);
00467     for(Index i = 0; i < lhs.cols(); ++i)
00468       res =  pmadd(lhs.template packet<LoadMode>(row, i), pset1<Packet>(rhs.coeff(i, col)), res);
00469   }
00470 };
00471 
00472 } // end namespace internal
00473 
00474 } // end namespace Eigen
00475 
00476 #endif // EIGEN_COEFFBASED_PRODUCT_H


turtlebot_exploration_3d
Author(s): Bona , Shawn
autogenerated on Thu Jun 6 2019 20:57:51