distributions.h 18 KB

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