RooQuasiRandomGenerator.cxx

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Project: RooFit                                                           *
00003  * Package: RooFitCore                                                       *
00004  * @(#)root/roofitcore:$Id: RooQuasiRandomGenerator.cxx 24285 2008-06-16 15:05:15Z wouter $
00005  * Authors:                                                                  *
00006  *   WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu       *
00007  *   DK, David Kirkby,    UC Irvine,         dkirkby@uci.edu                 *
00008  *                                                                           *
00009  * Copyright (c) 2000-2005, Regents of the University of California          *
00010  *                          and Stanford University. All rights reserved.    *
00011  *                                                                           *
00012  * Redistribution and use in source and binary forms,                        *
00013  * with or without modification, are permitted according to the terms        *
00014  * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
00015  *****************************************************************************/
00016 
00017 //////////////////////////////////////////////////////////////////////////////
00018 //
00019 // BEGIN_HTML
00020 // This class generates the quasi-random (aka "low discrepancy")
00021 // sequence for dimensions up to 12 using the Niederreiter base 2
00022 // algorithm described in Bratley, Fox, Niederreiter, ACM Trans.
00023 // Model. Comp. Sim. 2, 195 (1992). This implementation was adapted
00024 // from the 0.9 beta release of the GNU scientific library.
00025 // Quasi-random number sequences are useful for improving the
00026 // convergence of a Monte Carlo integration.
00027 // END_HTML
00028 //
00029 
00030 #include "RooFit.h"
00031 
00032 #include "RooQuasiRandomGenerator.h"
00033 #include "RooQuasiRandomGenerator.h"
00034 #include "RooMsgService.h"
00035 #include "TMath.h"
00036 
00037 #include "Riostream.h"
00038 #include <assert.h>
00039 
00040 ClassImp(RooQuasiRandomGenerator)
00041   ;
00042 
00043 
00044 
00045 //_____________________________________________________________________________
00046 RooQuasiRandomGenerator::RooQuasiRandomGenerator() 
00047 {
00048   // Perform one-time initialization of our static coefficient array if necessary
00049   // and initialize our workspace.
00050   
00051   if(!_coefsCalculated) {
00052     calculateCoefs(MaxDimension);
00053     _coefsCalculated= kTRUE;
00054   }
00055   // allocate workspace memory
00056   _nextq= new Int_t[MaxDimension];
00057   reset();
00058 }
00059 
00060 
00061 //_____________________________________________________________________________
00062 RooQuasiRandomGenerator::~RooQuasiRandomGenerator() 
00063 {
00064   // Destructor
00065 
00066   delete[] _nextq;
00067 }
00068 
00069 
00070 //_____________________________________________________________________________
00071 void RooQuasiRandomGenerator::reset() 
00072 {
00073   // Reset the workspace to its initial state.
00074 
00075   _sequenceCount= 0;
00076   for(Int_t dim= 0; dim < MaxDimension; dim++) _nextq[dim]= 0;
00077 }
00078 
00079 
00080 //_____________________________________________________________________________
00081 Bool_t RooQuasiRandomGenerator::generate(UInt_t dimension, Double_t vector[]) 
00082 {
00083   // Generate the next number in the sequence for the specified dimension.
00084   // The maximum dimension supported is 12.
00085   
00086   /* Load the result from the saved state. */
00087   static const Double_t recip = 1.0/(double)(1U << NBits); /* 2^(-nbits) */
00088 
00089   UInt_t dim;
00090   for(dim=0; dim < dimension; dim++) {
00091     vector[dim] = _nextq[dim] * recip;
00092   }
00093 
00094   /* Find the position of the least-significant zero in sequence_count.
00095    * This is the bit that changes in the Gray-code representation as
00096    * the count is advanced.
00097    */
00098   Int_t r(0),c(_sequenceCount);
00099   while(1) {
00100     if((c % 2) == 1) {
00101       ++r;
00102       c /= 2;
00103     }
00104     else break;
00105   }
00106   if(r >= NBits) {
00107     oocoutE((TObject*)0,Integration) << "RooQuasiRandomGenerator::generate: internal error!" << endl;
00108     return kFALSE;
00109   }
00110 
00111   /* Calculate the next state. */
00112   for(dim=0; dim<dimension; dim++) {
00113     _nextq[dim] ^= _cj[r][dim];
00114   }
00115   _sequenceCount++;
00116 
00117   return kTRUE;
00118 }
00119 
00120 
00121 //_____________________________________________________________________________
00122 void RooQuasiRandomGenerator::calculateCoefs(UInt_t dimension) 
00123 {
00124   // Calculate the coefficients for the given number of dimensions
00125 
00126   int ci[NBits][NBits];
00127   int v[NBits+MaxDegree+1];
00128   int r;
00129   unsigned int i_dim;
00130 
00131   for(i_dim=0; i_dim<dimension; i_dim++) {
00132 
00133     const int poly_index = i_dim + 1;
00134     int j, k;
00135 
00136     /* Niederreiter (page 56, after equation (7), defines two
00137      * variables Q and U.  We do not need Q explicitly, but we
00138      * do need U.
00139      */
00140     int u = 0;
00141 
00142     /* For each dimension, we need to calculate powers of an
00143      * appropriate irreducible polynomial, see Niederreiter
00144      * page 65, just below equation (19).
00145      * Copy the appropriate irreducible polynomial into PX,
00146      * and its degree into E.  Set polynomial B = PX ** 0 = 1.
00147      * M is the degree of B.  Subsequently B will hold higher
00148      * powers of PX.
00149      */
00150     int pb[MaxDegree+1];
00151     int px[MaxDegree+1];
00152     int px_degree = _polyDegree[poly_index];
00153     int pb_degree = 0;
00154 
00155     for(k=0; k<=px_degree; k++) {
00156       px[k] = _primitivePoly[poly_index][k];
00157       pb[k] = 0;
00158     }
00159     pb[0] = 1;
00160 
00161     for(j=0; j<NBits; j++) {
00162 
00163       /* If U = 0, we need to set B to the next power of PX
00164        * and recalculate V.
00165        */
00166       if(u == 0) calculateV(px, px_degree, pb, &pb_degree, v, NBits+MaxDegree);
00167 
00168       /* Now C is obtained from V.  Niederreiter
00169        * obtains A from V (page 65, near the bottom), and then gets
00170        * C from A (page 56, equation (7)).  However this can be done
00171        * in one step.  Here CI(J,R) corresponds to
00172        * Niederreiter's C(I,J,R).
00173        */
00174       for(r=0; r<NBits; r++) {
00175         ci[r][j] = v[r+u];
00176       }
00177 
00178       /* Advance Niederreiter's state variables. */
00179       ++u;
00180       if(u == px_degree) u = 0;
00181     }
00182 
00183     /* The array CI now holds the values of C(I,J,R) for this value
00184      * of I.  We pack them into array CJ so that CJ(I,R) holds all
00185      * the values of C(I,J,R) for J from 1 to NBITS.
00186      */
00187     for(r=0; r<NBits; r++) {
00188       int term = 0;
00189       for(j=0; j<NBits; j++) {
00190         term = 2*term + ci[r][j];
00191       }
00192       _cj[r][i_dim] = term;
00193     }
00194 
00195   }
00196 }
00197 
00198 
00199 //_____________________________________________________________________________
00200 void RooQuasiRandomGenerator::calculateV(const int px[], int px_degree,
00201                                          int pb[], int * pb_degree, int v[], int maxv) 
00202 {
00203   // Internal function
00204   
00205   const int nonzero_element = 1;    /* nonzero element of Z_2  */
00206   const int arbitrary_element = 1;  /* arbitray element of Z_2 */
00207 
00208   /* The polynomial ph is px**(J-1), which is the value of B on arrival.
00209    * In section 3.3, the values of Hi are defined with a minus sign:
00210    * don't forget this if you use them later !
00211    */
00212   int ph[MaxDegree+1];
00213   /* int ph_degree = *pb_degree; */
00214   int bigm = *pb_degree;      /* m from section 3.3 */
00215   int m;                      /* m from section 2.3 */
00216   int r, k, kj;
00217 
00218   for(k=0; k<=MaxDegree; k++) {
00219     ph[k] = pb[k];
00220   }
00221 
00222   /* Now multiply B by PX so B becomes PX**J.
00223    * In section 2.3, the values of Bi are defined with a minus sign :
00224    * don't forget this if you use them later !
00225    */
00226    polyMultiply(px, px_degree, pb, *pb_degree, pb, pb_degree);
00227    m = *pb_degree;
00228 
00229   /* Now choose a value of Kj as defined in section 3.3.
00230    * We must have 0 <= Kj < E*J = M.
00231    * The limit condition on Kj does not seem very relevant
00232    * in this program.
00233    */
00234   /* Quoting from BFN: "Our program currently sets each K_q
00235    * equal to eq. This has the effect of setting all unrestricted
00236    * values of v to 1."
00237    * Actually, it sets them to the arbitrary chosen value.
00238    * Whatever.
00239    */
00240   kj = bigm;
00241 
00242   /* Now choose values of V in accordance with
00243    * the conditions in section 3.3.
00244    */
00245   for(r=0; r<kj; r++) {
00246     v[r] = 0;
00247   }
00248   v[kj] = 1;
00249 
00250 
00251   if(kj >= bigm) {
00252     for(r=kj+1; r<m; r++) {
00253       v[r] = arbitrary_element;
00254     }
00255   }
00256   else {
00257     /* This block is never reached. */
00258 
00259     int term = sub(0, ph[kj]);
00260 
00261     for(r=kj+1; r<bigm; r++) {
00262       v[r] = arbitrary_element;
00263 
00264       /* Check the condition of section 3.3,
00265        * remembering that the H's have the opposite sign.  [????????]
00266        */
00267       term = sub(term, mul(ph[r], v[r]));
00268     }
00269 
00270     /* Now v[bigm] != term. */
00271     v[bigm] = add(nonzero_element, term);
00272 
00273     for(r=bigm+1; r<m; r++) {
00274       v[r] = arbitrary_element;
00275     }
00276   }
00277 
00278   /* Calculate the remaining V's using the recursion of section 2.3,
00279    * remembering that the B's have the opposite sign.
00280    */
00281   for(r=0; r<=maxv-m; r++) {
00282     int term = 0;
00283     for(k=0; k<m; k++) {
00284       term = sub(term, mul(pb[k], v[r+k]));
00285     }
00286     v[r+m] = term;
00287   }
00288 }
00289 
00290 
00291 //_____________________________________________________________________________
00292 void RooQuasiRandomGenerator::polyMultiply(const int pa[], int pa_degree, const int pb[],
00293                                            int pb_degree, int pc[], int  * pc_degree) 
00294 {
00295   // Internal function
00296 
00297   int j, k;
00298   int pt[MaxDegree+1];
00299   int pt_degree = pa_degree + pb_degree;
00300 
00301   for(k=0; k<=pt_degree; k++) {
00302     int term = 0;
00303     for(j=0; j<=k; j++) {
00304       const int conv_term = mul(pa[k-j], pb[j]);
00305       term = add(term, conv_term);
00306     }
00307     pt[k] = term;
00308   }
00309 
00310   for(k=0; k<=pt_degree; k++) {
00311     pc[k] = pt[k];
00312   }
00313   for(k=pt_degree+1; k<=MaxDegree; k++) {
00314     pc[k] = 0;
00315   }
00316 
00317   *pc_degree = pt_degree;
00318 }
00319 
00320 
00321 //_____________________________________________________________________________
00322 Int_t RooQuasiRandomGenerator::_cj[RooQuasiRandomGenerator::NBits]
00323 [RooQuasiRandomGenerator::MaxDimension];
00324 
00325 /* primitive polynomials in binary encoding */
00326 
00327 //_____________________________________________________________________________
00328 const Int_t RooQuasiRandomGenerator::_primitivePoly[RooQuasiRandomGenerator::MaxDimension+1]
00329 
00330 //_____________________________________________________________________________
00331 [RooQuasiRandomGenerator::MaxPrimitiveDegree+1] =
00332 {
00333   { 1, 0, 0, 0, 0, 0 },  /*  1               */
00334   { 0, 1, 0, 0, 0, 0 },  /*  x               */
00335   { 1, 1, 0, 0, 0, 0 },  /*  1 + x           */
00336   { 1, 1, 1, 0, 0, 0 },  /*  1 + x + x^2     */
00337   { 1, 1, 0, 1, 0, 0 },  /*  1 + x + x^3     */
00338   { 1, 0, 1, 1, 0, 0 },  /*  1 + x^2 + x^3   */
00339   { 1, 1, 0, 0, 1, 0 },  /*  1 + x + x^4     */
00340   { 1, 0, 0, 1, 1, 0 },  /*  1 + x^3 + x^4   */
00341   { 1, 1, 1, 1, 1, 0 },  /*  1 + x + x^2 + x^3 + x^4   */
00342   { 1, 0, 1, 0, 0, 1 },  /*  1 + x^2 + x^5             */
00343   { 1, 0, 0, 1, 0, 1 },  /*  1 + x^3 + x^5             */
00344   { 1, 1, 1, 1, 0, 1 },  /*  1 + x + x^2 + x^3 + x^5   */
00345   { 1, 1, 1, 0, 1, 1 }   /*  1 + x + x^2 + x^4 + x^5   */
00346 };
00347 
00348 /* degrees of primitive polynomials */
00349 
00350 //_____________________________________________________________________________
00351 const Int_t RooQuasiRandomGenerator::_polyDegree[RooQuasiRandomGenerator::MaxDimension+1] =
00352 {
00353   0, 1, 1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5
00354 };
00355 
00356 Bool_t RooQuasiRandomGenerator::_coefsCalculated= kFALSE;

Generated on Tue Jul 5 15:07:07 2011 for ROOT_528-00b_version by  doxygen 1.5.1