15 #include "absl/random/gaussian_distribution.h"
24 #include <type_traits>
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include "absl/base/internal/raw_logging.h"
30 #include "absl/base/macros.h"
31 #include "absl/numeric/internal/representation.h"
32 #include "absl/random/internal/chi_square.h"
33 #include "absl/random/internal/distribution_test_util.h"
34 #include "absl/random/internal/sequence_urbg.h"
35 #include "absl/random/random.h"
36 #include "absl/strings/str_cat.h"
37 #include "absl/strings/str_format.h"
38 #include "absl/strings/str_replace.h"
39 #include "absl/strings/strip.h"
45 template <
typename RealType>
59 TYPED_TEST(GaussianDistributionInterfaceTest, SerializeTest) {
63 const TypeParam kParams[] = {
66 std::nextafter(TypeParam(1), TypeParam(0)),
67 std::nextafter(TypeParam(1), TypeParam(2)),
69 TypeParam(1e-8), TypeParam(1e-4), TypeParam(2), TypeParam(1e4),
70 TypeParam(1e8), TypeParam(1e20), TypeParam(2.5),
72 std::numeric_limits<TypeParam>::infinity(),
74 std::numeric_limits<TypeParam>::epsilon(),
79 std::numeric_limits<TypeParam>::denorm_min(),
85 constexpr
int kCount = 1000;
90 for (
const auto mod : {0, 1, 2, 3}) {
91 for (
const auto x : kParams) {
93 for (
const auto y : kParams) {
94 const TypeParam mean = (mod & 0x1) ? -
x :
x;
95 const TypeParam stddev = (mod & 0x2) ? -
y :
y;
96 const param_type param(mean, stddev);
109 auto sample_min =
before.max();
110 auto sample_max =
before.min();
111 for (
int i = 0;
i < kCount;
i++) {
113 if (sample > sample_max) sample_max = sample;
114 if (sample < sample_min) sample_min = sample;
121 sample_min, sample_max));
124 std::stringstream ss;
145 << (ss.good() ?
"good " :
"")
146 << (ss.bad() ?
"bad " :
"")
147 << (ss.eof() ?
"eof " :
"")
148 << (ss.fail() ?
"fail " :
"");
156 class GaussianModel {
158 GaussianModel(
double mean,
double stddev) : mean_(mean), stddev_(stddev) {}
160 double mean()
const {
return mean_; }
161 double variance()
const {
return stddev() * stddev(); }
162 double stddev()
const {
return stddev_; }
163 double skew()
const {
return 0; }
164 double kurtosis()
const {
return 3.0; }
167 double InverseCDF(
double p) {
175 const double stddev_;
188 public GaussianModel {
190 GaussianDistributionTests()
191 : GaussianModel(GetParam().mean, GetParam().stddev) {}
195 template <
typename D>
196 bool SingleZTest(
const double p,
const size_t samples);
200 template <
typename D>
201 double SingleChiSquaredTest();
209 template <
typename D>
210 bool GaussianDistributionTests::SingleZTest(
const double p,
211 const size_t samples) {
212 D dis(mean(), stddev());
214 std::vector<double>
data;
215 data.reserve(samples);
216 for (
size_t i = 0;
i < samples;
i++) {
217 const double x = dis(
rng_);
239 static_cast<double>(
m.n) / 6.0 *
240 (std::pow(
m.skewness, 2.0) + std::pow(
m.kurtosis - 3.0, 2.0) / 4.0);
242 if (!pass || jb > 9.21) {
246 " stddev=%f vs. %f\n"
247 " skewness=%f vs. %f\n"
248 " kurtosis=%f vs. %f\n"
251 p, max_err,
m.mean, mean(), std::sqrt(
m.variance),
252 stddev(),
m.skewness, skew(),
m.kurtosis,
258 template <
typename D>
259 double GaussianDistributionTests::SingleChiSquaredTest() {
260 const size_t kSamples = 10000;
261 const int kBuckets = 50;
266 std::vector<double> cutoffs;
267 const double kInc = 1.0 /
static_cast<double>(kBuckets);
268 for (
double p = kInc;
p < 1.0;
p += kInc) {
269 cutoffs.push_back(InverseCDF(
p));
271 if (cutoffs.back() != std::numeric_limits<double>::infinity()) {
272 cutoffs.push_back(std::numeric_limits<double>::infinity());
275 D dis(mean(), stddev());
277 std::vector<int32_t> counts(cutoffs.size(), 0);
278 for (
int j = 0;
j < kSamples;
j++) {
279 const double x = dis(
rng_);
280 auto it = std::upper_bound(cutoffs.begin(), cutoffs.end(),
x);
281 counts[std::distance(cutoffs.begin(),
it)]++;
286 const int dof =
static_cast<int>(counts.size()) - 1;
291 const double expected =
292 static_cast<double>(kSamples) /
static_cast<double>(counts.size());
299 if (chi_square > threshold) {
300 for (
int i = 0;
i < cutoffs.size();
i++) {
307 " expected ", expected,
"\n",
314 TEST_P(GaussianDistributionTests, ZTest) {
317 const size_t kSamples = 10000;
318 const auto& param = GetParam();
319 const int expected_failures =
320 std::max(1,
static_cast<int>(std::ceil(param.trials * param.p_fail)));
322 param.p_fail, param.trials);
325 for (
int i = 0;
i < param.trials;
i++) {
327 SingleZTest<absl::gaussian_distribution<double>>(
p, kSamples) ? 0 : 1;
332 TEST_P(GaussianDistributionTests, ChiSquaredTest) {
333 const int kTrials = 20;
336 for (
int i = 0;
i < kTrials;
i++) {
338 SingleChiSquaredTest<absl::gaussian_distribution<double>>();
339 if (p_value < 0.0025) {
349 std::vector<Param> GenParams() {
352 Param{0.0, 1.0, 0.01, 100},
353 Param{0.0, 1e2, 0.01, 100},
354 Param{0.0, 1e4, 0.01, 100},
355 Param{0.0, 1e8, 0.01, 100},
356 Param{0.0, 1e16, 0.01, 100},
357 Param{0.0, 1
e-3, 0.01, 100},
358 Param{0.0, 1
e-5, 0.01, 100},
359 Param{0.0, 1
e-9, 0.01, 100},
360 Param{0.0, 1
e-17, 0.01, 100},
363 Param{1.0, 1.0, 0.01, 100},
364 Param{1.0, 1e2, 0.01, 100},
365 Param{1.0, 1
e-2, 0.01, 100},
368 Param{1e2, 1.0, 0.01, 100},
369 Param{-1e2, 1.0, 0.01, 100},
370 Param{1e2, 1e6, 0.01, 100},
371 Param{-1e2, 1e6, 0.01, 100},
374 Param{1e4, 1e4, 0.01, 100},
375 Param{1e8, 1e4, 0.01, 100},
376 Param{1e12, 1e4, 0.01, 100},
380 std::string ParamName(const ::testing::TestParamInfo<Param>& info) {
381 const auto&
p = info.param;
391 TEST(GaussianDistributionTest, StabilityTest) {
396 {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
397 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
398 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
399 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
401 std::vector<int>
output(11);
406 [&] {
return static_cast<int>(10000000.0 * dist(urbg)); });
411 -20373238, 3456682, 333530, -6804981,
412 -15279580, -16459654, 1494));
419 [&] {
return static_cast<int>(1000000.0f * dist(urbg)); });
425 33353, -680498, -1527958, -1645965, 149));
433 TEST(GaussianDistributionTest, AlgorithmBounds) {
447 0x1000000000000100ull, 0x2000000000000100ull, 0x3000000000000100ull,
448 0x4000000000000100ull, 0x5000000000000100ull, 0x6000000000000100ull,
450 0x9000000000000100ull, 0xa000000000000100ull, 0xb000000000000100ull,
451 0xc000000000000100ull, 0xd000000000000100ull, 0xe000000000000100ull};
455 0x7000000000000100ull, 0x7800000000000100ull,
456 0x7c00000000000100ull, 0x7e00000000000100ull,
458 0xf000000000000100ull, 0xf800000000000100ull,
459 0xfc00000000000100ull, 0xfe00000000000100ull};
462 return (
v & 0xffffffffffffff80ull) | box;
468 for (
uint64_t box = 0; box < 0x7f; box++) {
473 {make_box(
v, box), 0x0003eb76f6f7f755ull, 0x5FCEA50FDB2F953Bull});
476 EXPECT_EQ(1, urbg.invocations()) << box <<
" " << std::hex <<
v;
477 if (
v & 0x8000000000000000ull) {
483 if (box > 10 && box < 100) {
488 {make_box(
v, box), 0x0003eb76f6f7f755ull, 0x5FCEA50FDB2F953Bull});
491 EXPECT_EQ(1, urbg.invocations()) << box <<
" " << std::hex <<
v;
492 if (
v & 0x8000000000000000ull) {
504 auto make_fallback = [](
uint64_t v) {
return (
v & 0xffffffffffffff80ull); };
510 {make_fallback(0x7800000000000000ull), 0x13CCA830EB61BD96ull,
511 0x00000076f6f7f755ull});
512 tail[0] = dist(urbg);
519 {make_fallback(0xf800000000000000ull), 0x13CCA830EB61BD96ull,
520 0x00000076f6f7f755ull});
521 tail[1] = dist(urbg);
534 {make_box(0x7f00000000000000ull, 120), 0xe000000000000001ull,
535 0x13CCA830EB61BD96ull});
536 tail[0] = dist(urbg);
543 {make_box(0xff00000000000000ull, 120), 0xe000000000000001ull,
544 0x13CCA830EB61BD96ull});
545 tail[1] = dist(urbg);
556 {make_box(0xff00000000000000ull, 120), 0x1000000000000001,
557 make_box(0x1000000000000100ull, 50), 0x13CCA830EB61BD96ull});