Kea  2.3.9
random_number_generator.h
Go to the documentation of this file.
1 // Copyright (C) 2010-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #ifndef NSAS_RANDOM_NUMBER_GENERATOR_H
8 #define NSAS_RANDOM_NUMBER_GENERATOR_H
9 
10 #include <algorithm>
11 #include <cmath>
12 #include <iterator>
13 #include <numeric>
14 #include <vector>
15 
16 #include <exceptions/exceptions.h>
17 
18 #include <boost/random/mersenne_twister.hpp>
19 #include <boost/random/uniform_int.hpp>
20 #include <boost/random/uniform_real.hpp>
21 #include <boost/random/variate_generator.hpp>
22 
24 
25 namespace isc {
26 namespace perfdhcp {
27 
28 class InvalidLimits : public isc::BadValue {
29 public:
30  InvalidLimits(const char* file, size_t line, const char* what) :
31  isc::BadValue(file, line, what) {}
32 };
33 
34 class SumNotOne : public isc::BadValue {
35 public:
36  SumNotOne(const char* file, size_t line, const char* what) :
37  isc::BadValue(file, line, what) {}
38 };
39 
41 public:
42  InvalidProbValue(const char* file, size_t line, const char* what) :
43  isc::BadValue(file, line, what) {}
44 };
45 
46 
47 
52 public:
57  UniformRandomIntegerGenerator(int min, int max):
58  min_(std::min(min, max)), max_(std::max(min, max)),
59  dist_(min_, max_), generator_(rng_, dist_)
60  {
61  // To preserve the restriction of the underlying uniform_int class (and
62  // to retain compatibility with earlier versions of the class), we will
63  // abort if the minimum and maximum given are the wrong way round.
64  if (min > max) {
65  isc_throw(InvalidLimits, "minimum limit is greater than maximum "
66  "when initializing UniformRandomIntegerGenerator");
67  }
68 
69  // Init with the current time
70  rng_.seed(time(NULL));
71  }
72 
74  int operator()() { return generator_(); }
75 private:
79 
80  int min_;
81  int max_;
82  boost::uniform_int<> dist_;
83  boost::mt19937 rng_;
84  boost::variate_generator<boost::mt19937&, boost::uniform_int<> > generator_;
85 };
86 
91 public:
101  WeightedRandomIntegerGenerator(const std::vector<double>& probabilities,
102  size_t min = 0):
103  dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(min)
104  {
105  // The probabilities must be valid. Checking is quite an expensive
106  // operation, so is only done in a debug build.
107  areProbabilitiesValid(probabilities);
108 
109  // Calculate the partial sum of probabilities
110  std::partial_sum(probabilities.begin(), probabilities.end(),
111  std::back_inserter(cumulative_));
112  // Init with the current time
113  rng_.seed(time(NULL));
114  }
115 
119  dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(0)
120  {
121  }
122 
128  void reset(const std::vector<double>& probabilities, size_t min = 0)
129  {
130  // The probabilities must be valid.
131  areProbabilitiesValid(probabilities);
132 
133  // Reset the cumulative sum
134  cumulative_.clear();
135 
136  // Calculate the partial sum of probabilities
137  std::partial_sum(probabilities.begin(), probabilities.end(),
138  std::back_inserter(cumulative_));
139 
140  // Reset the minimum integer
141  min_ = min;
142  }
143 
145  size_t operator()()
146  {
147  return std::lower_bound(cumulative_.begin(), cumulative_.end(), uniform_real_gen_())
148  - cumulative_.begin() + min_;
149  }
150 
151 private:
164  void areProbabilitiesValid(const std::vector<double>& probabilities) const
165  {
166  double sum = probabilities.empty() ? 1.0 : 0.0;
167  for (const double it : probabilities) {
168  //The probability must be in [0, 1.0]
169  if (it < 0.0 || it > 1.0) {
171  "probability must be in the range 0..1");
172  }
173 
174  sum += it;
175  }
176 
177  double epsilon = 0.0001;
178  // The sum must be equal to 1
179  if (std::fabs(sum - 1.0) >= epsilon) {
180  isc_throw(SumNotOne, "Sum of probabilities is not equal to 1");
181  }
182 
183  return;
184  }
185 
186  std::vector<double> cumulative_;
187  boost::mt19937 rng_;
188  boost::uniform_real<> dist_;
189 
190  // Shortcut typedef
191  // This typedef is placed directly before its use, as the sunstudio
192  // compiler could not handle it being anywhere else (don't know why)
193  typedef boost::variate_generator<boost::mt19937&, boost::uniform_real<> > UniformRealGenerator;
194  UniformRealGenerator uniform_real_gen_;
195 
196  size_t min_;
197 };
198 
199 } // namespace perfdhcp
200 } // namespace isc
201 
202 #endif//NSAS_RANDOM_NUMBER_GENERATOR_H
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
InvalidLimits(const char *file, size_t line, const char *what)
InvalidProbValue(const char *file, size_t line, const char *what)
SumNotOne(const char *file, size_t line, const char *what)
int operator()()
Generate uniformly distributed integer.
UniformRandomIntegerGenerator(int min, int max)
Constructor.
WeightedRandomIntegerGenerator(const std::vector< double > &probabilities, size_t min=0)
Constructor.
void reset(const std::vector< double > &probabilities, size_t min=0)
Reset the probabilities.
size_t operator()()
Generate weighted random integer.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Defines the logger used by the top-level component of kea-lfc.