Scythe-1.0.3
lecuyer.h
Go to the documentation of this file.
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 */