TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
MersenneRNG.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2018 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2// Copyright (c) 2013-2018 Centre national de la recherche scientifique (CNRS)
3// Copyright (c) 2018-2020 Simons Foundation
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You may obtain a copy of the License at
16// https://www.gnu.org/licenses/gpl-3.0.txt
17//
18// Authors: Michel Ferrero, Olivier Parcollet, Nils Wentzell
19
24
25#ifndef MERSENNE_RNG_H
26#define MERSENNE_RNG_H
27
28#include <cstdlib>
29#include <float.h>
30#include <iostream>
31#include <iterator>
32#include <stdexcept>
33
34namespace triqs::mc_tools::RandomGenerators {
35
36 // This is the ``Mersenne Twister'' random number generator MT19937, which
37 // generates pseudorandom integers uniformly distributed in 0..(2^32 - 1)
38 // starting from any odd seed in 0..(2^32 - 1). This version is a recode
39 // by Shawn Cokus (Cokus@math.washington.edu) on March 8, 1998 of a version by
40 // Takuji Nishimura (who had suggestions from Topher Cooper and Marc Rieffel in
41 // July-August 1997).
42 //
43 // Effectiveness of the recoding (on Goedel2.math.washington.edu, a DEC Alpha
44 // running OSF/1) using GCC -O3 as a compiler: before recoding: 51.6 sec. to
45 // generate 300 million random numbers; after recoding: 24.0 sec. for the same
46 // (i.e., 46.5% of original time), so speed is now about 12.5 million random
47 // number generations per second on this machine.
48 //
49 // According to the URL <http://www.math.keio.ac.jp/~matumoto/emt.html>
50 // (and paraphrasing a bit in places), the Mersenne Twister is ``designed
51 // with consideration of the flaws of various existing generators,'' has
52 // a period of 2^19937 - 1, gives a sequence that is 623-dimensionally
53 // equidistributed, and ``has passed many stringent tests, including the
54 // die-hard test of G. Marsaglia and the load test of P. Hellekalek and
55 // S. Wegenkittl.'' It is efficient in memory usage (typically using 2506
56 // to 5012 bytes of static data, depending on data type sizes, and the code
57 // is quite short as well). It generates random numbers in batches of 624
58 // at a time, so the caching and pipelining of modern systems is exploited.
59 // It is also divide- and mod-free.
60 //
61 // This library is free software; you can redistribute it and/or modify it
62 // under the terms of the GNU Library General Public License as published by
63 // the Free Software Foundation (either version 2 of the License or, at your
64 // option, any later version). This library is distributed in the hope that
65 // it will be useful, but WITHOUT ANY WARRANTY, without even the implied
66 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
67 // the GNU Library General Public License for more details. You should have
68 // received a copy of the GNU Library General Public License along with this
69 // library; if not, write to the Free Software Foundation, Inc., 59 Temple
70 // Place, Suite 330, Boston, MA 02111-1307, USA.
71 //
72 // The code as Shawn received it included the following notice:
73 //
74 // Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. When
75 // you use this, send an e-mail to <matumoto@math.keio.ac.jp> with
76 // an appropriate reference to your work.
77 //
78 // It would be nice to CC: <Cokus@math.washington.edu> when you write.
79 //
80 // RandMT class created by Paul Gresham <gresham@mediavisual.com>
81 // There seems to be a slight performance deficit in process creation
82 // however I've not profiled the class to compare it with the straight
83 // C code.
84 //
85 // Use of a class removes many C nasties and also allows you to easily
86 // create multiple generators.
87 // To compile on GNU a simple line is:
88 // g++ -O3 RandMT.cc -o RandMT
89 //
90
91 typedef unsigned long uint32;
92
93 class RandMT {
94
95 static const int N = 624; // length of state vector
96 static const int M = 397; // a period parameter
97 static const uint32 K = 0x9908B0DFU; // a magic constant
98
99 // If you want a single generator, consider using a singleton class
100 // instead of trying to make these static.
101 uint32 state[N + 1]; // state vector + 1 extra to not violate ANSI C
102 uint32 *next; // next random value is computed from here
103 uint32 initseed; //
104 int left; // can *next++ this many times before reloading
105
106 inline uint32 hiBit(uint32 u) {
107 return u & 0x80000000U; // mask all but highest bit of u
108 }
109
110 inline uint32 loBit(uint32 u) {
111 return u & 0x00000001U; // mask all but lowest bit of u
112 }
113
114 inline uint32 loBits(uint32 u) {
115 return u & 0x7FFFFFFFU; // mask the highest bit of u
116 }
117
118 inline uint32 mixBits(uint32 u, uint32 v) {
119 return hiBit(u) | loBits(v); // move hi bit of u to hi bit of v
120 }
121
122 uint32 reloadMT(void) {
123 uint32 *p0 = state, *p2 = state + 2, *pM = state + M, s0, s1;
124 int j;
125
126 if (left < -1) seedMT(initseed);
127
128 left = N - 1, next = state + 1;
129
130 for (s0 = state[0], s1 = state[1], j = N - M + 1; --j; s0 = s1, s1 = *p2++) *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
131
132 for (pM = state, j = M; --j; s0 = s1, s1 = *p2++) *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
133
134 s1 = state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
135 s1 ^= (s1 >> 11);
136 s1 ^= (s1 << 7) & 0x9D2C5680U;
137 s1 ^= (s1 << 15) & 0xEFC60000U;
138 return (s1 ^ (s1 >> 18));
139 }
140
141 uint32 seed_save;
142
143 public:
144 RandMT() { seedMT(1U); }
145
146 RandMT(uint32 seed) { seedMT(seed); }
147
148 RandMT(RandMT const &R) { seedMT(R.seed_save); }
149
150 void seedMT(uint32 seed) {
151
152 seed_save = seed;
153
154 //
155 // We initialize state[0..(N-1)] via the generator
156 //
157 // x_new = (69069 * x_old) mod 2^32
158 //
159 // from Line 15 of Table 1, p. 106, Sec. 3.3.4 of Knuth's
160 // _The Art of Computer Programming_, Volume 2, 3rd ed.
161 //
162 // Notes (SJC): I do not know what the initial state requirements
163 // of the Mersenne Twister are, but it seems this seeding generator
164 // could be better. It achieves the maximum period for its modulus
165 // (2^30) iff x_initial is odd (p. 20-21, Sec. 3.2.1.2, Knuth); if
166 // x_initial can be even, you have sequences like 0, 0, 0, ...;
167 // 2^31, 2^31, 2^31, ...; 2^30, 2^30, 2^30, ...; 2^29, 2^29 + 2^31,
168 // 2^29, 2^29 + 2^31, ..., etc. so I force seed to be odd below.
169 //
170 // Even if x_initial is odd, if x_initial is 1 mod 4 then
171 //
172 // the lowest bit of x is always 1,
173 // the next-to-lowest bit of x is always 0,
174 // the 2nd-from-lowest bit of x alternates ... 0 1 0 1 0 1 0 1 ... ,
175 // the 3rd-from-lowest bit of x 4-cycles ... 0 1 1 0 0 1 1 0 ... ,
176 // the 4th-from-lowest bit of x has the 8-cycle ... 0 0 0 1 1 1 1 0 ... ,
177 // ...
178 //
179 // and if x_initial is 3 mod 4 then
180 //
181 // the lowest bit of x is always 1,
182 // the next-to-lowest bit of x is always 1,
183 // the 2nd-from-lowest bit of x alternates ... 0 1 0 1 0 1 0 1 ... ,
184 // the 3rd-from-lowest bit of x 4-cycles ... 0 0 1 1 0 0 1 1 ... ,
185 // the 4th-from-lowest bit of x has the 8-cycle ... 0 0 1 1 1 1 0 0 ... ,
186 // ...
187 //
188 // The generator's potency (min. s>=0 with (69069-1)^s = 0 mod 2^32) is
189 // 16, which seems to be alright by p. 25, Sec. 3.2.1.3 of Knuth. It
190 // also does well in the dimension 2..5 spectral tests, but it could be
191 // better in dimension 6 (Line 15, Table 1, p. 106, Sec. 3.3.4, Knuth).
192 //
193 // Note that the random number user does not see the values generated
194 // here directly since reloadMT() will always munge them first, so maybe
195 // none of all of this matters. In fact, the seed values made here could
196 // even be extra-special desirable if the Mersenne Twister theory says
197 // so-- that's why the only change I made is to to odd seeds.
198 //
199 initseed = seed;
200
201 uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = state;
202 int j;
203 left = 0;
204 for (*s++ = x, j = N; --j; *s++ = (x *= 69069U) & 0xFFFFFFFFU);
205 }
206
207 inline uint32 randomMT(void) {
208 uint32 y;
209
210 if (--left < 0) return (reloadMT());
211
212 y = *next++;
213 y ^= (y >> 11);
214 y ^= (y << 7) & 0x9D2C5680U;
215 y ^= (y << 15) & 0xEFC60000U;
216 return (y ^ (y >> 18));
217 }
218
219 double operator()() { return DBL_EPSILON + eval() * (1 - 2 * DBL_EPSILON); }
220
221 double eval();
222 // inline of this causes a BIG pb with g++ 4.1.2. WHY ?????
223 // inline double operator()() {
224 // return ((double)(randomMT())/0xFFFFFFFFU);
225 // }
226
227 // Same interface as boost::variate_generator.
228 [[nodiscard]] RandMT &engine() { return *this; }
229 [[nodiscard]] RandMT const &engine() const { return *this; }
230
231 // Write a textual representation of a RandMT object to `std::ostream`.
232 friend std::ostream &operator<<(std::ostream &os, const RandMT &rng) {
233 for (uint32 i = 0; i < std::size(rng.state); ++i) os << rng.state[i] << ' ';
234 long distance = rng.next - rng.state; // NOLINT
235 os << distance << ' ' << rng.left << ' ' << rng.initseed << ' ' << rng.seed_save;
236 if (!os) throw std::runtime_error("Error writing a triqs::mc_tools::RandomGenerators::RandMT to ostream.");
237 return os;
238 }
239
240 // Read a textual representation of a RandMT object from `std::istream`.
241 friend std::istream &operator>>(std::istream &is, RandMT &rng) {
242 for (uint32 i = 0; i < std::size(rng.state); ++i) { is >> rng.state[i] >> std::ws; }
243 long distance = 0;
244 is >> distance >> std::ws >> rng.left >> std::ws >> rng.initseed >> std::ws >> rng.seed_save;
245 rng.next = rng.state + distance; // NOLINT
246 if (!is) throw std::runtime_error("Error reading a triqs::mc_tools::RandomGenerators::RandMT from istream.");
247 return is;
248 };
249 };
250
251} // namespace triqs::mc_tools::RandomGenerators
252
253#endif
const_view_type operator()() const
Make a const view of *this.