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