Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:31:49

0001 // Copyright 2017 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 //
0015 // -----------------------------------------------------------------------------
0016 // File: distributions.h
0017 // -----------------------------------------------------------------------------
0018 //
0019 // This header defines functions representing distributions, which you use in
0020 // combination with an Abseil random bit generator to produce random values
0021 // according to the rules of that distribution.
0022 //
0023 // The Abseil random library defines the following distributions within this
0024 // file:
0025 //
0026 //   * `absl::Uniform` for uniform (constant) distributions having constant
0027 //     probability
0028 //   * `absl::Bernoulli` for discrete distributions having exactly two outcomes
0029 //   * `absl::Beta` for continuous distributions parameterized through two
0030 //     free parameters
0031 //   * `absl::Exponential` for discrete distributions of events occurring
0032 //     continuously and independently at a constant average rate
0033 //   * `absl::Gaussian` (also known as "normal distributions") for continuous
0034 //     distributions using an associated quadratic function
0035 //   * `absl::LogUniform` for discrete distributions where the log to the given
0036 //     base of all values is uniform
0037 //   * `absl::Poisson` for discrete probability distributions that express the
0038 //     probability of a given number of events occurring within a fixed interval
0039 //   * `absl::Zipf` for discrete probability distributions commonly used for
0040 //     modelling of rare events
0041 //
0042 // Prefer use of these distribution function classes over manual construction of
0043 // your own distribution classes, as it allows library maintainers greater
0044 // flexibility to change the underlying implementation in the future.
0045 
0046 #ifndef ABSL_RANDOM_DISTRIBUTIONS_H_
0047 #define ABSL_RANDOM_DISTRIBUTIONS_H_
0048 
0049 #include <limits>
0050 #include <type_traits>
0051 
0052 #include "absl/base/config.h"
0053 #include "absl/base/internal/inline_variable.h"
0054 #include "absl/meta/type_traits.h"
0055 #include "absl/random/bernoulli_distribution.h"
0056 #include "absl/random/beta_distribution.h"
0057 #include "absl/random/exponential_distribution.h"
0058 #include "absl/random/gaussian_distribution.h"
0059 #include "absl/random/internal/distribution_caller.h"  // IWYU pragma: export
0060 #include "absl/random/internal/traits.h"
0061 #include "absl/random/internal/uniform_helper.h"  // IWYU pragma: export
0062 #include "absl/random/log_uniform_int_distribution.h"
0063 #include "absl/random/poisson_distribution.h"
0064 #include "absl/random/uniform_int_distribution.h"  // IWYU pragma: export
0065 #include "absl/random/uniform_real_distribution.h"  // IWYU pragma: export
0066 #include "absl/random/zipf_distribution.h"
0067 
0068 namespace absl {
0069 ABSL_NAMESPACE_BEGIN
0070 
0071 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosedClosed,
0072                                {});
0073 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosed, {});
0074 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedOpenTag, IntervalClosedOpen, {});
0075 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenOpenTag, IntervalOpenOpen, {});
0076 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenOpenTag, IntervalOpen, {});
0077 ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenClosedTag, IntervalOpenClosed, {});
0078 
0079 // -----------------------------------------------------------------------------
0080 // absl::Uniform<T>(tag, bitgen, lo, hi)
0081 // -----------------------------------------------------------------------------
0082 //
0083 // `absl::Uniform()` produces random values of type `T` uniformly distributed in
0084 // a defined interval {lo, hi}. The interval `tag` defines the type of interval
0085 // which should be one of the following possible values:
0086 //
0087 //   * `absl::IntervalOpenOpen`
0088 //   * `absl::IntervalOpenClosed`
0089 //   * `absl::IntervalClosedOpen`
0090 //   * `absl::IntervalClosedClosed`
0091 //
0092 // where "open" refers to an exclusive value (excluded) from the output, while
0093 // "closed" refers to an inclusive value (included) from the output.
0094 //
0095 // In the absence of an explicit return type `T`, `absl::Uniform()` will deduce
0096 // the return type based on the provided endpoint arguments {A lo, B hi}.
0097 // Given these endpoints, one of {A, B} will be chosen as the return type, if
0098 // a type can be implicitly converted into the other in a lossless way. The
0099 // lack of any such implicit conversion between {A, B} will produce a
0100 // compile-time error
0101 //
0102 // See https://en.wikipedia.org/wiki/Uniform_distribution_(continuous)
0103 //
0104 // Example:
0105 //
0106 //   absl::BitGen bitgen;
0107 //
0108 //   // Produce a random float value between 0.0 and 1.0, inclusive
0109 //   auto x = absl::Uniform(absl::IntervalClosedClosed, bitgen, 0.0f, 1.0f);
0110 //
0111 //   // The most common interval of `absl::IntervalClosedOpen` is available by
0112 //   // default:
0113 //
0114 //   auto x = absl::Uniform(bitgen, 0.0f, 1.0f);
0115 //
0116 //   // Return-types are typically inferred from the arguments, however callers
0117 //   // can optionally provide an explicit return-type to the template.
0118 //
0119 //   auto x = absl::Uniform<float>(bitgen, 0, 1);
0120 //
0121 template <typename R = void, typename TagType, typename URBG>
0122 typename absl::enable_if_t<!std::is_same<R, void>::value, R>  //
0123 Uniform(TagType tag,
0124         URBG&& urbg,  // NOLINT(runtime/references)
0125         R lo, R hi) {
0126   using gen_t = absl::decay_t<URBG>;
0127   using distribution_t = random_internal::UniformDistributionWrapper<R>;
0128 
0129   auto a = random_internal::uniform_lower_bound(tag, lo, hi);
0130   auto b = random_internal::uniform_upper_bound(tag, lo, hi);
0131   if (!random_internal::is_uniform_range_valid(a, b)) return lo;
0132 
0133   return random_internal::DistributionCaller<gen_t>::template Call<
0134       distribution_t>(&urbg, tag, lo, hi);
0135 }
0136 
0137 // absl::Uniform<T>(bitgen, lo, hi)
0138 //
0139 // Overload of `Uniform()` using the default closed-open interval of [lo, hi),
0140 // and returning values of type `T`
0141 template <typename R = void, typename URBG>
0142 typename absl::enable_if_t<!std::is_same<R, void>::value, R>  //
0143 Uniform(URBG&& urbg,  // NOLINT(runtime/references)
0144         R lo, R hi) {
0145   using gen_t = absl::decay_t<URBG>;
0146   using distribution_t = random_internal::UniformDistributionWrapper<R>;
0147   constexpr auto tag = absl::IntervalClosedOpen;
0148 
0149   auto a = random_internal::uniform_lower_bound(tag, lo, hi);
0150   auto b = random_internal::uniform_upper_bound(tag, lo, hi);
0151   if (!random_internal::is_uniform_range_valid(a, b)) return lo;
0152 
0153   return random_internal::DistributionCaller<gen_t>::template Call<
0154       distribution_t>(&urbg, lo, hi);
0155 }
0156 
0157 // absl::Uniform(tag, bitgen, lo, hi)
0158 //
0159 // Overload of `Uniform()` using different (but compatible) lo, hi types. Note
0160 // that a compile-error will result if the return type cannot be deduced
0161 // correctly from the passed types.
0162 template <typename R = void, typename TagType, typename URBG, typename A,
0163           typename B>
0164 typename absl::enable_if_t<std::is_same<R, void>::value,
0165                            random_internal::uniform_inferred_return_t<A, B>>
0166 Uniform(TagType tag,
0167         URBG&& urbg,  // NOLINT(runtime/references)
0168         A lo, B hi) {
0169   using gen_t = absl::decay_t<URBG>;
0170   using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
0171   using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
0172 
0173   auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
0174   auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
0175   if (!random_internal::is_uniform_range_valid(a, b)) return lo;
0176 
0177   return random_internal::DistributionCaller<gen_t>::template Call<
0178       distribution_t>(&urbg, tag, static_cast<return_t>(lo),
0179                       static_cast<return_t>(hi));
0180 }
0181 
0182 // absl::Uniform(bitgen, lo, hi)
0183 //
0184 // Overload of `Uniform()` using different (but compatible) lo, hi types and the
0185 // default closed-open interval of [lo, hi). Note that a compile-error will
0186 // result if the return type cannot be deduced correctly from the passed types.
0187 template <typename R = void, typename URBG, typename A, typename B>
0188 typename absl::enable_if_t<std::is_same<R, void>::value,
0189                            random_internal::uniform_inferred_return_t<A, B>>
0190 Uniform(URBG&& urbg,  // NOLINT(runtime/references)
0191         A lo, B hi) {
0192   using gen_t = absl::decay_t<URBG>;
0193   using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
0194   using distribution_t = random_internal::UniformDistributionWrapper<return_t>;
0195 
0196   constexpr auto tag = absl::IntervalClosedOpen;
0197   auto a = random_internal::uniform_lower_bound<return_t>(tag, lo, hi);
0198   auto b = random_internal::uniform_upper_bound<return_t>(tag, lo, hi);
0199   if (!random_internal::is_uniform_range_valid(a, b)) return lo;
0200 
0201   return random_internal::DistributionCaller<gen_t>::template Call<
0202       distribution_t>(&urbg, static_cast<return_t>(lo),
0203                       static_cast<return_t>(hi));
0204 }
0205 
0206 // absl::Uniform<unsigned T>(bitgen)
0207 //
0208 // Overload of Uniform() using the minimum and maximum values of a given type
0209 // `T` (which must be unsigned), returning a value of type `unsigned T`
0210 template <typename R, typename URBG>
0211 typename absl::enable_if_t<!std::numeric_limits<R>::is_signed, R>  //
0212 Uniform(URBG&& urbg) {  // NOLINT(runtime/references)
0213   using gen_t = absl::decay_t<URBG>;
0214   using distribution_t = random_internal::UniformDistributionWrapper<R>;
0215 
0216   return random_internal::DistributionCaller<gen_t>::template Call<
0217       distribution_t>(&urbg);
0218 }
0219 
0220 // -----------------------------------------------------------------------------
0221 // absl::Bernoulli(bitgen, p)
0222 // -----------------------------------------------------------------------------
0223 //
0224 // `absl::Bernoulli` produces a random boolean value, with probability `p`
0225 // (where 0.0 <= p <= 1.0) equaling `true`.
0226 //
0227 // Prefer `absl::Bernoulli` to produce boolean values over other alternatives
0228 // such as comparing an `absl::Uniform()` value to a specific output.
0229 //
0230 // See https://en.wikipedia.org/wiki/Bernoulli_distribution
0231 //
0232 // Example:
0233 //
0234 //   absl::BitGen bitgen;
0235 //   ...
0236 //   if (absl::Bernoulli(bitgen, 1.0/3721.0)) {
0237 //     std::cout << "Asteroid field navigation successful.";
0238 //   }
0239 //
0240 template <typename URBG>
0241 bool Bernoulli(URBG&& urbg,  // NOLINT(runtime/references)
0242                double p) {
0243   using gen_t = absl::decay_t<URBG>;
0244   using distribution_t = absl::bernoulli_distribution;
0245 
0246   return random_internal::DistributionCaller<gen_t>::template Call<
0247       distribution_t>(&urbg, p);
0248 }
0249 
0250 // -----------------------------------------------------------------------------
0251 // absl::Beta<T>(bitgen, alpha, beta)
0252 // -----------------------------------------------------------------------------
0253 //
0254 // `absl::Beta` produces a floating point number distributed in the closed
0255 // interval [0,1] and parameterized by two values `alpha` and `beta` as per a
0256 // Beta distribution. `T` must be a floating point type, but may be inferred
0257 // from the types of `alpha` and `beta`.
0258 //
0259 // See https://en.wikipedia.org/wiki/Beta_distribution.
0260 //
0261 // Example:
0262 //
0263 //   absl::BitGen bitgen;
0264 //   ...
0265 //   double sample = absl::Beta(bitgen, 3.0, 2.0);
0266 //
0267 template <typename RealType, typename URBG>
0268 RealType Beta(URBG&& urbg,  // NOLINT(runtime/references)
0269               RealType alpha, RealType beta) {
0270   static_assert(
0271       std::is_floating_point<RealType>::value,
0272       "Template-argument 'RealType' must be a floating-point type, in "
0273       "absl::Beta<RealType, URBG>(...)");
0274 
0275   using gen_t = absl::decay_t<URBG>;
0276   using distribution_t = typename absl::beta_distribution<RealType>;
0277 
0278   return random_internal::DistributionCaller<gen_t>::template Call<
0279       distribution_t>(&urbg, alpha, beta);
0280 }
0281 
0282 // -----------------------------------------------------------------------------
0283 // absl::Exponential<T>(bitgen, lambda = 1)
0284 // -----------------------------------------------------------------------------
0285 //
0286 // `absl::Exponential` produces a floating point number representing the
0287 // distance (time) between two consecutive events in a point process of events
0288 // occurring continuously and independently at a constant average rate. `T` must
0289 // be a floating point type, but may be inferred from the type of `lambda`.
0290 //
0291 // See https://en.wikipedia.org/wiki/Exponential_distribution.
0292 //
0293 // Example:
0294 //
0295 //   absl::BitGen bitgen;
0296 //   ...
0297 //   double call_length = absl::Exponential(bitgen, 7.0);
0298 //
0299 template <typename RealType, typename URBG>
0300 RealType Exponential(URBG&& urbg,  // NOLINT(runtime/references)
0301                      RealType lambda = 1) {
0302   static_assert(
0303       std::is_floating_point<RealType>::value,
0304       "Template-argument 'RealType' must be a floating-point type, in "
0305       "absl::Exponential<RealType, URBG>(...)");
0306 
0307   using gen_t = absl::decay_t<URBG>;
0308   using distribution_t = typename absl::exponential_distribution<RealType>;
0309 
0310   return random_internal::DistributionCaller<gen_t>::template Call<
0311       distribution_t>(&urbg, lambda);
0312 }
0313 
0314 // -----------------------------------------------------------------------------
0315 // absl::Gaussian<T>(bitgen, mean = 0, stddev = 1)
0316 // -----------------------------------------------------------------------------
0317 //
0318 // `absl::Gaussian` produces a floating point number selected from the Gaussian
0319 // (ie. "Normal") distribution. `T` must be a floating point type, but may be
0320 // inferred from the types of `mean` and `stddev`.
0321 //
0322 // See https://en.wikipedia.org/wiki/Normal_distribution
0323 //
0324 // Example:
0325 //
0326 //   absl::BitGen bitgen;
0327 //   ...
0328 //   double giraffe_height = absl::Gaussian(bitgen, 16.3, 3.3);
0329 //
0330 template <typename RealType, typename URBG>
0331 RealType Gaussian(URBG&& urbg,  // NOLINT(runtime/references)
0332                   RealType mean = 0, RealType stddev = 1) {
0333   static_assert(
0334       std::is_floating_point<RealType>::value,
0335       "Template-argument 'RealType' must be a floating-point type, in "
0336       "absl::Gaussian<RealType, URBG>(...)");
0337 
0338   using gen_t = absl::decay_t<URBG>;
0339   using distribution_t = typename absl::gaussian_distribution<RealType>;
0340 
0341   return random_internal::DistributionCaller<gen_t>::template Call<
0342       distribution_t>(&urbg, mean, stddev);
0343 }
0344 
0345 // -----------------------------------------------------------------------------
0346 // absl::LogUniform<T>(bitgen, lo, hi, base = 2)
0347 // -----------------------------------------------------------------------------
0348 //
0349 // `absl::LogUniform` produces random values distributed where the log to a
0350 // given base of all values is uniform in a closed interval [lo, hi]. `T` must
0351 // be an integral type, but may be inferred from the types of `lo` and `hi`.
0352 //
0353 // I.e., `LogUniform(0, n, b)` is uniformly distributed across buckets
0354 // [0], [1, b-1], [b, b^2-1] .. [b^(k-1), (b^k)-1] .. [b^floor(log(n, b)), n]
0355 // and is uniformly distributed within each bucket.
0356 //
0357 // The resulting probability density is inversely related to bucket size, though
0358 // values in the final bucket may be more likely than previous values. (In the
0359 // extreme case where n = b^i the final value will be tied with zero as the most
0360 // probable result.
0361 //
0362 // If `lo` is nonzero then this distribution is shifted to the desired interval,
0363 // so LogUniform(lo, hi, b) is equivalent to LogUniform(0, hi-lo, b)+lo.
0364 //
0365 // See https://en.wikipedia.org/wiki/Reciprocal_distribution
0366 //
0367 // Example:
0368 //
0369 //   absl::BitGen bitgen;
0370 //   ...
0371 //   int v = absl::LogUniform(bitgen, 0, 1000);
0372 //
0373 template <typename IntType, typename URBG>
0374 IntType LogUniform(URBG&& urbg,  // NOLINT(runtime/references)
0375                    IntType lo, IntType hi, IntType base = 2) {
0376   static_assert(random_internal::IsIntegral<IntType>::value,
0377                 "Template-argument 'IntType' must be an integral type, in "
0378                 "absl::LogUniform<IntType, URBG>(...)");
0379 
0380   using gen_t = absl::decay_t<URBG>;
0381   using distribution_t = typename absl::log_uniform_int_distribution<IntType>;
0382 
0383   return random_internal::DistributionCaller<gen_t>::template Call<
0384       distribution_t>(&urbg, lo, hi, base);
0385 }
0386 
0387 // -----------------------------------------------------------------------------
0388 // absl::Poisson<T>(bitgen, mean = 1)
0389 // -----------------------------------------------------------------------------
0390 //
0391 // `absl::Poisson` produces discrete probabilities for a given number of events
0392 // occurring within a fixed interval within the closed interval [0, max]. `T`
0393 // must be an integral type.
0394 //
0395 // See https://en.wikipedia.org/wiki/Poisson_distribution
0396 //
0397 // Example:
0398 //
0399 //   absl::BitGen bitgen;
0400 //   ...
0401 //   int requests_per_minute = absl::Poisson<int>(bitgen, 3.2);
0402 //
0403 template <typename IntType, typename URBG>
0404 IntType Poisson(URBG&& urbg,  // NOLINT(runtime/references)
0405                 double mean = 1.0) {
0406   static_assert(random_internal::IsIntegral<IntType>::value,
0407                 "Template-argument 'IntType' must be an integral type, in "
0408                 "absl::Poisson<IntType, URBG>(...)");
0409 
0410   using gen_t = absl::decay_t<URBG>;
0411   using distribution_t = typename absl::poisson_distribution<IntType>;
0412 
0413   return random_internal::DistributionCaller<gen_t>::template Call<
0414       distribution_t>(&urbg, mean);
0415 }
0416 
0417 // -----------------------------------------------------------------------------
0418 // absl::Zipf<T>(bitgen, hi = max, q = 2, v = 1)
0419 // -----------------------------------------------------------------------------
0420 //
0421 // `absl::Zipf` produces discrete probabilities commonly used for modelling of
0422 // rare events over the closed interval [0, hi]. The parameters `v` and `q`
0423 // determine the skew of the distribution. `T`  must be an integral type, but
0424 // may be inferred from the type of `hi`.
0425 //
0426 // See http://mathworld.wolfram.com/ZipfDistribution.html
0427 //
0428 // Example:
0429 //
0430 //   absl::BitGen bitgen;
0431 //   ...
0432 //   int term_rank = absl::Zipf<int>(bitgen);
0433 //
0434 template <typename IntType, typename URBG>
0435 IntType Zipf(URBG&& urbg,  // NOLINT(runtime/references)
0436              IntType hi = (std::numeric_limits<IntType>::max)(), double q = 2.0,
0437              double v = 1.0) {
0438   static_assert(random_internal::IsIntegral<IntType>::value,
0439                 "Template-argument 'IntType' must be an integral type, in "
0440                 "absl::Zipf<IntType, URBG>(...)");
0441 
0442   using gen_t = absl::decay_t<URBG>;
0443   using distribution_t = typename absl::zipf_distribution<IntType>;
0444 
0445   return random_internal::DistributionCaller<gen_t>::template Call<
0446       distribution_t>(&urbg, hi, q, v);
0447 }
0448 
0449 ABSL_NAMESPACE_END
0450 }  // namespace absl
0451 
0452 #endif  // ABSL_RANDOM_DISTRIBUTIONS_H_