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> 304824e7fdSDimitry Andric class _LIBCPP_TEMPLATE_VIS gamma_distribution 314824e7fdSDimitry Andric { 32*5f757f3fSDimitry Andric static_assert(__libcpp_random_is_valid_realtype<_RealType>::value, 33*5f757f3fSDimitry Andric "RealType must be a supported floating-point type"); 34*5f757f3fSDimitry Andric 354824e7fdSDimitry Andric public: 364824e7fdSDimitry Andric // types 374824e7fdSDimitry Andric typedef _RealType result_type; 384824e7fdSDimitry Andric 394824e7fdSDimitry Andric class _LIBCPP_TEMPLATE_VIS param_type 404824e7fdSDimitry Andric { 414824e7fdSDimitry Andric result_type __alpha_; 424824e7fdSDimitry Andric result_type __beta_; 434824e7fdSDimitry Andric public: 444824e7fdSDimitry Andric typedef gamma_distribution distribution_type; 454824e7fdSDimitry Andric 46*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 474824e7fdSDimitry Andric explicit param_type(result_type __alpha = 1, result_type __beta = 1) 484824e7fdSDimitry Andric : __alpha_(__alpha), __beta_(__beta) {} 494824e7fdSDimitry Andric 50*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 514824e7fdSDimitry Andric result_type alpha() const {return __alpha_;} 52*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 534824e7fdSDimitry Andric result_type beta() const {return __beta_;} 544824e7fdSDimitry Andric 55*5f757f3fSDimitry Andric friend _LIBCPP_HIDE_FROM_ABI 564824e7fdSDimitry Andric bool operator==(const param_type& __x, const param_type& __y) 574824e7fdSDimitry Andric {return __x.__alpha_ == __y.__alpha_ && __x.__beta_ == __y.__beta_;} 58*5f757f3fSDimitry Andric friend _LIBCPP_HIDE_FROM_ABI 594824e7fdSDimitry Andric bool operator!=(const param_type& __x, const param_type& __y) 604824e7fdSDimitry Andric {return !(__x == __y);} 614824e7fdSDimitry Andric }; 624824e7fdSDimitry Andric 634824e7fdSDimitry Andric private: 644824e7fdSDimitry Andric param_type __p_; 654824e7fdSDimitry Andric 664824e7fdSDimitry Andric public: 674824e7fdSDimitry Andric // constructors and reset functions 684824e7fdSDimitry Andric #ifndef _LIBCPP_CXX03_LANG 69*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 704824e7fdSDimitry Andric gamma_distribution() : gamma_distribution(1) {} 71*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 724824e7fdSDimitry Andric explicit gamma_distribution(result_type __alpha, result_type __beta = 1) 734824e7fdSDimitry Andric : __p_(param_type(__alpha, __beta)) {} 744824e7fdSDimitry Andric #else 75*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 764824e7fdSDimitry Andric explicit gamma_distribution(result_type __alpha = 1, 774824e7fdSDimitry Andric result_type __beta = 1) 784824e7fdSDimitry Andric : __p_(param_type(__alpha, __beta)) {} 794824e7fdSDimitry Andric #endif 80*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 814824e7fdSDimitry Andric explicit gamma_distribution(const param_type& __p) 824824e7fdSDimitry Andric : __p_(__p) {} 83*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 844824e7fdSDimitry Andric void reset() {} 854824e7fdSDimitry Andric 864824e7fdSDimitry Andric // generating functions 874824e7fdSDimitry Andric template<class _URNG> 88*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 894824e7fdSDimitry Andric result_type operator()(_URNG& __g) 904824e7fdSDimitry Andric {return (*this)(__g, __p_);} 9106c3fb27SDimitry Andric template<class _URNG> 9206c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI result_type operator()(_URNG& __g, const param_type& __p); 934824e7fdSDimitry Andric 944824e7fdSDimitry Andric // property functions 95*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 964824e7fdSDimitry Andric result_type alpha() const {return __p_.alpha();} 97*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 984824e7fdSDimitry Andric result_type beta() const {return __p_.beta();} 994824e7fdSDimitry Andric 100*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 1014824e7fdSDimitry Andric param_type param() const {return __p_;} 102*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 1034824e7fdSDimitry Andric void param(const param_type& __p) {__p_ = __p;} 1044824e7fdSDimitry Andric 105*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 1064824e7fdSDimitry Andric result_type min() const {return 0;} 107*5f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI 1084824e7fdSDimitry Andric result_type max() const {return numeric_limits<result_type>::infinity();} 1094824e7fdSDimitry Andric 110*5f757f3fSDimitry Andric friend _LIBCPP_HIDE_FROM_ABI 1114824e7fdSDimitry Andric bool operator==(const gamma_distribution& __x, 1124824e7fdSDimitry Andric const gamma_distribution& __y) 1134824e7fdSDimitry Andric {return __x.__p_ == __y.__p_;} 114*5f757f3fSDimitry Andric friend _LIBCPP_HIDE_FROM_ABI 1154824e7fdSDimitry Andric bool operator!=(const gamma_distribution& __x, 1164824e7fdSDimitry Andric const gamma_distribution& __y) 1174824e7fdSDimitry Andric {return !(__x == __y);} 1184824e7fdSDimitry Andric }; 1194824e7fdSDimitry Andric 1204824e7fdSDimitry Andric template <class _RealType> 1214824e7fdSDimitry Andric template<class _URNG> 1224824e7fdSDimitry Andric _RealType 1234824e7fdSDimitry Andric gamma_distribution<_RealType>::operator()(_URNG& __g, const param_type& __p) 1244824e7fdSDimitry Andric { 12581ad6265SDimitry Andric static_assert(__libcpp_random_is_valid_urng<_URNG>::value, ""); 1264824e7fdSDimitry Andric result_type __a = __p.alpha(); 1274824e7fdSDimitry Andric uniform_real_distribution<result_type> __gen(0, 1); 1284824e7fdSDimitry Andric exponential_distribution<result_type> __egen; 1294824e7fdSDimitry Andric result_type __x; 1304824e7fdSDimitry Andric if (__a == 1) 1314824e7fdSDimitry Andric __x = __egen(__g); 1324824e7fdSDimitry Andric else if (__a > 1) 1334824e7fdSDimitry Andric { 1344824e7fdSDimitry Andric const result_type __b = __a - 1; 1354824e7fdSDimitry Andric const result_type __c = 3 * __a - result_type(0.75); 1364824e7fdSDimitry Andric while (true) 1374824e7fdSDimitry Andric { 1384824e7fdSDimitry Andric const result_type __u = __gen(__g); 1394824e7fdSDimitry Andric const result_type __v = __gen(__g); 1404824e7fdSDimitry Andric const result_type __w = __u * (1 - __u); 1414824e7fdSDimitry Andric if (__w != 0) 1424824e7fdSDimitry Andric { 143*5f757f3fSDimitry Andric const result_type __y = std::sqrt(__c / __w) * 1444824e7fdSDimitry Andric (__u - result_type(0.5)); 1454824e7fdSDimitry Andric __x = __b + __y; 1464824e7fdSDimitry Andric if (__x >= 0) 1474824e7fdSDimitry Andric { 1484824e7fdSDimitry Andric const result_type __z = 64 * __w * __w * __w * __v * __v; 1494824e7fdSDimitry Andric if (__z <= 1 - 2 * __y * __y / __x) 1504824e7fdSDimitry Andric break; 151*5f757f3fSDimitry Andric if (std::log(__z) <= 2 * (__b * std::log(__x / __b) - __y)) 1524824e7fdSDimitry Andric break; 1534824e7fdSDimitry Andric } 1544824e7fdSDimitry Andric } 1554824e7fdSDimitry Andric } 1564824e7fdSDimitry Andric } 1574824e7fdSDimitry Andric else // __a < 1 1584824e7fdSDimitry Andric { 1594824e7fdSDimitry Andric while (true) 1604824e7fdSDimitry Andric { 1614824e7fdSDimitry Andric const result_type __u = __gen(__g); 1624824e7fdSDimitry Andric const result_type __es = __egen(__g); 1634824e7fdSDimitry Andric if (__u <= 1 - __a) 1644824e7fdSDimitry Andric { 165*5f757f3fSDimitry Andric __x = std::pow(__u, 1 / __a); 1664824e7fdSDimitry Andric if (__x <= __es) 1674824e7fdSDimitry Andric break; 1684824e7fdSDimitry Andric } 1694824e7fdSDimitry Andric else 1704824e7fdSDimitry Andric { 171*5f757f3fSDimitry Andric const result_type __e = -std::log((1-__u)/__a); 172*5f757f3fSDimitry Andric __x = std::pow(1 - __a + __a * __e, 1 / __a); 1734824e7fdSDimitry Andric if (__x <= __e + __es) 1744824e7fdSDimitry Andric break; 1754824e7fdSDimitry Andric } 1764824e7fdSDimitry Andric } 1774824e7fdSDimitry Andric } 1784824e7fdSDimitry Andric return __x * __p.beta(); 1794824e7fdSDimitry Andric } 1804824e7fdSDimitry Andric 1814824e7fdSDimitry Andric template <class _CharT, class _Traits, class _RT> 182bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& 1834824e7fdSDimitry Andric operator<<(basic_ostream<_CharT, _Traits>& __os, 1844824e7fdSDimitry Andric const gamma_distribution<_RT>& __x) 1854824e7fdSDimitry Andric { 1864824e7fdSDimitry Andric __save_flags<_CharT, _Traits> __lx(__os); 1874824e7fdSDimitry Andric typedef basic_ostream<_CharT, _Traits> _OStream; 1884824e7fdSDimitry Andric __os.flags(_OStream::dec | _OStream::left | _OStream::fixed | 1894824e7fdSDimitry Andric _OStream::scientific); 1904824e7fdSDimitry Andric _CharT __sp = __os.widen(' '); 1914824e7fdSDimitry Andric __os.fill(__sp); 1924824e7fdSDimitry Andric __os << __x.alpha() << __sp << __x.beta(); 1934824e7fdSDimitry Andric return __os; 1944824e7fdSDimitry Andric } 1954824e7fdSDimitry Andric 1964824e7fdSDimitry Andric template <class _CharT, class _Traits, class _RT> 197bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI basic_istream<_CharT, _Traits>& 1984824e7fdSDimitry Andric operator>>(basic_istream<_CharT, _Traits>& __is, 1994824e7fdSDimitry Andric gamma_distribution<_RT>& __x) 2004824e7fdSDimitry Andric { 2014824e7fdSDimitry Andric typedef gamma_distribution<_RT> _Eng; 2024824e7fdSDimitry Andric typedef typename _Eng::result_type result_type; 2034824e7fdSDimitry Andric typedef typename _Eng::param_type param_type; 2044824e7fdSDimitry Andric __save_flags<_CharT, _Traits> __lx(__is); 2054824e7fdSDimitry Andric typedef basic_istream<_CharT, _Traits> _Istream; 2064824e7fdSDimitry Andric __is.flags(_Istream::dec | _Istream::skipws); 2074824e7fdSDimitry Andric result_type __alpha; 2084824e7fdSDimitry Andric result_type __beta; 2094824e7fdSDimitry Andric __is >> __alpha >> __beta; 2104824e7fdSDimitry Andric if (!__is.fail()) 2114824e7fdSDimitry Andric __x.param(param_type(__alpha, __beta)); 2124824e7fdSDimitry Andric return __is; 2134824e7fdSDimitry Andric } 2144824e7fdSDimitry Andric 2154824e7fdSDimitry Andric _LIBCPP_END_NAMESPACE_STD 2164824e7fdSDimitry Andric 2174824e7fdSDimitry Andric _LIBCPP_POP_MACROS 2184824e7fdSDimitry Andric 2194824e7fdSDimitry Andric #endif // _LIBCPP___RANDOM_GAMMA_DISTRIBUTION_H 220