Scythe-1.0.3
|
00001 /* 00002 * Scythe Statistical Library 00003 * Copyright (C) 2000-2002 Andrew D. Martin and Kevin M. Quinn; 00004 * 2002-present Andrew D. Martin, Kevin M. Quinn, and Daniel 00005 * Pemstein. All Rights Reserved. 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * under the terms of the GNU General Public License as published by 00009 * Free Software Foundation; either version 2 of the License, or (at 00010 * your option) any later version. See the text files COPYING 00011 * and LICENSE, distributed with this source code, for further 00012 * information. 00013 * -------------------------------------------------------------------- 00014 * scythestat/rng/lecuyer.h 00015 * 00016 * Provides the class definition for the L'Ecuyer random number 00017 * generator, a rng capable of generating many independent substreams. 00018 * This class extends the abstract rng class by implementing runif(). 00019 * Based on RngStream.cpp, by Pierre L'Ecuyer. 00020 * 00021 * Pierre L'Ecuyer agreed to the following dual-licensing terms in an 00022 * email received 7 August 2004. This dual-license was prompted by 00023 * the Debian maintainers of R and MCMCpack. 00024 * 00025 * This software is Copyright (C) 2004 Pierre L'Ecuyer. 00026 * 00027 * License: this code can be used freely for personal, academic, or 00028 * non-commercial purposes. For commercial licensing, please contact 00029 * P. L'Ecuyer at lecuyer@iro.umontreal.ca. 00030 * 00031 * This code may also be redistributed and modified under the terms of 00032 * the GNU General Public License as published by the Free Software 00033 * Foundation; either version 2 of the License, or (at your option) any 00034 * later version. 00035 * 00036 * This program is distributed in the hope that it will be useful, but 00037 * WITHOUT ANY WARRANTY; without even the implied warranty of 00038 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00039 * General Public License for more details. 00040 * 00041 * You should have received a copy of the GNU General Public License 00042 * along with this program; if not, write to the Free Software 00043 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 00044 * USA. 00045 * 00046 */ 00055 #ifndef SCYTHE_LECUYER_H 00056 #define SCYTHE_LECUYER_H 00057 00058 #include<cstdlib> 00059 #include<iostream> 00060 #include<string> 00061 00062 #ifdef SCYTHE_COMPILE_DIRECT 00063 #include "rng.h" 00064 #else 00065 #include "scythestat/rng.h" 00066 #endif 00067 00068 /* We want to use an anonymous namespace to make the following consts 00069 * and functions local to this file, but mingw doesn't play nice with 00070 * anonymous namespaces so we do things differently when using the 00071 * cross-compiler. 00072 */ 00073 #ifdef __MINGW32__ 00074 #define SCYTHE_MINGW32_STATIC static 00075 #else 00076 #define SCYTHE_MINGW32_STATIC 00077 #endif 00078 00079 namespace scythe { 00080 #ifndef __MINGW32__ 00081 namespace { 00082 #endif 00083 00084 SCYTHE_MINGW32_STATIC const double m1 = 4294967087.0; 00085 SCYTHE_MINGW32_STATIC const double m2 = 4294944443.0; 00086 SCYTHE_MINGW32_STATIC const double norm = 1.0 / (m1 + 1.0); 00087 SCYTHE_MINGW32_STATIC const double a12 = 1403580.0; 00088 SCYTHE_MINGW32_STATIC const double a13n = 810728.0; 00089 SCYTHE_MINGW32_STATIC const double a21 = 527612.0; 00090 SCYTHE_MINGW32_STATIC const double a23n = 1370589.0; 00091 SCYTHE_MINGW32_STATIC const double two17 =131072.0; 00092 SCYTHE_MINGW32_STATIC const double two53 =9007199254740992.0; 00093 /* 1/2^24 */ 00094 SCYTHE_MINGW32_STATIC const double fact = 5.9604644775390625e-8; 00095 00096 // The following are the transition matrices of the two MRG 00097 // components (in matrix form), raised to the powers -1, 1, 2^76, 00098 // and 2^127, resp. 00099 00100 SCYTHE_MINGW32_STATIC const double InvA1[3][3] = { // Inverse of A1p0 00101 { 184888585.0, 0.0, 1945170933.0 }, 00102 { 1.0, 0.0, 0.0 }, 00103 { 0.0, 1.0, 0.0 } }; 00104 00105 SCYTHE_MINGW32_STATIC const double InvA2[3][3] = { // Inverse of A2p0 00106 { 0.0, 360363334.0, 4225571728.0 }, 00107 { 1.0, 0.0, 0.0 }, 00108 { 0.0, 1.0, 0.0 } }; 00109 00110 SCYTHE_MINGW32_STATIC const double A1p0[3][3] = { 00111 { 0.0, 1.0, 0.0 }, 00112 { 0.0, 0.0, 1.0 }, 00113 { -810728.0, 1403580.0, 0.0 } }; 00114 00115 SCYTHE_MINGW32_STATIC const double A2p0[3][3] = { 00116 { 0.0, 1.0, 0.0 }, 00117 { 0.0, 0.0, 1.0 }, 00118 { -1370589.0, 0.0, 527612.0 } }; 00119 00120 SCYTHE_MINGW32_STATIC const double A1p76[3][3] = { 00121 { 82758667.0, 1871391091.0, 4127413238.0 }, 00122 { 3672831523.0, 69195019.0, 1871391091.0 }, 00123 { 3672091415.0, 3528743235.0, 69195019.0 } }; 00124 00125 SCYTHE_MINGW32_STATIC const double A2p76[3][3] = { 00126 { 1511326704.0, 3759209742.0, 1610795712.0 }, 00127 { 4292754251.0, 1511326704.0, 3889917532.0 }, 00128 { 3859662829.0, 4292754251.0, 3708466080.0 } }; 00129 00130 SCYTHE_MINGW32_STATIC const double A1p127[3][3] = { 00131 { 2427906178.0, 3580155704.0, 949770784.0 }, 00132 { 226153695.0, 1230515664.0, 3580155704.0 }, 00133 { 1988835001.0, 986791581.0, 1230515664.0 } }; 00134 00135 SCYTHE_MINGW32_STATIC const double A2p127[3][3] = { 00136 { 1464411153.0, 277697599.0, 1610723613.0 }, 00137 { 32183930.0, 1464411153.0, 1022607788.0 }, 00138 { 2824425944.0, 32183930.0, 2093834863.0 } }; 00139 00140 // Return (a*s + c) MOD m; a, s, c and m must be < 2^35 00141 SCYTHE_MINGW32_STATIC double 00142 MultModM (double a, double s, double c, double m) 00143 { 00144 double v; 00145 long a1; 00146 00147 v = a * s + c; 00148 00149 if (v >= two53 || v <= -two53) { 00150 a1 = static_cast<long> (a / two17); a -= a1 * two17; 00151 v = a1 * s; 00152 a1 = static_cast<long> (v / m); v -= a1 * m; 00153 v = v * two17 + a * s + c; 00154 } 00155 00156 a1 = static_cast<long> (v / m); 00157 /* in case v < 0)*/ 00158 if ((v -= a1 * m) < 0.0) return v += m; else return v; 00159 } 00160 00161 // Compute the vector v = A*s MOD m. Assume that -m < s[i] < m. 00162 // Works also when v = s. 00163 SCYTHE_MINGW32_STATIC void 00164 MatVecModM (const double A[3][3], const double s[3], 00165 double v[3], double m) 00166 { 00167 int i; 00168 double x[3]; // Necessary if v = s 00169 00170 for (i = 0; i < 3; ++i) { 00171 x[i] = MultModM (A[i][0], s[0], 0.0, m); 00172 x[i] = MultModM (A[i][1], s[1], x[i], m); 00173 x[i] = MultModM (A[i][2], s[2], x[i], m); 00174 } 00175 for (i = 0; i < 3; ++i) 00176 v[i] = x[i]; 00177 } 00178 00179 // Compute the matrix C = A*B MOD m. Assume that -m < s[i] < m. 00180 // Note: works also if A = C or B = C or A = B = C. 00181 SCYTHE_MINGW32_STATIC void 00182 MatMatModM (const double A[3][3], const double B[3][3], 00183 double C[3][3], double m) 00184 { 00185 int i, j; 00186 double V[3], W[3][3]; 00187 00188 for (i = 0; i < 3; ++i) { 00189 for (j = 0; j < 3; ++j) 00190 V[j] = B[j][i]; 00191 MatVecModM (A, V, V, m); 00192 for (j = 0; j < 3; ++j) 00193 W[j][i] = V[j]; 00194 } 00195 for (i = 0; i < 3; ++i) 00196 for (j = 0; j < 3; ++j) 00197 C[i][j] = W[i][j]; 00198 } 00199 00200 // Compute the matrix B = (A^(2^e) Mod m); works also if A = B. 00201 SCYTHE_MINGW32_STATIC void 00202 MatTwoPowModM(const double A[3][3], double B[3][3], 00203 double m, long e) 00204 { 00205 int i, j; 00206 00207 /* initialize: B = A */ 00208 if (A != B) { 00209 for (i = 0; i < 3; ++i) 00210 for (j = 0; j < 3; ++j) 00211 B[i][j] = A[i][j]; 00212 } 00213 /* Compute B = A^(2^e) mod m */ 00214 for (i = 0; i < e; i++) 00215 MatMatModM (B, B, B, m); 00216 } 00217 00218 // Compute the matrix B = (A^n Mod m); works even if A = B. 00219 SCYTHE_MINGW32_STATIC void 00220 MatPowModM (const double A[3][3], double B[3][3], double m, 00221 long n) 00222 { 00223 int i, j; 00224 double W[3][3]; 00225 00226 /* initialize: W = A; B = I */ 00227 for (i = 0; i < 3; ++i) 00228 for (j = 0; j < 3; ++j) { 00229 W[i][j] = A[i][j]; 00230 B[i][j] = 0.0; 00231 } 00232 for (j = 0; j < 3; ++j) 00233 B[j][j] = 1.0; 00234 00235 /* Compute B = A^n mod m using the binary decomposition of n */ 00236 while (n > 0) { 00237 if (n % 2) MatMatModM (W, B, B, m); 00238 MatMatModM (W, W, W, m); 00239 n /= 2; 00240 } 00241 } 00242 00243 // Check that the seeds are legitimate values. Returns 0 if legal 00244 // seeds, -1 otherwise. 00245 SCYTHE_MINGW32_STATIC int 00246 CheckSeed (const unsigned long seed[6]) 00247 { 00248 int i; 00249 00250 for (i = 0; i < 3; ++i) { 00251 if (seed[i] >= m1) { 00252 SCYTHE_THROW(scythe_randseed_error, 00253 "Seed[" << i << "] >= 4294967087, Seed is not set"); 00254 return -1; 00255 } 00256 } 00257 for (i = 3; i < 6; ++i) { 00258 if (seed[i] >= m2) { 00259 SCYTHE_THROW(scythe_randseed_error, 00260 "Seed[" << i << "] >= 4294944443, Seed is not set"); 00261 return -1; 00262 } 00263 } 00264 if (seed[0] == 0 && seed[1] == 0 && seed[2] == 0) { 00265 SCYTHE_THROW(scythe_randseed_error, "First 3 seeds = 0"); 00266 return -1; 00267 } 00268 if (seed[3] == 0 && seed[4] == 0 && seed[5] == 0) { 00269 SCYTHE_THROW(scythe_randseed_error, "Last 3 seeds = 0"); 00270 return -1; 00271 } 00272 00273 return 0; 00274 } 00275 00276 #ifndef __MINGW32__ 00277 } // end anonymous namespace 00278 #endif 00279 00298 class lecuyer : public rng<lecuyer> 00299 { 00300 public: 00301 00302 // Constructor 00320 lecuyer (std::string streamname = "") 00321 : rng<lecuyer> (), 00322 streamname_ (streamname) 00323 { 00324 anti = false; 00325 incPrec = false; 00326 00327 /* Information on a stream. The arrays {Cg, Bg, Ig} contain 00328 * the current state of the stream, the starting state of the 00329 * current SubStream, and the starting state of the stream. 00330 * This stream generates antithetic variates if anti = true. 00331 * It also generates numbers with extended precision (53 bits 00332 * if machine follows IEEE 754 standard) if incPrec = true. 00333 * nextSeed will be the seed of the next declared RngStream. 00334 */ 00335 00336 for (int i = 0; i < 6; ++i) { 00337 Bg[i] = Cg[i] = Ig[i] = nextSeed[i]; 00338 } 00339 00340 MatVecModM (A1p127, nextSeed, nextSeed, m1); 00341 MatVecModM (A2p127, &nextSeed[3], &nextSeed[3], m2); 00342 } 00343 00350 std::string 00351 name() const 00352 { 00353 return streamname_; 00354 } 00355 00364 void 00365 ResetStartStream () 00366 { 00367 for (int i = 0; i < 6; ++i) 00368 Cg[i] = Bg[i] = Ig[i]; 00369 } 00370 00382 void 00383 ResetStartSubstream () 00384 { 00385 for (int i = 0; i < 6; ++i) 00386 Cg[i] = Bg[i]; 00387 } 00388 00399 void 00400 ResetNextSubstream () 00401 { 00402 MatVecModM(A1p76, Bg, Bg, m1); 00403 MatVecModM(A2p76, &Bg[3], &Bg[3], m2); 00404 for (int i = 0; i < 6; ++i) 00405 Cg[i] = Bg[i]; 00406 } 00407 00424 static void 00425 SetPackageSeed (unsigned long seed[6]) 00426 { 00427 if (CheckSeed (seed)) return; 00428 for (int i = 0; i < 6; ++i) 00429 nextSeed[i] = seed[i]; 00430 } 00431 00454 void 00455 SetSeed (unsigned long seed[6]) 00456 { 00457 if (CheckSeed (seed)) return; 00458 for (int i = 0; i < 6; ++i) 00459 Cg[i] = Bg[i] = Ig[i] = seed[i]; 00460 } 00461 00462 // XXX: get the cases formula working! 00483 void 00484 AdvanceState (long e, long c) 00485 { 00486 double B1[3][3], C1[3][3], B2[3][3], C2[3][3]; 00487 00488 if (e > 0) { 00489 MatTwoPowModM (A1p0, B1, m1, e); 00490 MatTwoPowModM (A2p0, B2, m2, e); 00491 } else if (e < 0) { 00492 MatTwoPowModM (InvA1, B1, m1, -e); 00493 MatTwoPowModM (InvA2, B2, m2, -e); 00494 } 00495 00496 if (c >= 0) { 00497 MatPowModM (A1p0, C1, m1, c); 00498 MatPowModM (A2p0, C2, m2, c); 00499 } else { 00500 MatPowModM (InvA1, C1, m1, -c); 00501 MatPowModM (InvA2, C2, m2, -c); 00502 } 00503 00504 if (e) { 00505 MatMatModM (B1, C1, C1, m1); 00506 MatMatModM (B2, C2, C2, m2); 00507 } 00508 00509 MatVecModM (C1, Cg, Cg, m1); 00510 MatVecModM (C2, &Cg[3], &Cg[3], m2); 00511 } 00512 00524 void 00525 GetState (unsigned long seed[6]) const 00526 { 00527 for (int i = 0; i < 6; ++i) 00528 seed[i] = static_cast<unsigned long> (Cg[i]); 00529 } 00530 00547 void 00548 IncreasedPrecis (bool incp) 00549 { 00550 incPrec = incp; 00551 } 00552 00565 void 00566 SetAntithetic (bool a) 00567 { 00568 anti = a; 00569 } 00570 00582 double 00583 runif () 00584 { 00585 if (incPrec) 00586 return U01d(); 00587 else 00588 return U01(); 00589 } 00590 00591 /* We have to override the overloaded form of runif because 00592 * overloading the no-arg runif() hides the base class 00593 * definition; C++ stops looking once it finds the above. 00594 */ 00616 template <matrix_order O, matrix_style S> 00617 Matrix<double,O,S> runif(unsigned int rows, unsigned int cols) 00618 { 00619 return rng<lecuyer>::runif<O,S>(rows,cols); 00620 } 00621 00643 Matrix<double,Col,Concrete> runif(unsigned int rows, 00644 unsigned int cols) 00645 { 00646 return rng<lecuyer>::runif<Col,Concrete>(rows, cols); 00647 } 00648 00659 long 00660 RandInt (long low, long high) 00661 { 00662 return low + static_cast<long> ((high - low + 1) * runif ()); 00663 } 00664 00665 protected: 00666 // Generate the next random number. 00667 // 00668 double 00669 U01 () 00670 { 00671 long k; 00672 double p1, p2, u; 00673 00674 /* Component 1 */ 00675 p1 = a12 * Cg[1] - a13n * Cg[0]; 00676 k = static_cast<long> (p1 / m1); 00677 p1 -= k * m1; 00678 if (p1 < 0.0) p1 += m1; 00679 Cg[0] = Cg[1]; Cg[1] = Cg[2]; Cg[2] = p1; 00680 00681 /* Component 2 */ 00682 p2 = a21 * Cg[5] - a23n * Cg[3]; 00683 k = static_cast<long> (p2 / m2); 00684 p2 -= k * m2; 00685 if (p2 < 0.0) p2 += m2; 00686 Cg[3] = Cg[4]; Cg[4] = Cg[5]; Cg[5] = p2; 00687 00688 /* Combination */ 00689 u = ((p1 > p2) ? (p1 - p2) * norm : (p1 - p2 + m1) * norm); 00690 00691 return (anti == false) ? u : (1 - u); 00692 } 00693 00694 // Generate the next random number with extended (53 bits) precision. 00695 double 00696 U01d () 00697 { 00698 double u; 00699 u = U01(); 00700 if (anti) { 00701 // Don't forget that U01() returns 1 - u in the antithetic case 00702 u += (U01() - 1.0) * fact; 00703 return (u < 0.0) ? u + 1.0 : u; 00704 } else { 00705 u += U01() * fact; 00706 return (u < 1.0) ? u : (u - 1.0); 00707 } 00708 } 00709 00710 00711 // Public members of the class start here 00712 00713 // The default seed of the package; will be the seed of the first 00714 // declared RngStream, unless SetPackageSeed is called. 00715 static double nextSeed[6]; 00716 00717 /* Instance variables */ 00718 double Cg[6], Bg[6], Ig[6]; 00719 00720 00721 bool anti, incPrec; 00722 00723 00724 std::string streamname_; 00725 00726 }; 00727 00728 #ifndef SCYTHE_RPACK 00729 /* Default seed definition */ 00730 double lecuyer::nextSeed[6] = 00731 { 00732 12345.0, 12345.0, 12345.0, 12345.0, 12345.0, 12345.0 00733 }; 00734 #endif 00735 00736 } 00737 00738 #endif /* SCYTHE_LECUYER_H */