ExRandom  3.0
discrete_normal_distribution.hpp
Go to the documentation of this file.
1 /**
2  * @file discrete_normal_distribution.hpp
3  * @author Charles Karney <charles.karney@sri.com>
4  * @brief Definition of discrete_normal_distribution
5  *
6  * Copyright (c) Charles Karney (2014-2020) and licensed under the MIT/X11
7  * License. For more information, see http://exrandom.sourceforge.net/
8  */
9 
10 #if !defined(EXRANDOM_DISCRETE_NORMAL_DISTRIBUTION_HPP)
11 #define EXRANDOM_DISCRETE_NORMAL_DISTRIBUTION_HPP 1
12 
13 #include <iostream> // for std::ostream, etc.
14 #include <limits>
15 
16 #include <exrandom/rand_digit.hpp>
18 
19 namespace exrandom {
20 
21  /**
22  * @brief Sample exactly from the discrete normal distribution.
23  *
24  * This samples from the discrete normal distribution P<sub>i</sub> &prop;
25  * exp[&minus; ((i &minus; &mu;)/&sigma;)<sup>2</sup>/2], where &mu; and
26  * &sigma; &gt; 0 are specified as rational numbers (the ratio of two ints).
27  * This implements Algorithm D with improvements due to Du et al. (2020).
28  *
29  * This is a wrapper for discrete_normal_dist to turn it into a C++11 style
30  * random distribution. The base for discrete_normal_dist is set to
31  * 2<sup>16</sup>.
32  */
34  private:
35  static const uint_t _base = 1UL<<16;
36  public:
37  /**
38  * The type of the range of the distribution.
39  */
40  typedef int result_type;
41  /**
42  * @brief Parameter type for discrete_normal_distribution.
43  */
44  struct param_type : discrete_normal_dist<rand_digit<_base>>::param_type {
45  /**
46  * The type of the random number distribution.
47  */
49 
50  /**
51  * The default constructor.
52  *
53  * Sets &mu; = 0 and &sigma; = 1.
54  */
55  explicit param_type()
57 
58  /**
59  * Construct with integer parameters.
60  *
61  * @param mu the value of &mu;.
62  * @param sigma the value of &sigma;.
63  *
64  * Sets &mu; = @e mu and &sigma; = @e sigma.
65  */
66  explicit param_type(int mu, int sigma)
67  : discrete_normal_dist<rand_digit<_base>>::param_type(mu, sigma) {}
68 
69  /**
70  * Construct with parameters with a common denominator.
71  *
72  * @param mu_num the numerator of &mu;.
73  * @param sigma_num the numerator of &sigma;.
74  * @param den the common denominator.
75  *
76  * Sets &mu; = @e mu_num / @e den and &sigma; = @e sigma_num / @e den.
77  */
78  explicit param_type(int mu_num, int sigma_num, int den)
80  (mu_num, sigma_num, den) {}
81  /**
82  * Construct from the individual parameters.
83  *
84  * @param mu_num the numerator of &mu;.
85  * @param mu_den the denominator of &mu;.
86  * @param sigma_num the numerator of &sigma;.
87  * @param sigma_den the denominator of &sigma;.
88  *
89  * Sets &mu; = @e mu_num / @e mu_den and &sigma; = @e sigma_num
90  * / @e sigma_den.
91  */
92  explicit param_type(int mu_num, int mu_den, int sigma_num, int sigma_den)
95  };
96 
97  /**
98  * The default constructor.
99  *
100  * Sets &mu; = 0 and &sigma; = 1
101  */
102  explicit discrete_normal_distribution() : _normal_dist(_D) {}
103 
104  /**
105  * Construct from a param_type.
106  *
107  * @param p
108  */
110  : _param(p), _normal_dist(_D, _param) {}
111 
112  /**
113  * Construct with integer parameters.
114  *
115  * @param mu the value of &mu;.
116  * @param sigma the value of &sigma;.
117  *
118  * Sets &mu; = @e mu and &sigma; = @e sigma.
119  */
120  explicit discrete_normal_distribution(int mu, int sigma)
121  : _param(mu, sigma), _normal_dist(_D, _param) {}
122 
123  /**
124  * Construct with parameters with a common denominator.
125  *
126  * @param mu_num the numerator of &mu;.
127  * @param sigma_num the numerator of &sigma;.
128  * @param den the common denominator.
129  *
130  * Sets &mu; = @e mu_num / @e den and &sigma; = @e sigma_num
131  * / @e den.
132  */
133  explicit
135  : _param(mu_num, sigma_num, den), _normal_dist(_D, _param) {}
136 
137  /**
138  * Construct from the individual parameters.
139  *
140  * @param mu_num the numerator of &mu;.
141  * @param mu_den the denominator of &mu;.
142  * @param sigma_num the numerator of &sigma;.
143  * @param sigma_den the denominator of &sigma;.
144  *
145  * Sets &mu; = @e mu_num / @e mu_den and &sigma; = @e sigma_num / @e
146  * sigma_den.
147  */
148  explicit
150  int sigma_num, int sigma_den)
151  : _param(mu_num, mu_den, sigma_num, sigma_den)
152  , _normal_dist(_D, _param) {}
153 
154  /**
155  * Resets the distribution state.
156  */
157  void reset() {}
158 
159  /**
160  * @return the numerator of &mu;.
161  */
162  result_type mu_num() const { return _param.mu_num(); }
163  /**
164  * @return the denominator of &mu;.
165  */
166  result_type mu_den() const { return _param.mu_den(); }
167  /**
168  * @return the numerator of &sigma;.
169  */
170  result_type sigma_num() const { return _param.sigma_num(); }
171  /**
172  * @return the denominator of &sigma;.
173  */
174  result_type sigma_den() const { return _param.sigma_den(); }
175 
176  /**
177  * @return the parameter set of the distribution.
178  */
179  param_type param() const { return _param; }
180 
181  /**
182  * Sets the parameter set of the distribution.
183  * @param param The new parameter set of the distribution.
184  */
185  void param(const param_type& param)
186  { _param = param; _normal_dist.init(_param); }
187 
188  /**
189  * @return the greatest lower bound value of the distribution.
190  */
191  result_type min() const
192  { return std::numeric_limits<result_type>::min(); }
193 
194  /**
195  * @return the least upper bound value of the distribution.
196  */
197  result_type max() const
198  { return std::numeric_limits<result_type>::max(); }
199 
200  /**
201  * @tparam Generator the type of g.
202  * @param g the random generator engine.
203  * @return a discrete normal deviate.
204  */
205  template<typename Generator>
206  result_type operator()(Generator& g)
207  { return _normal_dist(g); }
208 
209  /**
210  * @tparam Generator the type of g.
211  * @param g the random generator engine.
212  * @param p a parameter set.
213  * @return a discrete normal deviate using the specified parameters.
214  */
215  template<typename Generator>
216  result_type operator()(Generator& g, const param_type& p) {
218  return N(g);
219  }
220 
221  /**
222  * @return true if two normal distributions have the same parameters.
223  */
224  friend bool
227  { return d1.param() == d2.param(); }
228 
229  /**
230  * @return false if two normal distributions have the same parameters.
231  */
232  friend bool
235  { return !(d1 == d2); }
236 
237  /**
238  * Inserts a discrete_normal_distribution random number distribution
239  * @e x into the output stream @e os.
240  *
241  * @param os an output stream.
242  * @param x a discrete_normal_distribution random number distribution.
243  * @return os.
244  */
245  friend std::ostream&
246  operator<<(std::ostream& os, const discrete_normal_distribution& x)
247  { os << x.param(); return os; }
248 
249  /**
250  * Extracts a discrete_normal_distribution random number distribution @e x
251  * from the input stream @e is.
252  *
253  * @param is an input stream.
254  * @param x a discrete_normal_distribution random number generator engine.
255  * @return is.
256  */
257  friend std::istream&
258  operator>>(std::istream& is, discrete_normal_distribution& x) {
260  is >> p;
261  x.param(p);
262  return is;
263  }
264 
265  private:
266  param_type _param;
269  };
270 
271 }
272 
273 #endif // EXRANDOM_DISCRETE_NORMAL_DISTRIBUTION_HPP
discrete_normal_distribution(int mu_num, int mu_den, int sigma_num, int sigma_den)
friend std::ostream & operator<<(std::ostream &os, const discrete_normal_distribution &x)
friend std::istream & operator>>(std::istream &is, discrete_normal_distribution &x)
friend bool operator!=(const discrete_normal_distribution &d1, const discrete_normal_distribution &d2)
result_type operator()(Generator &g, const param_type &p)
Machinery to convert a random generator into a random digit.
Definition: rand_digit.hpp:34
friend bool operator==(const discrete_normal_distribution &d1, const discrete_normal_distribution &d2)
param_type(int mu_num, int mu_den, int sigma_num, int sigma_den)
Definition of rand_digit.
Partially sample exactly from the discrete normal distribution.
discrete_normal_distribution(int mu_num, int sigma_num, int den)
The common namespace.
Definition: aux_info.hpp:18
Sample exactly from the discrete normal distribution.
Definition of discrete_normal_dist.
Parameter type for discrete_normal_distribution.