A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 
28 namespace
29 {
30 typedef double Matrix[3][3];
31 
32 const double m1 = 4294967087.0;
33 const double m2 = 4294944443.0;
34 const double norm = 1.0 / (m1 + 1.0);
35 const double a12 = 1403580.0;
36 const double a13n = 810728.0;
37 const double a21 = 527612.0;
38 const double a23n = 1370589.0;
39 const double two17 = 131072.0;
40 const double two53 = 9007199254740992.0;
41 const double fact = 5.9604644775390625e-8; /* 1 / 2^24 */
42 
43 const Matrix InvA1 = { // Inverse of A1p0
44  { 184888585.0, 0.0, 1945170933.0 },
45  { 1.0, 0.0, 0.0 },
46  { 0.0, 1.0, 0.0 }
47 };
48 
49 const Matrix InvA2 = { // Inverse of A2p0
50  { 0.0, 360363334.0, 4225571728.0 },
51  { 1.0, 0.0, 0.0 },
52  { 0.0, 1.0, 0.0 }
53 };
54 
55 const Matrix A1p0 = {
56  { 0.0, 1.0, 0.0 },
57  { 0.0, 0.0, 1.0 },
58  { -810728.0, 1403580.0, 0.0 }
59 };
60 
61 const Matrix A2p0 = {
62  { 0.0, 1.0, 0.0 },
63  { 0.0, 0.0, 1.0 },
64  { -1370589.0, 0.0, 527612.0 }
65 };
66 
67 
68 //-------------------------------------------------------------------------
69 // Return (a*s + c) MOD m; a, s, c and m must be < 2^35
70 //
71 double MultModM (double a, double s, double c, double m)
72 {
73  double v;
74  int32_t a1;
75 
76  v = a * s + c;
77 
78  if (v >= two53 || v <= -two53)
79  {
80  a1 = static_cast<int32_t> (a / two17);
81  a -= a1 * two17;
82  v = a1 * s;
83  a1 = static_cast<int32_t> (v / m);
84  v -= a1 * m;
85  v = v * two17 + a * s + c;
86  }
87 
88  a1 = static_cast<int32_t> (v / m);
89  /* in case v < 0)*/
90  if ((v -= a1 * m) < 0.0)
91  {
92  return v += m;
93  }
94  else
95  {
96  return v;
97  }
98 }
99 
100 
101 //-------------------------------------------------------------------------
102 // Compute the vector v = A*s MOD m. Assume that -m < s[i] < m.
103 // Works also when v = s.
104 //
105 void MatVecModM (const Matrix A, const double s[3], double v[3],
106  double m)
107 {
108  int i;
109  double x[3]; // Necessary if v = s
110 
111  for (i = 0; i < 3; ++i)
112  {
113  x[i] = MultModM (A[i][0], s[0], 0.0, m);
114  x[i] = MultModM (A[i][1], s[1], x[i], m);
115  x[i] = MultModM (A[i][2], s[2], x[i], m);
116  }
117  for (i = 0; i < 3; ++i)
118  {
119  v[i] = x[i];
120  }
121 }
122 
123 
124 //-------------------------------------------------------------------------
125 // Compute the matrix C = A*B MOD m. Assume that -m < s[i] < m.
126 // Note: works also if A = C or B = C or A = B = C.
127 //
128 void MatMatModM (const Matrix A, const Matrix B,
129  Matrix C, double m)
130 {
131  int i, j;
132  double V[3];
133  Matrix W;
134 
135  for (i = 0; i < 3; ++i)
136  {
137  for (j = 0; j < 3; ++j)
138  {
139  V[j] = B[j][i];
140  }
141  MatVecModM (A, V, V, m);
142  for (j = 0; j < 3; ++j)
143  {
144  W[j][i] = V[j];
145  }
146  }
147  for (i = 0; i < 3; ++i)
148  {
149  for (j = 0; j < 3; ++j)
150  {
151  C[i][j] = W[i][j];
152  }
153  }
154 }
155 
156 
157 //-------------------------------------------------------------------------
158 // Compute the matrix B = (A^(2^e) Mod m); works also if A = B.
159 //
160 void MatTwoPowModM (const Matrix src, Matrix dst, double m, int32_t e)
161 {
162  int i, j;
163 
164  /* initialize: dst = src */
165  for (i = 0; i < 3; ++i)
166  {
167  for (j = 0; j < 3; ++j)
168  {
169  dst[i][j] = src[i][j];
170  }
171  }
172  /* Compute dst = src^(2^e) mod m */
173  for (i = 0; i < e; i++)
174  {
175  MatMatModM (dst, dst, dst, m);
176  }
177 }
178 
179 
180 //-------------------------------------------------------------------------
181 // Compute the matrix B = (A^n Mod m); works even if A = B.
182 //
183 void MatPowModM (const double A[3][3], double B[3][3], double m, int32_t n)
184 {
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 // The following are the transition matrices of the two MRG components
215 // (in matrix form), raised to all powers of 2 from 1 to 191
217 {
218  Matrix a1[190];
219  Matrix a2[190];
220 };
222 {
223  struct Precalculated precalculated;
224  for (int i = 0; i < 190; i++)
225  {
226  int power = i + 1;
227  MatTwoPowModM (A1p0, precalculated.a1[i], m1, power);
228  MatTwoPowModM (A2p0, precalculated.a2[i], m2, power);
229  }
230  return precalculated;
231 }
232 void PowerOfTwoMatrix (int n, Matrix a1p, Matrix a2p)
233 {
234  static struct Precalculated constants = PowerOfTwoConstants ();
235  for (int i = 0; i < 3; i ++)
236  {
237  for (int j = 0; j < 3; j++)
238  {
239  a1p[i][j] = constants.a1[n-1][i][j];
240  a2p[i][j] = constants.a2[n-1][i][j];
241  }
242  }
243 }
244 
245 } // end of anonymous namespace
246 
247 
248 namespace ns3 {
249 //-------------------------------------------------------------------------
250 // Generate the next random number.
251 //
253 {
254  int32_t k;
255  double p1, p2, u;
256 
257  /* Component 1 */
258  p1 = a12 * m_currentState[1] - a13n * m_currentState[0];
259  k = static_cast<int32_t> (p1 / m1);
260  p1 -= k * m1;
261  if (p1 < 0.0)
262  {
263  p1 += m1;
264  }
265  m_currentState[0] = m_currentState[1]; m_currentState[1] = m_currentState[2]; m_currentState[2] = p1;
266 
267  /* Component 2 */
268  p2 = a21 * m_currentState[5] - a23n * m_currentState[3];
269  k = static_cast<int32_t> (p2 / m2);
270  p2 -= k * m2;
271  if (p2 < 0.0)
272  {
273  p2 += m2;
274  }
275  m_currentState[3] = m_currentState[4]; m_currentState[4] = m_currentState[5]; m_currentState[5] = p2;
276 
277  /* Combination */
278  u = ((p1 > p2) ? (p1 - p2) * norm : (p1 - p2 + m1) * norm);
279 
280  return u;
281 }
282 
283 RngStream::RngStream (uint32_t seedNumber, uint64_t stream, uint64_t substream)
284 {
285  if (seedNumber >= m1 || seedNumber >= m2 || seedNumber == 0)
286  {
287  NS_FATAL_ERROR ("invalid Seed " << seedNumber);
288  }
289  for (int i = 0; i < 6; ++i)
290  {
291  m_currentState[i] = seedNumber;
292  }
293  AdvanceNthBy (stream, 127, m_currentState);
294  AdvanceNthBy (substream, 76, m_currentState);
295 }
296 
298 {
299  for (int i = 0; i < 6; ++i)
300  {
301  m_currentState[i] = r.m_currentState[i];
302  }
303 }
304 
305 void
306 RngStream::AdvanceNthBy (uint64_t nth, int by, double state[6])
307 {
308  Matrix matrix1,matrix2;
309  for (int i = 0; i < 64; i++)
310  {
311  int nbit = 63 - i;
312  int bit = (nth >> nbit) & 0x1;
313  if (bit)
314  {
315  PowerOfTwoMatrix(by + nbit, matrix1, matrix2);
316  MatVecModM (matrix1, state, state, m1);
317  MatVecModM (matrix2, &state[3], &state[3], m2);
318  }
319  }
320 }
321 
322 } // namespace ns3