15 #include "absl/random/exponential_distribution.h"
27 #include <type_traits>
30 #include "gmock/gmock.h"
31 #include "gtest/gtest.h"
32 #include "absl/base/internal/raw_logging.h"
33 #include "absl/base/macros.h"
34 #include "absl/numeric/internal/representation.h"
35 #include "absl/random/internal/chi_square.h"
36 #include "absl/random/internal/distribution_test_util.h"
37 #include "absl/random/internal/pcg_engine.h"
38 #include "absl/random/internal/sequence_urbg.h"
39 #include "absl/random/random.h"
40 #include "absl/strings/str_cat.h"
41 #include "absl/strings/str_format.h"
42 #include "absl/strings/str_replace.h"
43 #include "absl/strings/strip.h"
49 template <
typename RealType>
63 TYPED_TEST(ExponentialDistributionTypedTest, SerializeTest) {
67 const TypeParam kParams[] = {
70 std::nextafter(TypeParam(1), TypeParam(0)),
71 std::nextafter(TypeParam(1), TypeParam(2)),
73 TypeParam(1e-8), TypeParam(1e-4), TypeParam(1), TypeParam(2),
74 TypeParam(1e4), TypeParam(1e8), TypeParam(1e20), TypeParam(2.5),
77 std::numeric_limits<TypeParam>::epsilon(),
82 std::numeric_limits<TypeParam>::denorm_min(),
88 constexpr
int kCount = 1000;
91 for (
const TypeParam lambda : kParams) {
96 const param_type param(lambda);
108 auto sample_min =
before.max();
109 auto sample_max =
before.min();
110 for (
int i = 0;
i < kCount;
i++) {
114 if (sample > sample_max) sample_max = sample;
115 if (sample < sample_min) sample_min = sample;
120 sample_min, sample_max, lambda));
123 std::stringstream ss;
141 << (ss.good() ?
"good " :
"")
142 << (ss.bad() ?
"bad " :
"")
143 << (ss.eof() ?
"eof " :
"")
144 << (ss.fail() ?
"fail " :
"");
150 class ExponentialModel {
152 explicit ExponentialModel(
double lambda)
153 : lambda_(lambda), beta_(1.0 / lambda) {}
155 double lambda()
const {
return lambda_; }
157 double mean()
const {
return beta_; }
158 double variance()
const {
return beta_ * beta_; }
159 double stddev()
const {
return std::sqrt(variance()); }
160 double skew()
const {
return 2; }
161 double kurtosis()
const {
return 6.0; }
163 double CDF(
double x) {
return 1.0 - std::exp(-lambda_ *
x); }
166 double InverseCDF(
double p) {
173 const double lambda_;
184 public ExponentialModel {
186 ExponentialDistributionTests() : ExponentialModel(GetParam().lambda) {}
190 template <
typename D>
191 bool SingleZTest(
const double p,
const size_t samples);
195 template <
typename D>
196 double SingleChiSquaredTest();
204 template <
typename D>
205 bool ExponentialDistributionTests::SingleZTest(
const double p,
206 const size_t samples) {
209 std::vector<double>
data;
210 data.reserve(samples);
211 for (
size_t i = 0;
i < samples;
i++) {
212 const double x = dis(
rng_);
226 " stddev=%f vs. %f\n"
227 " skewness=%f vs. %f\n"
228 " kurtosis=%f vs. %f\n"
230 p, max_err, lambda(),
m.mean, mean(),
231 std::sqrt(
m.variance), stddev(),
m.skewness,
232 skew(),
m.kurtosis, kurtosis(),
z));
237 template <
typename D>
238 double ExponentialDistributionTests::SingleChiSquaredTest() {
239 const size_t kSamples = 10000;
240 const int kBuckets = 50;
244 std::vector<double> cutoffs;
245 const double kInc = 1.0 /
static_cast<double>(kBuckets);
246 for (
double p = kInc;
p < 1.0;
p += kInc) {
247 cutoffs.push_back(InverseCDF(
p));
249 if (cutoffs.back() != std::numeric_limits<double>::infinity()) {
250 cutoffs.push_back(std::numeric_limits<double>::infinity());
255 std::vector<int32_t> counts(cutoffs.size(), 0);
256 for (
int j = 0;
j < kSamples;
j++) {
257 const double x = dis(
rng_);
258 auto it = std::upper_bound(cutoffs.begin(), cutoffs.end(),
x);
259 counts[std::distance(cutoffs.begin(),
it)]++;
264 const int dof =
static_cast<int>(counts.size()) - 1;
269 const double expected =
270 static_cast<double>(kSamples) /
static_cast<double>(counts.size());
276 if (chi_square > threshold) {
277 for (
int i = 0;
i < cutoffs.size();
i++) {
284 " expected ", expected,
"\n",
291 TEST_P(ExponentialDistributionTests, ZTest) {
292 const size_t kSamples = 10000;
293 const auto& param = GetParam();
294 const int expected_failures =
295 std::max(1,
static_cast<int>(std::ceil(param.trials * param.p_fail)));
297 param.p_fail, param.trials);
300 for (
int i = 0;
i < param.trials;
i++) {
301 failures += SingleZTest<absl::exponential_distribution<double>>(
p, kSamples)
308 TEST_P(ExponentialDistributionTests, ChiSquaredTest) {
309 const int kTrials = 20;
312 for (
int i = 0;
i < kTrials;
i++) {
314 SingleChiSquaredTest<absl::exponential_distribution<double>>();
315 if (p_value < 0.005) {
325 std::vector<Param> GenParams() {
327 Param{1.0, 0.02, 100},
328 Param{2.5, 0.02, 100},
329 Param{10, 0.02, 100},
331 Param{1e4, 0.02, 100},
332 Param{1e9, 0.02, 100},
334 Param{0.1, 0.02, 100},
340 std::string ParamName(const ::testing::TestParamInfo<Param>& info) {
341 const auto&
p = info.param;
350 TEST(ExponentialDistributionTest, StabilityTest) {
354 {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
355 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
356 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
357 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
359 std::vector<int>
output(14);
364 [&] {
return static_cast<int>(10000.0 * dist(urbg)); });
369 804, 126, 12337, 17984, 27002, 0, 71913));
376 [&] {
return static_cast<int>(10000.0f * dist(urbg)); });
381 804, 126, 12337, 17984, 27002, 0, 71913));
385 TEST(ExponentialDistributionTest, AlgorithmBounds) {
389 #if (defined(__i386__) || defined(_M_IX86)) && FLT_EVAL_METHOD != 0
394 <<
"Skipping the test because we detected x87 floating-point semantics";
402 double a = dist(urbg);
409 double a = dist(urbg);
417 double a = dist(urbg);
423 double a = dist(urbg);