• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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