CwiseBinaryOp.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
5 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
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_CWISE_BINARY_OP_H
27 #define EIGEN_CWISE_BINARY_OP_H
28 
29 namespace Eigen {
30 
51 namespace internal {
52 template<typename BinaryOp, typename Lhs, typename Rhs>
53 struct traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >
54 {
55  // we must not inherit from traits<Lhs> since it has
56  // the potential to cause problems with MSVC
57  typedef typename remove_all<Lhs>::type Ancestor;
58  typedef typename traits<Ancestor>::XprKind XprKind;
59  enum {
60  RowsAtCompileTime = traits<Ancestor>::RowsAtCompileTime,
61  ColsAtCompileTime = traits<Ancestor>::ColsAtCompileTime,
62  MaxRowsAtCompileTime = traits<Ancestor>::MaxRowsAtCompileTime,
63  MaxColsAtCompileTime = traits<Ancestor>::MaxColsAtCompileTime
64  };
65 
66  // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor),
67  // we still want to handle the case when the result type is different.
68  typedef typename result_of<
69  BinaryOp(
70  typename Lhs::Scalar,
71  typename Rhs::Scalar
72  )
73  >::type Scalar;
74  typedef typename promote_storage_type<typename traits<Lhs>::StorageKind,
75  typename traits<Rhs>::StorageKind>::ret StorageKind;
76  typedef typename promote_index_type<typename traits<Lhs>::Index,
77  typename traits<Rhs>::Index>::type Index;
78  typedef typename Lhs::Nested LhsNested;
79  typedef typename Rhs::Nested RhsNested;
80  typedef typename remove_reference<LhsNested>::type _LhsNested;
81  typedef typename remove_reference<RhsNested>::type _RhsNested;
82  enum {
83  LhsCoeffReadCost = _LhsNested::CoeffReadCost,
84  RhsCoeffReadCost = _RhsNested::CoeffReadCost,
85  LhsFlags = _LhsNested::Flags,
86  RhsFlags = _RhsNested::Flags,
87  SameType = is_same<typename _LhsNested::Scalar,typename _RhsNested::Scalar>::value,
88  StorageOrdersAgree = (int(Lhs::Flags)&RowMajorBit)==(int(Rhs::Flags)&RowMajorBit),
89  Flags0 = (int(LhsFlags) | int(RhsFlags)) & (
91  | (int(LhsFlags) & int(RhsFlags) &
92  ( AlignedBit
93  | (StorageOrdersAgree ? LinearAccessBit : 0)
94  | (functor_traits<BinaryOp>::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0)
95  )
96  )
97  ),
98  Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit),
99  CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits<BinaryOp>::Cost
100  };
101 };
102 } // end namespace internal
103 
104 // we require Lhs and Rhs to have the same scalar type. Currently there is no example of a binary functor
105 // that would take two operands of different types. If there were such an example, then this check should be
106 // moved to the BinaryOp functors, on a per-case basis. This would however require a change in the BinaryOp functors, as
107 // currently they take only one typename Scalar template parameter.
108 // It is tempting to always allow mixing different types but remember that this is often impossible in the vectorized paths.
109 // So allowing mixing different types gives very unexpected errors when enabling vectorization, when the user tries to
110 // add together a float matrix and a double matrix.
111 #define EIGEN_CHECK_BINARY_COMPATIBILIY(BINOP,LHS,RHS) \
112  EIGEN_STATIC_ASSERT((internal::functor_allows_mixing_real_and_complex<BINOP>::ret \
113  ? int(internal::is_same<typename NumTraits<LHS>::Real, typename NumTraits<RHS>::Real>::value) \
114  : int(internal::is_same<LHS, RHS>::value)), \
115  YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
116 
117 template<typename BinaryOp, typename Lhs, typename Rhs, typename StorageKind>
118 class CwiseBinaryOpImpl;
119 
120 template<typename BinaryOp, typename Lhs, typename Rhs>
121 class CwiseBinaryOp : internal::no_assignment_operator,
122  public CwiseBinaryOpImpl<
123  BinaryOp, Lhs, Rhs,
124  typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind,
125  typename internal::traits<Rhs>::StorageKind>::ret>
126 {
127  public:
128 
129  typedef typename CwiseBinaryOpImpl<
130  BinaryOp, Lhs, Rhs,
131  typename internal::promote_storage_type<typename internal::traits<Lhs>::StorageKind,
132  typename internal::traits<Rhs>::StorageKind>::ret>::Base Base;
134 
135  typedef typename internal::nested<Lhs>::type LhsNested;
136  typedef typename internal::nested<Rhs>::type RhsNested;
137  typedef typename internal::remove_reference<LhsNested>::type _LhsNested;
138  typedef typename internal::remove_reference<RhsNested>::type _RhsNested;
139 
140  EIGEN_STRONG_INLINE CwiseBinaryOp(const Lhs& lhs, const Rhs& rhs, const BinaryOp& func = BinaryOp())
141  : m_lhs(lhs), m_rhs(rhs), m_functor(func)
142  {
143  EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar);
144  // require the sizes to match
146  eigen_assert(lhs.rows() == rhs.rows() && lhs.cols() == rhs.cols());
147  }
148 
149  EIGEN_STRONG_INLINE Index rows() const {
150  // return the fixed size type if available to enable compile time optimizations
151  if (internal::traits<typename internal::remove_all<LhsNested>::type>::RowsAtCompileTime==Dynamic)
152  return m_rhs.rows();
153  else
154  return m_lhs.rows();
155  }
156  EIGEN_STRONG_INLINE Index cols() const {
157  // return the fixed size type if available to enable compile time optimizations
158  if (internal::traits<typename internal::remove_all<LhsNested>::type>::ColsAtCompileTime==Dynamic)
159  return m_rhs.cols();
160  else
161  return m_lhs.cols();
162  }
163 
165  const _LhsNested& lhs() const { return m_lhs; }
167  const _RhsNested& rhs() const { return m_rhs; }
169  const BinaryOp& functor() const { return m_functor; }
170 
171  protected:
174  const BinaryOp m_functor;
175 };
176 
177 template<typename BinaryOp, typename Lhs, typename Rhs>
178 class CwiseBinaryOpImpl<BinaryOp, Lhs, Rhs, Dense>
179  : public internal::dense_xpr_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type
180 {
182  public:
183 
184  typedef typename internal::dense_xpr_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >::type Base;
186 
187  EIGEN_STRONG_INLINE const Scalar coeff(Index row, Index col) const
188  {
189  return derived().functor()(derived().lhs().coeff(row, col),
190  derived().rhs().coeff(row, col));
191  }
192 
193  template<int LoadMode>
194  EIGEN_STRONG_INLINE PacketScalar packet(Index row, Index col) const
195  {
196  return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(row, col),
197  derived().rhs().template packet<LoadMode>(row, col));
198  }
199 
200  EIGEN_STRONG_INLINE const Scalar coeff(Index index) const
201  {
202  return derived().functor()(derived().lhs().coeff(index),
203  derived().rhs().coeff(index));
204  }
205 
206  template<int LoadMode>
207  EIGEN_STRONG_INLINE PacketScalar packet(Index index) const
208  {
209  return derived().functor().packetOp(derived().lhs().template packet<LoadMode>(index),
210  derived().rhs().template packet<LoadMode>(index));
211  }
212 };
213 
218 template<typename Derived>
219 template<typename OtherDerived>
220 EIGEN_STRONG_INLINE Derived &
222 {
223  SelfCwiseBinaryOp<internal::scalar_difference_op<Scalar>, Derived, OtherDerived> tmp(derived());
224  tmp = other.derived();
225  return derived();
226 }
227 
232 template<typename Derived>
233 template<typename OtherDerived>
234 EIGEN_STRONG_INLINE Derived &
236 {
237  SelfCwiseBinaryOp<internal::scalar_sum_op<Scalar>, Derived, OtherDerived> tmp(derived());
238  tmp = other.derived();
239  return derived();
240 }
241 
242 } // end namespace Eigen
243 
244 #endif // EIGEN_CWISE_BINARY_OP_H