abseil-cpp/absl/random/discrete_distribution_test.cc
Go to the documentation of this file.
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/discrete_distribution.h"
16 
17 #include <cmath>
18 #include <cstddef>
19 #include <cstdint>
20 #include <iterator>
21 #include <numeric>
22 #include <random>
23 #include <sstream>
24 #include <string>
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/strip.h"
37 
38 namespace {
39 
40 template <typename IntType>
41 class DiscreteDistributionTypeTest : public ::testing::Test {};
42 
45 TYPED_TEST_SUITE(DiscreteDistributionTypeTest, IntTypes);
46 
47 TYPED_TEST(DiscreteDistributionTypeTest, ParamSerializeTest) {
48  using param_type =
50 
52  EXPECT_THAT(empty.probabilities(), testing::ElementsAre(1.0));
53 
55 
56  // Validate that the probabilities sum to 1.0. We picked values which
57  // can be represented exactly to avoid floating-point roundoff error.
58  double s = 0;
59  for (const auto& x : before.probabilities()) {
60  s += x;
61  }
62  EXPECT_EQ(s, 1.0);
63  EXPECT_THAT(before.probabilities(), testing::ElementsAre(0.25, 0.5, 0.25));
64 
65  // Validate the same data via an initializer list.
66  {
67  std::vector<double> data({1.0, 2.0, 1.0});
68 
70  param_type(std::begin(data), std::end(data))};
71 
72  EXPECT_EQ(via_param, before);
73  }
74 
75  std::stringstream ss;
76  ss << before;
78 
80 
81  ss >> after;
82 
84 }
85 
86 TYPED_TEST(DiscreteDistributionTypeTest, Constructor) {
87  auto fn = [](double x) { return x; };
88  {
89  absl::discrete_distribution<int> unary(0, 1.0, 9.0, fn);
90  EXPECT_THAT(unary.probabilities(), testing::ElementsAre(1.0));
91  }
92 
93  {
94  absl::discrete_distribution<int> unary(2, 1.0, 9.0, fn);
95  // => fn(1.0 + 0 * 4 + 2) => 3
96  // => fn(1.0 + 1 * 4 + 2) => 7
97  EXPECT_THAT(unary.probabilities(), testing::ElementsAre(0.3, 0.7));
98  }
99 }
100 
101 TEST(DiscreteDistributionTest, InitDiscreteDistribution) {
102  using testing::_;
103  using testing::Pair;
104 
105  {
106  std::vector<double> p({1.0, 2.0, 3.0});
107  std::vector<std::pair<double, size_t>> q =
109 
110  EXPECT_THAT(p, testing::ElementsAre(1 / 6.0, 2 / 6.0, 3 / 6.0));
111 
112  // Each bucket is p=1/3, so bucket 0 will send half it's traffic
113  // to bucket 2, while the rest will retain all of their traffic.
114  EXPECT_THAT(q, testing::ElementsAre(Pair(0.5, 2), //
115  Pair(1.0, _), //
116  Pair(1.0, _)));
117  }
118 
119  {
120  std::vector<double> p({1.0, 2.0, 3.0, 5.0, 2.0});
121 
122  std::vector<std::pair<double, size_t>> q =
124 
125  EXPECT_THAT(p, testing::ElementsAre(1 / 13.0, 2 / 13.0, 3 / 13.0, 5 / 13.0,
126  2 / 13.0));
127 
128  // A more complex bucketing solution: Each bucket has p=0.2
129  // So buckets 0, 1, 4 will send their alternate traffic elsewhere, which
130  // happens to be bucket 3.
131  // However, summing up that alternate traffic gives bucket 3 too much
132  // traffic, so it will send some traffic to bucket 2.
133  constexpr double b0 = 1.0 / 13.0 / 0.2;
134  constexpr double b1 = 2.0 / 13.0 / 0.2;
135  constexpr double b3 = (5.0 / 13.0 / 0.2) - ((1 - b0) + (1 - b1) + (1 - b1));
136 
138  Pair(b1, 3), //
139  Pair(1.0, _), //
140  Pair(b3, 2), //
141  Pair(b1, 3)));
142  }
143 }
144 
145 TEST(DiscreteDistributionTest, ChiSquaredTest50) {
147 
148  constexpr size_t kTrials = 10000;
149  constexpr int kBuckets = 50; // inclusive, so actally +1
150 
151  // 1-in-100000 threshold, but remember, there are about 8 tests
152  // in this file. And the test could fail for other reasons.
153  // Empirically validated with --runs_per_test=10000.
154  const int kThreshold =
155  absl::random_internal::ChiSquareValue(kBuckets, 0.99999);
156 
157  std::vector<double> weights(kBuckets, 0);
158  std::iota(std::begin(weights), std::end(weights), 1);
160 
161  // We use a fixed bit generator for distribution accuracy tests. This allows
162  // these tests to be deterministic, while still testing the qualify of the
163  // implementation.
164  absl::random_internal::pcg64_2018_engine rng(0x2B7E151628AED2A6);
165 
166  std::vector<int32_t> counts(kBuckets, 0);
167  for (size_t i = 0; i < kTrials; i++) {
168  auto x = dist(rng);
169  counts[x]++;
170  }
171 
172  // Scale weights.
173  double sum = 0;
174  for (double x : weights) {
175  sum += x;
176  }
177  for (double& x : weights) {
178  x = kTrials * (x / sum);
179  }
180 
181  double chi_square =
184 
185  if (chi_square > kThreshold) {
186  double p_value =
187  absl::random_internal::ChiSquarePValue(chi_square, kBuckets);
188 
189  // Chi-squared test failed. Output does not appear to be uniform.
191  for (size_t i = 0; i < counts.size(); i++) {
192  absl::StrAppend(&msg, i, ": ", counts[i], " vs ", weights[i], "\n");
193  }
194  absl::StrAppend(&msg, kChiSquared, " p-value ", p_value, "\n");
195  absl::StrAppend(&msg, "High ", kChiSquared, " value: ", chi_square, " > ",
196  kThreshold);
197  ABSL_RAW_LOG(INFO, "%s", msg.c_str());
198  FAIL() << msg;
199  }
200 }
201 
202 TEST(DiscreteDistributionTest, StabilityTest) {
203  // absl::discrete_distribution stabilitiy relies on
204  // absl::uniform_int_distribution and absl::bernoulli_distribution.
206  {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
207  0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
208  0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
209  0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
210 
211  std::vector<int> output(6);
212 
213  {
214  absl::discrete_distribution<int32_t> dist({1.0, 2.0, 3.0, 5.0, 2.0});
215  EXPECT_EQ(0, dist.min());
216  EXPECT_EQ(4, dist.max());
217  for (auto& v : output) {
218  v = dist(urbg);
219  }
220  EXPECT_EQ(12, urbg.invocations());
221  }
222 
223  // With 12 calls to urbg, each call into discrete_distribution consumes
224  // precisely 2 values: one for the uniform call, and a second for the
225  // bernoulli.
226  //
227  // Given the alt mapping: 0=>3, 1=>3, 2=>2, 3=>2, 4=>3, we can
228  //
229  // uniform: 443210143131
230  // bernoulli: b0 000011100101
231  // bernoulli: b1 001111101101
232  // bernoulli: b2 111111111111
233  // bernoulli: b3 001111101111
234  // bernoulli: b4 001111101101
235  // ...
236  EXPECT_THAT(output, testing::ElementsAre(3, 3, 1, 3, 3, 3));
237 
238  {
239  urbg.reset();
240  absl::discrete_distribution<int64_t> dist({1.0, 2.0, 3.0, 5.0, 2.0});
241  EXPECT_EQ(0, dist.min());
242  EXPECT_EQ(4, dist.max());
243  for (auto& v : output) {
244  v = dist(urbg);
245  }
246  EXPECT_EQ(12, urbg.invocations());
247  }
248  EXPECT_THAT(output, testing::ElementsAre(3, 3, 0, 3, 0, 4));
249 }
250 
251 } // namespace
absl::StrAppend
void StrAppend(std::string *dest, const AlphaNum &a)
Definition: abseil-cpp/absl/strings/str_cat.cc:193
begin
char * begin
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1007
EXPECT_THAT
#define EXPECT_THAT(value, matcher)
uint16_t
unsigned short uint16_t
Definition: stdint-msvc2008.h:79
grpc::testing::sum
double sum(const T &container, F functor)
Definition: test/cpp/qps/stats.h:30
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
absl::FormatConversionChar::s
@ s
xds_manager.p
p
Definition: xds_manager.py:60
absl::random_internal::sequence_urbg
Definition: abseil-cpp/absl/random/internal/sequence_urbg.h:33
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
absl::discrete_distribution
Definition: abseil-cpp/absl/random/discrete_distribution.h:52
gen_synthetic_protos.weights
list weights
Definition: gen_synthetic_protos.py:71
testing::Test
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:402
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: iomgr/time_averaged_stats_test.cc:27
testing::ElementsAre
internal::ElementsAreMatcher< ::testing::tuple<> > ElementsAre()
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:13040
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
before
IntBeforeRegisterTypedTestSuiteP before
Definition: googletest/googletest/test/gtest-typed-test_test.cc:376
testing::internal::ProxyTypeList
Definition: googletest/googletest/include/gtest/internal/gtest-type-util.h:155
int16_t
signed short int16_t
Definition: stdint-msvc2008.h:76
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
absl::random_internal::InitDiscreteDistribution
std::vector< std::pair< double, size_t > > InitDiscreteDistribution(std::vector< double > *probabilities)
Definition: abseil-cpp/absl/random/discrete_distribution.cc:23
int64_t
signed __int64 int64_t
Definition: stdint-msvc2008.h:89
generate-asm-lcov.fn
fn
Definition: generate-asm-lcov.py:146
TEST
#define TEST(name, init_size,...)
Definition: arena_test.cc:75
gmock_output_test.output
output
Definition: bloaty/third_party/googletest/googlemock/test/gmock_output_test.py:175
python_utils.jobset.INFO
INFO
Definition: jobset.py:111
EXPECT_NE
#define EXPECT_NE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2028
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
TYPED_TEST
#define TYPED_TEST(CaseName, TestName)
Definition: googletest/googletest/include/gtest/gtest-typed-test.h:197
gmock_output_test._
_
Definition: bloaty/third_party/googletest/googlemock/test/gmock_output_test.py:175
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
FAIL
@ FAIL
Definition: call_creds.cc:42
absl::discrete_distribution::param_type
Definition: abseil-cpp/absl/random/discrete_distribution.h:56
absl::random_internal::ChiSquarePValue
double ChiSquarePValue(double chi_square, int dof)
Definition: abseil-cpp/absl/random/internal/chi_square.cc:157
x
int x
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3610
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
after
IntAfterTypedTestSuiteP after
Definition: googletest/googletest/test/gtest-typed-test_test.cc:375
msg
std::string msg
Definition: client_interceptors_end2end_test.cc:372
testing::Pair
internal::PairMatcher< FirstMatcher, SecondMatcher > Pair(FirstMatcher first_matcher, SecondMatcher second_matcher)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:9152
google_benchmark.example.empty
def empty(state)
Definition: example.py:31
b1
T::second_type b1
Definition: abseil-cpp/absl/container/internal/hash_function_defaults_test.cc:306
testing::_
const internal::AnythingMatcher _
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8548
absl::random_internal::pcg_engine
Definition: abseil-cpp/absl/random/internal/pcg_engine.h:41
TYPED_TEST_SUITE
#define TYPED_TEST_SUITE(CaseName, Types,...)
Definition: googletest/googletest/include/gtest/gtest-typed-test.h:191
absl::random_internal::ChiSquareValue
double ChiSquareValue(int dof, double p)
Definition: abseil-cpp/absl/random/internal/chi_square.cc:106
absl::str_format_internal::LengthMod::q
@ q
int8_t
signed char int8_t
Definition: stdint-msvc2008.h:75
absl::random_internal::kChiSquared
constexpr const char kChiSquared[]
Definition: abseil-cpp/absl/random/internal/chi_square.h:35
int32_t
signed int int32_t
Definition: stdint-msvc2008.h:77
ABSL_RAW_LOG
#define ABSL_RAW_LOG(severity,...)
Definition: abseil-cpp/absl/base/internal/raw_logging.h:44
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
absl::random_internal::ChiSquare
double ChiSquare(Iterator it, Iterator end, Expected eit, Expected eend)
Definition: abseil-cpp/absl/random/internal/chi_square.h:56


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:16