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 #include "absl/random/beta_distribution.h"
16
17 #include <algorithm>
18 #include <cstddef>
19 #include <cstdint>
20 #include <iterator>
21 #include <random>
22 #include <sstream>
23 #include <string>
24 #include <unordered_map>
25 #include <vector>
26
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include "absl/base/internal/raw_logging.h"
30 #include "absl/random/internal/chi_square.h"
31 #include "absl/random/internal/distribution_test_util.h"
32 #include "absl/random/internal/sequence_urbg.h"
33 #include "absl/random/random.h"
34 #include "absl/strings/str_cat.h"
35 #include "absl/strings/str_format.h"
36 #include "absl/strings/str_replace.h"
37 #include "absl/strings/strip.h"
38
39 namespace {
40
41 template <typename IntType>
42 class BetaDistributionInterfaceTest : public ::testing::Test {};
43
44 using RealTypes = ::testing::Types<float, double, long double>;
45 TYPED_TEST_CASE(BetaDistributionInterfaceTest, RealTypes);
46
TYPED_TEST(BetaDistributionInterfaceTest,SerializeTest)47 TYPED_TEST(BetaDistributionInterfaceTest, SerializeTest) {
48 // The threshold for whether std::exp(1/a) is finite.
49 const TypeParam kSmallA =
50 1.0f / std::log((std::numeric_limits<TypeParam>::max)());
51 // The threshold for whether a * std::log(a) is finite.
52 const TypeParam kLargeA =
53 std::exp(std::log((std::numeric_limits<TypeParam>::max)()) -
54 std::log(std::log((std::numeric_limits<TypeParam>::max)())));
55 const TypeParam kLargeAPPC = std::exp(
56 std::log((std::numeric_limits<TypeParam>::max)()) -
57 std::log(std::log((std::numeric_limits<TypeParam>::max)())) - 10.0f);
58 using param_type = typename absl::beta_distribution<TypeParam>::param_type;
59
60 constexpr int kCount = 1000;
61 absl::InsecureBitGen gen;
62 const TypeParam kValues[] = {
63 TypeParam(1e-20), TypeParam(1e-12), TypeParam(1e-8), TypeParam(1e-4),
64 TypeParam(1e-3), TypeParam(0.1), TypeParam(0.25),
65 std::nextafter(TypeParam(0.5), TypeParam(0)), // 0.5 - epsilon
66 std::nextafter(TypeParam(0.5), TypeParam(1)), // 0.5 + epsilon
67 TypeParam(0.5), TypeParam(1.0), //
68 std::nextafter(TypeParam(1), TypeParam(0)), // 1 - epsilon
69 std::nextafter(TypeParam(1), TypeParam(2)), // 1 + epsilon
70 TypeParam(12.5), TypeParam(1e2), TypeParam(1e8), TypeParam(1e12),
71 TypeParam(1e20), //
72 kSmallA, //
73 std::nextafter(kSmallA, TypeParam(0)), //
74 std::nextafter(kSmallA, TypeParam(1)), //
75 kLargeA, //
76 std::nextafter(kLargeA, TypeParam(0)), //
77 std::nextafter(kLargeA, std::numeric_limits<TypeParam>::max()),
78 kLargeAPPC, //
79 std::nextafter(kLargeAPPC, TypeParam(0)),
80 std::nextafter(kLargeAPPC, std::numeric_limits<TypeParam>::max()),
81 // Boundary cases.
82 std::numeric_limits<TypeParam>::max(),
83 std::numeric_limits<TypeParam>::epsilon(),
84 std::nextafter(std::numeric_limits<TypeParam>::min(),
85 TypeParam(1)), // min + epsilon
86 std::numeric_limits<TypeParam>::min(), // smallest normal
87 std::numeric_limits<TypeParam>::denorm_min(), // smallest denorm
88 std::numeric_limits<TypeParam>::min() / 2, // denorm
89 std::nextafter(std::numeric_limits<TypeParam>::min(),
90 TypeParam(0)), // denorm_max
91 };
92 for (TypeParam alpha : kValues) {
93 for (TypeParam beta : kValues) {
94 ABSL_INTERNAL_LOG(
95 INFO, absl::StrFormat("Smoke test for Beta(%a, %a)", alpha, beta));
96
97 param_type param(alpha, beta);
98 absl::beta_distribution<TypeParam> before(alpha, beta);
99 EXPECT_EQ(before.alpha(), param.alpha());
100 EXPECT_EQ(before.beta(), param.beta());
101
102 {
103 absl::beta_distribution<TypeParam> via_param(param);
104 EXPECT_EQ(via_param, before);
105 EXPECT_EQ(via_param.param(), before.param());
106 }
107
108 // Smoke test.
109 for (int i = 0; i < kCount; ++i) {
110 auto sample = before(gen);
111 EXPECT_TRUE(std::isfinite(sample));
112 EXPECT_GE(sample, before.min());
113 EXPECT_LE(sample, before.max());
114 }
115
116 // Validate stream serialization.
117 std::stringstream ss;
118 ss << before;
119 absl::beta_distribution<TypeParam> after(3.8f, 1.43f);
120 EXPECT_NE(before.alpha(), after.alpha());
121 EXPECT_NE(before.beta(), after.beta());
122 EXPECT_NE(before.param(), after.param());
123 EXPECT_NE(before, after);
124
125 ss >> after;
126
127 #if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
128 defined(__ppc__) || defined(__PPC__)
129 if (std::is_same<TypeParam, long double>::value) {
130 // Roundtripping floating point values requires sufficient precision
131 // to reconstruct the exact value. It turns out that long double
132 // has some errors doing this on ppc.
133 if (alpha <= std::numeric_limits<double>::max() &&
134 alpha >= std::numeric_limits<double>::lowest()) {
135 EXPECT_EQ(static_cast<double>(before.alpha()),
136 static_cast<double>(after.alpha()))
137 << ss.str();
138 }
139 if (beta <= std::numeric_limits<double>::max() &&
140 beta >= std::numeric_limits<double>::lowest()) {
141 EXPECT_EQ(static_cast<double>(before.beta()),
142 static_cast<double>(after.beta()))
143 << ss.str();
144 }
145 continue;
146 }
147 #endif
148
149 EXPECT_EQ(before.alpha(), after.alpha());
150 EXPECT_EQ(before.beta(), after.beta());
151 EXPECT_EQ(before, after) //
152 << ss.str() << " " //
153 << (ss.good() ? "good " : "") //
154 << (ss.bad() ? "bad " : "") //
155 << (ss.eof() ? "eof " : "") //
156 << (ss.fail() ? "fail " : "");
157 }
158 }
159 }
160
TYPED_TEST(BetaDistributionInterfaceTest,DegenerateCases)161 TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
162 // Extreme cases when the params are abnormal.
163 absl::InsecureBitGen gen;
164 constexpr int kCount = 1000;
165 const TypeParam kSmallValues[] = {
166 std::numeric_limits<TypeParam>::min(),
167 std::numeric_limits<TypeParam>::denorm_min(),
168 std::nextafter(std::numeric_limits<TypeParam>::min(),
169 TypeParam(0)), // denorm_max
170 std::numeric_limits<TypeParam>::epsilon(),
171 };
172 const TypeParam kLargeValues[] = {
173 std::numeric_limits<TypeParam>::max() * static_cast<TypeParam>(0.9999),
174 std::numeric_limits<TypeParam>::max() - 1,
175 std::numeric_limits<TypeParam>::max(),
176 };
177 {
178 // Small alpha and beta.
179 // Useful WolframAlpha plots:
180 // * plot InverseBetaRegularized[x, 0.0001, 0.0001] from 0.495 to 0.505
181 // * Beta[1.0, 0.0000001, 0.0000001]
182 // * Beta[0.9999, 0.0000001, 0.0000001]
183 for (TypeParam alpha : kSmallValues) {
184 for (TypeParam beta : kSmallValues) {
185 int zeros = 0;
186 int ones = 0;
187 absl::beta_distribution<TypeParam> d(alpha, beta);
188 for (int i = 0; i < kCount; ++i) {
189 TypeParam x = d(gen);
190 if (x == 0.0) {
191 zeros++;
192 } else if (x == 1.0) {
193 ones++;
194 }
195 }
196 EXPECT_EQ(ones + zeros, kCount);
197 if (alpha == beta) {
198 EXPECT_NE(ones, 0);
199 EXPECT_NE(zeros, 0);
200 }
201 }
202 }
203 }
204 {
205 // Small alpha, large beta.
206 // Useful WolframAlpha plots:
207 // * plot InverseBetaRegularized[x, 0.0001, 10000] from 0.995 to 1
208 // * Beta[0, 0.0000001, 1000000]
209 // * Beta[0.001, 0.0000001, 1000000]
210 // * Beta[1, 0.0000001, 1000000]
211 for (TypeParam alpha : kSmallValues) {
212 for (TypeParam beta : kLargeValues) {
213 absl::beta_distribution<TypeParam> d(alpha, beta);
214 for (int i = 0; i < kCount; ++i) {
215 EXPECT_EQ(d(gen), 0.0);
216 }
217 }
218 }
219 }
220 {
221 // Large alpha, small beta.
222 // Useful WolframAlpha plots:
223 // * plot InverseBetaRegularized[x, 10000, 0.0001] from 0 to 0.001
224 // * Beta[0.99, 1000000, 0.0000001]
225 // * Beta[1, 1000000, 0.0000001]
226 for (TypeParam alpha : kLargeValues) {
227 for (TypeParam beta : kSmallValues) {
228 absl::beta_distribution<TypeParam> d(alpha, beta);
229 for (int i = 0; i < kCount; ++i) {
230 EXPECT_EQ(d(gen), 1.0);
231 }
232 }
233 }
234 }
235 {
236 // Large alpha and beta.
237 absl::beta_distribution<TypeParam> d(std::numeric_limits<TypeParam>::max(),
238 std::numeric_limits<TypeParam>::max());
239 for (int i = 0; i < kCount; ++i) {
240 EXPECT_EQ(d(gen), 0.5);
241 }
242 }
243 {
244 // Large alpha and beta but unequal.
245 absl::beta_distribution<TypeParam> d(
246 std::numeric_limits<TypeParam>::max(),
247 std::numeric_limits<TypeParam>::max() * 0.9999);
248 for (int i = 0; i < kCount; ++i) {
249 TypeParam x = d(gen);
250 EXPECT_NE(x, 0.5f);
251 EXPECT_FLOAT_EQ(x, 0.500025f);
252 }
253 }
254 }
255
256 class BetaDistributionModel {
257 public:
BetaDistributionModel(::testing::tuple<double,double> p)258 explicit BetaDistributionModel(::testing::tuple<double, double> p)
259 : alpha_(::testing::get<0>(p)), beta_(::testing::get<1>(p)) {}
260
Mean() const261 double Mean() const { return alpha_ / (alpha_ + beta_); }
262
Variance() const263 double Variance() const {
264 return alpha_ * beta_ / (alpha_ + beta_ + 1) / (alpha_ + beta_) /
265 (alpha_ + beta_);
266 }
267
Kurtosis() const268 double Kurtosis() const {
269 return 3 + 6 *
270 ((alpha_ - beta_) * (alpha_ - beta_) * (alpha_ + beta_ + 1) -
271 alpha_ * beta_ * (2 + alpha_ + beta_)) /
272 alpha_ / beta_ / (alpha_ + beta_ + 2) / (alpha_ + beta_ + 3);
273 }
274
275 protected:
276 const double alpha_;
277 const double beta_;
278 };
279
280 class BetaDistributionTest
281 : public ::testing::TestWithParam<::testing::tuple<double, double>>,
282 public BetaDistributionModel {
283 public:
BetaDistributionTest()284 BetaDistributionTest() : BetaDistributionModel(GetParam()) {}
285
286 protected:
287 template <class D>
288 bool SingleZTestOnMeanAndVariance(double p, size_t samples);
289
290 template <class D>
291 bool SingleChiSquaredTest(double p, size_t samples, size_t buckets);
292
293 absl::InsecureBitGen rng_;
294 };
295
296 template <class D>
SingleZTestOnMeanAndVariance(double p,size_t samples)297 bool BetaDistributionTest::SingleZTestOnMeanAndVariance(double p,
298 size_t samples) {
299 D dis(alpha_, beta_);
300
301 std::vector<double> data;
302 data.reserve(samples);
303 for (size_t i = 0; i < samples; i++) {
304 const double variate = dis(rng_);
305 EXPECT_FALSE(std::isnan(variate));
306 // Note that equality is allowed on both sides.
307 EXPECT_GE(variate, 0.0);
308 EXPECT_LE(variate, 1.0);
309 data.push_back(variate);
310 }
311
312 // We validate that the sample mean and sample variance are indeed from a
313 // Beta distribution with the given shape parameters.
314 const auto m = absl::random_internal::ComputeDistributionMoments(data);
315
316 // The variance of the sample mean is variance / n.
317 const double mean_stddev = std::sqrt(Variance() / static_cast<double>(m.n));
318
319 // The variance of the sample variance is (approximately):
320 // (kurtosis - 1) * variance^2 / n
321 const double variance_stddev = std::sqrt(
322 (Kurtosis() - 1) * Variance() * Variance() / static_cast<double>(m.n));
323 // z score for the sample variance.
324 const double z_variance = (m.variance - Variance()) / variance_stddev;
325
326 const double max_err = absl::random_internal::MaxErrorTolerance(p);
327 const double z_mean = absl::random_internal::ZScore(Mean(), m);
328 const bool pass =
329 absl::random_internal::Near("z", z_mean, 0.0, max_err) &&
330 absl::random_internal::Near("z_variance", z_variance, 0.0, max_err);
331 if (!pass) {
332 ABSL_INTERNAL_LOG(
333 INFO,
334 absl::StrFormat(
335 "Beta(%f, %f), "
336 "mean: sample %f, expect %f, which is %f stddevs away, "
337 "variance: sample %f, expect %f, which is %f stddevs away.",
338 alpha_, beta_, m.mean, Mean(),
339 std::abs(m.mean - Mean()) / mean_stddev, m.variance, Variance(),
340 std::abs(m.variance - Variance()) / variance_stddev));
341 }
342 return pass;
343 }
344
345 template <class D>
SingleChiSquaredTest(double p,size_t samples,size_t buckets)346 bool BetaDistributionTest::SingleChiSquaredTest(double p, size_t samples,
347 size_t buckets) {
348 constexpr double kErr = 1e-7;
349 std::vector<double> cutoffs, expected;
350 const double bucket_width = 1.0 / static_cast<double>(buckets);
351 int i = 1;
352 int unmerged_buckets = 0;
353 for (; i < buckets; ++i) {
354 const double p = bucket_width * static_cast<double>(i);
355 const double boundary =
356 absl::random_internal::BetaIncompleteInv(alpha_, beta_, p);
357 // The intention is to add `boundary` to the list of `cutoffs`. It becomes
358 // problematic, however, when the boundary values are not monotone, due to
359 // numerical issues when computing the inverse regularized incomplete
360 // Beta function. In these cases, we merge that bucket with its previous
361 // neighbor and merge their expected counts.
362 if ((cutoffs.empty() && boundary < kErr) ||
363 (!cutoffs.empty() && boundary <= cutoffs.back())) {
364 unmerged_buckets++;
365 continue;
366 }
367 if (boundary >= 1.0 - 1e-10) {
368 break;
369 }
370 cutoffs.push_back(boundary);
371 expected.push_back(static_cast<double>(1 + unmerged_buckets) *
372 bucket_width * static_cast<double>(samples));
373 unmerged_buckets = 0;
374 }
375 cutoffs.push_back(std::numeric_limits<double>::infinity());
376 // Merge all remaining buckets.
377 expected.push_back(static_cast<double>(buckets - i + 1) * bucket_width *
378 static_cast<double>(samples));
379 // Make sure that we don't merge all the buckets, making this test
380 // meaningless.
381 EXPECT_GE(cutoffs.size(), 3) << alpha_ << ", " << beta_;
382
383 D dis(alpha_, beta_);
384
385 std::vector<int32_t> counts(cutoffs.size(), 0);
386 for (int i = 0; i < samples; i++) {
387 const double x = dis(rng_);
388 auto it = std::upper_bound(cutoffs.begin(), cutoffs.end(), x);
389 counts[std::distance(cutoffs.begin(), it)]++;
390 }
391
392 // Null-hypothesis is that the distribution is beta distributed with the
393 // provided alpha, beta params (not estimated from the data).
394 const int dof = cutoffs.size() - 1;
395
396 const double chi_square = absl::random_internal::ChiSquare(
397 counts.begin(), counts.end(), expected.begin(), expected.end());
398 const bool pass =
399 (absl::random_internal::ChiSquarePValue(chi_square, dof) >= p);
400 if (!pass) {
401 for (int i = 0; i < cutoffs.size(); i++) {
402 ABSL_INTERNAL_LOG(
403 INFO, absl::StrFormat("cutoff[%d] = %f, actual count %d, expected %d",
404 i, cutoffs[i], counts[i],
405 static_cast<int>(expected[i])));
406 }
407
408 ABSL_INTERNAL_LOG(
409 INFO, absl::StrFormat(
410 "Beta(%f, %f) %s %f, p = %f", alpha_, beta_,
411 absl::random_internal::kChiSquared, chi_square,
412 absl::random_internal::ChiSquarePValue(chi_square, dof)));
413 }
414 return pass;
415 }
416
TEST_P(BetaDistributionTest,TestSampleStatistics)417 TEST_P(BetaDistributionTest, TestSampleStatistics) {
418 static constexpr int kRuns = 20;
419 static constexpr double kPFail = 0.02;
420 const double p =
421 absl::random_internal::RequiredSuccessProbability(kPFail, kRuns);
422 static constexpr int kSampleCount = 10000;
423 static constexpr int kBucketCount = 100;
424 int failed = 0;
425 for (int i = 0; i < kRuns; ++i) {
426 if (!SingleZTestOnMeanAndVariance<absl::beta_distribution<double>>(
427 p, kSampleCount)) {
428 failed++;
429 }
430 if (!SingleChiSquaredTest<absl::beta_distribution<double>>(
431 0.005, kSampleCount, kBucketCount)) {
432 failed++;
433 }
434 }
435 // Set so that the test is not flaky at --runs_per_test=10000
436 EXPECT_LE(failed, 5);
437 }
438
ParamName(const::testing::TestParamInfo<::testing::tuple<double,double>> & info)439 std::string ParamName(
440 const ::testing::TestParamInfo<::testing::tuple<double, double>>& info) {
441 std::string name = absl::StrCat("alpha_", ::testing::get<0>(info.param),
442 "__beta_", ::testing::get<1>(info.param));
443 return absl::StrReplaceAll(name, {{"+", "_"}, {"-", "_"}, {".", "_"}});
444 }
445
446 INSTANTIATE_TEST_CASE_P(
447 TestSampleStatisticsCombinations, BetaDistributionTest,
448 ::testing::Combine(::testing::Values(0.1, 0.2, 0.9, 1.1, 2.5, 10.0, 123.4),
449 ::testing::Values(0.1, 0.2, 0.9, 1.1, 2.5, 10.0, 123.4)),
450 ParamName);
451
452 INSTANTIATE_TEST_CASE_P(
453 TestSampleStatistics_SelectedPairs, BetaDistributionTest,
454 ::testing::Values(std::make_pair(0.5, 1000), std::make_pair(1000, 0.5),
455 std::make_pair(900, 1000), std::make_pair(10000, 20000),
456 std::make_pair(4e5, 2e7), std::make_pair(1e7, 1e5)),
457 ParamName);
458
459 // NOTE: absl::beta_distribution is not guaranteed to be stable.
TEST(BetaDistributionTest,StabilityTest)460 TEST(BetaDistributionTest, StabilityTest) {
461 // absl::beta_distribution stability relies on the stability of
462 // absl::random_interna::RandU64ToDouble, std::exp, std::log, std::pow,
463 // and std::sqrt.
464 //
465 // This test also depends on the stability of std::frexp.
466 using testing::ElementsAre;
467 absl::random_internal::sequence_urbg urbg({
468 0xffff00000000e6c8ull, 0xffff0000000006c8ull, 0x800003766295CFA9ull,
469 0x11C819684E734A41ull, 0x832603766295CFA9ull, 0x7fbe76c8b4395800ull,
470 0xB3472DCA7B14A94Aull, 0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull,
471 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull, 0x00035C904C70A239ull,
472 0x00009E0BCBAADE14ull, 0x0000000000622CA7ull, 0x4864f22c059bf29eull,
473 0x247856d8b862665cull, 0xe46e86e9a1337e10ull, 0xd8c8541f3519b133ull,
474 0xffe75b52c567b9e4ull, 0xfffff732e5709c5bull, 0xff1f7f0b983532acull,
475 0x1ec2e8986d2362caull, 0xC332DDEFBE6C5AA5ull, 0x6558218568AB9702ull,
476 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull, 0xECDD4775619F1510ull,
477 0x814c8e35fe9a961aull, 0x0c3cd59c9b638a02ull, 0xcb3bb6478a07715cull,
478 0x1224e62c978bbc7full, 0x671ef2cb04e81f6eull, 0x3c1cbd811eaf1808ull,
479 0x1bbc23cfa8fac721ull, 0xa4c2cda65e596a51ull, 0xb77216fad37adf91ull,
480 0x836d794457c08849ull, 0xe083df03475f49d7ull, 0xbc9feb512e6b0d6cull,
481 0xb12d74fdd718c8c5ull, 0x12ff09653bfbe4caull, 0x8dd03a105bc4ee7eull,
482 0x5738341045ba0d85ull, 0xf3fd722dc65ad09eull, 0xfa14fd21ea2a5705ull,
483 0xffe6ea4d6edb0c73ull, 0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull,
484 0xEAAD8E716B93D5A0ull, 0xD08ED1D0AFC725E0ull, 0x8E3C5B2F8E7594B7ull,
485 0x8FF6E2FBF2122B64ull, 0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull,
486 0xD1CFF191B3A8C1ADull, 0x2F2F2218BE0E1777ull, 0xEA752DFE8B021FA1ull,
487 });
488
489 // Convert the real-valued result into a unit64 where we compare
490 // 5 (float) or 10 (double) decimal digits plus the base-2 exponent.
491 auto float_to_u64 = [](float d) {
492 int exp = 0;
493 auto f = std::frexp(d, &exp);
494 return (static_cast<uint64_t>(1e5 * f) * 10000) + std::abs(exp);
495 };
496 auto double_to_u64 = [](double d) {
497 int exp = 0;
498 auto f = std::frexp(d, &exp);
499 return (static_cast<uint64_t>(1e10 * f) * 10000) + std::abs(exp);
500 };
501
502 std::vector<uint64_t> output(20);
503 {
504 // Algorithm Joehnk (float)
505 absl::beta_distribution<float> dist(0.1f, 0.2f);
506 std::generate(std::begin(output), std::end(output),
507 [&] { return float_to_u64(dist(urbg)); });
508 EXPECT_EQ(44, urbg.invocations());
509 EXPECT_THAT(output, //
510 testing::ElementsAre(
511 998340000, 619030004, 500000001, 999990000, 996280000,
512 500000001, 844740004, 847210001, 999970000, 872320000,
513 585480007, 933280000, 869080042, 647670031, 528240004,
514 969980004, 626050008, 915930002, 833440033, 878040015));
515 }
516
517 urbg.reset();
518 {
519 // Algorithm Joehnk (double)
520 absl::beta_distribution<double> dist(0.1, 0.2);
521 std::generate(std::begin(output), std::end(output),
522 [&] { return double_to_u64(dist(urbg)); });
523 EXPECT_EQ(44, urbg.invocations());
524 EXPECT_THAT(
525 output, //
526 testing::ElementsAre(
527 99834713000000, 61903356870004, 50000000000001, 99999721170000,
528 99628374770000, 99999999990000, 84474397860004, 84721276240001,
529 99997407490000, 87232528120000, 58548364780007, 93328932910000,
530 86908237770042, 64767917930031, 52824581970004, 96998544140004,
531 62605946270008, 91593604380002, 83345031740033, 87804397230015));
532 }
533
534 urbg.reset();
535 {
536 // Algorithm Cheng 1
537 absl::beta_distribution<double> dist(0.9, 2.0);
538 std::generate(std::begin(output), std::end(output),
539 [&] { return double_to_u64(dist(urbg)); });
540 EXPECT_EQ(62, urbg.invocations());
541 EXPECT_THAT(
542 output, //
543 testing::ElementsAre(
544 62069004780001, 64433204450001, 53607416560000, 89644295430008,
545 61434586310019, 55172615890002, 62187161490000, 56433684810003,
546 80454622050005, 86418558710003, 92920514700001, 64645184680001,
547 58549183380000, 84881283650005, 71078728590002, 69949694970000,
548 73157461710001, 68592191300001, 70747623900000, 78584696930005));
549 }
550
551 urbg.reset();
552 {
553 // Algorithm Cheng 2
554 absl::beta_distribution<double> dist(1.5, 2.5);
555 std::generate(std::begin(output), std::end(output),
556 [&] { return double_to_u64(dist(urbg)); });
557 EXPECT_EQ(54, urbg.invocations());
558 EXPECT_THAT(
559 output, //
560 testing::ElementsAre(
561 75000029250001, 76751482860001, 53264575220000, 69193133650005,
562 78028324470013, 91573587560002, 59167523770000, 60658618560002,
563 80075870540000, 94141320460004, 63196592770003, 78883906300002,
564 96797992590001, 76907587800001, 56645167560000, 65408302280003,
565 53401156320001, 64731238570000, 83065573750001, 79788333820001));
566 }
567 }
568
569 // This is an implementation-specific test. If any part of the implementation
570 // changes, then it is likely that this test will change as well. Also, if
571 // dependencies of the distribution change, such as RandU64ToDouble, then this
572 // is also likely to change.
TEST(BetaDistributionTest,AlgorithmBounds)573 TEST(BetaDistributionTest, AlgorithmBounds) {
574 {
575 absl::random_internal::sequence_urbg urbg(
576 {0x7fbe76c8b4395800ull, 0x8000000000000000ull});
577 // u=0.499, v=0.5
578 absl::beta_distribution<double> dist(1e-4, 1e-4);
579 double a = dist(urbg);
580 EXPECT_EQ(a, 2.0202860861567108529e-09);
581 EXPECT_EQ(2, urbg.invocations());
582 }
583
584 // Test that both the float & double algorithms appropriately reject the
585 // initial draw.
586 {
587 // 1/alpha = 1/beta = 2.
588 absl::beta_distribution<float> dist(0.5, 0.5);
589
590 // first two outputs are close to 1.0 - epsilon,
591 // thus: (u ^ 2 + v ^ 2) > 1.0
592 absl::random_internal::sequence_urbg urbg(
593 {0xffff00000006e6c8ull, 0xffff00000007c7c8ull, 0x800003766295CFA9ull,
594 0x11C819684E734A41ull});
595 {
596 double y = absl::beta_distribution<double>(0.5, 0.5)(urbg);
597 EXPECT_EQ(4, urbg.invocations());
598 EXPECT_EQ(y, 0.9810668952633862) << y;
599 }
600
601 // ...and: log(u) * a ~= log(v) * b ~= -0.02
602 // thus z ~= -0.02 + log(1 + e(~0))
603 // ~= -0.02 + 0.69
604 // thus z > 0
605 urbg.reset();
606 {
607 float x = absl::beta_distribution<float>(0.5, 0.5)(urbg);
608 EXPECT_EQ(4, urbg.invocations());
609 EXPECT_NEAR(0.98106688261032104, x, 0.0000005) << x << "f";
610 }
611 }
612 }
613
614 } // namespace
615