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 // -----------------------------------------------------------------------------
16 // File: distributions.h
17 // -----------------------------------------------------------------------------
18 //
19 // This header defines functions representing distributions, which you use in
20 // combination with an Abseil random bit generator to produce random values
21 // according to the rules of that distribution.
22 //
23 // The Abseil random library defines the following distributions within this
24 // file:
25 //
26 // * `absl::Uniform` for uniform (constant) distributions having constant
27 // probability
28 // * `absl::Bernoulli` for discrete distributions having exactly two outcomes
29 // * `absl::Beta` for continuous distributions parameterized through two
30 // free parameters
31 // * `absl::Exponential` for discrete distributions of events occurring
32 // continuously and independently at a constant average rate
33 // * `absl::Gaussian` (also known as "normal distributions") for continuous
34 // distributions using an associated quadratic function
35 // * `absl::LogUniform` for discrete distributions where the log to the given
36 // base of all values is uniform
37 // * `absl::Poisson` for discrete probability distributions that express the
38 // probability of a given number of events occurring within a fixed interval
39 // * `absl::Zipf` for discrete probability distributions commonly used for
40 // modelling of rare events
41 //
42 // Prefer use of these distribution function classes over manual construction of
43 // your own distribution classes, as it allows library maintainers greater
44 // flexibility to change the underlying implementation in the future.
45
46 #ifndef ABSL_RANDOM_DISTRIBUTIONS_H_
47 #define ABSL_RANDOM_DISTRIBUTIONS_H_
48
49 #include <limits>
50 #include <type_traits>
51
52 #include "absl/base/config.h"
53 #include "absl/base/internal/inline_variable.h"
54 #include "absl/meta/type_traits.h"
55 #include "absl/random/bernoulli_distribution.h"
56 #include "absl/random/beta_distribution.h"
57 #include "absl/random/exponential_distribution.h"
58 #include "absl/random/gaussian_distribution.h"
59 #include "absl/random/internal/distribution_caller.h" // IWYU pragma: export
60 #include "absl/random/internal/traits.h"
61 #include "absl/random/internal/uniform_helper.h" // IWYU pragma: export
62 #include "absl/random/log_uniform_int_distribution.h"
63 #include "absl/random/poisson_distribution.h"
64 #include "absl/random/uniform_int_distribution.h" // IWYU pragma: export
65 #include "absl/random/uniform_real_distribution.h" // IWYU pragma: export
66 #include "absl/random/zipf_distribution.h"
67
68 namespace absl {
69 ABSL_NAMESPACE_BEGIN
70
71 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosedClosed,
72 {});
73 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosed, {});
74 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedOpenTag, IntervalClosedOpen, {});
75 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenOpenTag, IntervalOpenOpen, {});
76 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenOpenTag, IntervalOpen, {});
77 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenClosedTag, IntervalOpenClosed, {});
78
79 // -----------------------------------------------------------------------------
80 // absl::Uniform<T>(tag, bitgen, lo, hi)
81 // -----------------------------------------------------------------------------
82 //
83 // `absl::Uniform()` produces random values of type `T` uniformly distributed in
84 // a defined interval {lo, hi}. The interval `tag` defines the type of interval
85 // which should be one of the following possible values:
86 //
87 // * `absl::IntervalOpenOpen`
88 // * `absl::IntervalOpenClosed`
89 // * `absl::IntervalClosedOpen`
90 // * `absl::IntervalClosedClosed`
91 //
92 // where "open" refers to an exclusive value (excluded) from the output, while
93 // "closed" refers to an inclusive value (included) from the output.
94 //
95 // In the absence of an explicit return type `T`, `absl::Uniform()` will deduce
96 // the return type based on the provided endpoint arguments {A lo, B hi}.
97 // Given these endpoints, one of {A, B} will be chosen as the return type, if
98 // a type can be implicitly converted into the other in a lossless way. The
99 // lack of any such implicit conversion between {A, B} will produce a
100 // compile-time error
101 //
102 // See https://en.wikipedia.org/wiki/Uniform_distribution_(continuous)
103 //
104 // Example:
105 //
106 // absl::BitGen bitgen;
107 //
108 // // Produce a random float value between 0.0 and 1.0, inclusive
109 // auto x = absl::Uniform(absl::IntervalClosedClosed, bitgen, 0.0f, 1.0f);
110 //
111 // // The most common interval of `absl::IntervalClosedOpen` is available by
112 // // default:
113 //
114 // auto x = absl::Uniform(bitgen, 0.0f, 1.0f);
115 //
116 // // Return-types are typically inferred from the arguments, however callers
117 // // can optionally provide an explicit return-type to the template.
118 //
119 // auto x = absl::Uniform<float>(bitgen, 0, 1);
120 //
121 template <typename R = void, typename TagType, typename URBG>
122 typename absl::enable_if_t<!std::is_same<R, void>::value, R> //
Uniform(TagType tag,URBG && urbg,R lo,R hi)123 Uniform(TagType tag,
124 URBG&& urbg, // NOLINT(runtime/references)
125 R lo, R hi) {
126 using gen_t = absl::decay_t<URBG>;
127 using distribution_t = random_internal::UniformDistributionWrapper<R>;
128
129 auto a = random_internal::uniform_lower_bound(tag, lo, hi);
130 auto b = random_internal::uniform_upper_bound(tag, lo, hi);
131 if (!random_internal::is_uniform_range_valid(a, b)) return lo;
132
133 return random_internal::DistributionCaller<gen_t>::template Call<
134 distribution_t>(&urbg, tag, lo, hi);
135 }
136
137 // absl::Uniform<T>(bitgen, lo, hi)
138 //
139 // Overload of `Uniform()` using the default closed-open interval of [lo, hi),
140 // and returning values of type `T`
141 template <typename R = void, typename URBG>
142 typename absl::enable_if_t<!std::is_same<R, void>::value, R> //
Uniform(URBG && urbg,R lo,R hi)143 Uniform(URBG&& urbg, // NOLINT(runtime/references)
144 R lo, R hi) {
145 using gen_t = absl::decay_t<URBG>;
146 using distribution_t = random_internal::UniformDistributionWrapper<R>;
147 constexpr auto tag = absl::IntervalClosedOpen;
148
149 auto a = random_internal::uniform_lower_bound(tag, lo, hi);
150 auto b = random_internal::uniform_upper_bound(tag, lo, hi);
151 if (!random_internal::is_uniform_range_valid(a, b)) return lo;
152
153 return random_internal::DistributionCaller<gen_t>::template Call<
154 distribution_t>(&urbg, lo, hi);
155 }
156
157 // absl::Uniform(tag, bitgen, lo, hi)
158 //
159 // Overload of `Uniform()` using different (but compatible) lo, hi types. Note
160 // that a compile-error will result if the return type cannot be deduced
161 // correctly from the passed types.
162 template <typename R = void, typename TagType, typename URBG, typename A,
163 typename B>
164 typename absl::enable_if_t<std::is_same<R, void>::value,
165 random_internal::uniform_inferred_return_t<A, B>>
Uniform(TagType tag,URBG && urbg,A lo,B hi)166 Uniform(TagType tag,
167 URBG&& urbg, // NOLINT(runtime/references)
168 A lo, B hi) {
169 using gen_t = absl::decay_t<URBG>;
170 using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
171 using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
172
173 auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
174 auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
175 if (!random_internal::is_uniform_range_valid(a, b)) return lo;
176
177 return random_internal::DistributionCaller<gen_t>::template Call<
178 distribution_t>(&urbg, tag, static_cast<return_t>(lo),
179 static_cast<return_t>(hi));
180 }
181
182 // absl::Uniform(bitgen, lo, hi)
183 //
184 // Overload of `Uniform()` using different (but compatible) lo, hi types and the
185 // default closed-open interval of [lo, hi). Note that a compile-error will
186 // result if the return type cannot be deduced correctly from the passed types.
187 template <typename R = void, typename URBG, typename A, typename B>
188 typename absl::enable_if_t<std::is_same<R, void>::value,
189 random_internal::uniform_inferred_return_t<A, B>>
Uniform(URBG && urbg,A lo,B hi)190 Uniform(URBG&& urbg, // NOLINT(runtime/references)
191 A lo, B hi) {
192 using gen_t = absl::decay_t<URBG>;
193 using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
194 using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
195
196 constexpr auto tag = absl::IntervalClosedOpen;
197 auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
198 auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
199 if (!random_internal::is_uniform_range_valid(a, b)) return lo;
200
201 return random_internal::DistributionCaller<gen_t>::template Call<
202 distribution_t>(&urbg, static_cast<return_t>(lo),
203 static_cast<return_t>(hi));
204 }
205
206 // absl::Uniform<unsigned T>(bitgen)
207 //
208 // Overload of Uniform() using the minimum and maximum values of a given type
209 // `T` (which must be unsigned), returning a value of type `unsigned T`
210 template <typename R, typename URBG>
211 typename absl::enable_if_t<!std::numeric_limits<R>::is_signed, R> //
Uniform(URBG && urbg)212 Uniform(URBG&& urbg) { // NOLINT(runtime/references)
213 using gen_t = absl::decay_t<URBG>;
214 using distribution_t = random_internal::UniformDistributionWrapper<R>;
215
216 return random_internal::DistributionCaller<gen_t>::template Call<
217 distribution_t>(&urbg);
218 }
219
220 // -----------------------------------------------------------------------------
221 // absl::Bernoulli(bitgen, p)
222 // -----------------------------------------------------------------------------
223 //
224 // `absl::Bernoulli` produces a random boolean value, with probability `p`
225 // (where 0.0 <= p <= 1.0) equaling `true`.
226 //
227 // Prefer `absl::Bernoulli` to produce boolean values over other alternatives
228 // such as comparing an `absl::Uniform()` value to a specific output.
229 //
230 // See https://en.wikipedia.org/wiki/Bernoulli_distribution
231 //
232 // Example:
233 //
234 // absl::BitGen bitgen;
235 // ...
236 // if (absl::Bernoulli(bitgen, 1.0/3721.0)) {
237 // std::cout << "Asteroid field navigation successful.";
238 // }
239 //
240 template <typename URBG>
Bernoulli(URBG && urbg,double p)241 bool Bernoulli(URBG&& urbg, // NOLINT(runtime/references)
242 double p) {
243 using gen_t = absl::decay_t<URBG>;
244 using distribution_t = absl::bernoulli_distribution;
245
246 return random_internal::DistributionCaller<gen_t>::template Call<
247 distribution_t>(&urbg, p);
248 }
249
250 // -----------------------------------------------------------------------------
251 // absl::Beta<T>(bitgen, alpha, beta)
252 // -----------------------------------------------------------------------------
253 //
254 // `absl::Beta` produces a floating point number distributed in the closed
255 // interval [0,1] and parameterized by two values `alpha` and `beta` as per a
256 // Beta distribution. `T` must be a floating point type, but may be inferred
257 // from the types of `alpha` and `beta`.
258 //
259 // See https://en.wikipedia.org/wiki/Beta_distribution.
260 //
261 // Example:
262 //
263 // absl::BitGen bitgen;
264 // ...
265 // double sample = absl::Beta(bitgen, 3.0, 2.0);
266 //
267 template <typename RealType, typename URBG>
Beta(URBG && urbg,RealType alpha,RealType beta)268 RealType Beta(URBG&& urbg, // NOLINT(runtime/references)
269 RealType alpha, RealType beta) {
270 static_assert(
271 std::is_floating_point<RealType>::value,
272 "Template-argument 'RealType' must be a floating-point type, in "
273 "absl::Beta<RealType, URBG>(...)");
274
275 using gen_t = absl::decay_t<URBG>;
276 using distribution_t = typename absl::beta_distribution<RealType>;
277
278 return random_internal::DistributionCaller<gen_t>::template Call<
279 distribution_t>(&urbg, alpha, beta);
280 }
281
282 // -----------------------------------------------------------------------------
283 // absl::Exponential<T>(bitgen, lambda = 1)
284 // -----------------------------------------------------------------------------
285 //
286 // `absl::Exponential` produces a floating point number representing the
287 // distance (time) between two consecutive events in a point process of events
288 // occurring continuously and independently at a constant average rate. `T` must
289 // be a floating point type, but may be inferred from the type of `lambda`.
290 //
291 // See https://en.wikipedia.org/wiki/Exponential_distribution.
292 //
293 // Example:
294 //
295 // absl::BitGen bitgen;
296 // ...
297 // double call_length = absl::Exponential(bitgen, 7.0);
298 //
299 template <typename RealType, typename URBG>
300 RealType Exponential(URBG&& urbg, // NOLINT(runtime/references)
301 RealType lambda = 1) {
302 static_assert(
303 std::is_floating_point<RealType>::value,
304 "Template-argument 'RealType' must be a floating-point type, in "
305 "absl::Exponential<RealType, URBG>(...)");
306
307 using gen_t = absl::decay_t<URBG>;
308 using distribution_t = typename absl::exponential_distribution<RealType>;
309
310 return random_internal::DistributionCaller<gen_t>::template Call<
311 distribution_t>(&urbg, lambda);
312 }
313
314 // -----------------------------------------------------------------------------
315 // absl::Gaussian<T>(bitgen, mean = 0, stddev = 1)
316 // -----------------------------------------------------------------------------
317 //
318 // `absl::Gaussian` produces a floating point number selected from the Gaussian
319 // (ie. "Normal") distribution. `T` must be a floating point type, but may be
320 // inferred from the types of `mean` and `stddev`.
321 //
322 // See https://en.wikipedia.org/wiki/Normal_distribution
323 //
324 // Example:
325 //
326 // absl::BitGen bitgen;
327 // ...
328 // double giraffe_height = absl::Gaussian(bitgen, 16.3, 3.3);
329 //
330 template <typename RealType, typename URBG>
331 RealType Gaussian(URBG&& urbg, // NOLINT(runtime/references)
332 RealType mean = 0, RealType stddev = 1) {
333 static_assert(
334 std::is_floating_point<RealType>::value,
335 "Template-argument 'RealType' must be a floating-point type, in "
336 "absl::Gaussian<RealType, URBG>(...)");
337
338 using gen_t = absl::decay_t<URBG>;
339 using distribution_t = typename absl::gaussian_distribution<RealType>;
340
341 return random_internal::DistributionCaller<gen_t>::template Call<
342 distribution_t>(&urbg, mean, stddev);
343 }
344
345 // -----------------------------------------------------------------------------
346 // absl::LogUniform<T>(bitgen, lo, hi, base = 2)
347 // -----------------------------------------------------------------------------
348 //
349 // `absl::LogUniform` produces random values distributed where the log to a
350 // given base of all values is uniform in a closed interval [lo, hi]. `T` must
351 // be an integral type, but may be inferred from the types of `lo` and `hi`.
352 //
353 // I.e., `LogUniform(0, n, b)` is uniformly distributed across buckets
354 // [0], [1, b-1], [b, b^2-1] .. [b^(k-1), (b^k)-1] .. [b^floor(log(n, b)), n]
355 // and is uniformly distributed within each bucket.
356 //
357 // The resulting probability density is inversely related to bucket size, though
358 // values in the final bucket may be more likely than previous values. (In the
359 // extreme case where n = b^i the final value will be tied with zero as the most
360 // probable result.
361 //
362 // If `lo` is nonzero then this distribution is shifted to the desired interval,
363 // so LogUniform(lo, hi, b) is equivalent to LogUniform(0, hi-lo, b)+lo.
364 //
365 // See https://en.wikipedia.org/wiki/Reciprocal_distribution
366 //
367 // Example:
368 //
369 // absl::BitGen bitgen;
370 // ...
371 // int v = absl::LogUniform(bitgen, 0, 1000);
372 //
373 template <typename IntType, typename URBG>
374 IntType LogUniform(URBG&& urbg, // NOLINT(runtime/references)
375 IntType lo, IntType hi, IntType base = 2) {
376 static_assert(random_internal::IsIntegral<IntType>::value,
377 "Template-argument 'IntType' must be an integral type, in "
378 "absl::LogUniform<IntType, URBG>(...)");
379
380 using gen_t = absl::decay_t<URBG>;
381 using distribution_t = typename absl::log_uniform_int_distribution<IntType>;
382
383 return random_internal::DistributionCaller<gen_t>::template Call<
384 distribution_t>(&urbg, lo, hi, base);
385 }
386
387 // -----------------------------------------------------------------------------
388 // absl::Poisson<T>(bitgen, mean = 1)
389 // -----------------------------------------------------------------------------
390 //
391 // `absl::Poisson` produces discrete probabilities for a given number of events
392 // occurring within a fixed interval within the closed interval [0, max]. `T`
393 // must be an integral type.
394 //
395 // See https://en.wikipedia.org/wiki/Poisson_distribution
396 //
397 // Example:
398 //
399 // absl::BitGen bitgen;
400 // ...
401 // int requests_per_minute = absl::Poisson<int>(bitgen, 3.2);
402 //
403 template <typename IntType, typename URBG>
404 IntType Poisson(URBG&& urbg, // NOLINT(runtime/references)
405 double mean = 1.0) {
406 static_assert(random_internal::IsIntegral<IntType>::value,
407 "Template-argument 'IntType' must be an integral type, in "
408 "absl::Poisson<IntType, URBG>(...)");
409
410 using gen_t = absl::decay_t<URBG>;
411 using distribution_t = typename absl::poisson_distribution<IntType>;
412
413 return random_internal::DistributionCaller<gen_t>::template Call<
414 distribution_t>(&urbg, mean);
415 }
416
417 // -----------------------------------------------------------------------------
418 // absl::Zipf<T>(bitgen, hi = max, q = 2, v = 1)
419 // -----------------------------------------------------------------------------
420 //
421 // `absl::Zipf` produces discrete probabilities commonly used for modelling of
422 // rare events over the closed interval [0, hi]. The parameters `v` and `q`
423 // determine the skew of the distribution. `T` must be an integral type, but
424 // may be inferred from the type of `hi`.
425 //
426 // See http://mathworld.wolfram.com/ZipfDistribution.html
427 //
428 // Example:
429 //
430 // absl::BitGen bitgen;
431 // ...
432 // int term_rank = absl::Zipf<int>(bitgen);
433 //
434 template <typename IntType, typename URBG>
435 IntType Zipf(URBG&& urbg, // NOLINT(runtime/references)
436 IntType hi = (std::numeric_limits<IntType>::max)(), double q = 2.0,
437 double v = 1.0) {
438 static_assert(random_internal::IsIntegral<IntType>::value,
439 "Template-argument 'IntType' must be an integral type, in "
440 "absl::Zipf<IntType, URBG>(...)");
441
442 using gen_t = absl::decay_t<URBG>;
443 using distribution_t = typename absl::zipf_distribution<IntType>;
444
445 return random_internal::DistributionCaller<gen_t>::template Call<
446 distribution_t>(&urbg, hi, q, v);
447 }
448
449 ABSL_NAMESPACE_END
450 } // namespace absl
451
452 #endif // ABSL_RANDOM_DISTRIBUTIONS_H_
453