CwiseBinaryOp.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) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
00005 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
00006 //
00007 // Eigen is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU Lesser General Public
00009 // License as published by the Free Software Foundation; either
00010 // version 3 of the License, or (at your option) any later version.
00011 //
00012 // Alternatively, you can redistribute it and/or
00013 // modify it under the terms of the GNU General Public License as
00014 // published by the Free Software Foundation; either version 2 of
00015 // the License, or (at your option) any later version.
00016 //
00017 // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
00018 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00019 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
00020 // GNU General Public License for more details.
00021 //
00022 // You should have received a copy of the GNU Lesser General Public
00023 // License and a copy of the GNU General Public License along with
00024 // Eigen. If not, see <http://www.gnu.org/licenses/>.
00025 
00026 #ifndef EIGEN_CWISE_BINARY_OP_H
00027 #define EIGEN_CWISE_BINARY_OP_H
00028 
00029 namespace Eigen {
00030 
00051 namespace internal {
00052 template<typename BinaryOp, typename Lhs, typename Rhs>
00053 struct traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >
00054 {
00055   // we must not inherit from traits<Lhs> since it has
00056   // the potential to cause problems with MSVC
00057   typedef typename remove_all<Lhs>::type Ancestor;
00058   typedef typename traits<Ancestor>::XprKind XprKind;
00059   enum {
00060     RowsAtCompileTime = traits<Ancestor>::RowsAtCompileTime,
00061     ColsAtCompileTime = traits<Ancestor>::ColsAtCompileTime,
00062     MaxRowsAtCompileTime = traits<Ancestor>::MaxRowsAtCompileTime,
00063     MaxColsAtCompileTime = traits<Ancestor>::MaxColsAtCompileTime
00064   };
00065 
00066   // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor),
00067   // we still want to handle the case when the result type is different.
00068   typedef typename result_of<
00069                      BinaryOp(
00070                        typename Lhs::Scalar,
00071                        typename Rhs::Scalar
00072                      )
00073                    >::type Scalar;
00074   typedef typename promote_storage_type<typename traits<Lhs>::StorageKind,
00075                                            typename traits<Rhs>::StorageKind>::ret StorageKind;
00076   typedef typename promote_index_type<typename traits<Lhs>::Index,
00077                                          typename traits<Rhs>::Index>::type Index;
00078   typedef typename Lhs::Nested LhsNested;
00079   typedef typename Rhs::Nested RhsNested;
00080   typedef typename remove_reference<LhsNested>::type _LhsNested;
00081   typedef typename remove_reference<RhsNested>::type _RhsNested;
00082   enum {
00083     LhsCoeffReadCost = _LhsNested::CoeffReadCost,
00084     RhsCoeffReadCost = _RhsNested::CoeffReadCost,
00085     LhsFlags = _LhsNested::Flags,
00086     RhsFlags = _RhsNested::Flags,
00087     SameType = is_same<typename _LhsNested::Scalar,typename _RhsNested::Scalar>::value,
00088     StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit),
00089     Flags0 = (int(LhsFlags) | int(RhsFlags)) & (
00090         HereditaryBits
00091       | (int(LhsFlags) & int(RhsFlags) &
00092            ( AlignedBit
00093            | (StorageOrdersAgree ? LinearAccessBit : 0)
00094            | (functor_traits<BinaryOp>::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0)
00095            )
00096         )
00097      ),
00098     Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit),
00099     CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits<BinaryOp>::Cost
00100   };
00101 };
00102 } // end namespace internal
00103 
00104 // we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor
00105 // that would take two operands of different types. If there were such an example, then this check should be
00106 // moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as
00107 // currently they take only one typename Scalar template parameter.
00108 // It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths.
00109 // So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to
00110 // add together a float matrix and a double matrix.
00111 #define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \
00112   EIGEN_STATIC_ASSERT((internal::functor_allows_mixing_real_and_complex<BINOP>::ret \
00113                         ? int(internal::is_same<typename NumTraits<LHS>::Real, typename NumTraits<RHS>::Real>::value) \
00114                         : int(internal::is_same<LHS, RHS>::value)), \
00115     YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
00116 
00117 template<typename BinaryOp, typename Lhs, typename Rhs, typename StorageKind>
00118 class CwiseBinaryOpImpl;
00119 
00120 template<typename BinaryOp, typename Lhs, typename Rhs>
00121 class CwiseBinaryOp : internal::no_assignment_operator,
00122   public CwiseBinaryOpImpl<
00123           BinaryOp, Lhs, Rhs,
00124           typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind,
00125                                            typename internal::traits<Rhs>::StorageKind>::ret>
00126 {
00127   public:
00128 
00129     typedef typename CwiseBinaryOpImpl<
00130         BinaryOp, Lhs, Rhs,
00131         typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind,
00132                                          typename internal::traits<Rhs>::StorageKind>::ret>::Base Base;
00133     EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp)
00134 
00135     typedef typename internal::nested<Lhs>::type LhsNested;
00136     typedef typename internal::nested<Rhs>::type RhsNested;
00137     typedef typename internal::remove_reference<LhsNested>::type _LhsNested;
00138     typedef typename internal::remove_reference<RhsNested>::type _RhsNested;
00139 
00140     EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& lhs, const Rhs& rhs, const BinaryOp& func = BinaryOp())
00141       : m_lhs(lhs), m_rhs(rhs), m_functor(func)
00142     {
00143       EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar);
00144       // require the sizes to match
00145       EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Lhs, Rhs)
00146       eigen_assert(lhs.rows() == rhs.rows() && lhs.cols() == rhs.cols());
00147     }
00148 
00149     EIGEN_STRONG_INLINE Index rows() const {
00150       // return the fixed size type if available to enable compile time optimizations
00151       if (internal::traits<typename internal::remove_all<LhsNested>::type>::RowsAtCompileTime==Dynamic)
00152         return m_rhs.rows();
00153       else
00154         return m_lhs.rows();
00155     }
00156     EIGEN_STRONG_INLINE Index cols() const {
00157       // return the fixed size type if available to enable compile time optimizations
00158       if (internal::traits<typename internal::remove_all<LhsNested>::type>::ColsAtCompileTime==Dynamic)
00159         return m_rhs.cols();
00160       else
00161         return m_lhs.cols();
00162     }
00163 
00165     const _LhsNested& lhs() const { return m_lhs; }
00167     const _RhsNested& rhs() const { return m_rhs; }
00169     const BinaryOp& functor() const { return m_functor; }
00170 
00171   protected:
00172     LhsNested m_lhs;
00173     RhsNested m_rhs;
00174     const BinaryOp m_functor;
00175 };
00176 
00177 template<typename BinaryOp, typename Lhs, typename Rhs>
00178 class CwiseBinaryOpImpl<BinaryOp, Lhs, Rhs, Dense>
00179   : public internal::dense_xpr_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type
00180 {
00181     typedef CwiseBinaryOp<BinaryOp, Lhs, Rhs> Derived;
00182   public:
00183 
00184     typedef typename internal::dense_xpr_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type Base;
00185     EIGEN_DENSE_PUBLIC_INTERFACE( Derived )
00186 
00187     EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const
00188     {
00189       return derived().functor()(derived().lhs().coeff(row, col),
00190                                  derived().rhs().coeff(row, col));
00191     }
00192 
00193     template<int LoadMode>
00194     EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const
00195     {
00196       return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(row, col),
00197                                           derived().rhs().template packet<LoadMode>(row, col));
00198     }
00199 
00200     EIGEN_STRONG_INLINE const Scalar coeff(Index index) const
00201     {
00202       return derived().functor()(derived().lhs().coeff(index),
00203                                  derived().rhs().coeff(index));
00204     }
00205 
00206     template<int LoadMode>
00207     EIGEN_STRONG_INLINE PacketScalar packet(Index index) const
00208     {
00209       return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(index),
00210                                           derived().rhs().template packet<LoadMode>(index));
00211     }
00212 };
00213 
00218 template<typename Derived>
00219 template<typename OtherDerived>
00220 EIGEN_STRONG_INLINE Derived &
00221 MatrixBase<Derived>::operator-=(const MatrixBase<OtherDerived> &other)
00222 {
00223   SelfCwiseBinaryOp<internal::scalar_difference_op<Scalar>, Derived, OtherDerived> tmp(derived());
00224   tmp = other.derived();
00225   return derived();
00226 }
00227 
00232 template<typename Derived>
00233 template<typename OtherDerived>
00234 EIGEN_STRONG_INLINE Derived &
00235 MatrixBase<Derived>::operator+=(const MatrixBase<OtherDerived>& other)
00236 {
00237   SelfCwiseBinaryOp<internal::scalar_sum_op<Scalar>, Derived, OtherDerived> tmp(derived());
00238   tmp = other.derived();
00239   return derived();
00240 }
00241 
00242 } // end namespace Eigen
00243 
00244 #endif // EIGEN_CWISE_BINARY_OP_H