15 #include "absl/random/beta_distribution.h"
25 #include <type_traits>
26 #include <unordered_map>
29 #include "gmock/gmock.h"
30 #include "gtest/gtest.h"
31 #include "absl/base/internal/raw_logging.h"
32 #include "absl/numeric/internal/representation.h"
33 #include "absl/random/internal/chi_square.h"
34 #include "absl/random/internal/distribution_test_util.h"
35 #include "absl/random/internal/pcg_engine.h"
36 #include "absl/random/internal/sequence_urbg.h"
37 #include "absl/random/random.h"
38 #include "absl/strings/str_cat.h"
39 #include "absl/strings/str_format.h"
40 #include "absl/strings/str_replace.h"
41 #include "absl/strings/strip.h"
45 template <
typename IntType>
48 constexpr
bool ShouldExerciseLongDoubleTests() {
57 #if defined(__i686__) && defined(__x86_64__)
64 using RealTypes = std::conditional<ShouldExerciseLongDoubleTests(),
69 TYPED_TEST(BetaDistributionInterfaceTest, SerializeTest) {
71 const TypeParam kSmallA =
74 const TypeParam kLargeA =
79 constexpr
int kCount = 1000;
81 const TypeParam kValues[] = {
82 TypeParam(1e-20), TypeParam(1e-12), TypeParam(1e-8), TypeParam(1e-4),
83 TypeParam(1e-3), TypeParam(0.1), TypeParam(0.25),
84 std::nextafter(TypeParam(0.5), TypeParam(0)),
85 std::nextafter(TypeParam(0.5), TypeParam(1)),
86 TypeParam(0.5), TypeParam(1.0),
87 std::nextafter(TypeParam(1), TypeParam(0)),
88 std::nextafter(TypeParam(1), TypeParam(2)),
89 TypeParam(12.5), TypeParam(1e2), TypeParam(1e8), TypeParam(1e12),
92 std::nextafter(kSmallA, TypeParam(0)),
93 std::nextafter(kSmallA, TypeParam(1)),
95 std::nextafter(kLargeA, TypeParam(0)),
99 std::numeric_limits<TypeParam>::epsilon(),
103 std::numeric_limits<TypeParam>::denorm_min(),
108 for (TypeParam alpha : kValues) {
109 for (TypeParam
beta : kValues) {
113 param_type param(alpha,
beta);
125 for (
int i = 0;
i < kCount; ++
i) {
133 std::stringstream ss;
147 << (ss.good() ?
"good " :
"")
148 << (ss.bad() ?
"bad " :
"")
149 << (ss.eof() ?
"eof " :
"")
150 << (ss.fail() ?
"fail " :
"");
155 TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
162 constexpr
int kCount = 1000;
163 const TypeParam kSmallValues[] = {
165 std::numeric_limits<TypeParam>::denorm_min(),
168 std::numeric_limits<TypeParam>::epsilon(),
170 const TypeParam kLargeValues[] = {
181 for (TypeParam alpha : kSmallValues) {
182 for (TypeParam
beta : kSmallValues) {
186 for (
int i = 0;
i < kCount; ++
i) {
187 TypeParam
x =
d(rng);
190 }
else if (
x == 1.0) {
209 for (TypeParam alpha : kSmallValues) {
210 for (TypeParam
beta : kLargeValues) {
212 for (
int i = 0;
i < kCount; ++
i) {
224 for (TypeParam alpha : kLargeValues) {
225 for (TypeParam
beta : kSmallValues) {
227 for (
int i = 0;
i < kCount; ++
i) {
237 for (
int i = 0;
i < kCount; ++
i) {
246 for (
int i = 0;
i < kCount; ++
i) {
247 TypeParam
x =
d(rng);
254 class BetaDistributionModel {
256 explicit BetaDistributionModel(::testing::tuple<double, double>
p)
259 double Mean()
const {
return alpha_ / (alpha_ + beta_); }
261 double Variance()
const {
262 return alpha_ * beta_ / (alpha_ + beta_ + 1) / (alpha_ + beta_) /
266 double Kurtosis()
const {
268 ((alpha_ - beta_) * (alpha_ - beta_) * (alpha_ + beta_ + 1) -
269 alpha_ * beta_ * (2 + alpha_ + beta_)) /
270 alpha_ / beta_ / (alpha_ + beta_ + 2) / (alpha_ + beta_ + 3);
278 class BetaDistributionTest
280 public BetaDistributionModel {
282 BetaDistributionTest() : BetaDistributionModel(GetParam()) {}
286 bool SingleZTestOnMeanAndVariance(
double p,
size_t samples);
289 bool SingleChiSquaredTest(
double p,
size_t samples,
size_t buckets);
295 bool BetaDistributionTest::SingleZTestOnMeanAndVariance(
double p,
297 D dis(alpha_, beta_);
299 std::vector<double>
data;
300 data.reserve(samples);
301 for (
size_t i = 0;
i < samples;
i++) {
302 const double variate = dis(
rng_);
307 data.push_back(variate);
315 const double mean_stddev = std::sqrt(Variance() /
static_cast<double>(
m.n));
319 const double variance_stddev = std::sqrt(
320 (Kurtosis() - 1) * Variance() * Variance() /
static_cast<double>(
m.n));
322 const double z_variance = (
m.variance - Variance()) / variance_stddev;
334 "mean: sample %f, expect %f, which is %f stddevs away, "
335 "variance: sample %f, expect %f, which is %f stddevs away.",
336 alpha_, beta_,
m.mean, Mean(),
337 std::abs(
m.mean - Mean()) / mean_stddev,
m.variance, Variance(),
338 std::abs(
m.variance - Variance()) / variance_stddev));
344 bool BetaDistributionTest::SingleChiSquaredTest(
double p,
size_t samples,
346 constexpr
double kErr = 1
e-7;
347 std::vector<double> cutoffs, expected;
348 const double bucket_width = 1.0 /
static_cast<double>(buckets);
350 int unmerged_buckets = 0;
351 for (;
i < buckets; ++
i) {
352 const double p = bucket_width *
static_cast<double>(
i);
353 const double boundary =
360 if ((cutoffs.empty() && boundary < kErr) ||
361 (!cutoffs.empty() && boundary <= cutoffs.back())) {
365 if (boundary >= 1.0 - 1e-10) {
368 cutoffs.push_back(boundary);
369 expected.push_back(
static_cast<double>(1 + unmerged_buckets) *
370 bucket_width *
static_cast<double>(samples));
371 unmerged_buckets = 0;
373 cutoffs.push_back(std::numeric_limits<double>::infinity());
375 expected.push_back(
static_cast<double>(buckets -
i + 1) * bucket_width *
376 static_cast<double>(samples));
379 EXPECT_GE(cutoffs.size(), 3) << alpha_ <<
", " << beta_;
381 D dis(alpha_, beta_);
383 std::vector<int32_t> counts(cutoffs.size(), 0);
384 for (
int i = 0;
i < samples;
i++) {
385 const double x = dis(
rng_);
386 auto it = std::upper_bound(cutoffs.begin(), cutoffs.end(),
x);
387 counts[std::distance(cutoffs.begin(),
it)]++;
392 const int dof = cutoffs.size() - 1;
395 counts.begin(), counts.end(), expected.begin(), expected.end());
399 for (
int i = 0;
i < cutoffs.size();
i++) {
402 i, cutoffs[
i], counts[
i],
403 static_cast<int>(expected[
i])));
408 "Beta(%f, %f) %s %f, p = %f", alpha_, beta_,
415 TEST_P(BetaDistributionTest, TestSampleStatistics) {
416 static constexpr
int kRuns = 20;
417 static constexpr
double kPFail = 0.02;
420 static constexpr
int kSampleCount = 10000;
421 static constexpr
int kBucketCount = 100;
423 for (
int i = 0;
i < kRuns; ++
i) {
429 0.005, kSampleCount, kBucketCount)) {
438 const ::testing::TestParamInfo<::testing::tuple<double, double>>& info) {
440 "__beta_", ::testing::get<1>(info.param));
445 TestSampleStatisticsCombinations, BetaDistributionTest,
451 TestSampleStatistics_SelectedPairs, BetaDistributionTest,
452 ::
testing::Values(std::make_pair(0.5, 1000), std::make_pair(1000, 0.5),
453 std::make_pair(900, 1000), std::make_pair(10000, 20000),
454 std::make_pair(4e5, 2e7), std::make_pair(1e7, 1e5)),
458 TEST(BetaDistributionTest, StabilityTest) {
466 0xffff00000000e6c8ull, 0xffff0000000006c8ull, 0x800003766295CFA9ull,
467 0x11C819684E734A41ull, 0x832603766295CFA9ull, 0x7fbe76c8b4395800ull,
468 0xB3472DCA7B14A94Aull, 0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull,
469 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull, 0x00035C904C70A239ull,
470 0x00009E0BCBAADE14ull, 0x0000000000622CA7ull, 0x4864f22c059bf29eull,
471 0x247856d8b862665cull, 0xe46e86e9a1337e10ull, 0xd8c8541f3519b133ull,
472 0xffe75b52c567b9e4ull, 0xfffff732e5709c5bull, 0xff1f7f0b983532acull,
473 0x1ec2e8986d2362caull, 0xC332DDEFBE6C5AA5ull, 0x6558218568AB9702ull,
474 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull, 0xECDD4775619F1510ull,
475 0x814c8e35fe9a961aull, 0x0c3cd59c9b638a02ull, 0xcb3bb6478a07715cull,
476 0x1224e62c978bbc7full, 0x671ef2cb04e81f6eull, 0x3c1cbd811eaf1808ull,
477 0x1bbc23cfa8fac721ull, 0xa4c2cda65e596a51ull, 0xb77216fad37adf91ull,
478 0x836d794457c08849ull, 0xe083df03475f49d7ull, 0xbc9feb512e6b0d6cull,
479 0xb12d74fdd718c8c5ull, 0x12ff09653bfbe4caull, 0x8dd03a105bc4ee7eull,
480 0x5738341045ba0d85ull, 0xf3fd722dc65ad09eull, 0xfa14fd21ea2a5705ull,
481 0xffe6ea4d6edb0c73ull, 0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull,
482 0xEAAD8E716B93D5A0ull, 0xD08ED1D0AFC725E0ull, 0x8E3C5B2F8E7594B7ull,
483 0x8FF6E2FBF2122B64ull, 0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull,
484 0xD1CFF191B3A8C1ADull, 0x2F2F2218BE0E1777ull, 0xEA752DFE8B021FA1ull,
489 auto float_to_u64 = [](
float d) {
491 auto f = std::frexp(
d, &exp);
492 return (
static_cast<uint64_t>(1e5 *
f) * 10000) + std::abs(exp);
494 auto double_to_u64 = [](
double d) {
496 auto f = std::frexp(
d, &exp);
497 return (
static_cast<uint64_t>(1e10 *
f) * 10000) + std::abs(exp);
500 std::vector<uint64_t>
output(20);
505 [&] {
return float_to_u64(dist(urbg)); });
509 998340000, 619030004, 500000001, 999990000, 996280000,
510 500000001, 844740004, 847210001, 999970000, 872320000,
511 585480007, 933280000, 869080042, 647670031, 528240004,
512 969980004, 626050008, 915930002, 833440033, 878040015));
520 [&] {
return double_to_u64(dist(urbg)); });
525 99834713000000, 61903356870004, 50000000000001, 99999721170000,
526 99628374770000, 99999999990000, 84474397860004, 84721276240001,
527 99997407490000, 87232528120000, 58548364780007, 93328932910000,
528 86908237770042, 64767917930031, 52824581970004, 96998544140004,
529 62605946270008, 91593604380002, 83345031740033, 87804397230015));
537 [&] {
return double_to_u64(dist(urbg)); });
542 62069004780001, 64433204450001, 53607416560000, 89644295430008,
543 61434586310019, 55172615890002, 62187161490000, 56433684810003,
544 80454622050005, 86418558710003, 92920514700001, 64645184680001,
545 58549183380000, 84881283650005, 71078728590002, 69949694970000,
546 73157461710001, 68592191300001, 70747623900000, 78584696930005));
554 [&] {
return double_to_u64(dist(urbg)); });
559 75000029250001, 76751482860001, 53264575220000, 69193133650005,
560 78028324470013, 91573587560002, 59167523770000, 60658618560002,
561 80075870540000, 94141320460004, 63196592770003, 78883906300002,
562 96797992590001, 76907587800001, 56645167560000, 65408302280003,
563 53401156320001, 64731238570000, 83065573750001, 79788333820001));
571 TEST(BetaDistributionTest, AlgorithmBounds) {
572 #if (defined(__i386__) || defined(_M_IX86)) && FLT_EVAL_METHOD != 0
577 <<
"Skipping the test because we detected x87 floating-point semantics";
582 {0x7fbe76c8b4395800ull, 0x8000000000000000ull});
585 double a = dist(urbg);
599 {0xffff00000006e6c8ull, 0xffff00000007c7c8ull, 0x800003766295CFA9ull,
600 0x11C819684E734A41ull});