1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2014 Benoit Steiner <[email protected]> 5 // 6 // This Source Code Form is subject to the terms of the Mozilla 7 // Public License v. 2.0. If a copy of the MPL was not distributed 8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 10 #ifndef EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H 11 #define EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H 12 13 namespace Eigen { 14 namespace internal { 15 16 17 /** \internal 18 * \brief Template functor to compute the modulo between an array and a scalar. 19 */ 20 template <typename Scalar> 21 struct scalar_mod_op { scalar_mod_opscalar_mod_op22 EIGEN_DEVICE_FUNC scalar_mod_op(const Scalar& divisor) : m_divisor(divisor) {} operatorscalar_mod_op23 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a) const { return a % m_divisor; } 24 const Scalar m_divisor; 25 }; 26 template <typename Scalar> 27 struct functor_traits<scalar_mod_op<Scalar> > 28 { enum { Cost = scalar_div_cost<Scalar,false>::value, PacketAccess = false }; }; 29 30 31 /** \internal 32 * \brief Template functor to compute the modulo between 2 arrays. 33 */ 34 template <typename Scalar> 35 struct scalar_mod2_op { 36 EIGEN_EMPTY_STRUCT_CTOR(scalar_mod2_op) 37 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator() (const Scalar& a, const Scalar& b) const { return a % b; } 38 }; 39 template <typename Scalar> 40 struct functor_traits<scalar_mod2_op<Scalar> > 41 { enum { Cost = scalar_div_cost<Scalar,false>::value, PacketAccess = false }; }; 42 43 template <typename Scalar> 44 struct scalar_fmod_op { 45 EIGEN_EMPTY_STRUCT_CTOR(scalar_fmod_op) 46 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar 47 operator()(const Scalar& a, const Scalar& b) const { 48 return numext::fmod(a, b); 49 } 50 }; 51 template <typename Scalar> 52 struct functor_traits<scalar_fmod_op<Scalar> > { 53 enum { Cost = 13, // Reciprocal throughput of FPREM on Haswell. 54 PacketAccess = false }; 55 }; 56 57 template<typename Reducer, typename Device> 58 struct reducer_traits { 59 enum { 60 Cost = 1, 61 PacketAccess = false, 62 IsStateful = false, 63 IsExactlyAssociative = true 64 }; 65 }; 66 67 // Standard reduction functors 68 template <typename T> struct SumReducer 69 { 70 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const { 71 internal::scalar_sum_op<T> sum_op; 72 *accum = sum_op(*accum, t); 73 } 74 template <typename Packet> 75 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const { 76 (*accum) = padd<Packet>(*accum, p); 77 } 78 79 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { 80 internal::scalar_cast_op<int, T> conv; 81 return conv(0); 82 } 83 template <typename Packet> 84 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const { 85 return pset1<Packet>(initialize()); 86 } 87 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const { 88 return accum; 89 } 90 template <typename Packet> 91 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const { 92 return vaccum; 93 } 94 template <typename Packet> 95 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const { 96 internal::scalar_sum_op<T> sum_op; 97 return sum_op(saccum, predux(vaccum)); 98 } 99 }; 100 101 template <typename T, typename Device> 102 struct reducer_traits<SumReducer<T>, Device> { 103 enum { 104 Cost = NumTraits<T>::AddCost, 105 PacketAccess = PacketType<T, Device>::HasAdd, 106 IsStateful = false, 107 IsExactlyAssociative = NumTraits<T>::IsInteger 108 }; 109 }; 110 111 template <typename T> struct MeanReducer 112 { 113 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE 114 MeanReducer() : scalarCount_(0), packetCount_(0) { } 115 116 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) { 117 internal::scalar_sum_op<T> sum_op; 118 *accum = sum_op(*accum, t); 119 scalarCount_++; 120 } 121 template <typename Packet> 122 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) { 123 (*accum) = padd<Packet>(*accum, p); 124 packetCount_++; 125 } 126 127 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { 128 internal::scalar_cast_op<int, T> conv; 129 return conv(0); 130 } 131 template <typename Packet> 132 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const { 133 return pset1<Packet>(initialize()); 134 } 135 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const { 136 internal::scalar_quotient_op<T> quotient_op; 137 return quotient_op(accum, T(scalarCount_)); 138 } 139 template <typename Packet> 140 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const { 141 return pdiv(vaccum, pset1<Packet>(T(packetCount_))); 142 } 143 template <typename Packet> 144 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const { 145 internal::scalar_sum_op<T> sum_op; 146 internal::scalar_quotient_op<T> quotient_op; 147 return quotient_op( 148 sum_op(saccum, predux(vaccum)), 149 T(scalarCount_ + packetCount_ * unpacket_traits<Packet>::size)); 150 } 151 152 protected: 153 DenseIndex scalarCount_; 154 DenseIndex packetCount_; 155 }; 156 157 template <typename T, typename Device> 158 struct reducer_traits<MeanReducer<T>, Device> { 159 enum { 160 Cost = NumTraits<T>::AddCost, 161 PacketAccess = PacketType<T, Device>::HasAdd && 162 PacketType<T, Device>::HasDiv && !NumTraits<T>::IsInteger, 163 IsStateful = true, 164 IsExactlyAssociative = NumTraits<T>::IsInteger 165 }; 166 }; 167 168 169 template <typename T, bool IsMax = true, bool IsInteger = true> 170 struct MinMaxBottomValue { 171 EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() { 172 return Eigen::NumTraits<T>::lowest(); 173 } 174 }; 175 template <typename T> 176 struct MinMaxBottomValue<T, true, false> { 177 EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() { 178 return -Eigen::NumTraits<T>::infinity(); 179 } 180 }; 181 template <typename T> 182 struct MinMaxBottomValue<T, false, true> { 183 EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() { 184 return Eigen::NumTraits<T>::highest(); 185 } 186 }; 187 template <typename T> 188 struct MinMaxBottomValue<T, false, false> { 189 EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() { 190 return Eigen::NumTraits<T>::infinity(); 191 } 192 }; 193 194 195 template <typename T, int NaNPropagation=PropagateFast> struct MaxReducer 196 { 197 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const { 198 scalar_max_op<T, T, NaNPropagation> op; 199 *accum = op(t, *accum); 200 } 201 template <typename Packet> 202 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const { 203 scalar_max_op<T, T, NaNPropagation> op; 204 (*accum) = op.packetOp(*accum, p); 205 } 206 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { 207 return MinMaxBottomValue<T, /*IsMax=*/true, Eigen::NumTraits<T>::IsInteger>::bottom_value(); 208 } 209 template <typename Packet> 210 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const { 211 return pset1<Packet>(initialize()); 212 } 213 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const { 214 return accum; 215 } 216 template <typename Packet> 217 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const { 218 return vaccum; 219 } 220 template <typename Packet> 221 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const { 222 scalar_max_op<T, T, NaNPropagation> op; 223 return op(saccum, op.predux(vaccum)); 224 } 225 }; 226 227 template <typename T, typename Device, int NaNPropagation> 228 struct reducer_traits<MaxReducer<T, NaNPropagation>, Device> { 229 enum { 230 Cost = NumTraits<T>::AddCost, 231 PacketAccess = PacketType<T, Device>::HasMax, 232 IsStateful = false, 233 IsExactlyAssociative = (NaNPropagation!=PropagateFast) 234 }; 235 }; 236 237 template <typename T, int NaNPropagation=PropagateFast> struct MinReducer 238 { 239 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const { 240 scalar_min_op<T, T, NaNPropagation> op; 241 *accum = op(t, *accum); 242 } 243 template <typename Packet> 244 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const { 245 scalar_min_op<T, T, NaNPropagation> op; 246 (*accum) = op.packetOp(*accum, p); 247 } 248 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { 249 return MinMaxBottomValue<T, /*IsMax=*/false, Eigen::NumTraits<T>::IsInteger>::bottom_value(); 250 } 251 template <typename Packet> 252 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const { 253 return pset1<Packet>(initialize()); 254 } 255 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const { 256 return accum; 257 } 258 template <typename Packet> 259 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const { 260 return vaccum; 261 } 262 template <typename Packet> 263 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const { 264 scalar_min_op<T, T, NaNPropagation> op; 265 return op(saccum, op.predux(vaccum)); 266 } 267 }; 268 269 template <typename T, typename Device, int NaNPropagation> 270 struct reducer_traits<MinReducer<T, NaNPropagation>, Device> { 271 enum { 272 Cost = NumTraits<T>::AddCost, 273 PacketAccess = PacketType<T, Device>::HasMin, 274 IsStateful = false, 275 IsExactlyAssociative = (NaNPropagation!=PropagateFast) 276 }; 277 }; 278 279 template <typename T> struct ProdReducer 280 { 281 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const { 282 internal::scalar_product_op<T> prod_op; 283 (*accum) = prod_op(*accum, t); 284 } 285 template <typename Packet> 286 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const { 287 (*accum) = pmul<Packet>(*accum, p); 288 } 289 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { 290 internal::scalar_cast_op<int, T> conv; 291 return conv(1); 292 } 293 template <typename Packet> 294 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const { 295 return pset1<Packet>(initialize()); 296 } 297 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const { 298 return accum; 299 } 300 template <typename Packet> 301 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const { 302 return vaccum; 303 } 304 template <typename Packet> 305 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const { 306 internal::scalar_product_op<T> prod_op; 307 return prod_op(saccum, predux_mul(vaccum)); 308 } 309 }; 310 311 template <typename T, typename Device> 312 struct reducer_traits<ProdReducer<T>, Device> { 313 enum { 314 Cost = NumTraits<T>::MulCost, 315 PacketAccess = PacketType<T, Device>::HasMul, 316 IsStateful = false, 317 IsExactlyAssociative = true 318 }; 319 }; 320 321 322 struct AndReducer 323 { 324 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(bool t, bool* accum) const { 325 *accum = *accum && t; 326 } 327 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool initialize() const { 328 return true; 329 } 330 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool finalize(bool accum) const { 331 return accum; 332 } 333 }; 334 335 template <typename Device> 336 struct reducer_traits<AndReducer, Device> { 337 enum { 338 Cost = 1, 339 PacketAccess = false, 340 IsStateful = false, 341 IsExactlyAssociative = true 342 }; 343 }; 344 345 346 struct OrReducer { 347 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(bool t, bool* accum) const { 348 *accum = *accum || t; 349 } 350 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool initialize() const { 351 return false; 352 } 353 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool finalize(bool accum) const { 354 return accum; 355 } 356 }; 357 358 template <typename Device> 359 struct reducer_traits<OrReducer, Device> { 360 enum { 361 Cost = 1, 362 PacketAccess = false, 363 IsStateful = false, 364 IsExactlyAssociative = true 365 }; 366 }; 367 368 // Argmin/Argmax reducers. Returns the first occurrence if multiple locations 369 // contain the same min/max value. 370 template <typename T> struct ArgMaxTupleReducer 371 { 372 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const { 373 if (t.second < accum->second) { 374 return; 375 } else if (t.second > accum->second || accum->first > t.first ) { 376 *accum = t; 377 } 378 } 379 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { 380 return T(0, NumTraits<typename T::second_type>::lowest()); 381 } 382 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T& accum) const { 383 return accum; 384 } 385 }; 386 387 template <typename T, typename Device> 388 struct reducer_traits<ArgMaxTupleReducer<T>, Device> { 389 enum { 390 Cost = NumTraits<T>::AddCost, 391 PacketAccess = false, 392 IsStateful = false, 393 IsExactlyAssociative = true 394 }; 395 }; 396 397 398 template <typename T> struct ArgMinTupleReducer 399 { 400 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T& t, T* accum) const { 401 if (t.second > accum->second) { 402 return; 403 } else if (t.second < accum->second || accum->first > t.first) { 404 *accum = t; 405 } 406 } 407 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const { 408 return T(0, NumTraits<typename T::second_type>::highest()); 409 } 410 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T& accum) const { 411 return accum; 412 } 413 }; 414 415 template <typename T, typename Device> 416 struct reducer_traits<ArgMinTupleReducer<T>, Device> { 417 enum { 418 Cost = NumTraits<T>::AddCost, 419 PacketAccess = false, 420 IsStateful = false, 421 IsExactlyAssociative = true 422 }; 423 }; 424 425 426 template <typename T, typename Index, size_t NumDims> 427 class GaussianGenerator { 428 public: 429 static const bool PacketAccess = false; 430 431 EIGEN_DEVICE_FUNC GaussianGenerator(const array<T, NumDims>& means, 432 const array<T, NumDims>& std_devs) 433 : m_means(means) 434 { 435 EIGEN_UNROLL_LOOP 436 for (size_t i = 0; i < NumDims; ++i) { 437 m_two_sigmas[i] = std_devs[i] * std_devs[i] * 2; 438 } 439 } 440 441 EIGEN_DEVICE_FUNC T operator()(const array<Index, NumDims>& coordinates) const { 442 T tmp = T(0); 443 EIGEN_UNROLL_LOOP 444 for (size_t i = 0; i < NumDims; ++i) { 445 T offset = coordinates[i] - m_means[i]; 446 tmp += offset * offset / m_two_sigmas[i]; 447 } 448 return numext::exp(-tmp); 449 } 450 451 private: 452 array<T, NumDims> m_means; 453 array<T, NumDims> m_two_sigmas; 454 }; 455 456 template <typename T, typename Index, size_t NumDims> 457 struct functor_traits<GaussianGenerator<T, Index, NumDims> > { 458 enum { 459 Cost = NumDims * (2 * NumTraits<T>::AddCost + NumTraits<T>::MulCost + 460 functor_traits<scalar_quotient_op<T, T> >::Cost) + 461 functor_traits<scalar_exp_op<T> >::Cost, 462 PacketAccess = GaussianGenerator<T, Index, NumDims>::PacketAccess 463 }; 464 }; 465 466 template <typename Scalar> 467 struct scalar_clamp_op { 468 EIGEN_DEVICE_FUNC inline scalar_clamp_op(const Scalar& _min, const Scalar& _max) : m_min(_min), m_max(_max) {} 469 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar 470 operator()(const Scalar& x) const { 471 return numext::mini(numext::maxi(x, m_min), m_max); 472 } 473 template <typename Packet> 474 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet 475 packetOp(const Packet& x) const { 476 return internal::pmin(internal::pmax(x, pset1<Packet>(m_min)), pset1<Packet>(m_max)); 477 } 478 const Scalar m_min; 479 const Scalar m_max; 480 }; 481 template<typename Scalar> 482 struct functor_traits<scalar_clamp_op<Scalar> > 483 { enum { Cost = 2 * NumTraits<Scalar>::AddCost, PacketAccess = (packet_traits<Scalar>::HasMin && packet_traits<Scalar>::HasMax)}; }; 484 485 } // end namespace internal 486 } // end namespace Eigen 487 488 #endif // EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H 489