|
||||
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_
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |