MOAB
4.9.3pre
|
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