xref: /aosp_15_r20/external/abseil-cpp/absl/random/exponential_distribution.h (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker // Copyright 2017 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker 
15*9356374aSAndroid Build Coastguard Worker #ifndef ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_
16*9356374aSAndroid Build Coastguard Worker #define ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_
17*9356374aSAndroid Build Coastguard Worker 
18*9356374aSAndroid Build Coastguard Worker #include <cassert>
19*9356374aSAndroid Build Coastguard Worker #include <cmath>
20*9356374aSAndroid Build Coastguard Worker #include <istream>
21*9356374aSAndroid Build Coastguard Worker #include <limits>
22*9356374aSAndroid Build Coastguard Worker #include <type_traits>
23*9356374aSAndroid Build Coastguard Worker 
24*9356374aSAndroid Build Coastguard Worker #include "absl/meta/type_traits.h"
25*9356374aSAndroid Build Coastguard Worker #include "absl/random/internal/fast_uniform_bits.h"
26*9356374aSAndroid Build Coastguard Worker #include "absl/random/internal/generate_real.h"
27*9356374aSAndroid Build Coastguard Worker #include "absl/random/internal/iostream_state_saver.h"
28*9356374aSAndroid Build Coastguard Worker 
29*9356374aSAndroid Build Coastguard Worker namespace absl {
30*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
31*9356374aSAndroid Build Coastguard Worker 
32*9356374aSAndroid Build Coastguard Worker // absl::exponential_distribution:
33*9356374aSAndroid Build Coastguard Worker // Generates a number conforming to an exponential distribution and is
34*9356374aSAndroid Build Coastguard Worker // equivalent to the standard [rand.dist.pois.exp] distribution.
35*9356374aSAndroid Build Coastguard Worker template <typename RealType = double>
36*9356374aSAndroid Build Coastguard Worker class exponential_distribution {
37*9356374aSAndroid Build Coastguard Worker  public:
38*9356374aSAndroid Build Coastguard Worker   using result_type = RealType;
39*9356374aSAndroid Build Coastguard Worker 
40*9356374aSAndroid Build Coastguard Worker   class param_type {
41*9356374aSAndroid Build Coastguard Worker    public:
42*9356374aSAndroid Build Coastguard Worker     using distribution_type = exponential_distribution;
43*9356374aSAndroid Build Coastguard Worker 
lambda_(lambda)44*9356374aSAndroid Build Coastguard Worker     explicit param_type(result_type lambda = 1) : lambda_(lambda) {
45*9356374aSAndroid Build Coastguard Worker       assert(lambda > 0);
46*9356374aSAndroid Build Coastguard Worker       neg_inv_lambda_ = -result_type(1) / lambda_;
47*9356374aSAndroid Build Coastguard Worker     }
48*9356374aSAndroid Build Coastguard Worker 
lambda()49*9356374aSAndroid Build Coastguard Worker     result_type lambda() const { return lambda_; }
50*9356374aSAndroid Build Coastguard Worker 
51*9356374aSAndroid Build Coastguard Worker     friend bool operator==(const param_type& a, const param_type& b) {
52*9356374aSAndroid Build Coastguard Worker       return a.lambda_ == b.lambda_;
53*9356374aSAndroid Build Coastguard Worker     }
54*9356374aSAndroid Build Coastguard Worker 
55*9356374aSAndroid Build Coastguard Worker     friend bool operator!=(const param_type& a, const param_type& b) {
56*9356374aSAndroid Build Coastguard Worker       return !(a == b);
57*9356374aSAndroid Build Coastguard Worker     }
58*9356374aSAndroid Build Coastguard Worker 
59*9356374aSAndroid Build Coastguard Worker    private:
60*9356374aSAndroid Build Coastguard Worker     friend class exponential_distribution;
61*9356374aSAndroid Build Coastguard Worker 
62*9356374aSAndroid Build Coastguard Worker     result_type lambda_;
63*9356374aSAndroid Build Coastguard Worker     result_type neg_inv_lambda_;
64*9356374aSAndroid Build Coastguard Worker 
65*9356374aSAndroid Build Coastguard Worker     static_assert(
66*9356374aSAndroid Build Coastguard Worker         std::is_floating_point<RealType>::value,
67*9356374aSAndroid Build Coastguard Worker         "Class-template absl::exponential_distribution<> must be parameterized "
68*9356374aSAndroid Build Coastguard Worker         "using a floating-point type.");
69*9356374aSAndroid Build Coastguard Worker   };
70*9356374aSAndroid Build Coastguard Worker 
exponential_distribution()71*9356374aSAndroid Build Coastguard Worker   exponential_distribution() : exponential_distribution(1) {}
72*9356374aSAndroid Build Coastguard Worker 
exponential_distribution(result_type lambda)73*9356374aSAndroid Build Coastguard Worker   explicit exponential_distribution(result_type lambda) : param_(lambda) {}
74*9356374aSAndroid Build Coastguard Worker 
exponential_distribution(const param_type & p)75*9356374aSAndroid Build Coastguard Worker   explicit exponential_distribution(const param_type& p) : param_(p) {}
76*9356374aSAndroid Build Coastguard Worker 
reset()77*9356374aSAndroid Build Coastguard Worker   void reset() {}
78*9356374aSAndroid Build Coastguard Worker 
79*9356374aSAndroid Build Coastguard Worker   // Generating functions
80*9356374aSAndroid Build Coastguard Worker   template <typename URBG>
operator()81*9356374aSAndroid Build Coastguard Worker   result_type operator()(URBG& g) {  // NOLINT(runtime/references)
82*9356374aSAndroid Build Coastguard Worker     return (*this)(g, param_);
83*9356374aSAndroid Build Coastguard Worker   }
84*9356374aSAndroid Build Coastguard Worker 
85*9356374aSAndroid Build Coastguard Worker   template <typename URBG>
86*9356374aSAndroid Build Coastguard Worker   result_type operator()(URBG& g,  // NOLINT(runtime/references)
87*9356374aSAndroid Build Coastguard Worker                          const param_type& p);
88*9356374aSAndroid Build Coastguard Worker 
param()89*9356374aSAndroid Build Coastguard Worker   param_type param() const { return param_; }
param(const param_type & p)90*9356374aSAndroid Build Coastguard Worker   void param(const param_type& p) { param_ = p; }
91*9356374aSAndroid Build Coastguard Worker 
result_type(min)92*9356374aSAndroid Build Coastguard Worker   result_type(min)() const { return 0; }
result_type(max)93*9356374aSAndroid Build Coastguard Worker   result_type(max)() const {
94*9356374aSAndroid Build Coastguard Worker     return std::numeric_limits<result_type>::infinity();
95*9356374aSAndroid Build Coastguard Worker   }
96*9356374aSAndroid Build Coastguard Worker 
lambda()97*9356374aSAndroid Build Coastguard Worker   result_type lambda() const { return param_.lambda(); }
98*9356374aSAndroid Build Coastguard Worker 
99*9356374aSAndroid Build Coastguard Worker   friend bool operator==(const exponential_distribution& a,
100*9356374aSAndroid Build Coastguard Worker                          const exponential_distribution& b) {
101*9356374aSAndroid Build Coastguard Worker     return a.param_ == b.param_;
102*9356374aSAndroid Build Coastguard Worker   }
103*9356374aSAndroid Build Coastguard Worker   friend bool operator!=(const exponential_distribution& a,
104*9356374aSAndroid Build Coastguard Worker                          const exponential_distribution& b) {
105*9356374aSAndroid Build Coastguard Worker     return a.param_ != b.param_;
106*9356374aSAndroid Build Coastguard Worker   }
107*9356374aSAndroid Build Coastguard Worker 
108*9356374aSAndroid Build Coastguard Worker  private:
109*9356374aSAndroid Build Coastguard Worker   param_type param_;
110*9356374aSAndroid Build Coastguard Worker   random_internal::FastUniformBits<uint64_t> fast_u64_;
111*9356374aSAndroid Build Coastguard Worker };
112*9356374aSAndroid Build Coastguard Worker 
113*9356374aSAndroid Build Coastguard Worker // --------------------------------------------------------------------------
114*9356374aSAndroid Build Coastguard Worker // Implementation details follow
115*9356374aSAndroid Build Coastguard Worker // --------------------------------------------------------------------------
116*9356374aSAndroid Build Coastguard Worker 
117*9356374aSAndroid Build Coastguard Worker template <typename RealType>
118*9356374aSAndroid Build Coastguard Worker template <typename URBG>
119*9356374aSAndroid Build Coastguard Worker typename exponential_distribution<RealType>::result_type
operator()120*9356374aSAndroid Build Coastguard Worker exponential_distribution<RealType>::operator()(
121*9356374aSAndroid Build Coastguard Worker     URBG& g,  // NOLINT(runtime/references)
122*9356374aSAndroid Build Coastguard Worker     const param_type& p) {
123*9356374aSAndroid Build Coastguard Worker   using random_internal::GenerateNegativeTag;
124*9356374aSAndroid Build Coastguard Worker   using random_internal::GenerateRealFromBits;
125*9356374aSAndroid Build Coastguard Worker   using real_type =
126*9356374aSAndroid Build Coastguard Worker       absl::conditional_t<std::is_same<RealType, float>::value, float, double>;
127*9356374aSAndroid Build Coastguard Worker 
128*9356374aSAndroid Build Coastguard Worker   const result_type u = GenerateRealFromBits<real_type, GenerateNegativeTag,
129*9356374aSAndroid Build Coastguard Worker                                              false>(fast_u64_(g));  // U(-1, 0)
130*9356374aSAndroid Build Coastguard Worker 
131*9356374aSAndroid Build Coastguard Worker   // log1p(-x) is mathematically equivalent to log(1 - x) but has more
132*9356374aSAndroid Build Coastguard Worker   // accuracy for x near zero.
133*9356374aSAndroid Build Coastguard Worker   return p.neg_inv_lambda_ * std::log1p(u);
134*9356374aSAndroid Build Coastguard Worker }
135*9356374aSAndroid Build Coastguard Worker 
136*9356374aSAndroid Build Coastguard Worker template <typename CharT, typename Traits, typename RealType>
137*9356374aSAndroid Build Coastguard Worker std::basic_ostream<CharT, Traits>& operator<<(
138*9356374aSAndroid Build Coastguard Worker     std::basic_ostream<CharT, Traits>& os,  // NOLINT(runtime/references)
139*9356374aSAndroid Build Coastguard Worker     const exponential_distribution<RealType>& x) {
140*9356374aSAndroid Build Coastguard Worker   auto saver = random_internal::make_ostream_state_saver(os);
141*9356374aSAndroid Build Coastguard Worker   os.precision(random_internal::stream_precision_helper<RealType>::kPrecision);
142*9356374aSAndroid Build Coastguard Worker   os << x.lambda();
143*9356374aSAndroid Build Coastguard Worker   return os;
144*9356374aSAndroid Build Coastguard Worker }
145*9356374aSAndroid Build Coastguard Worker 
146*9356374aSAndroid Build Coastguard Worker template <typename CharT, typename Traits, typename RealType>
147*9356374aSAndroid Build Coastguard Worker std::basic_istream<CharT, Traits>& operator>>(
148*9356374aSAndroid Build Coastguard Worker     std::basic_istream<CharT, Traits>& is,    // NOLINT(runtime/references)
149*9356374aSAndroid Build Coastguard Worker     exponential_distribution<RealType>& x) {  // NOLINT(runtime/references)
150*9356374aSAndroid Build Coastguard Worker   using result_type = typename exponential_distribution<RealType>::result_type;
151*9356374aSAndroid Build Coastguard Worker   using param_type = typename exponential_distribution<RealType>::param_type;
152*9356374aSAndroid Build Coastguard Worker   result_type lambda;
153*9356374aSAndroid Build Coastguard Worker 
154*9356374aSAndroid Build Coastguard Worker   auto saver = random_internal::make_istream_state_saver(is);
155*9356374aSAndroid Build Coastguard Worker   lambda = random_internal::read_floating_point<result_type>(is);
156*9356374aSAndroid Build Coastguard Worker   if (!is.fail()) {
157*9356374aSAndroid Build Coastguard Worker     x.param(param_type(lambda));
158*9356374aSAndroid Build Coastguard Worker   }
159*9356374aSAndroid Build Coastguard Worker   return is;
160*9356374aSAndroid Build Coastguard Worker }
161*9356374aSAndroid Build Coastguard Worker 
162*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
163*9356374aSAndroid Build Coastguard Worker }  // namespace absl
164*9356374aSAndroid Build Coastguard Worker 
165*9356374aSAndroid Build Coastguard Worker #endif  // ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_
166