14824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 24824e7fdSDimitry Andric // 34824e7fdSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44824e7fdSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 54824e7fdSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64824e7fdSDimitry Andric // 74824e7fdSDimitry Andric //===----------------------------------------------------------------------===// 84824e7fdSDimitry Andric 94824e7fdSDimitry Andric #ifndef _LIBCPP___RANDOM_GAMMA_DISTRIBUTION_H 104824e7fdSDimitry Andric #define _LIBCPP___RANDOM_GAMMA_DISTRIBUTION_H 114824e7fdSDimitry Andric 124824e7fdSDimitry Andric #include <__config> 134824e7fdSDimitry Andric #include <__random/exponential_distribution.h> 1481ad6265SDimitry Andric #include <__random/is_valid.h> 1504eeddc0SDimitry Andric #include <__random/uniform_real_distribution.h> 164824e7fdSDimitry Andric #include <cmath> 174824e7fdSDimitry Andric #include <iosfwd> 184824e7fdSDimitry Andric #include <limits> 194824e7fdSDimitry Andric 204824e7fdSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 214824e7fdSDimitry Andric # pragma GCC system_header 224824e7fdSDimitry Andric #endif 234824e7fdSDimitry Andric 244824e7fdSDimitry Andric _LIBCPP_PUSH_MACROS 254824e7fdSDimitry Andric #include <__undef_macros> 264824e7fdSDimitry Andric 274824e7fdSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 284824e7fdSDimitry Andric 294824e7fdSDimitry Andric template <class _RealType = double> 30*cb14a3feSDimitry Andric class _LIBCPP_TEMPLATE_VIS gamma_distribution { 315f757f3fSDimitry Andric static_assert(__libcpp_random_is_valid_realtype<_RealType>::value, 325f757f3fSDimitry Andric "RealType must be a supported floating-point type"); 335f757f3fSDimitry Andric 344824e7fdSDimitry Andric public: 354824e7fdSDimitry Andric // types 364824e7fdSDimitry Andric typedef _RealType result_type; 374824e7fdSDimitry Andric 38*cb14a3feSDimitry Andric class _LIBCPP_TEMPLATE_VIS param_type { 394824e7fdSDimitry Andric result_type __alpha_; 404824e7fdSDimitry Andric result_type __beta_; 41*cb14a3feSDimitry Andric 424824e7fdSDimitry Andric public: 434824e7fdSDimitry Andric typedef gamma_distribution distribution_type; 444824e7fdSDimitry Andric 45*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit param_type(result_type __alpha = 1, result_type __beta = 1) 464824e7fdSDimitry Andric : __alpha_(__alpha), __beta_(__beta) {} 474824e7fdSDimitry Andric 48*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type alpha() const { return __alpha_; } 49*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type beta() const { return __beta_; } 504824e7fdSDimitry Andric 51*cb14a3feSDimitry Andric friend _LIBCPP_HIDE_FROM_ABI bool operator==(const param_type& __x, const param_type& __y) { 52*cb14a3feSDimitry Andric return __x.__alpha_ == __y.__alpha_ && __x.__beta_ == __y.__beta_; 53*cb14a3feSDimitry Andric } 54*cb14a3feSDimitry Andric friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const param_type& __x, const param_type& __y) { return !(__x == __y); } 554824e7fdSDimitry Andric }; 564824e7fdSDimitry Andric 574824e7fdSDimitry Andric private: 584824e7fdSDimitry Andric param_type __p_; 594824e7fdSDimitry Andric 604824e7fdSDimitry Andric public: 614824e7fdSDimitry Andric // constructors and reset functions 624824e7fdSDimitry Andric #ifndef _LIBCPP_CXX03_LANG 63*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI gamma_distribution() : gamma_distribution(1) {} 64*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit gamma_distribution(result_type __alpha, result_type __beta = 1) 654824e7fdSDimitry Andric : __p_(param_type(__alpha, __beta)) {} 664824e7fdSDimitry Andric #else 67*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit gamma_distribution(result_type __alpha = 1, result_type __beta = 1) 684824e7fdSDimitry Andric : __p_(param_type(__alpha, __beta)) {} 694824e7fdSDimitry Andric #endif 70*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit gamma_distribution(const param_type& __p) : __p_(__p) {} 71*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI void reset() {} 724824e7fdSDimitry Andric 734824e7fdSDimitry Andric // generating functions 744824e7fdSDimitry Andric template <class _URNG> 75*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type operator()(_URNG& __g) { 76*cb14a3feSDimitry Andric return (*this)(__g, __p_); 77*cb14a3feSDimitry Andric } 7806c3fb27SDimitry Andric template <class _URNG> 7906c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type operator()(_URNG& __g, const param_type& __p); 804824e7fdSDimitry Andric 814824e7fdSDimitry Andric // property functions 82*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type alpha() const { return __p_.alpha(); } 83*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type beta() const { return __p_.beta(); } 844824e7fdSDimitry Andric 85*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI param_type param() const { return __p_; } 86*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI void param(const param_type& __p) { __p_ = __p; } 874824e7fdSDimitry Andric 88*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type min() const { return 0; } 89*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type max() const { return numeric_limits<result_type>::infinity(); } 904824e7fdSDimitry Andric 91*cb14a3feSDimitry Andric friend _LIBCPP_HIDE_FROM_ABI bool operator==(const gamma_distribution& __x, const gamma_distribution& __y) { 92*cb14a3feSDimitry Andric return __x.__p_ == __y.__p_; 93*cb14a3feSDimitry Andric } 94*cb14a3feSDimitry Andric friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const gamma_distribution& __x, const gamma_distribution& __y) { 95*cb14a3feSDimitry Andric return !(__x == __y); 96*cb14a3feSDimitry Andric } 974824e7fdSDimitry Andric }; 984824e7fdSDimitry Andric 994824e7fdSDimitry Andric template <class _RealType> 1004824e7fdSDimitry Andric template <class _URNG> 101*cb14a3feSDimitry Andric _RealType gamma_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) { 10281ad6265SDimitry Andric static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); 1034824e7fdSDimitry Andric result_type __a = __p.alpha(); 1044824e7fdSDimitry Andric uniform_real_distribution<result_type> __gen(0, 1); 1054824e7fdSDimitry Andric exponential_distribution<result_type> __egen; 1064824e7fdSDimitry Andric result_type __x; 1074824e7fdSDimitry Andric if (__a == 1) 1084824e7fdSDimitry Andric __x = __egen(__g); 109*cb14a3feSDimitry Andric else if (__a > 1) { 1104824e7fdSDimitry Andric const result_type __b = __a - 1; 1114824e7fdSDimitry Andric const result_type __c = 3 * __a - result_type(0.75); 112*cb14a3feSDimitry Andric while (true) { 1134824e7fdSDimitry Andric const result_type __u = __gen(__g); 1144824e7fdSDimitry Andric const result_type __v = __gen(__g); 1154824e7fdSDimitry Andric const result_type __w = __u * (1 - __u); 116*cb14a3feSDimitry Andric if (__w != 0) { 117*cb14a3feSDimitry Andric const result_type __y = std::sqrt(__c / __w) * (__u - result_type(0.5)); 1184824e7fdSDimitry Andric __x = __b + __y; 119*cb14a3feSDimitry Andric if (__x >= 0) { 1204824e7fdSDimitry Andric const result_type __z = 64 * __w * __w * __w * __v * __v; 1214824e7fdSDimitry Andric if (__z <= 1 - 2 * __y * __y / __x) 1224824e7fdSDimitry Andric break; 1235f757f3fSDimitry Andric if (std::log(__z) <= 2 * (__b * std::log(__x / __b) - __y)) 1244824e7fdSDimitry Andric break; 1254824e7fdSDimitry Andric } 1264824e7fdSDimitry Andric } 1274824e7fdSDimitry Andric } 128*cb14a3feSDimitry Andric } else // __a < 1 1294824e7fdSDimitry Andric { 130*cb14a3feSDimitry Andric while (true) { 1314824e7fdSDimitry Andric const result_type __u = __gen(__g); 1324824e7fdSDimitry Andric const result_type __es = __egen(__g); 133*cb14a3feSDimitry Andric if (__u <= 1 - __a) { 1345f757f3fSDimitry Andric __x = std::pow(__u, 1 / __a); 1354824e7fdSDimitry Andric if (__x <= __es) 1364824e7fdSDimitry Andric break; 137*cb14a3feSDimitry Andric } else { 1385f757f3fSDimitry Andric const result_type __e = -std::log((1 - __u) / __a); 1395f757f3fSDimitry Andric __x = std::pow(1 - __a + __a * __e, 1 / __a); 1404824e7fdSDimitry Andric if (__x <= __e + __es) 1414824e7fdSDimitry Andric break; 1424824e7fdSDimitry Andric } 1434824e7fdSDimitry Andric } 1444824e7fdSDimitry Andric } 1454824e7fdSDimitry Andric return __x * __p.beta(); 1464824e7fdSDimitry Andric } 1474824e7fdSDimitry Andric 1484824e7fdSDimitry Andric template <class _CharT, class _Traits, class _RT> 149bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 150*cb14a3feSDimitry Andric operator<<(basic_ostream<_CharT, _Traits>& __os, const gamma_distribution<_RT>& __x) { 1514824e7fdSDimitry Andric __save_flags<_CharT, _Traits> __lx(__os); 1524824e7fdSDimitry Andric typedef basic_ostream<_CharT, _Traits> _OStream; 153*cb14a3feSDimitry Andric __os.flags(_OStream::dec | _OStream::left | _OStream::fixed | _OStream::scientific); 1544824e7fdSDimitry Andric _CharT __sp = __os.widen(' '); 1554824e7fdSDimitry Andric __os.fill(__sp); 1564824e7fdSDimitry Andric __os << __x.alpha() << __sp << __x.beta(); 1574824e7fdSDimitry Andric return __os; 1584824e7fdSDimitry Andric } 1594824e7fdSDimitry Andric 1604824e7fdSDimitry Andric template <class _CharT, class _Traits, class _RT> 161bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_istream<_CharT, _Traits>& 162*cb14a3feSDimitry Andric operator>>(basic_istream<_CharT, _Traits>& __is, gamma_distribution<_RT>& __x) { 1634824e7fdSDimitry Andric typedef gamma_distribution<_RT> _Eng; 1644824e7fdSDimitry Andric typedef typename _Eng::result_type result_type; 1654824e7fdSDimitry Andric typedef typename _Eng::param_type param_type; 1664824e7fdSDimitry Andric __save_flags<_CharT, _Traits> __lx(__is); 1674824e7fdSDimitry Andric typedef basic_istream<_CharT, _Traits> _Istream; 1684824e7fdSDimitry Andric __is.flags(_Istream::dec | _Istream::skipws); 1694824e7fdSDimitry Andric result_type __alpha; 1704824e7fdSDimitry Andric result_type __beta; 1714824e7fdSDimitry Andric __is >> __alpha >> __beta; 1724824e7fdSDimitry Andric if (!__is.fail()) 1734824e7fdSDimitry Andric __x.param(param_type(__alpha, __beta)); 1744824e7fdSDimitry Andric return __is; 1754824e7fdSDimitry Andric } 1764824e7fdSDimitry Andric 1774824e7fdSDimitry Andric _LIBCPP_END_NAMESPACE_STD 1784824e7fdSDimitry Andric 1794824e7fdSDimitry Andric _LIBCPP_POP_MACROS 1804824e7fdSDimitry Andric 1814824e7fdSDimitry Andric #endif // _LIBCPP___RANDOM_GAMMA_DISTRIBUTION_H 182