#ifndef BOOST_STATS_TRIANGULAR_HPP
#define BOOST_STATS_TRIANGULAR_HPP
#include <boost/math/tools/config.hpp>
#include <boost/math/tools/tuple.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/math/distributions/complement.hpp>
#include <boost/math/constants/constants.hpp>
namespace boost{ namespace math
{
namespace detail
{
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline bool check_triangular_lower(
const char* function,
RealType lower,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(lower))
{
return true;
}
else
{
*result = policies::raise_domain_error<RealType>(
function,
"Lower parameter is %1%, but must be finite!", lower, pol);
return false;
}
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline bool check_triangular_mode(
const char* function,
RealType mode,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(mode))
{
return true;
}
else
{
*result = policies::raise_domain_error<RealType>(
function,
"Mode parameter is %1%, but must be finite!", mode, pol);
return false;
}
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline bool check_triangular_upper(
const char* function,
RealType upper,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(upper))
{
return true;
}
else
{
*result = policies::raise_domain_error<RealType>(
function,
"Upper parameter is %1%, but must be finite!", upper, pol);
return false;
}
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline bool check_triangular_x(
const char* function,
RealType const& x,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(x))
{
return true;
}
else
{
*result = policies::raise_domain_error<RealType>(
function,
"x parameter is %1%, but must be finite!", x, pol);
return false;
}
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline bool check_triangular(
const char* function,
RealType lower,
RealType mode,
RealType upper,
RealType* result, const Policy& pol)
{
if ((check_triangular_lower(function, lower, result, pol) == false)
|| (check_triangular_mode(function, mode, result, pol) == false)
|| (check_triangular_upper(function, upper, result, pol) == false))
{
return false;
}
else if (lower >= upper)
{
*result = policies::raise_domain_error<RealType>(
function,
"lower parameter is %1%, but must be less than upper!", lower, pol);
return false;
}
else
{
if (mode < lower)
{
*result = policies::raise_domain_error<RealType>(
function,
"mode parameter is %1%, but must be >= than lower!", lower, pol);
return false;
}
if (mode > upper)
{
*result = policies::raise_domain_error<RealType>(
function,
"mode parameter is %1%, but must be <= than upper!", upper, pol);
return false;
}
return true;
}
}
}
template <class RealType = double, class Policy = policies::policy<> >
class triangular_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
BOOST_MATH_GPU_ENABLED triangular_distribution(RealType l_lower = -1, RealType l_mode = 0, RealType l_upper = 1)
: m_lower(l_lower), m_mode(l_mode), m_upper(l_upper) // Constructor.
{
RealType result;
detail::check_triangular("boost::math::triangular_distribution<%1%>::triangular_distribution",l_lower, l_mode, l_upper, &result, Policy());
}
BOOST_MATH_GPU_ENABLED RealType lower()const
{
return m_lower;
}
BOOST_MATH_GPU_ENABLED RealType mode()const
{
return m_mode;
}
BOOST_MATH_GPU_ENABLED RealType upper()const
{
return m_upper;
}
private:
RealType m_lower;
RealType m_mode;
RealType m_upper;
};
typedef triangular_distribution<double> triangular;
#ifdef __cpp_deduction_guides
template <class RealType>
triangular_distribution(RealType)->triangular_distribution<typename boost::math::tools::promote_args<RealType>::type>;
template <class RealType>
triangular_distribution(RealType,RealType)->triangular_distribution<typename boost::math::tools::promote_args<RealType>::type>;
template <class RealType>
triangular_distribution(RealType,RealType,RealType)->triangular_distribution<typename boost::math::tools::promote_args<RealType>::type>;
#endif
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> range(const triangular_distribution<RealType, Policy>& )
{
using boost::math::tools::max_value;
return boost::math::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> support(const triangular_distribution<RealType, Policy>& dist)
{
return boost::math::pair<RealType, RealType>(dist.lower(), dist.upper());
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED RealType pdf(const triangular_distribution<RealType, Policy>& dist, const RealType& x)
{
constexpr auto function = "boost::math::pdf(const triangular_distribution<%1%>&, %1%)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result = 0;
if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_triangular_x(function, x, &result, Policy()))
{
return result;
}
if((x < lower) || (x > upper))
{
return 0;
}
if (x == lower)
{
return (mode == lower) ? 2 / (upper - lower) : RealType(0);
}
else if (x == upper)
{
return (mode == upper) ? 2 / (upper - lower) : RealType(0);
}
else if (x <= mode)
{
return 2 * (x - lower) / ((upper - lower) * (mode - lower));
}
else
{
return 2 * (upper - x) / ((upper - lower) * (upper - mode));
}
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType cdf(const triangular_distribution<RealType, Policy>& dist, const RealType& x)
{
constexpr auto function = "boost::math::cdf(const triangular_distribution<%1%>&, %1%)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result = 0;
if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_triangular_x(function, x, &result, Policy()))
{
return result;
}
if((x <= lower))
{
return 0;
}
if (x >= upper)
{
return 1;
}
if (x <= mode)
{
return ((x - lower) * (x - lower)) / ((upper - lower) * (mode - lower));
}
else
{
return 1 - (upper - x) * (upper - x) / ((upper - lower) * (upper - mode));
}
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED RealType quantile(const triangular_distribution<RealType, Policy>& dist, const RealType& p)
{
BOOST_MATH_STD_USING
constexpr auto function = "boost::math::quantile(const triangular_distribution<%1%>&, %1%)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result = 0;
if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_probability(function, p, &result, Policy()))
{
return result;
}
if(p == 0)
{
return lower;
}
if(p == 1)
{
return upper;
}
RealType p0 = (mode - lower) / (upper - lower);
RealType q = 1 - p;
if (p < p0)
{
result = sqrt((upper - lower) * (mode - lower) * p) + lower;
}
else if (p == p0)
{
result = mode;
}
else
{
result = upper - sqrt((upper - lower) * (upper - mode) * q);
}
return result;
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED RealType cdf(const complemented2_type<triangular_distribution<RealType, Policy>, RealType>& c)
{
constexpr auto function = "boost::math::cdf(const triangular_distribution<%1%>&, %1%)";
RealType lower = c.dist.lower();
RealType mode = c.dist.mode();
RealType upper = c.dist.upper();
RealType x = c.param;
RealType result = 0;
if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_triangular_x(function, x, &result, Policy()))
{
return result;
}
if (x <= lower)
{
return 1;
}
if (x >= upper)
{
return 0;
}
if (x <= mode)
{
return 1 - ((x - lower) * (x - lower)) / ((upper - lower) * (mode - lower));
}
else
{
return (upper - x) * (upper - x) / ((upper - lower) * (upper - mode));
}
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED RealType quantile(const complemented2_type<triangular_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING
constexpr auto function = "boost::math::quantile(const triangular_distribution<%1%>&, %1%)";
RealType l = c.dist.lower();
RealType m = c.dist.mode();
RealType u = c.dist.upper();
RealType q = c.param;
RealType result = 0;
if(false == detail::check_triangular(function, l, m, u, &result, Policy()))
{
return result;
}
if(false == detail::check_probability(function, q, &result, Policy()))
{
return result;
}
if(q == 0)
{
return u;
}
if(q == 1)
{
return l;
}
RealType lower = c.dist.lower();
RealType mode = c.dist.mode();
RealType upper = c.dist.upper();
RealType p = 1 - q;
RealType p0 = (mode - lower) / (upper - lower);
if(p < p0)
{
RealType s = (upper - lower) * (mode - lower);
s *= p;
result = sqrt((upper - lower) * (mode - lower) * p) + lower;
}
else if (p == p0)
{
result = mode;
}
else
{
result = upper - sqrt((upper - lower) * (upper - mode) * q);
}
return result;
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType mean(const triangular_distribution<RealType, Policy>& dist)
{
constexpr auto function = "boost::math::mean(const triangular_distribution<%1%>&)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result = 0;
if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy()))
{
return result;
}
return (lower + upper + mode) / 3;
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType variance(const triangular_distribution<RealType, Policy>& dist)
{
constexpr auto function = "boost::math::mean(const triangular_distribution<%1%>&)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result = 0;
if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy()))
{
return result;
}
return (lower * lower + upper * upper + mode * mode - lower * upper - lower * mode - upper * mode) / 18;
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType mode(const triangular_distribution<RealType, Policy>& dist)
{
constexpr auto function = "boost::math::mode(const triangular_distribution<%1%>&)";
RealType mode = dist.mode();
RealType result = 0;
if(false == detail::check_triangular_mode(function, mode, &result, Policy()))
{
return result;
}
return mode;
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType median(const triangular_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING
constexpr auto function = "boost::math::median(const triangular_distribution<%1%>&)";
RealType mode = dist.mode();
RealType result = 0;
if(false == detail::check_triangular_mode(function, mode, &result, Policy()))
{
return result;
}
RealType lower = dist.lower();
RealType upper = dist.upper();
if (mode >= (upper + lower) / 2)
{
return lower + sqrt((upper - lower) * (mode - lower)) / constants::root_two<RealType>();
}
else
{
return upper - sqrt((upper - lower) * (upper - mode)) / constants::root_two<RealType>();
}
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType skewness(const triangular_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING
using namespace boost::math::constants;
constexpr auto function = "boost::math::skewness(const triangular_distribution<%1%>&)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result = 0;
if(false == boost::math::detail::check_triangular(function,lower, mode, upper, &result, Policy()))
{
return result;
}
return root_two<RealType>() * (lower + upper - 2 * mode) * (2 * lower - upper - mode) * (lower - 2 * upper + mode) /
(5 * pow((lower * lower + upper * upper + mode * mode
- lower * upper - lower * mode - upper * mode), RealType(3)/RealType(2)));
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType kurtosis(const triangular_distribution<RealType, Policy>& dist)
{
constexpr auto function = "boost::math::kurtosis(const triangular_distribution<%1%>&)";
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType mode = dist.mode();
RealType result = 0;
if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy()))
{
return result;
}
return static_cast<RealType>(12)/5;
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType kurtosis_excess(const triangular_distribution<RealType, Policy>& dist)
{
constexpr auto function = "boost::math::kurtosis_excess(const triangular_distribution<%1%>&)";
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType mode = dist.mode();
RealType result = 0;
if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy()))
{
return result;
}
return static_cast<RealType>(-3)/5;
}
template <class RealType, class Policy>
BOOST_MATH_GPU_ENABLED inline RealType entropy(const triangular_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING
return constants::half<RealType>() + log((dist.upper() - dist.lower())/2);
}
}
}
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif