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