]> git.donarmstrong.com Git - rsem.git/blob - boost/random/subtract_with_carry.hpp
Updated boost to v1.55.0
[rsem.git] / boost / random / subtract_with_carry.hpp
1 /* boost random/subtract_with_carry.hpp header file
2  *
3  * Copyright Jens Maurer 2002
4  * Distributed under the Boost Software License, Version 1.0. (See
5  * accompanying file LICENSE_1_0.txt or copy at
6  * http://www.boost.org/LICENSE_1_0.txt)
7  *
8  * See http://www.boost.org for most recent version including documentation.
9  *
10  * $Id: subtract_with_carry.hpp 85813 2013-09-21 20:17:00Z jewillco $
11  *
12  * Revision history
13  *  2002-03-02  created
14  */
15
16 #ifndef BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
17 #define BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP
18
19 #include <boost/config/no_tr1/cmath.hpp>         // std::pow
20 #include <iostream>
21 #include <algorithm>     // std::equal
22 #include <stdexcept>
23 #include <boost/config.hpp>
24 #include <boost/limits.hpp>
25 #include <boost/cstdint.hpp>
26 #include <boost/static_assert.hpp>
27 #include <boost/integer/static_log2.hpp>
28 #include <boost/integer/integer_mask.hpp>
29 #include <boost/detail/workaround.hpp>
30 #include <boost/random/detail/config.hpp>
31 #include <boost/random/detail/seed.hpp>
32 #include <boost/random/detail/operators.hpp>
33 #include <boost/random/detail/seed_impl.hpp>
34 #include <boost/random/detail/generator_seed_seq.hpp>
35 #include <boost/random/linear_congruential.hpp>
36
37
38 namespace boost {
39 namespace random {
40
41 namespace detail {
42    
43 struct subtract_with_carry_discard
44 {
45     template<class Engine>
46     static void apply(Engine& eng, boost::uintmax_t z)
47     {
48         typedef typename Engine::result_type IntType;
49         const std::size_t short_lag = Engine::short_lag;
50         const std::size_t long_lag = Engine::long_lag;
51         std::size_t k = eng.k;
52         IntType carry = eng.carry;
53         if(k != 0) {
54             // increment k until it becomes 0.
55             if(k < short_lag) {
56                 std::size_t limit = (short_lag - k) < z?
57                     short_lag : (k + static_cast<std::size_t>(z));
58                 for(std::size_t j = k; j < limit; ++j) {
59                     carry = eng.do_update(j, j + long_lag - short_lag, carry);
60                 }
61             }
62             std::size_t limit = (long_lag - k) < z?
63                 long_lag : (k + static_cast<std::size_t>(z));
64             std::size_t start = (k < short_lag ? short_lag : k);
65             for(std::size_t j = start; j < limit; ++j) {
66                 carry = eng.do_update(j, j - short_lag, carry);
67             }
68         }
69
70         k = ((z % long_lag) + k) % long_lag;
71
72         if(k < z) {
73             // main loop: update full blocks from k = 0 to long_lag
74             for(std::size_t i = 0; i < (z - k) / long_lag; ++i) {
75                 for(std::size_t j = 0; j < short_lag; ++j) {
76                     carry = eng.do_update(j, j + long_lag - short_lag, carry);
77                 }
78                 for(std::size_t j = short_lag; j < long_lag; ++j) {
79                     carry = eng.do_update(j, j - short_lag, carry);
80                 }
81             }
82
83             // Update the last partial block
84             std::size_t limit = short_lag < k? short_lag : k; 
85             for(std::size_t j = 0; j < limit; ++j) {
86                 carry = eng.do_update(j, j + long_lag - short_lag, carry);
87             }
88             for(std::size_t j = short_lag; j < k; ++j) {
89                 carry = eng.do_update(j, j - short_lag, carry);
90             }
91         }
92         eng.carry = carry;
93         eng.k = k;
94     }
95 };
96
97 }
98
99 /**
100  * Instantiations of @c subtract_with_carry_engine model a
101  * \pseudo_random_number_generator.  The algorithm is
102  * described in
103  *
104  *  @blockquote
105  *  "A New Class of Random Number Generators", George
106  *  Marsaglia and Arif Zaman, Annals of Applied Probability,
107  *  Volume 1, Number 3 (1991), 462-480.
108  *  @endblockquote
109  */
110 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
111 class subtract_with_carry_engine
112 {
113 public:
114     typedef IntType result_type;
115     BOOST_STATIC_CONSTANT(std::size_t, word_size = w);
116     BOOST_STATIC_CONSTANT(std::size_t, long_lag = r);
117     BOOST_STATIC_CONSTANT(std::size_t, short_lag = s);
118     BOOST_STATIC_CONSTANT(uint32_t, default_seed = 19780503u);
119
120     // Required by the old Boost.Random concepts
121     BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
122     // Backwards compatibility
123     BOOST_STATIC_CONSTANT(result_type, modulus = (result_type(1) << w));
124     
125     BOOST_STATIC_ASSERT(std::numeric_limits<result_type>::is_integer);
126
127     /**
128      * Constructs a new @c subtract_with_carry_engine and seeds
129      * it with the default seed.
130      */
131     subtract_with_carry_engine() { seed(); }
132     /**
133      * Constructs a new @c subtract_with_carry_engine and seeds
134      * it with @c value.
135      */
136     BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_engine,
137                                                IntType, value)
138     { seed(value); }
139     /**
140      * Constructs a new @c subtract_with_carry_engine and seeds
141      * it with values produced by @c seq.generate().
142      */
143     BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(subtract_with_carry_engine,
144                                              SeedSeq, seq)
145     { seed(seq); }
146     /**
147      * Constructs a new @c subtract_with_carry_engine and seeds
148      * it with values from a range.  first is updated to point
149      * one past the last value consumed.  If there are not
150      * enough elements in the range to fill the entire state of
151      * the generator, throws @c std::invalid_argument.
152      */
153     template<class It> subtract_with_carry_engine(It& first, It last)
154     { seed(first,last); }
155
156     // compiler-generated copy ctor and assignment operator are fine
157
158     /** Seeds the generator with the default seed. */
159     void seed() { seed(default_seed); }
160     BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_engine,
161                                         IntType, value)
162     {
163         typedef linear_congruential_engine<uint32_t,40014,0,2147483563> gen_t;
164         gen_t intgen(static_cast<boost::uint32_t>(value == 0 ? default_seed : value));
165         detail::generator_seed_seq<gen_t> gen(intgen);
166         seed(gen);
167     }
168
169     /** Seeds the generator with values produced by @c seq.generate(). */
170     BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(subtract_with_carry, SeedSeq, seq)
171     {
172         detail::seed_array_int<w>(seq, x);
173         carry = (x[long_lag-1] == 0);
174         k = 0;
175     }
176
177     /**
178      * Seeds the generator with values from a range.  Updates @c first to
179      * point one past the last consumed value.  If the range does not
180      * contain enough elements to fill the entire state of the generator,
181      * throws @c std::invalid_argument.
182      */
183     template<class It>
184     void seed(It& first, It last)
185     {
186         detail::fill_array_int<w>(first, last, x);
187         carry = (x[long_lag-1] == 0);
188         k = 0;
189     }
190
191     /** Returns the smallest value that the generator can produce. */
192     static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
193     { return 0; }
194     /** Returns the largest value that the generator can produce. */
195     static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
196     { return boost::low_bits_mask_t<w>::sig_bits; }
197
198     /** Returns the next value of the generator. */
199     result_type operator()()
200     {
201         std::size_t short_index =
202             (k < short_lag)?
203                 (k + long_lag - short_lag) :
204                 (k - short_lag);
205         carry = do_update(k, short_index, carry);
206         IntType result = x[k];
207         ++k;
208         if(k >= long_lag)
209             k = 0;
210         return result;
211     }
212
213     /** Advances the state of the generator by @c z. */
214     void discard(boost::uintmax_t z)
215     {
216         detail::subtract_with_carry_discard::apply(*this, z);
217     }
218
219     /** Fills a range with random values. */
220     template<class It>
221     void generate(It first, It last)
222     { detail::generate_from_int(*this, first, last); }
223  
224     /** Writes a @c subtract_with_carry_engine to a @c std::ostream. */
225     BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, subtract_with_carry_engine, f)
226     {
227         for(unsigned int j = 0; j < f.long_lag; ++j)
228             os << f.compute(j) << ' ';
229         os << f.carry;
230         return os;
231     }
232
233     /** Reads a @c subtract_with_carry_engine from a @c std::istream. */
234     BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, subtract_with_carry_engine, f)
235     {
236         for(unsigned int j = 0; j < f.long_lag; ++j)
237             is >> f.x[j] >> std::ws;
238         is >> f.carry;
239         f.k = 0;
240         return is;
241     }
242
243     /**
244      * Returns true if the two generators will produce identical
245      * sequences of values.
246      */
247     BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(subtract_with_carry_engine, x, y)
248     {
249         for(unsigned int j = 0; j < r; ++j)
250             if(x.compute(j) != y.compute(j))
251                 return false;
252         return true;
253     }
254
255     /**
256      * Returns true if the two generators will produce different
257      * sequences of values.
258      */
259     BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(subtract_with_carry_engine)
260
261 private:
262     /// \cond show_private
263     // returns x(i-r+index), where index is in 0..r-1
264     IntType compute(unsigned int index) const
265     {
266         return x[(k+index) % long_lag];
267     }
268
269     friend struct detail::subtract_with_carry_discard;
270
271     IntType do_update(std::size_t current, std::size_t short_index, IntType carry)
272     {
273         IntType delta;
274         IntType temp = x[current] + carry;
275         if (x[short_index] >= temp) {
276             // x(n) >= 0
277             delta =  x[short_index] - temp;
278             carry = 0;
279         } else {
280             // x(n) < 0
281             delta = modulus - temp + x[short_index];
282             carry = 1;
283         }
284         x[current] = delta;
285         return carry;
286     }
287     /// \endcond
288
289     // state representation; next output (state) is x(i)
290     //   x[0]  ... x[k] x[k+1] ... x[long_lag-1]     represents
291     //  x(i-k) ... x(i) x(i+1) ... x(i-k+long_lag-1)
292     // speed: base: 20-25 nsec
293     // ranlux_4: 230 nsec, ranlux_7: 430 nsec, ranlux_14: 810 nsec
294     // This state representation makes operator== and save/restore more
295     // difficult, because we've already computed "too much" and thus
296     // have to undo some steps to get at x(i-r) etc.
297
298     // state representation: next output (state) is x(i)
299     //   x[0]  ... x[k] x[k+1]          ... x[long_lag-1]     represents
300     //  x(i-k) ... x(i) x(i-long_lag+1) ... x(i-k-1)
301     // speed: base 28 nsec
302     // ranlux_4: 370 nsec, ranlux_7: 688 nsec, ranlux_14: 1343 nsec
303     IntType x[long_lag];
304     std::size_t k;
305     IntType carry;
306 };
307
308 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
309 //  A definition is required even for integral static constants
310 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
311 const bool subtract_with_carry_engine<IntType, w, s, r>::has_fixed_range;
312 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
313 const IntType subtract_with_carry_engine<IntType, w, s, r>::modulus;
314 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
315 const std::size_t subtract_with_carry_engine<IntType, w, s, r>::word_size;
316 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
317 const std::size_t subtract_with_carry_engine<IntType, w, s, r>::long_lag;
318 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
319 const std::size_t subtract_with_carry_engine<IntType, w, s, r>::short_lag;
320 template<class IntType, std::size_t w, std::size_t s, std::size_t r>
321 const uint32_t subtract_with_carry_engine<IntType, w, s, r>::default_seed;
322 #endif
323
324
325 // use a floating-point representation to produce values in [0..1)
326 /**
327  * Instantiations of \subtract_with_carry_01_engine model a
328  * \pseudo_random_number_generator.  The algorithm is
329  * described in
330  *
331  *  @blockquote
332  *  "A New Class of Random Number Generators", George
333  *  Marsaglia and Arif Zaman, Annals of Applied Probability,
334  *  Volume 1, Number 3 (1991), 462-480.
335  *  @endblockquote
336  */
337 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
338 class subtract_with_carry_01_engine
339 {
340 public:
341     typedef RealType result_type;
342     BOOST_STATIC_CONSTANT(bool, has_fixed_range = false);
343     BOOST_STATIC_CONSTANT(std::size_t, word_size = w);
344     BOOST_STATIC_CONSTANT(std::size_t, long_lag = r);
345     BOOST_STATIC_CONSTANT(std::size_t, short_lag = s);
346     BOOST_STATIC_CONSTANT(boost::uint32_t, default_seed = 19780503u);
347
348     BOOST_STATIC_ASSERT(!std::numeric_limits<result_type>::is_integer);
349
350     /** Creates a new \subtract_with_carry_01_engine using the default seed. */
351     subtract_with_carry_01_engine() { init_modulus(); seed(); }
352     /** Creates a new subtract_with_carry_01_engine and seeds it with value. */
353     BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_01_engine,
354                                                boost::uint32_t, value)
355     { init_modulus(); seed(value); }
356     /**
357      * Creates a new \subtract_with_carry_01_engine and seeds with values
358      * produced by seq.generate().
359      */
360     BOOST_RANDOM_DETAIL_SEED_SEQ_CONSTRUCTOR(subtract_with_carry_01_engine,
361                                              SeedSeq, seq)
362     { init_modulus(); seed(seq); }
363     /**
364      * Creates a new \subtract_with_carry_01_engine and seeds it with values
365      * from a range.  Advances first to point one past the last consumed
366      * value.  If the range does not contain enough elements to fill the
367      * entire state, throws @c std::invalid_argument.
368      */
369     template<class It> subtract_with_carry_01_engine(It& first, It last)
370     { init_modulus(); seed(first,last); }
371
372 private:
373     /// \cond show_private
374     void init_modulus()
375     {
376 #ifndef BOOST_NO_STDC_NAMESPACE
377         // allow for Koenig lookup
378         using std::pow;
379 #endif
380         _modulus = pow(RealType(2), RealType(word_size));
381     }
382     /// \endcond
383
384 public:
385     // compiler-generated copy ctor and assignment operator are fine
386
387     /** Seeds the generator with the default seed. */
388     void seed() { seed(default_seed); }
389
390     /** Seeds the generator with @c value. */
391     BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_01_engine,
392                                         boost::uint32_t, value)
393     {
394         typedef linear_congruential_engine<uint32_t, 40014, 0, 2147483563> gen_t;
395         gen_t intgen(value == 0 ? default_seed : value);
396         detail::generator_seed_seq<gen_t> gen(intgen);
397         seed(gen);
398     }
399
400     /** Seeds the generator with values produced by @c seq.generate(). */
401     BOOST_RANDOM_DETAIL_SEED_SEQ_SEED(subtract_with_carry_01_engine,
402                                       SeedSeq, seq)
403     {
404         detail::seed_array_real<w>(seq, x);
405         carry = (x[long_lag-1] ? 0 : 1 / _modulus);
406         k = 0;
407     }
408
409     /**
410      * Seeds the generator with values from a range.  Updates first to
411      * point one past the last consumed element.  If there are not
412      * enough elements in the range to fill the entire state, throws
413      * @c std::invalid_argument.
414      */
415     template<class It>
416     void seed(It& first, It last)
417     {
418         detail::fill_array_real<w>(first, last, x);
419         carry = (x[long_lag-1] ? 0 : 1 / _modulus);
420         k = 0;
421     }
422
423     /** Returns the smallest value that the generator can produce. */
424     static result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
425     { return result_type(0); }
426     /** Returns the largest value that the generator can produce. */
427     static result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
428     { return result_type(1); }
429
430     /** Returns the next value of the generator. */
431     result_type operator()()
432     {
433         std::size_t short_index =
434             (k < short_lag) ?
435                 (k + long_lag - short_lag) :
436                 (k - short_lag);
437         carry = do_update(k, short_index, carry);
438         RealType result = x[k];
439         ++k;
440         if(k >= long_lag)
441             k = 0;
442         return result;
443     }
444
445     /** Advances the state of the generator by @c z. */
446     void discard(boost::uintmax_t z)
447     { detail::subtract_with_carry_discard::apply(*this, z); }
448
449     /** Fills a range with random values. */
450     template<class Iter>
451     void generate(Iter first, Iter last)
452     { detail::generate_from_real(*this, first, last); }
453
454     /** Writes a \subtract_with_carry_01_engine to a @c std::ostream. */
455     BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, subtract_with_carry_01_engine, f)
456     {
457         std::ios_base::fmtflags oldflags =
458             os.flags(os.dec | os.fixed | os.left); 
459         for(unsigned int j = 0; j < f.long_lag; ++j)
460             os << (f.compute(j) * f._modulus) << ' ';
461         os << (f.carry * f._modulus);
462         os.flags(oldflags);
463         return os;
464     }
465     
466     /** Reads a \subtract_with_carry_01_engine from a @c std::istream. */
467     BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, subtract_with_carry_01_engine, f)
468     {
469         RealType value;
470         for(unsigned int j = 0; j < long_lag; ++j) {
471             is >> value >> std::ws;
472             f.x[j] = value / f._modulus;
473         }
474         is >> value;
475         f.carry = value / f._modulus;
476         f.k = 0;
477         return is;
478     }
479
480     /** Returns true if the two generators will produce identical sequences. */
481     BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(subtract_with_carry_01_engine, x, y)
482     {
483         for(unsigned int j = 0; j < r; ++j)
484             if(x.compute(j) != y.compute(j))
485                 return false;
486         return true;
487     }
488
489     /** Returns true if the two generators will produce different sequences. */
490     BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(subtract_with_carry_01_engine)
491
492 private:
493     /// \cond show_private
494     RealType compute(unsigned int index) const
495     {
496         return x[(k+index) % long_lag];
497     }
498
499     friend struct detail::subtract_with_carry_discard;
500
501     RealType do_update(std::size_t current, std::size_t short_index, RealType carry)
502     {
503         RealType delta = x[short_index] - x[current] - carry;
504         if(delta < 0) {
505             delta += RealType(1);
506             carry = RealType(1)/_modulus;
507         } else {
508             carry = 0;
509         }
510         x[current] = delta;
511         return carry;
512     }
513     /// \endcond
514     std::size_t k;
515     RealType carry;
516     RealType x[long_lag];
517     RealType _modulus;
518 };
519
520 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
521 //  A definition is required even for integral static constants
522 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
523 const bool subtract_with_carry_01_engine<RealType, w, s, r>::has_fixed_range;
524 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
525 const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::word_size;
526 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
527 const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::long_lag;
528 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
529 const std::size_t subtract_with_carry_01_engine<RealType, w, s, r>::short_lag;
530 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
531 const uint32_t subtract_with_carry_01_engine<RealType, w, s, r>::default_seed;
532 #endif
533
534
535 /// \cond show_deprecated
536
537 template<class IntType, IntType m, unsigned s, unsigned r, IntType v>
538 class subtract_with_carry :
539     public subtract_with_carry_engine<IntType,
540         boost::static_log2<m>::value, s, r>
541 {
542     typedef subtract_with_carry_engine<IntType,
543         boost::static_log2<m>::value, s, r> base_type;
544 public:
545     subtract_with_carry() {}
546     BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry, Gen, gen)
547     { seed(gen); }
548     BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry,
549                                                IntType, val)
550     { seed(val); }
551     template<class It>
552     subtract_with_carry(It& first, It last) : base_type(first, last) {}
553     void seed() { base_type::seed(); }
554     BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry, Gen, gen)
555     {
556         detail::generator_seed_seq<Gen> seq(gen);
557         base_type::seed(seq);
558     }
559     BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry, IntType, val)
560     { base_type::seed(val); }
561     template<class It>
562     void seed(It& first, It last) { base_type::seed(first, last); }
563 };
564
565 template<class RealType, int w, unsigned s, unsigned r, int v = 0>
566 class subtract_with_carry_01 :
567     public subtract_with_carry_01_engine<RealType, w, s, r>
568 {
569     typedef subtract_with_carry_01_engine<RealType, w, s, r> base_type;
570 public:
571     subtract_with_carry_01() {}
572     BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry_01, Gen, gen)
573     { seed(gen); }
574     BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry_01,
575                                                uint32_t, val)
576     { seed(val); }
577     template<class It>
578     subtract_with_carry_01(It& first, It last) : base_type(first, last) {}
579     void seed() { base_type::seed(); }
580     BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry_01, Gen, gen)
581     {
582         detail::generator_seed_seq<Gen> seq(gen);
583         base_type::seed(seq);
584     }
585     BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry_01, uint32_t, val)
586     { base_type::seed(val); }
587     template<class It>
588     void seed(It& first, It last) { base_type::seed(first, last); }
589 };
590
591 /// \endcond
592
593 namespace detail {
594
595 template<class Engine>
596 struct generator_bits;
597
598 template<class RealType, std::size_t w, std::size_t s, std::size_t r>
599 struct generator_bits<subtract_with_carry_01_engine<RealType, w, s, r> > {
600     static std::size_t value() { return w; }
601 };
602
603 template<class RealType, int w, unsigned s, unsigned r, int v>
604 struct generator_bits<subtract_with_carry_01<RealType, w, s, r, v> > {
605     static std::size_t value() { return w; }
606 };
607
608 }
609
610 } // namespace random
611 } // namespace boost
612
613 #endif // BOOST_RANDOM_SUBTRACT_WITH_CARRY_HPP