Kea  1.9.9-git
random_number_generator.h
Go to the documentation of this file.
1 // Copyright (C) 2010-2020 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 util {
27 namespace random {
28 
29 class InvalidLimits : public isc::BadValue {
30 public:
31  InvalidLimits(const char* file, size_t line, const char* what) :
32  isc::BadValue(file, line, what) {}
33 };
34 
35 class SumNotOne : public isc::BadValue {
36 public:
37  SumNotOne(const char* file, size_t line, const char* what) :
38  isc::BadValue(file, line, what) {}
39 };
40 
42 public:
43  InvalidProbValue(const char* file, size_t line, const char* what) :
44  isc::BadValue(file, line, what) {}
45 };
46 
47 
48 
53 public:
58  UniformRandomIntegerGenerator(int min, int max):
59  min_(std::min(min, max)), max_(std::max(min, max)),
60  dist_(min_, max_), generator_(rng_, dist_)
61  {
62  // To preserve the restriction of the underlying uniform_int class (and
63  // to retain compatibility with earlier versions of the class), we will
64  // abort if the minimum and maximum given are the wrong way round.
65  if (min > max) {
66  isc_throw(InvalidLimits, "minimum limit is greater than maximum "
67  "when initializing UniformRandomIntegerGenerator");
68  }
69 
70  // Init with the current time
71  rng_.seed(time(NULL));
72  }
73 
75  int operator()() { return generator_(); }
76 private:
80 
81  int min_;
82  int max_;
83  boost::uniform_int<> dist_;
84  boost::mt19937 rng_;
85  boost::variate_generator<boost::mt19937&, boost::uniform_int<> > generator_;
86 };
87 
92 public:
102  WeightedRandomIntegerGenerator(const std::vector<double>& probabilities,
103  size_t min = 0):
104  dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(min)
105  {
106  // The probabilities must be valid. Checking is quite an expensive
107  // operation, so is only done in a debug build.
108  areProbabilitiesValid(probabilities);
109 
110  // Calculate the partial sum of probabilities
111  std::partial_sum(probabilities.begin(), probabilities.end(),
112  std::back_inserter(cumulative_));
113  // Init with the current time
114  rng_.seed(time(NULL));
115  }
116 
120  dist_(0, 1.0), uniform_real_gen_(rng_, dist_), min_(0)
121  {
122  }
123 
129  void reset(const std::vector<double>& probabilities, size_t min = 0)
130  {
131  // The probabilities must be valid.
132  areProbabilitiesValid(probabilities);
133 
134  // Reset the cumulative sum
135  cumulative_.clear();
136 
137  // Calculate the partial sum of probabilities
138  std::partial_sum(probabilities.begin(), probabilities.end(),
139  std::back_inserter(cumulative_));
140 
141  // Reset the minimum integer
142  min_ = min;
143  }
144 
146  size_t operator()()
147  {
148  return std::lower_bound(cumulative_.begin(), cumulative_.end(), uniform_real_gen_())
149  - cumulative_.begin() + min_;
150  }
151 
152 private:
165  void areProbabilitiesValid(const std::vector<double>& probabilities) const
166  {
167  double sum = probabilities.empty() ? 1.0 : 0.0;
168  for (const double it : probabilities) {
169  //The probability must be in [0, 1.0]
170  if (it < 0.0 || it > 1.0) {
172  "probability must be in the range 0..1");
173  }
174 
175  sum += it;
176  }
177 
178  double epsilon = 0.0001;
179  // The sum must be equal to 1
180  if (std::fabs(sum - 1.0) >= epsilon) {
181  isc_throw(SumNotOne, "Sum of probabilities is not equal to 1");
182  }
183 
184  return;
185  }
186 
187  std::vector<double> cumulative_;
188  boost::mt19937 rng_;
189  boost::uniform_real<> dist_;
190 
191  // Shortcut typedef
192  // This typedef is placed directly before its use, as the sunstudio
193  // compiler could not handle it being anywhere else (don't know why)
194  typedef boost::variate_generator<boost::mt19937&, boost::uniform_real<> > UniformRealGenerator;
195  UniformRealGenerator uniform_real_gen_;
196 
197  size_t min_;
198 };
199 
200 } // namespace random
201 } // namespace util
202 } // namespace isc
203 
204 #endif//NSAS_RANDOM_NUMBER_GENERATOR_H
WeightedRandomIntegerGenerator(const std::vector< double > &probabilities, size_t min=0)
Constructor.
SumNotOne(const char *file, size_t line, const char *what)
InvalidProbValue(const char *file, size_t line, const char *what)
int operator()()
Generate uniformly distributed integer.
STL namespace.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
size_t operator()()
Generate weighted random integer.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Defines the logger used by the top-level component of kea-dhcp-ddns.
UniformRandomIntegerGenerator(int min, int max)
Constructor.
void reset(const std::vector< double > &probabilities, size_t min=0)
Reset the probabilities.
InvalidLimits(const char *file, size_t line, const char *what)