15 #include "absl/random/poisson_distribution.h"
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
28 #include "absl/base/internal/raw_logging.h"
29 #include "absl/base/macros.h"
30 #include "absl/container/flat_hash_map.h"
31 #include "absl/random/internal/chi_square.h"
32 #include "absl/random/internal/distribution_test_util.h"
33 #include "absl/random/internal/pcg_engine.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"
71 template <
typename IntType>
78 TYPED_TEST(PoissonDistributionInterfaceTest, SerializeTest) {
84 const double kParams[] = {
87 std::nextafter(1.0, 0.0),
88 std::nextafter(1.0, 2.0),
96 100, 1e4, 1e8, 1.5e9, 1e20,
99 std::numeric_limits<double>::epsilon(),
103 std::numeric_limits<double>::denorm_min(),
110 constexpr
int kCount = 1000;
112 for (
const double m : kParams) {
114 const param_type param(mean);
127 auto sample_min =
before.max();
128 auto sample_max =
before.min();
129 for (
int i = 0;
i < kCount;
i++) {
133 if (sample > sample_max) sample_max = sample;
134 if (sample < sample_min) sample_min = sample;
138 +sample_min,
", ", +sample_max));
141 std::stringstream ss;
154 << (ss.good() ?
"good " :
"")
155 << (ss.bad() ?
"bad " :
"")
156 << (ss.eof() ?
"eof " :
"")
157 << (ss.fail() ?
"fail " :
"");
165 explicit PoissonModel(
double mean) : mean_(mean) {}
167 double mean()
const {
return mean_; }
168 double variance()
const {
return mean_; }
169 double stddev()
const {
return std::sqrt(variance()); }
170 double skew()
const {
return 1.0 / mean_; }
171 double kurtosis()
const {
return 3.0 + 1.0 / mean_; }
182 CDF InverseCDF(
double p) {
184 auto it = std::upper_bound(
186 [](
const CDF&
a,
const CDF&
b) {
return a.cdf <
b.cdf; });
192 for (
const auto c : cdf_) {
201 std::vector<CDF> cdf_;
210 void PoissonModel::InitCDF() {
217 const size_t max_i = 50 * stddev() + mean();
218 const double e_neg_mean = std::exp(-mean());
222 double last_result = e_neg_mean;
223 double cumulative = e_neg_mean;
224 if (e_neg_mean > 1e-10) {
225 cdf_.push_back({0, e_neg_mean, cumulative});
227 for (
size_t i = 1;
i < max_i;
i++) {
229 double result = e_neg_mean *
d;
231 if (
result < 1e-10 && result < last_result && cumulative > 0.999999) {
235 cdf_.push_back({
i,
result, cumulative});
252 public PoissonModel {
254 PoissonDistributionZTest() : PoissonModel(GetParam().mean) {}
258 template <
typename D>
259 bool SingleZTest(
const double p,
const size_t samples);
267 template <
typename D>
268 bool PoissonDistributionZTest::SingleZTest(
const double p,
269 const size_t samples) {
273 std::vector<double>
data;
274 data.reserve(samples);
275 for (
int j = 0;
j < samples;
j++) {
276 const auto x = dis(
rng_);
292 " stddev=%f vs. %f\n"
293 " skewness=%f vs. %f\n"
294 " kurtosis=%f vs. %f\n"
296 p, max_err,
m.mean, mean(), std::sqrt(
m.variance),
297 stddev(),
m.skewness, skew(),
m.kurtosis,
303 TEST_P(PoissonDistributionZTest, AbslPoissonDistribution) {
304 const auto& param = GetParam();
305 const int expected_failures =
306 std::max(1,
static_cast<int>(std::ceil(param.trials * param.p_fail)));
308 param.p_fail, param.trials);
311 for (
int i = 0;
i < param.trials;
i++) {
313 SingleZTest<absl::poisson_distribution<int32_t>>(
p, param.samples) ? 0
319 std::vector<ZParam> GetZParams() {
325 return std::vector<ZParam>({
327 ZParam{0.5, 0.01, 100, 1000},
328 ZParam{1.0, 0.01, 100, 1000},
329 ZParam{10.0, 0.01, 100, 5000},
331 ZParam{20.0, 0.01, 100, 10000},
332 ZParam{50.0, 0.01, 100, 10000},
334 ZParam{51.0, 0.01, 100, 10000},
335 ZParam{200.0, 0.05, 10, 100000},
336 ZParam{100000.0, 0.05, 10, 1000000},
340 std::string ZParamName(const ::testing::TestParamInfo<ZParam>& info) {
341 const auto&
p = info.param;
352 public PoissonModel {
354 PoissonDistributionChiSquaredTest() : PoissonModel(GetParam()) {}
358 template <
typename D>
359 double ChiSquaredTestImpl();
362 void InitChiSquaredTest(
const double buckets);
364 std::vector<size_t> cutoffs_;
373 void PoissonDistributionChiSquaredTest::InitChiSquaredTest(
374 const double buckets) {
375 if (!cutoffs_.empty() && !
expected_.empty()) {
385 const double inc = 1.0 / buckets;
386 for (
double p =
inc;
p <= 1.0;
p +=
inc) {
388 if (!cutoffs_.empty() && cutoffs_.back() ==
result.index) {
391 double d =
result.cdf - last_cdf;
392 cutoffs_.push_back(
result.index);
400 template <
typename D>
401 double PoissonDistributionChiSquaredTest::ChiSquaredTestImpl() {
402 const int kSamples = 2000;
403 const int kBuckets = 50;
409 InitChiSquaredTest(kBuckets);
413 std::vector<int32_t> counts(cutoffs_.size(), 0);
414 for (
int j = 0;
j < kSamples;
j++) {
415 const size_t x = dis(
rng_);
417 counts[std::distance(cutoffs_.begin(),
it)]++;
422 for (
int i = 0;
i <
e.size();
i++) {
428 const int dof =
static_cast<int>(counts.size()) - 1;
439 if (chi_square > threshold) {
443 " samples=", kSamples));
444 for (
size_t i = 0;
i < counts.size();
i++) {
452 p,
")\n",
" vs.\n",
kChiSquared,
" @ 0.98 = ", threshold));
457 TEST_P(PoissonDistributionChiSquaredTest, AbslPoissonDistribution) {
458 const int kTrials = 20;
463 if (mean() > 200.0) {
468 for (
int i = 0;
i < kTrials;
i++) {
469 double p_value = ChiSquaredTestImpl<absl::poisson_distribution<int32_t>>();
470 if (p_value < 0.005) {
484 TEST(PoissonDistributionTest, StabilityTest) {
490 0x035b0dc7e0a18acfull, 0x06cebe0d2653682eull, 0x0061e9b23861596bull,
491 0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
492 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
493 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
494 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull,
495 0x4864f22c059bf29eull, 0x247856d8b862665cull, 0xe46e86e9a1337e10ull,
496 0xd8c8541f3519b133ull, 0xe75b5162c567b9e4ull, 0xf732e5ded7009c5bull,
497 0xb170b98353121eacull, 0x1ec2e8986d2362caull, 0x814c8e35fe9a961aull,
498 0x0c3cd59c9b638a02ull, 0xcb3bb6478a07715cull, 0x1224e62c978bbc7full,
499 0x671ef2cb04e81f6eull, 0x3c1cbd811eaf1808ull, 0x1bbc23cfa8fac721ull,
500 0xa4c2cda65e596a51ull, 0xb77216fad37adf91ull, 0x836d794457c08849ull,
501 0xe083df03475f49d7ull, 0xbc9feb512e6b0d6cull, 0xb12d74fdd718c8c5ull,
502 0x12ff09653bfbe4caull, 0x8dd03a105bc4ee7eull, 0x5738341045ba0d85ull,
503 0xf3fd722dc65ad09eull, 0xfa14fd21ea2a5705ull, 0xffe6ea4d6edb0c73ull,
504 0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull, 0xEAAD8E716B93D5A0ull,
505 0xD08ED1D0AFC725E0ull, 0x8E3C5B2F8E7594B7ull, 0x8FF6E2FBF2122B64ull,
506 0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull, 0xD1CFF191B3A8C1ADull,
507 0x2F2F2218BE0E1777ull, 0xEA752DFE8B021FA1ull, 0xE5A0CC0FB56F74E8ull,
508 0x18ACF3D6CE89E299ull, 0xB4A84FE0FD13E0B7ull, 0x7CC43B81D2ADA8D9ull,
509 0x165FA26680957705ull, 0x93CC7314211A1477ull, 0xE6AD206577B5FA86ull,
510 0xC75442F5FB9D35CFull, 0xEBCDAF0C7B3E89A0ull, 0xD6411BD3AE1E7E49ull,
511 0x00250E2D2071B35Eull, 0x226800BB57B8E0AFull, 0x2464369BF009B91Eull,
512 0x5563911D59DFA6AAull, 0x78C14389D95A537Full, 0x207D5BA202E5B9C5ull,
513 0x832603766295CFA9ull, 0x11C819684E734A41ull, 0xB3472DCA7B14A94Aull,
516 std::vector<int>
output(10);
522 [&] {
return dist(urbg); });
532 [&] {
return dist(urbg); });
535 ElementsAre(9, 35, 18, 10, 35, 18, 10, 35, 18, 10));
542 [&] {
return dist(urbg); });
545 ElementsAre(161, 122, 129, 124, 112, 112, 117, 120, 130, 114));
548 TEST(PoissonDistributionTest, AlgorithmExpectedValue_1) {
556 TEST(PoissonDistributionTest, AlgorithmExpectedValue_2) {
564 TEST(PoissonDistributionTest, AlgorithmExpectedValue_3) {
567 {0x7fffffffffffffffull, 0x8000000000000000ull});