Built motion from commit 44377920.|2.6.11
[motion2.git] / legacy-libs / grpc / deps / grpc / third_party / abseil-cpp / absl / random / poisson_distribution.h
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef ABSL_RANDOM_POISSON_DISTRIBUTION_H_
16 #define ABSL_RANDOM_POISSON_DISTRIBUTION_H_
17
18 #include <cassert>
19 #include <cmath>
20 #include <istream>
21 #include <limits>
22 #include <ostream>
23 #include <type_traits>
24
25 #include "absl/random/internal/distribution_impl.h"
26 #include "absl/random/internal/fast_uniform_bits.h"
27 #include "absl/random/internal/fastmath.h"
28 #include "absl/random/internal/iostream_state_saver.h"
29
30 namespace absl {
31
32 // absl::poisson_distribution:
33 // Generates discrete variates conforming to a Poisson distribution.
34 //   p(n) = (mean^n / n!) exp(-mean)
35 //
36 // Depending on the parameter, the distribution selects one of the following
37 // algorithms:
38 // * The standard algorithm, attributed to Knuth, extended using a split method
39 // for larger values
40 // * The "Ratio of Uniforms as a convenient method for sampling from classical
41 // discrete distributions", Stadlober, 1989.
42 // http://www.sciencedirect.com/science/article/pii/0377042790903495
43 //
44 // NOTE: param_type.mean() is a double, which permits values larger than
45 // poisson_distribution<IntType>::max(), however this should be avoided and
46 // the distribution results are limited to the max() value.
47 //
48 // The goals of this implementation are to provide good performance while still
49 // beig thread-safe: This limits the implementation to not using lgamma provided
50 // by <math.h>.
51 //
52 template <typename IntType = int>
53 class poisson_distribution {
54  public:
55   using result_type = IntType;
56
57   class param_type {
58    public:
59     using distribution_type = poisson_distribution;
60     explicit param_type(double mean = 1.0);
61
62     double mean() const { return mean_; }
63
64     friend bool operator==(const param_type& a, const param_type& b) {
65       return a.mean_ == b.mean_;
66     }
67
68     friend bool operator!=(const param_type& a, const param_type& b) {
69       return !(a == b);
70     }
71
72    private:
73     friend class poisson_distribution;
74
75     double mean_;
76     double emu_;  // e ^ -mean_
77     double lmu_;  // ln(mean_)
78     double s_;
79     double log_k_;
80     int split_;
81
82     static_assert(std::is_integral<IntType>::value,
83                   "Class-template absl::poisson_distribution<> must be "
84                   "parameterized using an integral type.");
85   };
86
87   poisson_distribution() : poisson_distribution(1.0) {}
88
89   explicit poisson_distribution(double mean) : param_(mean) {}
90
91   explicit poisson_distribution(const param_type& p) : param_(p) {}
92
93   void reset() {}
94
95   // generating functions
96   template <typename URBG>
97   result_type operator()(URBG& g) {  // NOLINT(runtime/references)
98     return (*this)(g, param_);
99   }
100
101   template <typename URBG>
102   result_type operator()(URBG& g,  // NOLINT(runtime/references)
103                          const param_type& p);
104
105   param_type param() const { return param_; }
106   void param(const param_type& p) { param_ = p; }
107
108   result_type(min)() const { return 0; }
109   result_type(max)() const { return (std::numeric_limits<result_type>::max)(); }
110
111   double mean() const { return param_.mean(); }
112
113   friend bool operator==(const poisson_distribution& a,
114                          const poisson_distribution& b) {
115     return a.param_ == b.param_;
116   }
117   friend bool operator!=(const poisson_distribution& a,
118                          const poisson_distribution& b) {
119     return a.param_ != b.param_;
120   }
121
122  private:
123   param_type param_;
124   random_internal::FastUniformBits<uint64_t> fast_u64_;
125 };
126
127 // -----------------------------------------------------------------------------
128 // Implementation details follow
129 // -----------------------------------------------------------------------------
130
131 template <typename IntType>
132 poisson_distribution<IntType>::param_type::param_type(double mean)
133     : mean_(mean), split_(0) {
134   assert(mean >= 0);
135   assert(mean <= (std::numeric_limits<result_type>::max)());
136   // As a defensive measure, avoid large values of the mean.  The rejection
137   // algorithm used does not support very large values well.  It my be worth
138   // changing algorithms to better deal with these cases.
139   assert(mean <= 1e10);
140   if (mean_ < 10) {
141     // For small lambda, use the knuth method.
142     split_ = 1;
143     emu_ = std::exp(-mean_);
144   } else if (mean_ <= 50) {
145     // Use split-knuth method.
146     split_ = 1 + static_cast<int>(mean_ / 10.0);
147     emu_ = std::exp(-mean_ / static_cast<double>(split_));
148   } else {
149     // Use ratio of uniforms method.
150     constexpr double k2E = 0.7357588823428846;
151     constexpr double kSA = 0.4494580810294493;
152
153     lmu_ = std::log(mean_);
154     double a = mean_ + 0.5;
155     s_ = kSA + std::sqrt(k2E * a);
156     const double mode = std::ceil(mean_) - 1;
157     log_k_ = lmu_ * mode - absl::random_internal::StirlingLogFactorial(mode);
158   }
159 }
160
161 template <typename IntType>
162 template <typename URBG>
163 typename poisson_distribution<IntType>::result_type
164 poisson_distribution<IntType>::operator()(
165     URBG& g,  // NOLINT(runtime/references)
166     const param_type& p) {
167   using random_internal::PositiveValueT;
168   using random_internal::RandU64ToDouble;
169   using random_internal::SignedValueT;
170
171   if (p.split_ != 0) {
172     // Use Knuth's algorithm with range splitting to avoid floating-point
173     // errors. Knuth's algorithm is: Ui is a sequence of uniform variates on
174     // (0,1); return the number of variates required for product(Ui) <
175     // exp(-lambda).
176     //
177     // The expected number of variates required for Knuth's method can be
178     // computed as follows:
179     // The expected value of U is 0.5, so solving for 0.5^n < exp(-lambda) gives
180     // the expected number of uniform variates
181     // required for a given lambda, which is:
182     //  lambda = [2, 5,  9, 10, 11, 12, 13, 14, 15, 16, 17]
183     //  n      = [3, 8, 13, 15, 16, 18, 19, 21, 22, 24, 25]
184     //
185     result_type n = 0;
186     for (int split = p.split_; split > 0; --split) {
187       double r = 1.0;
188       do {
189         r *= RandU64ToDouble<PositiveValueT, true>(fast_u64_(g));
190         ++n;
191       } while (r > p.emu_);
192       --n;
193     }
194     return n;
195   }
196
197   // Use ratio of uniforms method.
198   //
199   // Let u ~ Uniform(0, 1), v ~ Uniform(-1, 1),
200   //     a = lambda + 1/2,
201   //     s = 1.5 - sqrt(3/e) + sqrt(2(lambda + 1/2)/e),
202   //     x = s * v/u + a.
203   // P(floor(x) = k | u^2 < f(floor(x))/k), where
204   // f(m) = lambda^m exp(-lambda)/ m!, for 0 <= m, and f(m) = 0 otherwise,
205   // and k = max(f).
206   const double a = p.mean_ + 0.5;
207   for (;;) {
208     const double u =
209         RandU64ToDouble<PositiveValueT, false>(fast_u64_(g));  // (0, 1)
210     const double v =
211         RandU64ToDouble<SignedValueT, false>(fast_u64_(g));  // (-1, 1)
212     const double x = std::floor(p.s_ * v / u + a);
213     if (x < 0) continue;  // f(negative) = 0
214     const double rhs = x * p.lmu_;
215     // clang-format off
216     double s = (x <= 1.0) ? 0.0
217              : (x == 2.0) ? 0.693147180559945
218              : absl::random_internal::StirlingLogFactorial(x);
219     // clang-format on
220     const double lhs = 2.0 * std::log(u) + p.log_k_ + s;
221     if (lhs < rhs) {
222       return x > (max)() ? (max)()
223                          : static_cast<result_type>(x);  // f(x)/k >= u^2
224     }
225   }
226 }
227
228 template <typename CharT, typename Traits, typename IntType>
229 std::basic_ostream<CharT, Traits>& operator<<(
230     std::basic_ostream<CharT, Traits>& os,  // NOLINT(runtime/references)
231     const poisson_distribution<IntType>& x) {
232   auto saver = random_internal::make_ostream_state_saver(os);
233   os.precision(random_internal::stream_precision_helper<double>::kPrecision);
234   os << x.mean();
235   return os;
236 }
237
238 template <typename CharT, typename Traits, typename IntType>
239 std::basic_istream<CharT, Traits>& operator>>(
240     std::basic_istream<CharT, Traits>& is,  // NOLINT(runtime/references)
241     poisson_distribution<IntType>& x) {     // NOLINT(runtime/references)
242   using param_type = typename poisson_distribution<IntType>::param_type;
243
244   auto saver = random_internal::make_istream_state_saver(is);
245   double mean = random_internal::read_floating_point<double>(is);
246   if (!is.fail()) {
247     x.param(param_type(mean));
248   }
249   return is;
250 }
251
252 }  // namespace absl
253
254 #endif  // ABSL_RANDOM_POISSON_DISTRIBUTION_H_