Microsimulation API
RngStream.cpp
Go to the documentation of this file.
1 
21 //#include <iostream>
22 //#include <R.h>
23 #include <RngStream.h>
24 
25 namespace ssim {
26 
27 namespace
28 {
29 
30 using namespace std;
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 // The following are the transition matrices of the two MRG components
44 // (in matrix form), raised to the powers -1, 1, 2^76, and 2^127, resp.
45 
46 const double InvA1[3][3] = { // Inverse of A1p0
47  { 184888585.0, 0.0, 1945170933.0 },
48  { 1.0, 0.0, 0.0 },
49  { 0.0, 1.0, 0.0 }
50  };
51 
52 const double InvA2[3][3] = { // Inverse of A2p0
53  { 0.0, 360363334.0, 4225571728.0 },
54  { 1.0, 0.0, 0.0 },
55  { 0.0, 1.0, 0.0 }
56  };
57 
58 const double A1p0[3][3] = {
59  { 0.0, 1.0, 0.0 },
60  { 0.0, 0.0, 1.0 },
61  { -810728.0, 1403580.0, 0.0 }
62  };
63 
64 const double A2p0[3][3] = {
65  { 0.0, 1.0, 0.0 },
66  { 0.0, 0.0, 1.0 },
67  { -1370589.0, 0.0, 527612.0 }
68  };
69 
70 const double A1p76[3][3] = {
71  { 82758667.0, 1871391091.0, 4127413238.0 },
72  { 3672831523.0, 69195019.0, 1871391091.0 },
73  { 3672091415.0, 3528743235.0, 69195019.0 }
74  };
75 
76 const double A2p76[3][3] = {
77  { 1511326704.0, 3759209742.0, 1610795712.0 },
78  { 4292754251.0, 1511326704.0, 3889917532.0 },
79  { 3859662829.0, 4292754251.0, 3708466080.0 }
80  };
81 
82 const double A1p127[3][3] = {
83  { 2427906178.0, 3580155704.0, 949770784.0 },
84  { 226153695.0, 1230515664.0, 3580155704.0 },
85  { 1988835001.0, 986791581.0, 1230515664.0 }
86  };
87 
88 const double A2p127[3][3] = {
89  { 1464411153.0, 277697599.0, 1610723613.0 },
90  { 32183930.0, 1464411153.0, 1022607788.0 },
91  { 2824425944.0, 32183930.0, 2093834863.0 }
92  };
93 
94 const double InvA1p76[3][3] = {
95 { 2585822061.0, 2346541846.0, 600781890.0},
96 { 42385315.0, 4257896290.0, 2346541846.0},
97 { 1248824805.0, 2390631828.0, 4257896290.0}
98 };
99 
100 const double InvA2p76[3][3] = {
101 { 855407695.0, 4134906251.0, 112088500.0},
102 { 2897599610.0, 855407695.0, 1987588141.0},
103 { 854109890.0, 2897599610.0, 1099731892.0}
104 };
105 
106 const double InvA1p127[3][3] = {
107 { 1737602145.0, 4223429791.0, 3623540388.0},
108 { 296220492.0, 2329649265.0, 4223429791.0},
109 { 2348335727.0, 4013827785.0, 2329649265.0}
110 };
111 
112 const double InvA2p127[3][3] = {
113 { 3244453311.0, 924928292.0, 95182267.0},
114 { 3169310862.0, 3244453311.0, 3740757140.0},
115 { 2096686917.0, 3169310862.0, 2895877872.0}
116 };
117 
118 
119 //-------------------------------------------------------------------------
120 // Return (a*s + c) MOD m; a, s, c and m must be < 2^35
121 //
122 double MultModM (double a, double s, double c, double m)
123 {
124  double v;
125  int32_t a1;
126 
127  v = a * s + c;
128 
129  if (v >= two53 || v <= -two53) {
130  a1 = static_cast<int32_t> (a / two17); a -= a1 * two17;
131  v = a1 * s;
132  a1 = static_cast<int32_t> (v / m); v -= a1 * m;
133  v = v * two17 + a * s + c;
134  }
135 
136  a1 = static_cast<int32_t> (v / m);
137  /* in case v < 0)*/
138  if ((v -= a1 * m) < 0.0) return v += m; else return v;
139 }
140 
141 
142 //-------------------------------------------------------------------------
143 // Compute the vector v = A*s MOD m. Assume that -m < s[i] < m.
144 // Works also when v = s.
145 //
146 void MatVecModM (const double A[3][3], const double s[3], double v[3],
147  double m)
148 {
149  int i;
150  double x[3]; // Necessary if v = s
151 
152  for (i = 0; i < 3; ++i) {
153  x[i] = MultModM (A[i][0], s[0], 0.0, m);
154  x[i] = MultModM (A[i][1], s[1], x[i], m);
155  x[i] = MultModM (A[i][2], s[2], x[i], m);
156  }
157  for (i = 0; i < 3; ++i)
158  v[i] = x[i];
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 void MatMatModM (const double A[3][3], const double B[3][3],
167  double C[3][3], double m)
168 {
169  int i, j;
170  double V[3], W[3][3];
171 
172  for (i = 0; i < 3; ++i) {
173  for (j = 0; j < 3; ++j)
174  V[j] = B[j][i];
175  MatVecModM (A, V, V, m);
176  for (j = 0; j < 3; ++j)
177  W[j][i] = V[j];
178  }
179  for (i = 0; i < 3; ++i)
180  for (j = 0; j < 3; ++j)
181  C[i][j] = W[i][j];
182 }
183 
184 
185 //-------------------------------------------------------------------------
186 // Compute the matrix B = (A^(2^e) Mod m); works also if A = B.
187 //
188 void MatTwoPowModM (const double A[3][3], double B[3][3], double m, int32_t e)
189 {
190  int i, j;
191 
192  /* initialize: B = A */
193  if (A != B) {
194  for (i = 0; i < 3; ++i)
195  for (j = 0; j < 3; ++j)
196  B[i][j] = A[i][j];
197  }
198  /* Compute B = A^(2^e) mod m */
199  for (i = 0; i < e; i++)
200  MatMatModM (B, B, B, m);
201 }
202 
203 
204 //-------------------------------------------------------------------------
205 // Compute the matrix B = (A^n Mod m); works even if A = B.
206 //
207 void MatPowModM (const double A[3][3], double B[3][3], double m, int32_t n)
208 {
209  int i, j;
210  double W[3][3];
211 
212  /* initialize: W = A; B = I */
213  for (i = 0; i < 3; ++i)
214  for (j = 0; j < 3; ++j) {
215  W[i][j] = A[i][j];
216  B[i][j] = 0.0;
217  }
218  for (j = 0; j < 3; ++j)
219  B[j][j] = 1.0;
220 
221  /* Compute B = A^n mod m using the binary decomposition of n */
222  while (n > 0) {
223  if (n % 2) MatMatModM (W, B, B, m);
224  MatMatModM (W, W, W, m);
225  n /= 2;
226  }
227 }
228 
229 
230 //-------------------------------------------------------------------------
231 // Check that the seeds are legitimate values. Returns 0 if legal seeds,
232 // -1 otherwise.
233 //
234 int CheckSeed (const double seed[6])
235 {
236  int i;
237 
238  for (i = 0; i < 3; ++i) {
239  if (seed[i] >= m1) {
240  // REprintf("****************************************\n");
241  // REprintf("ERROR: Seed[%i] >= 4294967087, Seed is not set.",i);
242  // REprintf("\n****************************************\n\n");
243  return (-1);
244  }
245  }
246  for (i = 3; i < 6; ++i) {
247  if (seed[i] >= m2) {
248  // REprintf("*****************************************\n");
249  // REprintf("ERROR: Seed[%i] >= 4294944443, Seed is not set.",i);
250  // REprintf("\n*****************************************\n\n");
251  return (-1);
252  }
253  }
254  if (seed[0] == 0 && seed[1] == 0 && seed[2] == 0) {
255  // REprintf("****************************\n");
256  // REprintf("ERROR: First 3 seeds = 0.\n");
257  // REprintf("****************************\n\n");
258  return (-1);
259  }
260  if (seed[3] == 0 && seed[4] == 0 && seed[5] == 0) {
261  // REprintf("****************************\n");
262  // REprintf("ERROR: Last 3 seeds = 0.\n");
263  // REprintf("****************************\n\n");
264  return (-1);
265  }
266 
267  return 0;
268 }
269 
270 } // end of anonymous namespace
271 
272 
273 //-------------------------------------------------------------------------
274 // Generate the next random number.
275 //
276 double RngStream::U01 ()
277 {
278  int32_t k;
279  double p1, p2, u;
280 
281  /* Component 1 */
282  p1 = a12 * Cg[1] - a13n * Cg[0];
283  k = static_cast<int32_t> (p1 / m1);
284  p1 -= k * m1;
285  if (p1 < 0.0) p1 += m1;
286  Cg[0] = Cg[1]; Cg[1] = Cg[2]; Cg[2] = p1;
287 
288  /* Component 2 */
289  p2 = a21 * Cg[5] - a23n * Cg[3];
290  k = static_cast<int32_t> (p2 / m2);
291  p2 -= k * m2;
292  if (p2 < 0.0) p2 += m2;
293  Cg[3] = Cg[4]; Cg[4] = Cg[5]; Cg[5] = p2;
294 
295  /* Combination */
296  u = ((p1 > p2) ? (p1 - p2) * norm : (p1 - p2 + m1) * norm);
297 
298  return (anti == false) ? u : (1 - u);
299 }
300 
301 
302 //-------------------------------------------------------------------------
303 // Generate the next random number with extended (53 bits) precision.
304 //
305 double RngStream::U01d ()
306 {
307  double u;
308  u = U01();
309  if (anti) {
310  // Don't forget that U01() returns 1 - u in the antithetic case
311  u += (U01() - 1.0) * fact;
312  return (u < 0.0) ? u + 1.0 : u;
313  } else {
314  u += U01() * fact;
315  return (u < 1.0) ? u : (u - 1.0);
316  }
317 }
318 
319 
320 //*************************************************************************
321 // Public members of the class start here
322 
323 
324 //-------------------------------------------------------------------------
325 // The default seed of the package; will be the seed of the first
326 // declared RngStream, unless SetPackageSeed is called.
327 //
328 double RngStream::nextSeed[6] =
329 {
330  12345.0, 12345.0, 12345.0, 12345.0, 12345.0, 12345.0
331 };
332 
333 
334 //-------------------------------------------------------------------------
335 // constructor
336 //
337 RngStream::RngStream (const char *s) : name (s)
338 {
339  anti = false;
340  incPrec = false;
341 
342  /* Information on a stream. The arrays {Cg, Bg, Ig} contain the current
343  state of the stream, the starting state of the current SubStream, and the
344  starting state of the stream. This stream generates antithetic variates
345  if anti = true. It also generates numbers with extended precision (53
346  bits if machine follows IEEE 754 standard) if incPrec = true. nextSeed
347  will be the seed of the next declared RngStream. */
348 
349  for (int i = 0; i < 6; ++i) {
350  Bg[i] = Cg[i] = Ig[i] = nextSeed[i];
351  }
352 
353  MatVecModM (A1p127, nextSeed, nextSeed, m1);
354  MatVecModM (A2p127, &nextSeed[3], &nextSeed[3], m2);
355 }
356 
357 
358 //-------------------------------------------------------------------------
359 // Reset Stream to beginning of Stream.
360 //
362 {
363  for (int i = 0; i < 6; ++i)
364  Cg[i] = Bg[i] = Ig[i];
365 }
366 
367 
368 //-------------------------------------------------------------------------
369 // Reset Stream to beginning of SubStream.
370 //
372 {
373  for (int i = 0; i < 6; ++i)
374  Cg[i] = Bg[i];
375 }
376 
377 
378 //-------------------------------------------------------------------------
379 // Reset Stream to NextSubStream.
380 //
382 {
383  MatVecModM(A1p76, Bg, Bg, m1);
384  MatVecModM(A2p76, &Bg[3], &Bg[3], m2);
385  for (int i = 0; i < 6; ++i)
386  Cg[i] = Bg[i];
387 }
388 
389 
390 //-------------------------------------------------------------------------
391 bool RngStream::SetPackageSeed (const double seed[6])
392 {
393  if (CheckSeed (seed))
394  return false; // FAILURE
395  for (int i = 0; i < 6; ++i)
396  nextSeed[i] = seed[i];
397  return true; // SUCCESS
398 }
399 
400 
401 //-------------------------------------------------------------------------
402 bool RngStream::SetSeed (const double seed[6])
403 {
404  if (CheckSeed (seed))
405  return false; // FAILURE
406  for (int i = 0; i < 6; ++i)
407  Cg[i] = Bg[i] = Ig[i] = seed[i];
408  return true; // SUCCESS
409 }
410 
411 
412 //-------------------------------------------------------------------------
413 // if e > 0, let n = 2^e + c;
414 // if e < 0, let n = -2^(-e) + c;
415 // if e = 0, let n = c.
416 // Jump n steps forward if n > 0, backwards if n < 0.
417 //
418 void RngStream::GenAdvanceState (int32_t e, int32_t c,
419  const double A1[3][3], const double A2[3][3],
420  const double InvA1[3][3], const double InvA2[3][3])
421 {
422  double B1[3][3], C1[3][3], B2[3][3], C2[3][3];
423 
424  if (e > 0) {
425  MatTwoPowModM (A1, B1, m1, e);
426  MatTwoPowModM (A2, B2, m2, e);
427  } else if (e < 0) {
428  MatTwoPowModM (InvA1, B1, m1, -e);
429  MatTwoPowModM (InvA2, B2, m2, -e);
430  }
431 
432  if (c >= 0) {
433  MatPowModM (A1, C1, m1, c);
434  MatPowModM (A2, C2, m2, c);
435  } else {
436  MatPowModM (InvA1, C1, m1, -c);
437  MatPowModM (InvA2, C2, m2, -c);
438  }
439 
440  if (e) {
441  MatMatModM (B1, C1, C1, m1);
442  MatMatModM (B2, C2, C2, m2);
443  }
444 
445  MatVecModM (C1, Cg, Cg, m1);
446  MatVecModM (C2, &Cg[3], &Cg[3], m2);
447 }
448 
449 
450 void RngStream::AdvanceState (int32_t e, int32_t c) {
451  GenAdvanceState(e, c, A1p0, A2p0, InvA1, InvA2);
452 }
453 
454 void RngStream::AdvanceSubstream (int32_t e, int32_t c) {
455  GenAdvanceState(e, c, A1p76, A2p76, InvA1p76, InvA2p76);
456  for (int i = 0; i < 6; ++i)
457  Bg[i] = Cg[i];
458 }
459 
460 void RngStream::AdvanceStream (int32_t e, int32_t c) {
461  GenAdvanceState(e, c, A1p127, A2p127, InvA1p127, InvA2p127);
462  for (int i = 0; i < 6; ++i)
463  Ig[i] = Bg[i] = Cg[i];
464 }
465 
466 
467 void RngStream::CalcMatrix (int32_t e, int32_t c, double C1[3][3], double C2[3][3])
468 {
469  double B1[3][3], B2[3][3];
470 
471  if (e > 0) {
472  MatTwoPowModM (A1p0, B1, m1, e);
473  MatTwoPowModM (A2p0, B2, m2, e);
474  }
475  else if (e < 0) {
476  MatTwoPowModM (InvA1, B1, m1, -e);
477  MatTwoPowModM (InvA2, B2, m2, -e);
478  }
479 
480  if (c >= 0) {
481  MatPowModM (A1p0, C1, m1, c);
482  MatPowModM (A2p0, C2, m2, c);
483  }
484  else {
485  MatPowModM (InvA1, C1, m1, -c);
486  MatPowModM (InvA2, C2, m2, -c);
487  }
488 
489  if (e) {
490  MatMatModM (B1, C1, C1, m1);
491  MatMatModM (B2, C2, C2, m2);
492  }
493 }
494 
495 //-------------------------------------------------------------------------
496 void RngStream::GetState (double seed[6]) const
497 {
498  for (int i = 0; i < 6; ++i)
499  seed[i] = Cg[i];
500 }
501 
502 
503 //-------------------------------------------------------------------------
504 // void RngStream::WriteState () const
505 // {
506 // std::cout << "The current state of the Rngstream";
507 // if (name.size() > 0)
508 // std::cout << " " << name;
509 // std::cout << ":\n Cg = { ";
510 
511 // for (int i = 0; i < 5; i++) {
512 // std::cout << static_cast<unsigned long> (Cg [i]) << ", ";
513 // }
514 // std::cout << static_cast<unsigned long> (Cg [5]) << " }\n\n";
515 // }
516 
517 
518 //-------------------------------------------------------------------------
519 // void RngStream::WriteStateFull () const
520 // {
521 // int i;
522 
523 // std::cout << "The RngStream";
524 // if (name.size() > 0)
525 // cout << " " << name;
526 // std::cout << ":\n anti = " << (anti ? "true" : "false") << "\n";
527 // std::cout << " incPrec = " << (incPrec ? "true" : "false") << "\n";
528 
529 // std::cout << " Ig = { ";
530 // for (i = 0; i < 5; i++) {
531 // std::cout << static_cast<unsigned long> (Ig [i]) << ", ";
532 // }
533 // std::cout << static_cast<unsigned long> (Ig [5]) << " }\n";
534 
535 // std::cout << " Bg = { ";
536 // for (i = 0; i < 5; i++) {
537 // std::cout << static_cast<unsigned long> (Bg [i]) << ", ";
538 // }
539 // std::cout << static_cast<unsigned long> (Bg [5]) << " }\n";
540 
541 // std::cout << " Cg = { ";
542 // for (i = 0; i < 5; i++) {
543 // std::cout << static_cast<unsigned long> (Cg [i]) << ", ";
544 // }
545 // std::cout << static_cast<unsigned long> (Cg [5]) << " }\n\n";
546 // }
547 
548 
549 //-------------------------------------------------------------------------
550 void RngStream::IncreasedPrecis (bool incp)
551 {
552  incPrec = incp;
553 }
554 
555 
556 //-------------------------------------------------------------------------
557 void RngStream::SetAntithetic (bool a)
558 {
559  anti = a;
560 }
561 
562 
563 //-------------------------------------------------------------------------
564 // Generate the next random number.
565 //
566 double RngStream::RandU01 ()
567 {
568  if (incPrec)
569  return U01d();
570  else
571  return U01();
572 }
573 
574 
575 //-------------------------------------------------------------------------
576 // Generate the next random integer.
577 //
578 int RngStream::RandInt (int low, int high)
579 {
580  return low + static_cast<int> ((high - low + 1.0) * RandU01 ());
581 }
582 
583 } // namespace ssim;
ssim::RngStream::U01d
double U01d()
Definition: RngStream.cpp:305
ssim::RngStream::RngStream
RngStream(const char *name="")
Definition: RngStream.cpp:337
ssim::RngStream::Cg
double Cg[6]
Definition: RngStream.h:93
ssim::RngStream::SetPackageSeed
static bool SetPackageSeed(const double seed[6])
Definition: RngStream.cpp:391
RngStream.h
ssim::RngStream::AdvanceSubstream
void AdvanceSubstream(int32_t e, int32_t c)
Definition: RngStream.cpp:454
ssim::RngStream::nextSeed
static double nextSeed[6]
Definition: RngStream.h:102
ssim::RngStream::CalcMatrix
void CalcMatrix(int32_t e, int32_t c, double C1[3][3], double C2[3][3])
Definition: RngStream.cpp:467
ssim::RngStream::AdvanceStream
void AdvanceStream(int32_t e, int32_t c)
Definition: RngStream.cpp:460
ssim::RngStream::ResetStartStream
void ResetStartStream()
Definition: RngStream.cpp:361
ssim::RngStream::GenAdvanceState
void GenAdvanceState(int32_t e, int32_t c, const double A1[3][3], const double A2[3][3], const double InvA1[3][3], const double InvA2[3][3])
Definition: RngStream.cpp:418
ssim::RngStream::RandInt
int RandInt(int i, int j)
Definition: RngStream.cpp:578
ssim::RngStream::U01
double U01()
Definition: RngStream.cpp:276
ssim::RngStream::SetSeed
bool SetSeed(const double seed[6])
Definition: RngStream.cpp:402
ssim::RngStream::ResetNextSubstream
void ResetNextSubstream()
Definition: RngStream.cpp:381
ssim::RngStream::GetState
void GetState(double seed[6]) const
Definition: RngStream.cpp:496
ssim::RngStream::incPrec
bool incPrec
Definition: RngStream.h:96
ssim::RngStream::Ig
double Ig[6]
Definition: RngStream.h:93
ssim::RngStream::anti
bool anti
Definition: RngStream.h:96
ssim::RngStream::ResetStartSubstream
void ResetStartSubstream()
Definition: RngStream.cpp:371
ssim
name space for the Siena simulator.
Definition: microsimulation.cc:3
ssim::RngStream::RandU01
double RandU01()
Definition: RngStream.cpp:566
ssim::RngStream::IncreasedPrecis
void IncreasedPrecis(bool incp)
Definition: RngStream.cpp:550
ssim::RngStream::Bg
double Bg[6]
Definition: RngStream.h:93
ssim::RngStream::SetAntithetic
void SetAntithetic(bool a)
Definition: RngStream.cpp:557
ssim::RngStream::AdvanceState
void AdvanceState(int32_t e, int32_t c)
Definition: RngStream.cpp:450