abseil-cpp/absl/random/poisson_distribution.h
Go to the documentation of this file.
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/fast_uniform_bits.h"
26 #include "absl/random/internal/fastmath.h"
27 #include "absl/random/internal/generate_real.h"
28 #include "absl/random/internal/iostream_state_saver.h"
29 #include "absl/random/internal/traits.h"
30 
31 namespace absl {
33 
34 // absl::poisson_distribution:
35 // Generates discrete variates conforming to a Poisson distribution.
36 // p(n) = (mean^n / n!) exp(-mean)
37 //
38 // Depending on the parameter, the distribution selects one of the following
39 // algorithms:
40 // * The standard algorithm, attributed to Knuth, extended using a split method
41 // for larger values
42 // * The "Ratio of Uniforms as a convenient method for sampling from classical
43 // discrete distributions", Stadlober, 1989.
44 // http://www.sciencedirect.com/science/article/pii/0377042790903495
45 //
46 // NOTE: param_type.mean() is a double, which permits values larger than
47 // poisson_distribution<IntType>::max(), however this should be avoided and
48 // the distribution results are limited to the max() value.
49 //
50 // The goals of this implementation are to provide good performance while still
51 // beig thread-safe: This limits the implementation to not using lgamma provided
52 // by <math.h>.
53 //
54 template <typename IntType = int>
56  public:
57  using result_type = IntType;
58 
59  class param_type {
60  public:
62  explicit param_type(double mean = 1.0);
63 
64  double mean() const { return mean_; }
65 
66  friend bool operator==(const param_type& a, const param_type& b) {
67  return a.mean_ == b.mean_;
68  }
69 
70  friend bool operator!=(const param_type& a, const param_type& b) {
71  return !(a == b);
72  }
73 
74  private:
75  friend class poisson_distribution;
76 
77  double mean_;
78  double emu_; // e ^ -mean_
79  double lmu_; // ln(mean_)
80  double s_;
81  double log_k_;
82  int split_;
83 
85  "Class-template absl::poisson_distribution<> must be "
86  "parameterized using an integral type.");
87  };
88 
90 
91  explicit poisson_distribution(double mean) : param_(mean) {}
92 
93  explicit poisson_distribution(const param_type& p) : param_(p) {}
94 
95  void reset() {}
96 
97  // generating functions
98  template <typename URBG>
99  result_type operator()(URBG& g) { // NOLINT(runtime/references)
100  return (*this)(g, param_);
101  }
102 
103  template <typename URBG>
104  result_type operator()(URBG& g, // NOLINT(runtime/references)
105  const param_type& p);
106 
107  param_type param() const { return param_; }
108  void param(const param_type& p) { param_ = p; }
109 
110  result_type(min)() const { return 0; }
112 
113  double mean() const { return param_.mean(); }
114 
115  friend bool operator==(const poisson_distribution& a,
116  const poisson_distribution& b) {
117  return a.param_ == b.param_;
118  }
119  friend bool operator!=(const poisson_distribution& a,
120  const poisson_distribution& b) {
121  return a.param_ != b.param_;
122  }
123 
124  private:
127 };
128 
129 // -----------------------------------------------------------------------------
130 // Implementation details follow
131 // -----------------------------------------------------------------------------
132 
133 template <typename IntType>
135  : mean_(mean), split_(0) {
136  assert(mean >= 0);
137  assert(mean <=
138  static_cast<double>((std::numeric_limits<result_type>::max)()));
139  // As a defensive measure, avoid large values of the mean. The rejection
140  // algorithm used does not support very large values well. It my be worth
141  // changing algorithms to better deal with these cases.
142  assert(mean <= 1e10);
143  if (mean_ < 10) {
144  // For small lambda, use the knuth method.
145  split_ = 1;
146  emu_ = std::exp(-mean_);
147  } else if (mean_ <= 50) {
148  // Use split-knuth method.
149  split_ = 1 + static_cast<int>(mean_ / 10.0);
150  emu_ = std::exp(-mean_ / static_cast<double>(split_));
151  } else {
152  // Use ratio of uniforms method.
153  constexpr double k2E = 0.7357588823428846;
154  constexpr double kSA = 0.4494580810294493;
155 
156  lmu_ = std::log(mean_);
157  double a = mean_ + 0.5;
158  s_ = kSA + std::sqrt(k2E * a);
159  const double mode = std::ceil(mean_) - 1;
161  }
162 }
163 
164 template <typename IntType>
165 template <typename URBG>
168  URBG& g, // NOLINT(runtime/references)
169  const param_type& p) {
173 
174  if (p.split_ != 0) {
175  // Use Knuth's algorithm with range splitting to avoid floating-point
176  // errors. Knuth's algorithm is: Ui is a sequence of uniform variates on
177  // (0,1); return the number of variates required for product(Ui) <
178  // exp(-lambda).
179  //
180  // The expected number of variates required for Knuth's method can be
181  // computed as follows:
182  // The expected value of U is 0.5, so solving for 0.5^n < exp(-lambda) gives
183  // the expected number of uniform variates
184  // required for a given lambda, which is:
185  // lambda = [2, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17]
186  // n = [3, 8, 13, 15, 16, 18, 19, 21, 22, 24, 25]
187  //
188  result_type n = 0;
189  for (int split = p.split_; split > 0; --split) {
190  double r = 1.0;
191  do {
192  r *= GenerateRealFromBits<double, GeneratePositiveTag, true>(
193  fast_u64_(g)); // U(-1, 0)
194  ++n;
195  } while (r > p.emu_);
196  --n;
197  }
198  return n;
199  }
200 
201  // Use ratio of uniforms method.
202  //
203  // Let u ~ Uniform(0, 1), v ~ Uniform(-1, 1),
204  // a = lambda + 1/2,
205  // s = 1.5 - sqrt(3/e) + sqrt(2(lambda + 1/2)/e),
206  // x = s * v/u + a.
207  // P(floor(x) = k | u^2 < f(floor(x))/k), where
208  // f(m) = lambda^m exp(-lambda)/ m!, for 0 <= m, and f(m) = 0 otherwise,
209  // and k = max(f).
210  const double a = p.mean_ + 0.5;
211  for (;;) {
212  const double u = GenerateRealFromBits<double, GeneratePositiveTag, false>(
213  fast_u64_(g)); // U(0, 1)
214  const double v = GenerateRealFromBits<double, GenerateSignedTag, false>(
215  fast_u64_(g)); // U(-1, 1)
216 
217  const double x = std::floor(p.s_ * v / u + a);
218  if (x < 0) continue; // f(negative) = 0
219  const double rhs = x * p.lmu_;
220  // clang-format off
221  double s = (x <= 1.0) ? 0.0
222  : (x == 2.0) ? 0.693147180559945
224  // clang-format on
225  const double lhs = 2.0 * std::log(u) + p.log_k_ + s;
226  if (lhs < rhs) {
227  return x > static_cast<double>((max)())
228  ? (max)()
229  : static_cast<result_type>(x); // f(x)/k >= u^2
230  }
231  }
232 }
233 
234 template <typename CharT, typename Traits, typename IntType>
235 std::basic_ostream<CharT, Traits>& operator<<(
236  std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
240  os << x.mean();
241  return os;
242 }
243 
244 template <typename CharT, typename Traits, typename IntType>
245 std::basic_istream<CharT, Traits>& operator>>(
246  std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
247  poisson_distribution<IntType>& x) { // NOLINT(runtime/references)
248  using param_type = typename poisson_distribution<IntType>::param_type;
249 
251  double mean = random_internal::read_floating_point<double>(is);
252  if (!is.fail()) {
253  x.param(param_type(mean));
254  }
255  return is;
256 }
257 
259 } // namespace absl
260 
261 #endif // ABSL_RANDOM_POISSON_DISTRIBUTION_H_
absl::poisson_distribution::param_type::mean_
double mean_
Definition: abseil-cpp/absl/random/poisson_distribution.h:77
absl::random_internal::make_istream_state_saver
istream_state_saver< std::basic_istream< CharT, Traits > > make_istream_state_saver(std::basic_istream< CharT, Traits > &is, std::ios_base::fmtflags flags=std::ios_base::dec|std::ios_base::scientific|std::ios_base::skipws)
Definition: abseil-cpp/absl/random/internal/iostream_state_saver.h:149
absl::poisson_distribution::param
param_type param() const
Definition: abseil-cpp/absl/random/poisson_distribution.h:107
absl::operator<<
ABSL_NAMESPACE_BEGIN std::ostream & operator<<(std::ostream &os, absl::LogSeverity s)
Definition: abseil-cpp/absl/base/log_severity.cc:24
absl::poisson_distribution::poisson_distribution
poisson_distribution(const param_type &p)
Definition: abseil-cpp/absl/random/poisson_distribution.h:93
absl::random_internal::GenerateSignedTag
Definition: abseil-cpp/absl/random/internal/generate_real.h:38
absl::poisson_distribution::poisson_distribution
poisson_distribution()
Definition: abseil-cpp/absl/random/poisson_distribution.h:89
u
OPENSSL_EXPORT pem_password_cb void * u
Definition: pem.h:351
mode
const char int mode
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
absl::FormatConversionChar::s
@ s
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
absl::random_internal::GeneratePositiveTag
Definition: abseil-cpp/absl/random/internal/generate_real.h:36
xds_manager.p
p
Definition: xds_manager.py:60
absl::random_internal::IsIntegral
Definition: abseil-cpp/absl/random/internal/traits.h:65
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::poisson_distribution::param_type::param_type
param_type(double mean=1.0)
Definition: abseil-cpp/absl/random/poisson_distribution.h:134
absl::random_internal::GenerateRealFromBits
RealType GenerateRealFromBits(uint64_t bits, int exp_bias=0)
Definition: abseil-cpp/absl/random/internal/generate_real.h:70
absl::poisson_distribution
Definition: abseil-cpp/absl/random/poisson_distribution.h:55
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::poisson_distribution::param_type::poisson_distribution
friend class poisson_distribution
Definition: abseil-cpp/absl/random/poisson_distribution.h:75
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
absl::poisson_distribution::param_type::split_
int split_
Definition: abseil-cpp/absl/random/poisson_distribution.h:82
absl::poisson_distribution::operator()
result_type operator()(URBG &g)
Definition: abseil-cpp/absl/random/poisson_distribution.h:99
absl::poisson_distribution::param_type::mean
double mean() const
Definition: abseil-cpp/absl/random/poisson_distribution.h:64
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
absl::poisson_distribution::result_type
IntType result_type
Definition: abseil-cpp/absl/random/poisson_distribution.h:57
absl::poisson_distribution::max
result_type() max() const
Definition: abseil-cpp/absl/random/poisson_distribution.h:111
absl::poisson_distribution::param_type::operator!=
friend bool operator!=(const param_type &a, const param_type &b)
Definition: abseil-cpp/absl/random/poisson_distribution.h:70
x
int x
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3610
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
g
struct @717 g
absl::poisson_distribution::param_type::operator==
friend bool operator==(const param_type &a, const param_type &b)
Definition: abseil-cpp/absl/random/poisson_distribution.h:66
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
absl::poisson_distribution::param_
param_type param_
Definition: abseil-cpp/absl/random/poisson_distribution.h:125
absl::random_internal::stream_precision_helper
Definition: abseil-cpp/absl/random/internal/iostream_state_saver.h:107
absl::poisson_distribution::param_type::s_
double s_
Definition: abseil-cpp/absl/random/poisson_distribution.h:80
absl::poisson_distribution::poisson_distribution
poisson_distribution(double mean)
Definition: abseil-cpp/absl/random/poisson_distribution.h:91
absl::poisson_distribution::param_type::lmu_
double lmu_
Definition: abseil-cpp/absl/random/poisson_distribution.h:79
absl::poisson_distribution::operator==
friend bool operator==(const poisson_distribution &a, const poisson_distribution &b)
Definition: abseil-cpp/absl/random/poisson_distribution.h:115
absl::poisson_distribution::param_type
Definition: abseil-cpp/absl/random/poisson_distribution.h:59
absl::poisson_distribution::min
result_type() min() const
Definition: abseil-cpp/absl/random/poisson_distribution.h:110
absl::operator>>
constexpr uint128 operator>>(uint128 lhs, int amount)
Definition: abseil-cpp/absl/numeric/int128.h:917
absl::poisson_distribution::param_type::emu_
double emu_
Definition: abseil-cpp/absl/random/poisson_distribution.h:78
absl::poisson_distribution::reset
void reset()
Definition: abseil-cpp/absl/random/poisson_distribution.h:95
absl::poisson_distribution::operator!=
friend bool operator!=(const poisson_distribution &a, const poisson_distribution &b)
Definition: abseil-cpp/absl/random/poisson_distribution.h:119
fix_build_deps.r
r
Definition: fix_build_deps.py:491
absl::random_internal::StirlingLogFactorial
double StirlingLogFactorial(double n)
Definition: abseil-cpp/absl/random/internal/fastmath.h:43
log
bool log
Definition: abseil-cpp/absl/synchronization/mutex.cc:310
absl::poisson_distribution::fast_u64_
random_internal::FastUniformBits< uint64_t > fast_u64_
Definition: abseil-cpp/absl/random/poisson_distribution.h:126
absl::poisson_distribution::mean
double mean() const
Definition: abseil-cpp/absl/random/poisson_distribution.h:113
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::poisson_distribution::param
void param(const param_type &p)
Definition: abseil-cpp/absl/random/poisson_distribution.h:108
absl::random_internal::make_ostream_state_saver
ostream_state_saver< std::basic_ostream< CharT, Traits > > make_ostream_state_saver(std::basic_ostream< CharT, Traits > &os, std::ios_base::fmtflags flags=std::ios_base::dec|std::ios_base::left|std::ios_base::scientific)
Definition: abseil-cpp/absl/random/internal/iostream_state_saver.h:82
split
static void split(const char *s, char ***ss, size_t *ns)
Definition: debug/trace.cc:111
absl::poisson_distribution::param_type::log_k_
double log_k_
Definition: abseil-cpp/absl/random/poisson_distribution.h:81
absl::random_internal::FastUniformBits< uint64_t >


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:44