]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3207] Remove weighted random generator
authorSlawek Figiel <slawek@isc.org>
Fri, 9 Feb 2024 10:31:12 +0000 (11:31 +0100)
committerSlawek Figiel <slawek@isc.org>
Tue, 20 Feb 2024 08:33:35 +0000 (09:33 +0100)
src/bin/perfdhcp/random_number_generator.h
src/bin/perfdhcp/tests/random_number_generator_unittest.cc

index c03e6aea16bfa1477726959ccf131dddf9739844..eb4ddc0c367a05aba8b280f3408cb55be6d12864 100644 (file)
@@ -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
 
index 58da95586b8efc710e4a2a40c2443585d0e58256..613386062aab078f12f39f86bd144bd6634762a1 100644 (file)
@@ -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);
-}