2016-07-08 11:13:55 +02:00
|
|
|
// This file is part of Eigen, a lightweight C++ template library
|
|
|
|
|
// for linear algebra.
|
|
|
|
|
//
|
|
|
|
|
// Copyright (C) 2016 Eugene Brevdo <ebrevdo@gmail.com>
|
|
|
|
|
// Copyright (C) 2016 Gael Guennebaud <gael.guennebaud@inria.fr>
|
|
|
|
|
//
|
|
|
|
|
// 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 http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
|
|
#ifndef EIGEN_SPECIALFUNCTIONS_FUNCTORS_H
|
|
|
|
|
#define EIGEN_SPECIALFUNCTIONS_FUNCTORS_H
|
|
|
|
|
|
2023-08-21 16:25:22 +00:00
|
|
|
// IWYU pragma: private
|
2021-09-10 19:12:26 +00:00
|
|
|
#include "./InternalHeaderCheck.h"
|
|
|
|
|
|
2016-07-08 11:13:55 +02:00
|
|
|
namespace Eigen {
|
|
|
|
|
|
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute the incomplete gamma function igamma(a, x)
|
|
|
|
|
*
|
|
|
|
|
* \sa class CwiseBinaryOp, Cwise::igamma
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_igamma_op : binary_op_base<Scalar, Scalar> {
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a, const Scalar& x) const {
|
|
|
|
|
using numext::igamma;
|
|
|
|
|
return igamma(a, x);
|
|
|
|
|
}
|
|
|
|
|
template <typename Packet>
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& x) const {
|
|
|
|
|
return internal::pigamma(a, x);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_igamma_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// Guesstimate
|
|
|
|
|
Cost = 20 * NumTraits<Scalar>::MulCost + 10 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasIGamma
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
Derivative of the incomplete Gamma function and the sample of a Gamma random variable.
In addition to igamma(a, x), this code implements:
* igamma_der_a(a, x) = d igamma(a, x) / da -- derivative of igamma with respect to the parameter
* gamma_sample_der_alpha(alpha, sample) -- reparameterization derivative of a Gamma(alpha, 1) random variable sample with respect to the alpha parameter
The derivatives are computed by forward mode differentiation of the igamma(a, x) code. Although gamma_sample_der_alpha can be implemented via igamma_der_a, a separate function is more accurate and efficient due to analytical cancellation of some terms. All three functions are implemented by a method parameterized with "mode" that always computes the derivatives, but does not return them unless required by the mode. The compiler is expected to (and, based on benchmarks, does) skip the unnecessary computations depending on the mode.
2018-06-06 18:49:26 +01:00
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute the derivative of the incomplete gamma
|
|
|
|
|
* function igamma_der_a(a, x)
|
|
|
|
|
*
|
|
|
|
|
* \sa class CwiseBinaryOp, Cwise::igamma_der_a
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_igamma_der_a_op {
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a, const Scalar& x) const {
|
|
|
|
|
using numext::igamma_der_a;
|
|
|
|
|
return igamma_der_a(a, x);
|
|
|
|
|
}
|
|
|
|
|
template <typename Packet>
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& x) const {
|
|
|
|
|
return internal::pigamma_der_a(a, x);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_igamma_der_a_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// 2x the cost of igamma
|
|
|
|
|
Cost = 40 * NumTraits<Scalar>::MulCost + 20 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasIGammaDerA
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute the derivative of the sample
|
|
|
|
|
* of a Gamma(alpha, 1) random variable with respect to the parameter alpha
|
|
|
|
|
* gamma_sample_der_alpha(alpha, sample)
|
|
|
|
|
*
|
|
|
|
|
* \sa class CwiseBinaryOp, Cwise::gamma_sample_der_alpha
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_gamma_sample_der_alpha_op {
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& alpha, const Scalar& sample) const {
|
|
|
|
|
using numext::gamma_sample_der_alpha;
|
|
|
|
|
return gamma_sample_der_alpha(alpha, sample);
|
|
|
|
|
}
|
|
|
|
|
template <typename Packet>
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& alpha, const Packet& sample) const {
|
|
|
|
|
return internal::pgamma_sample_der_alpha(alpha, sample);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_gamma_sample_der_alpha_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// 2x the cost of igamma, minus the lgamma cost (the lgamma cancels out)
|
|
|
|
|
Cost = 30 * NumTraits<Scalar>::MulCost + 15 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasGammaSampleDerAlpha
|
|
|
|
|
};
|
|
|
|
|
};
|
2016-07-08 11:13:55 +02:00
|
|
|
|
|
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute the complementary incomplete gamma function igammac(a, x)
|
|
|
|
|
*
|
|
|
|
|
* \sa class CwiseBinaryOp, Cwise::igammac
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_igammac_op : binary_op_base<Scalar, Scalar> {
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a, const Scalar& x) const {
|
|
|
|
|
using numext::igammac;
|
|
|
|
|
return igammac(a, x);
|
|
|
|
|
}
|
|
|
|
|
template <typename Packet>
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& a, const Packet& x) const {
|
|
|
|
|
return internal::pigammac(a, x);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_igammac_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// Guesstimate
|
|
|
|
|
Cost = 20 * NumTraits<Scalar>::MulCost + 10 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasIGammac
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute the incomplete beta integral betainc(a, b, x)
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_betainc_op {
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& x, const Scalar& a,
|
|
|
|
|
const Scalar& b) const {
|
|
|
|
|
using numext::betainc;
|
|
|
|
|
return betainc(x, a, b);
|
|
|
|
|
}
|
|
|
|
|
template <typename Packet>
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Packet packetOp(const Packet& x, const Packet& a, const Packet& b) const {
|
|
|
|
|
return internal::pbetainc(x, a, b);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_betainc_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// Guesstimate
|
|
|
|
|
Cost = 400 * NumTraits<Scalar>::MulCost + 400 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasBetaInc
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute the natural log of the absolute
|
|
|
|
|
* value of Gamma of a scalar
|
|
|
|
|
* \sa class CwiseUnaryOp, Cwise::lgamma()
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_lgamma_op {
|
2018-08-01 10:47:49 +01:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const {
|
2016-07-08 11:13:55 +02:00
|
|
|
using numext::lgamma;
|
|
|
|
|
return lgamma(a);
|
|
|
|
|
}
|
|
|
|
|
typedef typename packet_traits<Scalar>::type Packet;
|
2018-08-01 10:47:49 +01:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const { return internal::plgamma(a); }
|
2016-07-08 11:13:55 +02:00
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_lgamma_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// Guesstimate
|
|
|
|
|
Cost = 10 * NumTraits<Scalar>::MulCost + 5 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasLGamma
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute psi, the derivative of lgamma of a scalar.
|
|
|
|
|
* \sa class CwiseUnaryOp, Cwise::digamma()
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_digamma_op {
|
2018-08-01 10:47:49 +01:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const {
|
2016-07-08 11:13:55 +02:00
|
|
|
using numext::digamma;
|
|
|
|
|
return digamma(a);
|
|
|
|
|
}
|
|
|
|
|
typedef typename packet_traits<Scalar>::type Packet;
|
2018-08-01 10:47:49 +01:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const { return internal::pdigamma(a); }
|
2016-07-08 11:13:55 +02:00
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_digamma_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// Guesstimate
|
|
|
|
|
Cost = 10 * NumTraits<Scalar>::MulCost + 5 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasDiGamma
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute the Riemann Zeta function of two arguments.
|
|
|
|
|
* \sa class CwiseUnaryOp, Cwise::zeta()
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_zeta_op {
|
2018-08-01 10:47:49 +01:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& x, const Scalar& q) const {
|
2016-07-08 11:13:55 +02:00
|
|
|
using numext::zeta;
|
|
|
|
|
return zeta(x, q);
|
|
|
|
|
}
|
|
|
|
|
typedef typename packet_traits<Scalar>::type Packet;
|
2018-08-01 10:47:49 +01:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& x, const Packet& q) const {
|
|
|
|
|
return internal::pzeta(x, q);
|
|
|
|
|
}
|
2016-07-08 11:13:55 +02:00
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_zeta_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// Guesstimate
|
|
|
|
|
Cost = 10 * NumTraits<Scalar>::MulCost + 5 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasZeta
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute the polygamma function.
|
|
|
|
|
* \sa class CwiseUnaryOp, Cwise::polygamma()
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_polygamma_op {
|
2018-08-01 10:47:49 +01:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& n, const Scalar& x) const {
|
2016-07-08 11:13:55 +02:00
|
|
|
using numext::polygamma;
|
|
|
|
|
return polygamma(n, x);
|
|
|
|
|
}
|
|
|
|
|
typedef typename packet_traits<Scalar>::type Packet;
|
2018-08-01 10:47:49 +01:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& n, const Packet& x) const {
|
|
|
|
|
return internal::ppolygamma(n, x);
|
|
|
|
|
}
|
2016-07-08 11:13:55 +02:00
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_polygamma_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// Guesstimate
|
|
|
|
|
Cost = 10 * NumTraits<Scalar>::MulCost + 5 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasPolygamma
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** \internal
|
2019-09-19 12:48:30 -07:00
|
|
|
* \brief Template functor to compute the error function of a scalar
|
|
|
|
|
* \sa class CwiseUnaryOp, ArrayBase::erf()
|
2016-07-08 11:13:55 +02:00
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_erf_op {
|
2019-09-19 12:48:30 -07:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const { return numext::erf(a); }
|
|
|
|
|
template <typename Packet>
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& x) const {
|
|
|
|
|
return perf(x);
|
2016-07-08 11:13:55 +02:00
|
|
|
}
|
|
|
|
|
};
|
2019-09-19 12:48:30 -07:00
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_erf_op<Scalar> > {
|
2016-07-08 11:13:55 +02:00
|
|
|
enum {
|
2019-09-19 12:48:30 -07:00
|
|
|
PacketAccess = packet_traits<Scalar>::HasErf,
|
|
|
|
|
Cost = (PacketAccess
|
|
|
|
|
#ifdef EIGEN_VECTORIZE_FMA
|
2019-09-24 16:39:25 -07:00
|
|
|
// TODO(rmlarsen): Move the FMA cost model to a central location.
|
2019-09-19 12:48:30 -07:00
|
|
|
// Haswell can issue 2 add/mul/madd per cycle.
|
|
|
|
|
// 10 pmadd, 2 pmul, 1 div, 2 other
|
|
|
|
|
? (2 * NumTraits<Scalar>::AddCost + 7 * NumTraits<Scalar>::MulCost +
|
|
|
|
|
scalar_div_cost<Scalar, packet_traits<Scalar>::HasDiv>::value)
|
|
|
|
|
#else
|
|
|
|
|
? (12 * NumTraits<Scalar>::AddCost + 12 * NumTraits<Scalar>::MulCost +
|
|
|
|
|
scalar_div_cost<Scalar, packet_traits<Scalar>::HasDiv>::value)
|
|
|
|
|
#endif
|
|
|
|
|
// Assume for simplicity that this is as expensive as an exp().
|
|
|
|
|
: (functor_traits<scalar_exp_op<Scalar> >::Cost))
|
2016-07-08 11:13:55 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute the Complementary Error Function
|
|
|
|
|
* of a scalar
|
|
|
|
|
* \sa class CwiseUnaryOp, Cwise::erfc()
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_erfc_op {
|
2018-08-01 10:47:49 +01:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const {
|
2016-07-08 11:13:55 +02:00
|
|
|
using numext::erfc;
|
|
|
|
|
return erfc(a);
|
|
|
|
|
}
|
|
|
|
|
typedef typename packet_traits<Scalar>::type Packet;
|
2018-08-01 10:47:49 +01:00
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const { return internal::perfc(a); }
|
2016-07-08 11:13:55 +02:00
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_erfc_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// Guesstimate
|
|
|
|
|
Cost = 10 * NumTraits<Scalar>::MulCost + 5 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasErfc
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2019-08-12 19:26:29 -04:00
|
|
|
/** \internal
|
|
|
|
|
* \brief Template functor to compute the Inverse of the normal distribution
|
|
|
|
|
* function of a scalar
|
|
|
|
|
* \sa class CwiseUnaryOp, Cwise::ndtri()
|
|
|
|
|
*/
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct scalar_ndtri_op {
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar operator()(const Scalar& a) const {
|
|
|
|
|
using numext::ndtri;
|
|
|
|
|
return ndtri(a);
|
|
|
|
|
}
|
|
|
|
|
typedef typename packet_traits<Scalar>::type Packet;
|
|
|
|
|
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& a) const { return internal::pndtri(a); }
|
|
|
|
|
};
|
|
|
|
|
template <typename Scalar>
|
|
|
|
|
struct functor_traits<scalar_ndtri_op<Scalar> > {
|
|
|
|
|
enum {
|
|
|
|
|
// On average, We are evaluating rational functions with degree N=9 in the
|
|
|
|
|
// numerator and denominator. This results in 2*N additions and 2*N
|
|
|
|
|
// multiplications.
|
|
|
|
|
Cost = 18 * NumTraits<Scalar>::MulCost + 18 * NumTraits<Scalar>::AddCost,
|
|
|
|
|
PacketAccess = packet_traits<Scalar>::HasNdtri
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2016-07-08 11:13:55 +02:00
|
|
|
} // end namespace internal
|
|
|
|
|
|
|
|
|
|
} // end namespace Eigen
|
|
|
|
|
|
|
|
|
|
#endif // EIGEN_SPECIALFUNCTIONS_FUNCTORS_H
|