MOAB  4.9.3pre
NullaryFunctors.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-2010 Gael Guennebaud <[email protected]>
00005 //
00006 // This Source Code Form is subject to the terms of the Mozilla
00007 // Public License v. 2.0. If a copy of the MPL was not distributed
00008 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00009 
00010 #ifndef EIGEN_NULLARY_FUNCTORS_H
00011 #define EIGEN_NULLARY_FUNCTORS_H
00012 
00013 namespace Eigen {
00014 
00015 namespace internal {
00016 
00017 template<typename Scalar>
00018 struct scalar_constant_op {
00019   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE scalar_constant_op(const scalar_constant_op& other) : m_other(other.m_other) { }
00020   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE scalar_constant_op(const Scalar& other) : m_other(other) { }
00021   template<typename Index>
00022   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (Index, Index = 0) const { return m_other; }
00023   template<typename Index, typename PacketType>
00024   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const PacketType packetOp(Index, Index = 0) const { return internal::pset1<PacketType>(m_other); }
00025   const Scalar m_other;
00026 };
00027 template<typename Scalar>
00028 struct functor_traits<scalar_constant_op<Scalar> >
00029 { enum { Cost = 1, PacketAccess = packet_traits<Scalar>::Vectorizable, IsRepeatable = true }; };
00030 
00031 template<typename Scalar> struct scalar_identity_op {
00032   EIGEN_EMPTY_STRUCT_CTOR(scalar_identity_op)
00033   template<typename Index>
00034   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const { return row==col ? Scalar(1) : Scalar(0); }
00035 };
00036 template<typename Scalar>
00037 struct functor_traits<scalar_identity_op<Scalar> >
00038 { enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = false, IsRepeatable = true }; };
00039 
00040 template <typename Scalar, typename Packet, bool RandomAccess, bool IsInteger> struct linspaced_op_impl;
00041 
00042 // linear access for packet ops:
00043 // 1) initialization
00044 //   base = [low, ..., low] + ([step, ..., step] * [-size, ..., 0])
00045 // 2) each step (where size is 1 for coeff access or PacketSize for packet access)
00046 //   base += [size*step, ..., size*step]
00047 //
00048 // TODO: Perhaps it's better to initialize lazily (so not in the constructor but in packetOp)
00049 //       in order to avoid the padd() in operator() ?
00050 template <typename Scalar, typename Packet>
00051 struct linspaced_op_impl<Scalar,Packet,/*RandomAccess*/false,/*IsInteger*/false>
00052 {
00053   linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps) :
00054     m_low(low), m_step(num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1)),
00055     m_packetStep(pset1<Packet>(unpacket_traits<Packet>::size*m_step)),
00056     m_base(padd(pset1<Packet>(low), pmul(pset1<Packet>(m_step),plset<Packet>(-unpacket_traits<Packet>::size)))) {}
00057 
00058   template<typename Index>
00059   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (Index i) const 
00060   { 
00061     m_base = padd(m_base, pset1<Packet>(m_step));
00062     return m_low+Scalar(i)*m_step; 
00063   }
00064 
00065   template<typename Index>
00066   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(Index) const { return m_base = padd(m_base,m_packetStep); }
00067 
00068   const Scalar m_low;
00069   const Scalar m_step;
00070   const Packet m_packetStep;
00071   mutable Packet m_base;
00072 };
00073 
00074 // random access for packet ops:
00075 // 1) each step
00076 //   [low, ..., low] + ( [step, ..., step] * ( [i, ..., i] + [0, ..., size] ) )
00077 template <typename Scalar, typename Packet>
00078 struct linspaced_op_impl<Scalar,Packet,/*RandomAccess*/true,/*IsInteger*/false>
00079 {
00080   linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps) :
00081     m_low(low), m_step(num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1)),
00082     m_lowPacket(pset1<Packet>(m_low)), m_stepPacket(pset1<Packet>(m_step)), m_interPacket(plset<Packet>(0)) {}
00083 
00084   template<typename Index>
00085   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return m_low+i*m_step; }
00086 
00087   template<typename Index>
00088   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(Index i) const
00089   { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1<Packet>(Scalar(i)),m_interPacket))); }
00090 
00091   const Scalar m_low;
00092   const Scalar m_step;
00093   const Packet m_lowPacket;
00094   const Packet m_stepPacket;
00095   const Packet m_interPacket;
00096 };
00097 
00098 template <typename Scalar, typename Packet>
00099 struct linspaced_op_impl<Scalar,Packet,/*RandomAccess*/true,/*IsInteger*/true>
00100 {
00101   linspaced_op_impl(const Scalar& low, const Scalar& high, Index num_steps) :
00102     m_low(low), m_length(high-low), m_divisor(num_steps==1?1:num_steps-1), m_interPacket(plset<Packet>(0))
00103   {}
00104 
00105   template<typename Index>
00106   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
00107   const Scalar operator() (Index i) const {
00108     return m_low + (m_length*Scalar(i))/m_divisor;
00109   }
00110 
00111   template<typename Index>
00112   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
00113   const Packet packetOp(Index i) const {
00114     return internal::padd(pset1<Packet>(m_low), pdiv(pmul(pset1<Packet>(m_length), padd(pset1<Packet>(Scalar(i)),m_interPacket)),
00115                                                      pset1<Packet>(m_divisor))); }
00116 
00117   const Scalar m_low;
00118   const Scalar m_length;
00119   const Index  m_divisor;
00120   const Packet m_interPacket;
00121 };
00122 
00123 // ----- Linspace functor ----------------------------------------------------------------
00124 
00125 // Forward declaration (we default to random access which does not really give
00126 // us a speed gain when using packet access but it allows to use the functor in
00127 // nested expressions).
00128 template <typename Scalar, typename PacketType, bool RandomAccess = true> struct linspaced_op;
00129 template <typename Scalar, typename PacketType, bool RandomAccess> struct functor_traits< linspaced_op<Scalar,PacketType,RandomAccess> >
00130 {
00131   enum
00132   {
00133     Cost = 1,
00134     PacketAccess =   packet_traits<Scalar>::HasSetLinear
00135                   && ((!NumTraits<Scalar>::IsInteger) || packet_traits<Scalar>::HasDiv),
00136     IsRepeatable = true
00137   };
00138 };
00139 template <typename Scalar, typename PacketType, bool RandomAccess> struct linspaced_op
00140 {
00141   linspaced_op(const Scalar& low, const Scalar& high, Index num_steps)
00142     : impl((num_steps==1 ? high : low),high,num_steps)
00143   {}
00144 
00145   template<typename Index>
00146   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return impl(i); }
00147 
00148   // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since
00149   // there row==0 and col is used for the actual iteration.
00150   template<typename Index>
00151   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator() (Index row, Index col) const 
00152   {
00153     eigen_assert(col==0 || row==0);
00154     return impl(col + row);
00155   }
00156 
00157   template<typename Index, typename Packet>
00158   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(Index i) const { return impl.packetOp(i); }
00159 
00160   // We need this function when assigning e.g. a RowVectorXd to a MatrixXd since
00161   // there row==0 and col is used for the actual iteration.
00162   template<typename Index, typename Packet>
00163   EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(Index row, Index col) const
00164   {
00165     eigen_assert(col==0 || row==0);
00166     return impl.packetOp(col + row);
00167   }
00168 
00169   // This proxy object handles the actual required temporaries, the different
00170   // implementations (random vs. sequential access) as well as the
00171   // correct piping to size 2/4 packet operations.
00172   // As long as we don't have a Bresenham-like implementation for linear-access and integer types,
00173   // we have to by-pass RandomAccess for integer types. See bug 698.
00174   const linspaced_op_impl<Scalar,PacketType,(NumTraits<Scalar>::IsInteger?true:RandomAccess),NumTraits<Scalar>::IsInteger> impl;
00175 };
00176 
00177 // all functors allow linear access, except scalar_identity_op. So we fix here a quick meta
00178 // to indicate whether a functor allows linear access, just always answering 'yes' except for
00179 // scalar_identity_op.
00180 template<typename Functor> struct functor_has_linear_access { enum { ret = 1 }; };
00181 template<typename Scalar> struct functor_has_linear_access<scalar_identity_op<Scalar> > { enum { ret = 0 }; };
00182 
00183 } // end namespace internal
00184 
00185 } // end namespace Eigen
00186 
00187 #endif // EIGEN_NULLARY_FUNCTORS_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines