490 lines
14 KiB
C++
490 lines
14 KiB
C++
// This file is part of Eigen, a lightweight C++ template library
|
|
// for linear algebra.
|
|
//
|
|
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
|
//
|
|
// This Source Code Form is subject to the terms of the Mozilla
|
|
// Public License v. 2.0. If a copy of the MPL was not distributed
|
|
// with this file, You can obtain one at the mozilla.org home page
|
|
|
|
#ifndef EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H
|
|
#define EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H
|
|
|
|
namespace Eigen {
|
|
namespace internal {
|
|
|
|
|
|
/** \internal
|
|
* \brief Template functor to compute the modulo between an array and a scalar.
|
|
*/
|
|
template <typename Scalar>
|
|
struct scalar_mod_op {
|
|
EIGEN_DEVICE_FUNC scalar_mod_op(const Scalar& divisor) : m_divisor(divisor) {}
|
|
EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a) const { return a % m_divisor; }
|
|
const Scalar m_divisor;
|
|
};
|
|
template <typename Scalar>
|
|
struct functor_traits<scalar_mod_op<Scalar> >
|
|
{ enum { Cost = scalar_div_cost<Scalar,false>::value, PacketAccess = false }; };
|
|
|
|
|
|
/** \internal
|
|
* \brief Template functor to compute the modulo between 2 arrays.
|
|
*/
|
|
template <typename Scalar>
|
|
struct scalar_mod2_op {
|
|
EIGEN_EMPTY_STRUCT_CTOR(scalar_mod2_op);
|
|
EIGEN_DEVICE_FUNC inline Scalar operator() (const Scalar& a, const Scalar& b) const { return a % b; }
|
|
};
|
|
template <typename Scalar>
|
|
struct functor_traits<scalar_mod2_op<Scalar> >
|
|
{ enum { Cost = scalar_div_cost<Scalar,false>::value, PacketAccess = false }; };
|
|
|
|
template <typename Scalar>
|
|
struct scalar_fmod_op {
|
|
EIGEN_EMPTY_STRUCT_CTOR(scalar_fmod_op);
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar
|
|
operator()(const Scalar& a, const Scalar& b) const {
|
|
return numext::fmod(a, b);
|
|
}
|
|
};
|
|
template <typename Scalar>
|
|
struct functor_traits<scalar_fmod_op<Scalar> > {
|
|
enum { Cost = 13, // Reciprocal throughput of FPREM on Haswell.
|
|
PacketAccess = false };
|
|
};
|
|
|
|
|
|
/** \internal
|
|
* \brief Template functor to compute the sigmoid of a scalar
|
|
* \sa class CwiseUnaryOp, ArrayBase::sigmoid()
|
|
*/
|
|
template <typename T>
|
|
struct scalar_sigmoid_op {
|
|
EIGEN_EMPTY_STRUCT_CTOR(scalar_sigmoid_op)
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T operator()(const T& x) const {
|
|
const T one = T(1);
|
|
return one / (one + numext::exp(-x));
|
|
}
|
|
|
|
template <typename Packet> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
|
Packet packetOp(const Packet& x) const {
|
|
const Packet one = pset1<Packet>(T(1));
|
|
return pdiv(one, padd(one, pexp(pnegate(x))));
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct functor_traits<scalar_sigmoid_op<T> > {
|
|
enum {
|
|
Cost = NumTraits<T>::AddCost * 2 + NumTraits<T>::MulCost * 6,
|
|
PacketAccess = packet_traits<T>::HasAdd && packet_traits<T>::HasDiv &&
|
|
packet_traits<T>::HasNegate && packet_traits<T>::HasExp
|
|
};
|
|
};
|
|
|
|
|
|
template<typename Reducer, typename Device>
|
|
struct reducer_traits {
|
|
enum {
|
|
Cost = 1,
|
|
PacketAccess = false
|
|
};
|
|
};
|
|
|
|
// Standard reduction functors
|
|
template <typename T> struct SumReducer
|
|
{
|
|
static const bool PacketAccess = packet_traits<T>::HasAdd;
|
|
static const bool IsStateful = false;
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
|
|
internal::scalar_sum_op<T> sum_op;
|
|
*accum = sum_op(*accum, t);
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
|
|
(*accum) = padd<Packet>(*accum, p);
|
|
}
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
|
|
internal::scalar_cast_op<int, T> conv;
|
|
return conv(0);
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
|
|
return pset1<Packet>(initialize());
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
|
|
return accum;
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
|
|
return vaccum;
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
|
|
internal::scalar_sum_op<T> sum_op;
|
|
return sum_op(saccum, predux(vaccum));
|
|
}
|
|
};
|
|
|
|
template <typename T, typename Device>
|
|
struct reducer_traits<SumReducer<T>, Device> {
|
|
enum {
|
|
Cost = NumTraits<T>::AddCost,
|
|
PacketAccess = PacketType<T, Device>::HasAdd
|
|
};
|
|
};
|
|
|
|
|
|
template <typename T> struct MeanReducer
|
|
{
|
|
static const bool PacketAccess = packet_traits<T>::HasAdd && !NumTraits<T>::IsInteger;
|
|
static const bool IsStateful = true;
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
|
MeanReducer() : scalarCount_(0), packetCount_(0) { }
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) {
|
|
internal::scalar_sum_op<T> sum_op;
|
|
*accum = sum_op(*accum, t);
|
|
scalarCount_++;
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) {
|
|
(*accum) = padd<Packet>(*accum, p);
|
|
packetCount_++;
|
|
}
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
|
|
internal::scalar_cast_op<int, T> conv;
|
|
return conv(0);
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
|
|
return pset1<Packet>(initialize());
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
|
|
return accum / scalarCount_;
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
|
|
return pdiv(vaccum, pset1<Packet>(packetCount_));
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
|
|
internal::scalar_sum_op<T> sum_op;
|
|
return sum_op(saccum, predux(vaccum)) / (scalarCount_ + packetCount_ * unpacket_traits<Packet>::size);
|
|
}
|
|
|
|
protected:
|
|
DenseIndex scalarCount_;
|
|
DenseIndex packetCount_;
|
|
};
|
|
|
|
template <typename T, typename Device>
|
|
struct reducer_traits<MeanReducer<T>, Device> {
|
|
enum {
|
|
Cost = NumTraits<T>::AddCost,
|
|
PacketAccess = PacketType<T, Device>::HasAdd
|
|
};
|
|
};
|
|
|
|
|
|
template <typename T, bool IsMax = true, bool IsInteger = true>
|
|
struct MinMaxBottomValue {
|
|
EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
|
|
return Eigen::NumTraits<T>::lowest();
|
|
}
|
|
};
|
|
template <typename T>
|
|
struct MinMaxBottomValue<T, true, false> {
|
|
EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
|
|
return -Eigen::NumTraits<T>::infinity();
|
|
}
|
|
};
|
|
template <typename T>
|
|
struct MinMaxBottomValue<T, false, true> {
|
|
EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
|
|
return Eigen::NumTraits<T>::highest();
|
|
}
|
|
};
|
|
template <typename T>
|
|
struct MinMaxBottomValue<T, false, false> {
|
|
EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE T bottom_value() {
|
|
return Eigen::NumTraits<T>::infinity();
|
|
}
|
|
};
|
|
|
|
|
|
template <typename T> struct MaxReducer
|
|
{
|
|
static const bool PacketAccess = packet_traits<T>::HasMax;
|
|
static const bool IsStateful = false;
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
|
|
if (t > *accum) { *accum = t; }
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
|
|
(*accum) = pmax<Packet>(*accum, p);
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
|
|
return MinMaxBottomValue<T, true, Eigen::NumTraits<T>::IsInteger>::bottom_value();
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
|
|
return pset1<Packet>(initialize());
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
|
|
return accum;
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
|
|
return vaccum;
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
|
|
return numext::maxi(saccum, predux_max(vaccum));
|
|
}
|
|
};
|
|
|
|
template <typename T, typename Device>
|
|
struct reducer_traits<MaxReducer<T>, Device> {
|
|
enum {
|
|
Cost = NumTraits<T>::AddCost,
|
|
PacketAccess = PacketType<T, Device>::HasMax
|
|
};
|
|
};
|
|
|
|
|
|
template <typename T> struct MinReducer
|
|
{
|
|
static const bool PacketAccess = packet_traits<T>::HasMin;
|
|
static const bool IsStateful = false;
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
|
|
if (t < *accum) { *accum = t; }
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
|
|
(*accum) = pmin<Packet>(*accum, p);
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
|
|
return MinMaxBottomValue<T, false, Eigen::NumTraits<T>::IsInteger>::bottom_value();
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
|
|
return pset1<Packet>(initialize());
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
|
|
return accum;
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
|
|
return vaccum;
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
|
|
return numext::mini(saccum, predux_min(vaccum));
|
|
}
|
|
};
|
|
|
|
template <typename T, typename Device>
|
|
struct reducer_traits<MinReducer<T>, Device> {
|
|
enum {
|
|
Cost = NumTraits<T>::AddCost,
|
|
PacketAccess = PacketType<T, Device>::HasMin
|
|
};
|
|
};
|
|
|
|
|
|
template <typename T> struct ProdReducer
|
|
{
|
|
static const bool PacketAccess = packet_traits<T>::HasMul;
|
|
static const bool IsStateful = false;
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
|
|
internal::scalar_product_op<T> prod_op;
|
|
(*accum) = prod_op(*accum, t);
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reducePacket(const Packet& p, Packet* accum) const {
|
|
(*accum) = pmul<Packet>(*accum, p);
|
|
}
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
|
|
internal::scalar_cast_op<int, T> conv;
|
|
return conv(1);
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet initializePacket() const {
|
|
return pset1<Packet>(initialize());
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T accum) const {
|
|
return accum;
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet finalizePacket(const Packet& vaccum) const {
|
|
return vaccum;
|
|
}
|
|
template <typename Packet>
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalizeBoth(const T saccum, const Packet& vaccum) const {
|
|
internal::scalar_product_op<T> prod_op;
|
|
return prod_op(saccum, predux_mul(vaccum));
|
|
}
|
|
};
|
|
|
|
template <typename T, typename Device>
|
|
struct reducer_traits<ProdReducer<T>, Device> {
|
|
enum {
|
|
Cost = NumTraits<T>::MulCost,
|
|
PacketAccess = PacketType<T, Device>::HasMul
|
|
};
|
|
};
|
|
|
|
|
|
struct AndReducer
|
|
{
|
|
static const bool PacketAccess = false;
|
|
static const bool IsStateful = false;
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(bool t, bool* accum) const {
|
|
*accum = *accum && t;
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool initialize() const {
|
|
return true;
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool finalize(bool accum) const {
|
|
return accum;
|
|
}
|
|
};
|
|
|
|
template <typename Device>
|
|
struct reducer_traits<AndReducer, Device> {
|
|
enum {
|
|
Cost = 1,
|
|
PacketAccess = false
|
|
};
|
|
};
|
|
|
|
|
|
struct OrReducer {
|
|
static const bool PacketAccess = false;
|
|
static const bool IsStateful = false;
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(bool t, bool* accum) const {
|
|
*accum = *accum || t;
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool initialize() const {
|
|
return false;
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool finalize(bool accum) const {
|
|
return accum;
|
|
}
|
|
};
|
|
|
|
template <typename Device>
|
|
struct reducer_traits<OrReducer, Device> {
|
|
enum {
|
|
Cost = 1,
|
|
PacketAccess = false
|
|
};
|
|
};
|
|
|
|
|
|
// Argmin/Argmax reducers
|
|
template <typename T> struct ArgMaxTupleReducer
|
|
{
|
|
static const bool PacketAccess = false;
|
|
static const bool IsStateful = false;
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T t, T* accum) const {
|
|
if (t.second > accum->second) { *accum = t; }
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
|
|
return T(0, NumTraits<typename T::second_type>::lowest());
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T& accum) const {
|
|
return accum;
|
|
}
|
|
};
|
|
|
|
template <typename T, typename Device>
|
|
struct reducer_traits<ArgMaxTupleReducer<T>, Device> {
|
|
enum {
|
|
Cost = NumTraits<T>::AddCost,
|
|
PacketAccess = false
|
|
};
|
|
};
|
|
|
|
|
|
template <typename T> struct ArgMinTupleReducer
|
|
{
|
|
static const bool PacketAccess = false;
|
|
static const bool IsStateful = false;
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void reduce(const T& t, T* accum) const {
|
|
if (t.second < accum->second) { *accum = t; }
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T initialize() const {
|
|
return T(0, NumTraits<typename T::second_type>::highest());
|
|
}
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T finalize(const T& accum) const {
|
|
return accum;
|
|
}
|
|
};
|
|
|
|
template <typename T, typename Device>
|
|
struct reducer_traits<ArgMinTupleReducer<T>, Device> {
|
|
enum {
|
|
Cost = NumTraits<T>::AddCost,
|
|
PacketAccess = false
|
|
};
|
|
};
|
|
|
|
|
|
template <typename T, typename Index, size_t NumDims>
|
|
class GaussianGenerator {
|
|
public:
|
|
static const bool PacketAccess = false;
|
|
|
|
EIGEN_DEVICE_FUNC GaussianGenerator(const array<T, NumDims>& means,
|
|
const array<T, NumDims>& std_devs)
|
|
: m_means(means)
|
|
{
|
|
for (size_t i = 0; i < NumDims; ++i) {
|
|
m_two_sigmas[i] = std_devs[i] * std_devs[i] * 2;
|
|
}
|
|
}
|
|
|
|
EIGEN_DEVICE_FUNC T operator()(const array<Index, NumDims>& coordinates) const {
|
|
T tmp = T(0);
|
|
for (size_t i = 0; i < NumDims; ++i) {
|
|
T offset = coordinates[i] - m_means[i];
|
|
tmp += offset * offset / m_two_sigmas[i];
|
|
}
|
|
return numext::exp(-tmp);
|
|
}
|
|
|
|
private:
|
|
array<T, NumDims> m_means;
|
|
array<T, NumDims> m_two_sigmas;
|
|
};
|
|
|
|
template <typename T, typename Index, size_t NumDims>
|
|
struct functor_traits<GaussianGenerator<T, Index, NumDims> > {
|
|
enum {
|
|
Cost = NumDims * (2 * NumTraits<T>::AddCost + NumTraits<T>::MulCost +
|
|
functor_traits<scalar_quotient_op<T, T> >::Cost) +
|
|
functor_traits<scalar_exp_op<T> >::Cost,
|
|
PacketAccess = GaussianGenerator<T, Index, NumDims>::PacketAccess
|
|
};
|
|
};
|
|
|
|
} // end namespace internal
|
|
} // end namespace Eigen
|
|
|
|
#endif // EIGEN_CXX11_TENSOR_TENSOR_FUNCTORS_H
|