A Discrete-Event Network Simulator
API
rng-stream.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 //
3 // Copyright (C) 2001 Pierre L'Ecuyer (lecuyer@iro.umontreal.ca)
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 version 2 as
7 // published by the Free Software Foundation;
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 //
18 // Modified for ns-3 by:
19 // - Rajib Bhattacharjea<raj.b@gatech.edu>
20 // - Mathieu Lacage <mathieu.lacage@gmail.com>
21 //
22 
23 #include <cstdlib>
24 #include <iostream>
25 #include "rng-stream.h"
26 #include "fatal-error.h"
27 #include "log.h"
28 
29 namespace ns3 {
30 
31 // Note: Logging in this file is largely avoided due to the
32 // number of calls that are made to these functions and the possibility
33 // of causing recursions leading to stack overflow
34 NS_LOG_COMPONENT_DEFINE ("RngStream");
35 
36 } // namespace ns3
37 
38 
39 namespace
40 {
41 typedef double Matrix[3][3];
42 
43 const double m1 = 4294967087.0;
44 const double m2 = 4294944443.0;
45 const double norm = 1.0 / (m1 + 1.0);
46 const double a12 = 1403580.0;
47 const double a13n = 810728.0;
48 const double a21 = 527612.0;
49 const double a23n = 1370589.0;
50 const double two17 = 131072.0;
51 const double two53 = 9007199254740992.0;
52 
53 const Matrix A1p0 = {
54  { 0.0, 1.0, 0.0 },
55  { 0.0, 0.0, 1.0 },
56  { -810728.0, 1403580.0, 0.0 }
57 };
58 
59 const Matrix A2p0 = {
60  { 0.0, 1.0, 0.0 },
61  { 0.0, 0.0, 1.0 },
62  { -1370589.0, 0.0, 527612.0 }
63 };
64 
65 
66 //-------------------------------------------------------------------------
67 // Return (a*s + c) MOD m; a, s, c and m must be < 2^35
68 //
69 double MultModM (double a, double s, double c, double m)
70 {
71  double v;
72  int32_t a1;
73 
74  v = a * s + c;
75 
76  if (v >= two53 || v <= -two53)
77  {
78  a1 = static_cast<int32_t> (a / two17);
79  a -= a1 * two17;
80  v = a1 * s;
81  a1 = static_cast<int32_t> (v / m);
82  v -= a1 * m;
83  v = v * two17 + a * s + c;
84  }
85 
86  a1 = static_cast<int32_t> (v / m);
87  /* in case v < 0)*/
88  if ((v -= a1 * m) < 0.0)
89  {
90  return v += m;
91  }
92  else
93  {
94  return v;
95  }
96 }
97 
98 
99 //-------------------------------------------------------------------------
100 // Compute the vector v = A*s MOD m. Assume that -m < s[i] < m.
101 // Works also when v = s.
102 //
103 void MatVecModM (const Matrix A, const double s[3], double v[3],
104  double m)
105 {
106  int i;
107  double x[3]; // Necessary if v = s
108 
109  for (i = 0; i < 3; ++i)
110  {
111  x[i] = MultModM (A[i][0], s[0], 0.0, m);
112  x[i] = MultModM (A[i][1], s[1], x[i], m);
113  x[i] = MultModM (A[i][2], s[2], x[i], m);
114  }
115  for (i = 0; i < 3; ++i)
116  {
117  v[i] = x[i];
118  }
119 }
120 
121 
122 //-------------------------------------------------------------------------
123 // Compute the matrix C = A*B MOD m. Assume that -m < s[i] < m.
124 // Note: works also if A = C or B = C or A = B = C.
125 //
126 void MatMatModM (const Matrix A, const Matrix B,
127  Matrix C, double m)
128 {
129  int i, j;
130  double V[3];
131  Matrix W;
132 
133  for (i = 0; i < 3; ++i)
134  {
135  for (j = 0; j < 3; ++j)
136  {
137  V[j] = B[j][i];
138  }
139  MatVecModM (A, V, V, m);
140  for (j = 0; j < 3; ++j)
141  {
142  W[j][i] = V[j];
143  }
144  }
145  for (i = 0; i < 3; ++i)
146  {
147  for (j = 0; j < 3; ++j)
148  {
149  C[i][j] = W[i][j];
150  }
151  }
152 }
153 
154 
155 //-------------------------------------------------------------------------
156 // Compute the matrix B = (A^(2^e) Mod m); works also if A = B.
157 //
158 void MatTwoPowModM (const Matrix src, Matrix dst, double m, int32_t e)
159 {
160  int i, j;
161 
162  /* initialize: dst = src */
163  for (i = 0; i < 3; ++i)
164  {
165  for (j = 0; j < 3; ++j)
166  {
167  dst[i][j] = src[i][j];
168  }
169  }
170  /* Compute dst = src^(2^e) mod m */
171  for (i = 0; i < e; i++)
172  {
173  MatMatModM (dst, dst, dst, m);
174  }
175 }
176 
177 
178 //-------------------------------------------------------------------------
179 // Compute the matrix B = (A^n Mod m); works even if A = B.
180 //
181 /*
182 void MatPowModM (const double A[3][3], double B[3][3], double m, int32_t n)
183 {
184  NS_LOG_FUNCTION (A << B << m << n);
185  int i, j;
186  double W[3][3];
187 
188  // initialize: W = A; B = I
189  for (i = 0; i < 3; ++i)
190  {
191  for (j = 0; j < 3; ++j)
192  {
193  W[i][j] = A[i][j];
194  B[i][j] = 0.0;
195  }
196  }
197  for (j = 0; j < 3; ++j)
198  {
199  B[j][j] = 1.0;
200  }
201 
202  // Compute B = A^n mod m using the binary decomposition of n
203  while (n > 0)
204  {
205  if (n % 2)
206  {
207  MatMatModM (W, B, B, m);
208  }
209  MatMatModM (W, W, W, m);
210  n /= 2;
211  }
212 }
213 */
214 
215 // The following are the transition matrices of the two MRG components
216 // (in matrix form), raised to all powers of 2 from 1 to 191
218 {
219  Matrix a1[190];
220  Matrix a2[190];
221 };
223 {
224  struct Precalculated precalculated;
225  for (int i = 0; i < 190; i++)
226  {
227  int power = i + 1;
228  MatTwoPowModM (A1p0, precalculated.a1[i], m1, power);
229  MatTwoPowModM (A2p0, precalculated.a2[i], m2, power);
230  }
231  return precalculated;
232 }
233 void PowerOfTwoMatrix (int n, Matrix a1p, Matrix a2p)
234 {
235  static struct Precalculated constants = PowerOfTwoConstants ();
236  for (int i = 0; i < 3; i ++)
237  {
238  for (int j = 0; j < 3; j++)
239  {
240  a1p[i][j] = constants.a1[n-1][i][j];
241  a2p[i][j] = constants.a2[n-1][i][j];
242  }
243  }
244 }
245 
246 } // end of anonymous namespace
247 
248 
249 namespace ns3 {
250 //-------------------------------------------------------------------------
251 // Generate the next random number.
252 //
254 {
255  int32_t k;
256  double p1, p2, u;
257 
258  /* Component 1 */
259  p1 = a12 * m_currentState[1] - a13n * m_currentState[0];
260  k = static_cast<int32_t> (p1 / m1);
261  p1 -= k * m1;
262  if (p1 < 0.0)
263  {
264  p1 += m1;
265  }
266  m_currentState[0] = m_currentState[1]; m_currentState[1] = m_currentState[2]; m_currentState[2] = p1;
267 
268  /* Component 2 */
269  p2 = a21 * m_currentState[5] - a23n * m_currentState[3];
270  k = static_cast<int32_t> (p2 / m2);
271  p2 -= k * m2;
272  if (p2 < 0.0)
273  {
274  p2 += m2;
275  }
276  m_currentState[3] = m_currentState[4]; m_currentState[4] = m_currentState[5]; m_currentState[5] = p2;
277 
278  /* Combination */
279  u = ((p1 > p2) ? (p1 - p2) * norm : (p1 - p2 + m1) * norm);
280 
281  return u;
282 }
283 
284 RngStream::RngStream (uint32_t seedNumber, uint64_t stream, uint64_t substream)
285 {
286  if (seedNumber >= m1 || seedNumber >= m2 || seedNumber == 0)
287  {
288  NS_FATAL_ERROR ("invalid Seed " << seedNumber);
289  }
290  for (int i = 0; i < 6; ++i)
291  {
292  m_currentState[i] = seedNumber;
293  }
294  AdvanceNthBy (stream, 127, m_currentState);
295  AdvanceNthBy (substream, 76, m_currentState);
296 }
297 
299 {
300  for (int i = 0; i < 6; ++i)
301  {
302  m_currentState[i] = r.m_currentState[i];
303  }
304 }
305 
306 void
307 RngStream::AdvanceNthBy (uint64_t nth, int by, double state[6])
308 {
309  Matrix matrix1,matrix2;
310  for (int i = 0; i < 64; i++)
311  {
312  int nbit = 63 - i;
313  int bit = (nth >> nbit) & 0x1;
314  if (bit)
315  {
316  PowerOfTwoMatrix(by + nbit, matrix1, matrix2);
317  MatVecModM (matrix1, state, state, m1);
318  MatVecModM (matrix2, &state[3], &state[3], m2);
319  }
320  }
321 }
322 
323 } // namespace ns3
NS_FATAL_x macro definitions.
void MatTwoPowModM(const Matrix src, Matrix dst, double m, int32_t e)
Definition: rng-stream.cc:158
void MatVecModM(const Matrix A, const double s[3], double v[3], double m)
Definition: rng-stream.cc:103
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
#define NS_FATAL_ERROR(msg)
Fatal error handling.
Definition: fatal-error.h:100
double MultModM(double a, double s, double c, double m)
Definition: rng-stream.cc:69
Combined Multiple-Recursive Generator MRG32k3a.
Definition: rng-stream.h:38
void AdvanceNthBy(uint64_t nth, int by, double state[6])
Definition: rng-stream.cc:307
double m_currentState[6]
Definition: rng-stream.h:52
RngStream(uint32_t seed, uint64_t stream, uint64_t substream)
Definition: rng-stream.cc:284
Every class exported by the ns3 library is enclosed in the ns3 namespace.
struct Precalculated PowerOfTwoConstants(void)
Definition: rng-stream.cc:222
double RandU01(void)
Generate the next random number for this stream.
Definition: rng-stream.cc:253
void PowerOfTwoMatrix(int n, Matrix a1p, Matrix a2p)
Definition: rng-stream.cc:233
void MatMatModM(const Matrix A, const Matrix B, Matrix C, double m)
Definition: rng-stream.cc:126
Debug message logging.