diff options
author | Slawek Figiel <slawek@isc.org> | 2024-02-09 11:31:12 +0100 |
---|---|---|
committer | Slawek Figiel <slawek@isc.org> | 2024-02-20 09:33:35 +0100 |
commit | 2aa867b602f2869c697f30b4c43f2e1b30691e1a (patch) | |
tree | 1901cbb698925ec7104bc7698070debf3a8bc748 /src/bin/perfdhcp | |
parent | [#2022] fix User-Password example in ARM (diff) | |
download | kea-2aa867b602f2869c697f30b4c43f2e1b30691e1a.tar.xz kea-2aa867b602f2869c697f30b4c43f2e1b30691e1a.zip |
[#3207] Remove weighted random generator
Diffstat (limited to 'src/bin/perfdhcp')
-rw-r--r-- | src/bin/perfdhcp/random_number_generator.h | 112 | ||||
-rw-r--r-- | src/bin/perfdhcp/tests/random_number_generator_unittest.cc | 222 |
2 files changed, 0 insertions, 334 deletions
diff --git a/src/bin/perfdhcp/random_number_generator.h b/src/bin/perfdhcp/random_number_generator.h index c03e6aea16..eb4ddc0c36 100644 --- a/src/bin/perfdhcp/random_number_generator.h +++ b/src/bin/perfdhcp/random_number_generator.h @@ -84,118 +84,6 @@ private: boost::variate_generator<boost::mt19937&, boost::uniform_int<> > generator_; ///< Uniform generator }; -/// \brief Weighted random integer generator -/// -/// Generate random integers according different probabilities -class WeightedRandomIntegerGenerator { -public: - /// \brief Constructor - /// - /// \param probabilities The probabilities for all the integers, the probability must be - /// between 0 and 1.0, the sum of probabilities must be equal to 1. - /// For example, if the probabilities contains the following values: - /// 0.5 0.3 0.2, the 1st integer will be generated more frequently than the - /// other integers and the probability is proportional to its value. - /// \param min The minimum integer that generated, other integers will be - /// min, min + 1, ..., min + probabilities.size() - 1 - WeightedRandomIntegerGenerator(const std::vector<double>& probabilities, - size_t min = 0): - dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(min) - { - // The probabilities must be valid. Checking is quite an expensive - // operation, so is only done in a debug build. - areProbabilitiesValid(probabilities); - - // Calculate the partial sum of probabilities - std::partial_sum(probabilities.begin(), probabilities.end(), - std::back_inserter(cumulative_)); - // Init with the current time - rng_.seed(time(NULL)); - } - - /// \brief Default constructor - /// - WeightedRandomIntegerGenerator(): - dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(0) - { - } - - /// \brief Reset the probabilities - /// - /// Change the weights of each integers - /// \param probabilities The probabilities for all the integers - /// \param min The minimum integer that generated - void reset(const std::vector<double>& probabilities, size_t min = 0) - { - // The probabilities must be valid. - areProbabilitiesValid(probabilities); - - // Reset the cumulative sum - cumulative_.clear(); - - // Calculate the partial sum of probabilities - std::partial_sum(probabilities.begin(), probabilities.end(), - std::back_inserter(cumulative_)); - - // Reset the minimum integer - min_ = min; - } - - /// \brief Generate weighted random integer - size_t operator()() - { - return std::lower_bound(cumulative_.begin(), cumulative_.end(), uniform_real_gen_()) - - cumulative_.begin() + min_; - } - -private: - /// \brief Check the validation of probabilities vector - /// - /// The probability must be in range of [0, 1.0] and the sum must be equal - /// to 1.0. Empty probabilities are also valid. - /// - /// Checking the probabilities is quite an expensive operation, so it is - /// only done during a debug build (via a call through assert()). However, - /// instead of letting assert() call abort(), if this method encounters an - /// error, an exception is thrown. This makes unit testing somewhat easier. - /// - /// \param probabilities Vector of probabilities. - /// \throw InvalidProbValue or SumNotOne when not valid. - void areProbabilitiesValid(const std::vector<double>& probabilities) const - { - double sum = probabilities.empty() ? 1.0 : 0.0; - for (const double it : probabilities) { - //The probability must be in [0, 1.0] - if (it < 0.0 || it > 1.0) { - isc_throw(InvalidProbValue, - "probability must be in the range 0..1"); - } - - sum += it; - } - - double epsilon = 0.0001; - // The sum must be equal to 1 - if (std::fabs(sum - 1.0) >= epsilon) { - isc_throw(SumNotOne, "Sum of probabilities is not equal to 1"); - } - - return; - } - - std::vector<double> cumulative_; ///< Partial sum of the probabilities - boost::mt19937 rng_; ///< Mersenne Twister: A 623-dimensionally equidistributed uniform pseudo-random number generator - boost::uniform_real<> dist_; ///< Uniformly distributed real numbers - - // Shortcut typedef - // This typedef is placed directly before its use, as the sunstudio - // compiler could not handle it being anywhere else (don't know why) - typedef boost::variate_generator<boost::mt19937&, boost::uniform_real<> > UniformRealGenerator; - UniformRealGenerator uniform_real_gen_; ///< Uniformly distributed random real numbers generator - - size_t min_; ///< The minimum integer that will be generated -}; - } // namespace perfdhcp } // namespace isc diff --git a/src/bin/perfdhcp/tests/random_number_generator_unittest.cc b/src/bin/perfdhcp/tests/random_number_generator_unittest.cc index 58da95586b..613386062a 100644 --- a/src/bin/perfdhcp/tests/random_number_generator_unittest.cc +++ b/src/bin/perfdhcp/tests/random_number_generator_unittest.cc @@ -72,225 +72,3 @@ TEST_F(UniformRandomIntegerGeneratorTest, IntegerRange) { // make sure the numbers are in range [min, max] ASSERT_EQ(it - numbers.begin(), max() - min() + 1); } - -/// \brief Test Fixture Class for weighted random number generator -class WeightedRandomIntegerGeneratorTest : public ::testing::Test { -public: - WeightedRandomIntegerGeneratorTest() - { } - - virtual ~WeightedRandomIntegerGeneratorTest() - { } -}; - -// Test of the weighted random number generator constructor -TEST_F(WeightedRandomIntegerGeneratorTest, Constructor) { - vector<double> probabilities; - - // If no probabilities is provided, the smallest integer will always - // be generated - WeightedRandomIntegerGenerator gen(probabilities, 123); - for (int i = 0; i < 100; ++i) { - ASSERT_EQ(gen(), 123); - } - -/// Some validation tests will incur performance penalty, so the tests are -/// made only in "debug" version with assert(). But if NDEBUG is defined -/// the tests will be failed since assert() is non-op in non-debug version. -/// The "#ifndef NDEBUG" is added to make the tests be performed only in -/// non-debug environment. -#if !defined(NDEBUG) - //The probability must be >= 0 - probabilities.push_back(-0.1); - probabilities.push_back(1.1); - ASSERT_THROW(WeightedRandomIntegerGenerator gen2(probabilities), - InvalidProbValue); - - //The probability must be <= 1.0 - probabilities.clear(); - probabilities.push_back(0.1); - probabilities.push_back(1.1); - ASSERT_THROW(WeightedRandomIntegerGenerator gen3(probabilities), - InvalidProbValue); - - //The sum must be equal to 1.0 - probabilities.clear(); - probabilities.push_back(0.2); - probabilities.push_back(0.9); - ASSERT_THROW(WeightedRandomIntegerGenerator gen4(probabilities), SumNotOne); - - //The sum must be equal to 1.0 - probabilities.clear(); - probabilities.push_back(0.3); - probabilities.push_back(0.2); - probabilities.push_back(0.1); - ASSERT_THROW(WeightedRandomIntegerGenerator gen5(probabilities), SumNotOne); -#endif -} - -// Test the randomization of the generator -TEST_F(WeightedRandomIntegerGeneratorTest, WeightedRandomization) { - const int repeats = 100000; - // We repeat the simulation for N=repeats times - // for each probability p, its average is mu = N*p - // variance sigma^2 = N * p * (1-p) - // sigma = sqrt(N*2/9) - // we should make sure that mu - 4sigma < count < mu + 4sigma - // which means for 99.99366% of the time this should be true - { - double p = 0.5; - vector<double> probabilities; - probabilities.push_back(p); - probabilities.push_back(p); - - // Uniformly generated integers - WeightedRandomIntegerGenerator gen(probabilities); - int c1 = 0; - int c2 = 0; - for (int i = 0; i < repeats; ++i){ - int n = gen(); - if (n == 0) { - ++c1; - } else if (n == 1) { - ++c2; - } - } - double mu = repeats * p; - double sigma = sqrt(repeats * p * (1 - p)); - ASSERT_TRUE(fabs(c1 - mu) < 4*sigma); - ASSERT_TRUE(fabs(c2 - mu) < 4*sigma); - } - - { - vector<double> probabilities; - int c1 = 0; - int c2 = 0; - double p1 = 0.2; - double p2 = 0.8; - probabilities.push_back(p1); - probabilities.push_back(p2); - WeightedRandomIntegerGenerator gen(probabilities); - for (int i = 0; i < repeats; ++i) { - int n = gen(); - if (n == 0) { - ++c1; - } else if (n == 1) { - ++c2; - } - } - double mu1 = repeats * p1; - double mu2 = repeats * p2; - double sigma1 = sqrt(repeats * p1 * (1 - p1)); - double sigma2 = sqrt(repeats * p2 * (1 - p2)); - ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1); - ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); - } - - { - vector<double> probabilities; - int c1 = 0; - int c2 = 0; - double p1 = 0.8; - double p2 = 0.2; - probabilities.push_back(p1); - probabilities.push_back(p2); - WeightedRandomIntegerGenerator gen(probabilities); - for (int i = 0; i < repeats; ++i) { - int n = gen(); - if (n == 0) { - ++c1; - } else if (n == 1) { - ++c2; - } - } - double mu1 = repeats * p1; - double mu2 = repeats * p2; - double sigma1 = sqrt(repeats * p1 * (1 - p1)); - double sigma2 = sqrt(repeats * p2 * (1 - p2)); - ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1); - ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); - } - - { - vector<double> probabilities; - int c1 = 0; - int c2 = 0; - int c3 = 0; - double p1 = 0.5; - double p2 = 0.25; - double p3 = 0.25; - probabilities.push_back(p1); - probabilities.push_back(p2); - probabilities.push_back(p3); - WeightedRandomIntegerGenerator gen(probabilities); - for (int i = 0; i < repeats; ++i){ - int n = gen(); - if (n == 0) { - ++c1; - } else if (n == 1) { - ++c2; - } else if (n == 2) { - ++c3; - } - } - double mu1 = repeats * p1; - double mu2 = repeats * p2; - double mu3 = repeats * p3; - double sigma1 = sqrt(repeats * p1 * (1 - p1)); - double sigma2 = sqrt(repeats * p2 * (1 - p2)); - double sigma3 = sqrt(repeats * p3 * (1 - p3)); - ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1); - ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); - ASSERT_TRUE(fabs(c3 - mu3) < 4*sigma3); - } -} - -// Test the reset function of generator -TEST_F(WeightedRandomIntegerGeneratorTest, ResetProbabilities) { - const int repeats = 100000; - vector<double> probabilities; - int c1 = 0; - int c2 = 0; - double p1 = 0.8; - double p2 = 0.2; - probabilities.push_back(p1); - probabilities.push_back(p2); - WeightedRandomIntegerGenerator gen(probabilities); - for (int i = 0; i < repeats; ++i) { - int n = gen(); - if (n == 0) { - ++c1; - } else if (n == 1) { - ++c2; - } - } - double mu1 = repeats * p1; - double mu2 = repeats * p2; - double sigma1 = sqrt(repeats * p1 * (1 - p1)); - double sigma2 = sqrt(repeats * p2 * (1 - p2)); - ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1); - ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); - - // Reset the probabilities - probabilities.clear(); - c1 = c2 = 0; - p1 = 0.2; - p2 = 0.8; - probabilities.push_back(p1); - probabilities.push_back(p2); - gen.reset(probabilities); - for (int i = 0; i < repeats; ++i) { - int n = gen(); - if (n == 0) { - ++c1; - } else if (n == 1) { - ++c2; - } - } - mu1 = repeats * p1; - mu2 = repeats * p2; - sigma1 = sqrt(repeats * p1 * (1 - p1)); - sigma2 = sqrt(repeats * p2 * (1 - p2)); - ASSERT_TRUE(fabs(c1 - mu1) < 4*sigma1); - ASSERT_TRUE(fabs(c2 - mu2) < 4*sigma2); -} |