RandomLib  1.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
UniformInteger.hpp
Go to the documentation of this file.
1 /**
2  * \file UniformInteger.hpp
3  * \brief Header for UniformInteger
4  *
5  * Partially sample a uniform integer distribution.
6  *
7  * Copyright (c) Charles Karney (2013) <charles@karney.com> and licensed
8  * under the MIT/X11 License. For more information, see
9  * http://randomlib.sourceforge.net/
10  **********************************************************************/
11 
12 #if !defined(RANDOMLIB_UNIFORMINTEGER_HPP)
13 #define RANDOMLIB_UNIFORMINTEGER_HPP 1
14 
15 #include <limits>
16 
17 namespace RandomLib {
18  /**
19  * \brief The partial uniform integer distribution.
20  *
21  * A class to sample in [0, \e m). For background, see:
22  * - D. E. Knuth and A. C. Yao, The Complexity of Nonuniform Random Number
23  * Generation, in "Algorithms and Complexity" (Academic Press, 1976),
24  * pp. 357--428.
25  * - J. Lumbroso, Optimal Discrete Uniform Generation from Coin Flips,
26  * and Applications, http://arxiv.org/abs/1304.1916 (2013)
27  * .
28  * Lumbroso's algorithm is a realization of the Knuth-Yao method for the case
29  * of uniform probabilities. This class generalizes the method to accept
30  * random digits in a base, \e b = 2<sup>\e bits</sup>. An important
31  * additional feature is that only sufficient random digits are drawn to
32  * narrow the allowed range to a power of b. Thus after
33  * <code>UniformInteger<int,1> u(r,5)</code>, \e u represents \verbatim
34  range prob
35  [0,4) 8/15
36  [0,2) 2/15
37  [2,4) 2/15
38  4 1/5 \endverbatim
39  * <code>u.Min()</code> and <code>u.Max()</code> give the extent of the
40  * closed range. The number of additional random digits needed to fix the
41  * value is given by <code>u.Entropy()</code>. The comparison operations may
42  * require additional digits to be drawn and so the range might be narrowed
43  * down. If you need a definite value then use <code>u(r)</code>.
44  *
45  * The DiscreteNormalAlt class uses UniformInteger to achieve an
46  * asymptotically ideal scaling wherein the number of random bits required
47  * per sample is constant + log<sub>2</sub>&sigma;. If Lumbroso's algorithm
48  * for sampling in [0,\e m) were used the log<sub>2</sub>&sigma; term would
49  * be multiplied by about 1.4.
50  *
51  * It is instructive to look at the Knuth-Yao discrete distribution
52  * generating (DDG) tree for the case \e m = 5 (the binary expansion of 1/5
53  * is 0.00110011...); Lumbroso's algorithm implements this tree.
54  * \image html ky-5.png "Knuth-Yao for \e m = 5"
55  *
56  * UniformInteger collapses all of the full subtrees above to their parent
57  * nodes to yield this tree where now some of the outcomes are ranges.
58  * \image html ky-5-collapse.png "Collapsed Knuth-Yao for \e m = 5"
59  *
60  * Averaging over many samples, the maximum number of digits required to
61  * construct a UniformInteger, i.e., invoking
62  * <code>UniformInteger(r,m)</code>, is (2\e b &minus; 1)/(\e b &minus; 1).
63  * (Note that this does not increase as \e m increases.) The maximum number
64  * of digits required to sample specific integers, i.e., invoking
65  * <code>UniformInteger(r,m)(r)</code>, is <i>b</i>/(\e b &minus; 1) +
66  * log<sub>\e b</sub>\e m. The worst cases are when \e m is slightly more
67  * than a power of \e b.
68  *
69  * The number of random bits required for sampling is shown as a function of
70  * the fractional part of log<sub>2</sub>\e m below. The red line shows what
71  * Lumbroso calls the "toll", the number of bits in excess of the entropy
72  * that are required for sampling.
73  * \image html
74  * uniform-bits.png "Random bits to sample in [0,\e m) for \e b = 2"
75  *
76  * @tparam IntType the type of the integer (must be signed).
77  * @tparam bits the number of bits in each digit used for sampling;
78  * the base for sampling is \e b = 2<sup>\e bits</sup>.
79  **********************************************************************/
80  template<typename IntType = int, int bits = 1> class UniformInteger {
81  public:
82  /**
83  * Constructor creating a partially sampled integer in [0, \e m)
84  *
85  * @param[in] r random object.
86  * @param[in] m constructed object represents an integer in [0, \e m).
87  * @param[in] flip if true, rearrange the ranges so that the widest ones
88  * are at near the upper end of [0, \e m) (default false).
89  *
90  * The samples enough random digits to obtain a uniform range whose size is
91  * a power of the base. The range can subsequently be narrowed by sampling
92  * additional digits.
93  **********************************************************************/
94  template<class Random>
95  UniformInteger(Random& r, IntType m, bool flip = false);
96  /**
97  * @return the minimum of the current range.
98  **********************************************************************/
99  IntType Min() const { return _a; }
100  /**
101  * @return the maximum of the current range.
102  **********************************************************************/
103  IntType Max() const { return _a + (IntType(1) << (_l * bits)) - 1; }
104  /**
105  * @return the entropy of the current range (in units of random digits).
106  *
107  * Max() + 1 - Min() = 2<sup>Entropy() * \e bits</sup>.
108  **********************************************************************/
109  IntType Entropy() const { return _l; }
110  /**
111  * Sample until the entropy vanishes, i.e., Min() = Max().
112  *
113  * @return the resulting integer sample.
114  **********************************************************************/
115  template<class Random> IntType operator()(Random& r)
116  { while (_l) Refine(r); return _a; }
117  /**
118  * Negate the range, [Min(), Max()] &rarr; [&minus;Max(), &minus;Min()].
119  **********************************************************************/
120  void Negate() { _a = -Max(); }
121  /**
122  * Add a constant to the range
123  *
124  * @param[in] c the constant to be added.
125  *
126  * [Min(), Max()] &rarr; [Min() + \e c, Max() + \e c].
127  **********************************************************************/
128  void Add(IntType c) { _a += c; }
129  /**
130  * Compare with a fraction, *this &lt; <i>p</i>/<i>q</i>
131  *
132  * @tparam Random the type of the random generator.
133  * @param[in,out] r a random generator.
134  * @param[in] p the numerator of the fraction.
135  * @param[in] q the denominator of the fraction (require \e q &gt; 0).
136  * @return true if *this &lt; <i>p</i>/<i>q</i>.
137  **********************************************************************/
138  // test j < p/q (require q > 0)
139  template<class Random> bool LessThan(Random& r, IntType p, IntType q) {
140  for (;;) {
141  if ( (q * Max() < p)) return true;
142  if (!(q * Min() < p)) return false;
143  Refine(r);
144  }
145  }
146  /**
147  * Compare with a fraction, *this &le; <i>p</i>/<i>q</i>
148  *
149  * @tparam Random the type of the random generator.
150  * @param[in,out] r a random generator.
151  * @param[in] p the numerator of the fraction.
152  * @param[in] q the denominator of the fraction (require \e q &gt; 0).
153  * @return true if *this &le; <i>p</i>/<i>q</i>.
154  **********************************************************************/
155  template<class Random>
156  bool LessThanEqual(Random& r, IntType p, IntType q)
157  { return LessThan(r, p + 1, q); }
158  /**
159  * Compare with a fraction, *this &gt; <i>p</i>/<i>q</i>
160  *
161  * @tparam Random the type of the random generator.
162  * @param[in,out] r a random generator.
163  * @param[in] p the numerator of the fraction.
164  * @param[in] q the denominator of the fraction (require \e q &gt; 0).
165  * @return true if *this &gt; <i>p</i>/<i>q</i>.
166  **********************************************************************/
167  template<class Random>
168  bool GreaterThan(Random& r, IntType p, IntType q)
169  { return !LessThanEqual(r, p, q); }
170  /**
171  * Compare with a fraction, *this &ge; <i>p</i>/<i>q</i>
172  *
173  * @tparam Random the type of the random generator.
174  * @param[in,out] r a random generator.
175  * @param[in] p the numerator of the fraction.
176  * @param[in] q the denominator of the fraction (require \e q &gt; 0).
177  * @return true if *this &ge; <i>p</i>/<i>q</i>.
178  **********************************************************************/
179  template<class Random>
180  bool GreaterThanEqual(Random& r, IntType p, IntType q)
181  { return !LessThan(r, p, q); }
182  /**
183  * Check that overflow will not happen.
184  *
185  * @param[in] mmax the largest \e m in the constructor.
186  * @param[in] qmax the largest \e q in LessThan().
187  * @return true if overflow will not happen.
188  *
189  * It is important that this check be carried out. If overflow occurs,
190  * incorrect results are obtained and the constructor may never terminate.
191  **********************************************************************/
192  static bool Check(IntType mmax, IntType qmax) {
193  return ( mmax - 1 <= ((std::numeric_limits<IntType>::max)() >> bits) &&
194  mmax - 1 <= (std::numeric_limits<IntType>::max)() / qmax );
195  }
196  private:
197  IntType _a, _l; // current range is _a + [0, 2^(bits*_l)).
198  template<class Random> static unsigned RandomDigit(Random& r) throw()
199  { return unsigned(r.template Integer<bits>()); }
200  template<class Random> void Refine(Random& r) // only gets called if _l > 0.
201  { _a += IntType(RandomDigit(r) << (bits * --_l)); }
202  };
203 
204  template<typename IntType, int bits> template<class Random>
206  {
207  STATIC_ASSERT(std::numeric_limits<IntType>::is_integer,
208  "UniformInteger: invalid integer type IntType");
209  STATIC_ASSERT(std::numeric_limits<IntType>::is_signed,
210  "UniformInteger: IntType must be a signed type");
211  STATIC_ASSERT(bits > 0 && bits < std::numeric_limits<IntType>::digits &&
212  bits <= std::numeric_limits<unsigned>::digits,
213  "UniformInteger: bits out of range");
214  m = m < 1 ? 1 : m;
215  for (IntType v = 1, c = 0;;) {
216  _l = 0; _a = c;
217  for (IntType w = v, a = c, d = 1;;) {
218  // play out Lumbroso's algorithm without drawing random digits with w
219  // playing the role of v and c represented by the range [a, a + d).
220  // Return if both ends of range qualify as return values at the same
221  // time. Otherwise, fail and draw another random digit.
222  if (w >= m) {
223  IntType j = (a / m) * m; a -= j; w -= j;
224  if (w >= m) {
225  if (a + d <= m) { _a = !flip ? a : m - a - d; return; }
226  break;
227  }
228  }
229  w <<= bits; a <<= bits; d <<= bits; ++_l;
230  }
231  IntType j = (v / m) * m; v -= j; c -= j;
232  v <<= bits; c <<= bits; c += IntType(RandomDigit(r));
233  }
234  }
235 
236  /**
237  * \relates UniformInteger
238  * Print a UniformInteger. Format is [\e min,\e max] unless the entropy is
239  * zero, in which case it's \e val.
240  **********************************************************************/
241  template<typename IntType, int bits>
242  std::ostream& operator<<(std::ostream& os,
244  if (u.Entropy())
245  os << "[" << u.Min() << "," << u.Max() << "]";
246  else
247  os << u.Min();
248  return os;
249  }
250 
251 } // namespace RandomLib
252 
253 #endif // RANDOMLIB_UNIFORMINTEGER_HPP
bool LessThan(Random &r, IntType p, IntType q)
Generate random integers, reals, and booleans.
bool GreaterThanEqual(Random &r, IntType p, IntType q)
The partial uniform integer distribution.
IntType operator()(Random &r)
UniformInteger(Random &r, IntType m, bool flip=false)
bool LessThanEqual(Random &r, IntType p, IntType q)
#define STATIC_ASSERT(cond, reason)
Definition: MPFRRandom.hpp:31
std::ostream & operator<<(std::ostream &os, const UniformInteger< IntType, bits > &u)
RandomCanonical< RandomGenerator > Random
Definition: Random.hpp:135
static bool Check(IntType mmax, IntType qmax)
bool GreaterThan(Random &r, IntType p, IntType q)