A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
rng-stream.cc
Go to the documentation of this file.
1//
2// Copyright (C) 2001 Pierre L'Ecuyer (lecuyer@iro.umontreal.ca)
3//
4// SPDX-License-Identifier: GPL-2.0-only
5//
6// Modified for ns-3 by:
7// - Rajib Bhattacharjea<raj.b@gatech.edu>
8// - Mathieu Lacage <mathieu.lacage@gmail.com>
9//
10
11#include "rng-stream.h"
12
13#include "fatal-error.h"
14#include "log.h"
15
16#include <iostream>
17
18/**
19 * @file
20 * @ingroup rngimpl
21 * ns3::RngStream and MRG32k3a implementations.
22 */
23
24namespace ns3
25{
26
27// Note: Logging in this file is largely avoided due to the
28// number of calls that are made to these functions and the possibility
29// of causing recursions leading to stack overflow
30NS_LOG_COMPONENT_DEFINE("RngStream");
31
32} // namespace ns3
33
34/**
35 * @ingroup rngimpl
36 * @{
37 */
38/** Namespace for MRG32k3a implementation details. */
39namespace MRG32k3a
40{
41
42// clang-format off
43
44/** Type for 3x3 matrix of doubles. */
45typedef double Matrix[3][3];
46
47/** First component modulus, 2<sup>32</sup> - 209. */
48const double m1 = 4294967087.0;
49
50/** Second component modulus, 2<sup>32</sup> - 22853. */
51const double m2 = 4294944443.0;
52
53/** Normalization to obtain randoms on [0,1). */
54const double norm = 1.0 / (m1 + 1.0);
55
56/** First component multiplier of <i>n</i> - 2 value. */
57const double a12 = 1403580.0;
58
59/** First component multiplier of <i>n</i> - 3 value. */
60const double a13n = 810728.0;
61
62/** Second component multiplier of <i>n</i> - 1 value. */
63const double a21 = 527612.0;
64
65/** Second component multiplier of <i>n</i> - 3 value. */
66const double a23n = 1370589.0;
67
68/** Decomposition factor for computing a*s in less than 53 bits, 2<sup>17</sup> */
69const double two17 = 131072.0;
70
71/** IEEE-754 floating point precision, 2<sup>53</sup> */
72const double two53 = 9007199254740992.0;
73
74/** First component transition matrix. */
75const Matrix A1p0 = {
76 { 0.0, 1.0, 0.0 },
77 { 0.0, 0.0, 1.0 },
78 { -810728.0, 1403580.0, 0.0 }
79};
80
81/** Second component transition matrix. */
82const Matrix A2p0 = {
83 { 0.0, 1.0, 0.0 },
84 { 0.0, 0.0, 1.0 },
85 { -1370589.0, 0.0, 527612.0 }
86};
87
88
89//-------------------------------------------------------------------------
90/**
91 * Return (a*s + c) MOD m; a, s, c and m must be < 2^35
92 *
93 * This computes the result exactly, without exceeding the 53 bit
94 * precision of doubles.
95 *
96 * \param [in] a First multiplicative argument.
97 * \param [in] s Second multiplicative argument.
98 * \param [in] c Additive argument.
99 * \param [in] m Modulus.
100 * \returns ``(a*s +c) MOD m``
101 */
102double MultModM (double a, double s, double c, double m)
103{
104 double v;
105 int32_t a1;
106
107 v = a * s + c;
108
109 if (v >= two53 || v <= -two53)
110 {
111 a1 = static_cast<int32_t> (a / two17);
112 a -= a1 * two17;
113 v = a1 * s;
114 a1 = static_cast<int32_t> (v / m);
115 v -= a1 * m;
116 v = v * two17 + a * s + c;
117 }
118
119 a1 = static_cast<int32_t> (v / m);
120 /* in case v < 0)*/
121 if ((v -= a1 * m) < 0.0)
122 {
123 return v += m;
124 }
125 else
126 {
127 return v;
128 }
129}
130
131
132//-------------------------------------------------------------------------
133/**
134 * Compute the vector v = A*s MOD m. Assume that -m < s[i] < m.
135 * Works also when v = s.
136 *
137 * \param [in] A Matrix argument, 3x3.
138 * \param [in] s Three component input vector.
139 * \param [out] v Three component output vector.
140 * \param [in] m Modulus.
141 */
142void MatVecModM (const Matrix A, const double s[3], double v[3],
143 double m)
144{
145 int i;
146 double x[3]; // Necessary if v = s
147
148 for (i = 0; i < 3; ++i)
149 {
150 x[i] = MultModM (A[i][0], s[0], 0.0, m);
151 x[i] = MultModM (A[i][1], s[1], x[i], m);
152 x[i] = MultModM (A[i][2], s[2], x[i], m);
153 }
154 for (i = 0; i < 3; ++i)
155 {
156 v[i] = x[i];
157 }
158}
159
160
161//-------------------------------------------------------------------------
162/**
163 * Compute the matrix C = A*B MOD m. Assume that -m < s[i] < m.
164 * Note: works also if A = C or B = C or A = B = C.
165 *
166 * \param [in] A First matrix argument.
167 * \param [in] B Second matrix argument.
168 * \param [out] C Result matrix.
169 * \param [in] m Modulus.
170 */
171void MatMatModM (const Matrix A, const Matrix B,
172 Matrix C, double m)
173{
174 int i;
175 int j;
176 double V[3];
177 Matrix W;
178
179 for (i = 0; i < 3; ++i)
180 {
181 for (j = 0; j < 3; ++j)
182 {
183 V[j] = B[j][i];
184 }
185 MatVecModM (A, V, V, m);
186 for (j = 0; j < 3; ++j)
187 {
188 W[j][i] = V[j];
189 }
190 }
191 for (i = 0; i < 3; ++i)
192 {
193 for (j = 0; j < 3; ++j)
194 {
195 C[i][j] = W[i][j];
196 }
197 }
198}
199
200
201//-------------------------------------------------------------------------
202/**
203 * Compute the matrix B = (A^(2^e) Mod m); works also if A = B.
204 *
205 * \param [in] src Matrix input argument \c A.
206 * \param [out] dst Matrix output \c B.
207 * \param [in] m Modulus.
208 * \param [in] e The exponent.
209 */
210void MatTwoPowModM (const Matrix src, Matrix dst, double m, int32_t e)
211{
212 int i;
213 int j;
214
215 /* initialize: dst = src */
216 for (i = 0; i < 3; ++i)
217 {
218 for (j = 0; j < 3; ++j)
219 {
220 dst[i][j] = src[i][j];
221 }
222 }
223 /* Compute dst = src^(2^e) mod m */
224 for (i = 0; i < e; i++)
225 {
226 MatMatModM (dst, dst, dst, m);
227 }
228}
229
230
231//-------------------------------------------------------------------------
232/**
233 * Compute the matrix B = (A^n Mod m); works even if A = B.
234 *
235 * \param [in] A Matrix input argument.
236 * \param [out] B Matrix output.
237 * \param [in] m Modulus.
238 * \param [in] n Exponent.
239 */
240void MatPowModM (const double A[3][3], double B[3][3], double m, int32_t n)
241{
242 int i;
243 int j;
244 double W[3][3];
245
246 // initialize: W = A; B = I
247 for (i = 0; i < 3; ++i)
248 {
249 for (j = 0; j < 3; ++j)
250 {
251 W[i][j] = A[i][j];
252 B[i][j] = 0.0;
253 }
254 }
255 for (j = 0; j < 3; ++j)
256 {
257 B[j][j] = 1.0;
258 }
259
260 // Compute B = A^n mod m using the binary decomposition of n
261 while (n > 0)
262 {
263 if (n % 2)
264 {
265 MatMatModM (W, B, B, m);
266 }
267 MatMatModM (W, W, W, m);
268 n /= 2;
269 }
270}
271
272/**
273 * The transition matrices of the two MRG components
274 * (in matrix form), raised to all powers of 2 from 1 to 191
275 */
277{
278 Matrix a1[190]; //!< First component transition matrix powers.
279 Matrix a2[190]; //!< Second component transition matrix powers.
280};
281
282/**
283 * Compute the transition matrices of the two MRG components
284 * raised to all powers of 2 from 1 to 191.
285 *
286 * \returns The precalculated powers of the transition matrices.
287 */
289{
290 Precalculated precalculated;
291 for (int i = 0; i < 190; i++)
292 {
293 int power = i + 1;
294 MatTwoPowModM (A1p0, precalculated.a1[i], m1, power);
295 MatTwoPowModM (A2p0, precalculated.a2[i], m2, power);
296 }
297 return precalculated;
298}
299/**
300 * Get the transition matrices raised to a power of 2.
301 *
302 * \param [in] n The power of 2.
303 * \param [out] a1p The first transition matrix power.
304 * \param [out] a2p The second transition matrix power.
305 */
306void PowerOfTwoMatrix (int n, Matrix a1p, Matrix a2p)
307{
308 static Precalculated constants = PowerOfTwoConstants ();
309 for (int i = 0; i < 3; i ++)
310 {
311 for (int j = 0; j < 3; j++)
312 {
313 a1p[i][j] = constants.a1[n-1][i][j];
314 a2p[i][j] = constants.a2[n-1][i][j];
315 }
316 }
317}
318
319} // namespace MRG32k3a
320
321// clang-format on
322
323namespace ns3
324{
325
326using namespace MRG32k3a;
327
328double
330{
331 int32_t k;
332 double p1;
333 double p2;
334 double u;
335
336 /* Component 1 */
337 p1 = a12 * m_currentState[1] - a13n * m_currentState[0];
338 k = static_cast<int32_t>(p1 / m1);
339 p1 -= k * m1;
340 if (p1 < 0.0)
341 {
342 p1 += m1;
343 }
346 m_currentState[2] = p1;
347
348 /* Component 2 */
349 p2 = a21 * m_currentState[5] - a23n * m_currentState[3];
350 k = static_cast<int32_t>(p2 / m2);
351 p2 -= k * m2;
352 if (p2 < 0.0)
353 {
354 p2 += m2;
355 }
358 m_currentState[5] = p2;
359
360 /* Combination */
361 u = ((p1 > p2) ? (p1 - p2) * MRG32k3a::norm : (p1 - p2 + m1) * MRG32k3a::norm);
362
363 return u;
364}
365
366RngStream::RngStream(uint32_t seedNumber, uint64_t stream, uint64_t substream)
367{
368 if (seedNumber >= m1 || seedNumber >= m2 || seedNumber == 0)
369 {
370 NS_FATAL_ERROR("invalid Seed " << seedNumber);
371 }
372 for (int i = 0; i < 6; ++i)
373 {
374 m_currentState[i] = seedNumber;
375 }
376 AdvanceNthBy(stream, 127, m_currentState);
377 AdvanceNthBy(substream, 76, m_currentState);
378}
379
381{
382 for (int i = 0; i < 6; ++i)
383 {
384 m_currentState[i] = r.m_currentState[i];
385 }
386}
387
388void
389RngStream::AdvanceNthBy(uint64_t nth, int by, double state[6])
390{
391 Matrix matrix1;
392 Matrix matrix2;
393 for (int i = 0; i < 64; i++)
394 {
395 int nbit = 63 - i;
396 int bit = (nth >> nbit) & 0x1;
397 if (bit)
398 {
399 PowerOfTwoMatrix(by + nbit, matrix1, matrix2);
400 MatVecModM(matrix1, state, state, m1);
401 MatVecModM(matrix2, &state[3], &state[3], m2);
402 }
403 }
404}
405
406} // namespace ns3
407
408/**@}*/ // \ingroup rngimpl
cairo_uint64_t x
_cairo_uint_96by64_32x64_divrem:
uint32_t r
uint32_t v
uint32_t u
RngStream(uint32_t seed, uint64_t stream, uint64_t substream)
Construct from explicit seed, stream and substream values.
double m_currentState[6]
The RNG state vector.
Definition rng-stream.h:74
void AdvanceNthBy(uint64_t nth, int by, double state[6])
Advance state of the RNG by leaps and bounds.
double RandU01()
Generate the next random number for this stream.
NS_FATAL_x macro definitions.
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
Debug message logging.
Namespace for MRG32k3a implementation details.
Definition rng-stream.cc:40
const double a21
Second component multiplier of n - 1 value.
Definition rng-stream.cc:63
const double m1
First component modulus, 232 - 209.
Definition rng-stream.cc:48
void MatMatModM(const Matrix A, const Matrix B, Matrix C, double m)
Compute the matrix C = A*B MOD m.
const Matrix A1p0
First component transition matrix.
Definition rng-stream.cc:75
const double a23n
Second component multiplier of n - 3 value.
Definition rng-stream.cc:66
const double two17
Decomposition factor for computing a*s in less than 53 bits, 217.
Definition rng-stream.cc:69
void PowerOfTwoMatrix(int n, Matrix a1p, Matrix a2p)
Get the transition matrices raised to a power of 2.
const double norm
Normalization to obtain randoms on [0,1).
Definition rng-stream.cc:54
const double a12
First component multiplier of n - 2 value.
Definition rng-stream.cc:57
void MatPowModM(const double A[3][3], double B[3][3], double m, int32_t n)
Compute the matrix B = (A^n Mod m); works even if A = B.
void MatTwoPowModM(const Matrix src, Matrix dst, double m, int32_t e)
Compute the matrix B = (A^(2^e) Mod m); works also if A = B.
const Matrix A2p0
Second component transition matrix.
Definition rng-stream.cc:82
double Matrix[3][3]
Type for 3x3 matrix of doubles.
Definition rng-stream.cc:45
const double m2
Second component modulus, 232 - 22853.
Definition rng-stream.cc:51
const double a13n
First component multiplier of n - 3 value.
Definition rng-stream.cc:60
const double two53
IEEE-754 floating point precision, 253.
Definition rng-stream.cc:72
double MultModM(double a, double s, double c, double m)
Return (a*s + c) MOD m; a, s, c and m must be < 2^35.
void MatVecModM(const Matrix A, const double s[3], double v[3], double m)
Compute the vector v = A*s MOD m.
Precalculated PowerOfTwoConstants()
Compute the transition matrices of the two MRG components raised to all powers of 2 from 1 to 191.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
ns3::RngStream declaration.
The transition matrices of the two MRG components (in matrix form), raised to all powers of 2 from 1 ...
Matrix a1[190]
First component transition matrix powers.
Matrix a2[190]
Second component transition matrix powers.