Main Page | Namespace List | Class Hierarchy | Compound List | File List | Namespace Members | Compound Members | File Members

seed.cxx

Go to the documentation of this file.
00001 /**************************************************************************
00002 ***    
00003 *** Copyright (c) 1995-2000 Regents of the University of California,
00004 ***               Andrew E. Caldwell, Andrew B. Kahng and Igor L. Markov
00005 *** Copyright (c) 2000-2004 Regents of the University of Michigan,
00006 ***               Saurabh N. Adya, Jarrod A. Roy and Igor L. Markov
00007 ***
00008 ***  Contact author(s): abk@cs.ucsd.edu, imarkov@umich.edu
00009 ***  Original Affiliation:   UCLA, Computer Science Department,
00010 ***                          Los Angeles, CA 90095-1596 USA
00011 ***
00012 ***  Permission is hereby granted, free of charge, to any person obtaining 
00013 ***  a copy of this software and associated documentation files (the
00014 ***  "Software"), to deal in the Software without restriction, including
00015 ***  without limitation 
00016 ***  the rights to use, copy, modify, merge, publish, distribute, sublicense, 
00017 ***  and/or sell copies of the Software, and to permit persons to whom the 
00018 ***  Software is furnished to do so, subject to the following conditions:
00019 ***
00020 ***  The above copyright notice and this permission notice shall be included
00021 ***  in all copies or substantial portions of the Software.
00022 ***
00023 *** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
00024 *** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00025 *** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
00026 *** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
00027 *** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
00028 *** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
00029 *** THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00030 ***
00031 ***
00032 ***************************************************************************/
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 //  Created : November 1997, Mike Oliver, VLSI CAD ABKGROUP UCLA 
00044 //  020811  ilm   ported to g++ 3.0
00045 
00046 #ifdef _MSC_VER
00047 #pragma warning(disable:4786)
00048 #endif
00049 
00050 #include "abktimer.h"
00051 #include "abkrand.h"
00052 #include "abkMD5.h"
00053 
00054 #include <fstream>
00055 #include <stdio.h>
00056 #ifdef WIN32
00057 #define _X86_
00058 #include <stdarg.h>
00059 #include <windef.h>
00060 #include <winbase.h>
00061 #include <process.h>
00062 #include <stdio.h>
00063 #else
00064 #include <unistd.h>
00065 #endif
00066 
00067 using std::ios;
00068 
00069 ofstream *SeedHandler::_PseedOutFile = NULL;
00070 ifstream *SeedHandler::_PseedInFile = NULL;
00071 unsigned  SeedHandler::_nextSeed = UINT_MAX;
00072 bool      SeedHandler::_loggingOff=false;
00073 bool      SeedHandler::_haveRandObj=false;
00074 bool      SeedHandler::_cleaned=false;
00075 unsigned  SeedHandler::_externalSeed=UINT_MAX;
00076 unsigned  SeedHandler::_progOverrideExternalSeed=UINT_MAX;
00077 
00078 std::map<std::string,unsigned,SeedHandlerCompareStrings > SeedHandler::_counters;
00079 
00080 SeedCleaner   cleaner; //when this object goes out of scope at the end of
00081                    //execution, it will make sure that SeedHandler::clean()
00082                    //gets called
00083 
00084 
00085 //: Maintains all random seeds used by a process.
00086 //Idea:  First time you create a random object, an initial nondeterministic
00087 //       seed (also called the "external seed" is created from system
00088 //       information and logged to seeds.out.
00089 //       Any random object created with a seed of UINT_MAX ("nondeterministic"),
00090 //       and that does not use the snazzy new "local independence" feature,
00091 //       then uses seeds from a sequence starting with the initial value
00092 //       and increasing by 1 with each new nondeterministic random object
00093 //       created.
00094 //
00095 //       If the seed is overridden with a value other than UINT_MAX it is used,
00096 //       and logged to seeds.out .
00097 //
00098 //       However if seeds.in exists, the initial nondeterministic value
00099 //       is taken from the second line of seeds.in rather than the system
00100 //       clock, and subsequent *deterministic* values are taken from successive
00101 //       lines of seeds.in rather than from the value passed.
00102 //
00103 //       If seeds.out is in use or other errors occur trying to create it,
00104 //       a warning is generated that the seeds will not be logged, and
00105 //       the initial nondeterministic seed is printed (which should be
00106 //       sufficient to recreate the run provided that all "deterministic"
00107 //       seeds truly *are* deterministic (e.g. don't depend on external
00108 //       devices).
00109 //
00110 //       You can disable the logging function by calling the static
00111 //       function SeedHandler::turnOffLogging().  This will not disable
00112 //       the ability to override seeding with seeds.in .
00113 //NEW ULTRA-COOL FEATURE: (17 June 1999)
00114 //       You now have the option, which I (Mike) highly recommend,
00115 //       of specifying, instead of a seed, a "local identifier", which
00116 //       is a string that should identify uniquely the random variable
00117 //       (not necessarily the random object) being used.  The suggested
00118 //       format of this string is as follows: If your
00119 //       RNG is called _rng and is a member of MyClass, pass
00120 //       the string "MyClass::_rng".  If it's a local variable
00121 //       called rng in the method MyClass::myMethod(), pass
00122 //       the string "MyClass::myMethod(),_rng".
00123 //
00124 //       SeedHandler will maintain a collection of counters associated
00125 //       with each of these strings.  The sequence of random numbers
00126 //       from a random object will be determined by three things:
00127 //            1) the "external seed" (same as "initial nondeterm seed").
00128 //            2) the "local identifier" (the string described above).
00129 //            3) the counter saying how many RNG objects have previously
00130 //                 been created with the same local identifier.
00131 //       When any one of these changes, the output should be effectively
00132 //       independent of the previous RNG.  Moreover you don't have
00133 //       to worry about your regressions changing simply because someone
00134 //       else's code which you call has changed the number of RNG objects
00135 //       it uses.
00136 //ANOTHER NEW FEATURE (21 February 2001)
00137 //       At times you may wish to control the external seed yourself, e.g.
00138 //       by specifying the seed on the command line, rather than
00139 //       using either seeds.in or the nondeterministic chooser.
00140 //       To enable this, a static method SeedHandler::overrideExternalSeed()
00141 //       has been added.  If you call this method before any random
00142 //       object has been created, you can set the external seed.
00143 //       The file seeds.out will still be created unless you call
00144 //       SeedHandler::turnOffLogging().  If seeds.in exists, it
00145 //       will control -- your call to overrideExternalSeed() will
00146 //       print a warning message and otherwise be ignored.
00147 
00148 
00149 //****************************************************************************
00150 //****************************************************************************
00151 //****************************************************************************
00152 
00153 void SeedHandler::_init()
00154     {
00155     abkfatal(!_cleaned,"Can't create random object"
00156                        " after calling SeedHandler::clean()");
00157 
00158     if (!_haveRandObj)
00159         {
00160         _chooseInitNondetSeed();
00161 
00162         if (!_loggingOff)
00163             {
00164             _initializeOutFile();
00165             }
00166         }
00167 
00168     _haveRandObj=true;
00169 
00170     }
00171 
00172 //****************************************************************************
00173 //****************************************************************************
00174 
00175 SeedHandler::SeedHandler(unsigned seed):
00176                _locIdent(NULL),_counter(UINT_MAX),_isSeedMultipartite(false)
00177     {
00178     _init();
00179     if (seed==UINT_MAX)
00180         _seed = _nextSeed++;
00181     else                     //deterministic seed, take value given unless
00182                              //seeds.in exists with valid value
00183         {
00184         if (_PseedInFile)
00185             {
00186             *_PseedInFile>>_seed;
00187             //cerr << "Seed read was " << _seed << endl;
00188 
00189             if (_PseedInFile->fail()) //if we've run out, go back to accepting
00190                                       //seeds given
00191                 {
00192                 _PseedInFile->close();
00193                 delete _PseedInFile;
00194                 _PseedInFile = NULL;
00195                 _seed=seed;
00196                 //cerr << "But read failed, substituting seed " << _seed;
00197                 }
00198 
00199             }
00200         else
00201             _seed = seed;
00202 
00203         if (!_loggingOff)
00204             {
00205             abkfatal(_PseedOutFile,"Internal error: unable to log "
00206                                    "random seed to file");
00207             *_PseedOutFile << _seed << endl;
00208             }
00209         }
00210     }
00211 
00212 //****************************************************************************
00213 //****************************************************************************
00214 SeedHandler::SeedHandler(const char *locIdent,
00215                          unsigned counterOverride):
00216             _isSeedMultipartite(true)
00217     {
00218     _init();
00219     _locIdent = strdup(locIdent);
00220 
00221     if (counterOverride!=UINT_MAX)
00222         _counter=counterOverride;
00223     else
00224         {
00225         std::map<std::string,unsigned,SeedHandlerCompareStrings >::iterator iC;
00226         iC = _counters.find(_locIdent);
00227         if (iC==_counters.end()) _counters[_locIdent]=_counter=0;
00228         else { iC->second++; _counter=iC->second; }
00229         }
00230     }
00231 
00232 //****************************************************************************
00233 //****************************************************************************
00234 SeedHandler::~SeedHandler()
00235     {
00236     if (!_isSeedMultipartite)
00237         {
00238         abkassert(_locIdent==NULL,"Non-null _locIdent with old-style seed");
00239         }
00240     else
00241         {
00242           free(_locIdent);
00243           _locIdent=NULL;
00244         }
00245     }
00246 //****************************************************************************
00247 //****************************************************************************
00248 
00249 void SeedHandler::turnOffLogging()
00250     {
00251     _loggingOff=true;
00252     }
00253 
00254 //****************************************************************************
00255 //****************************************************************************
00256 
00257 void SeedHandler::overrideExternalSeed(unsigned extseed)
00258     {
00259     abkfatal(!_haveRandObj,"Can't call SeedHandler::overrideExternalSeed() "
00260         "after creating a random object");
00261     abkfatal(extseed != UINT_MAX,
00262         "Can't pass UINT_MAX to SeedHandler::overrideExternalSeed()");
00263     _progOverrideExternalSeed=extseed;
00264     }
00265 
00266 //****************************************************************************
00267 //****************************************************************************
00268 
00269 void SeedHandler::clean()
00270     {
00271     _cleaned=true;
00272 
00273     if(_PseedOutFile)
00274         {
00275         _PseedOutFile->seekp(0,ios::beg); //rewind file
00276         _PseedOutFile->put('0');          //mark not in use
00277         _PseedOutFile->close();
00278         }
00279 
00280     if(_PseedInFile)_PseedInFile->close();
00281 
00282     delete _PseedOutFile;delete _PseedInFile;
00283     _PseedOutFile=NULL;
00284     _PseedInFile=NULL;
00285     }
00286 
00287 
00288 //****************************************************************************
00289 //****************************************************************************
00290 
00291 void SeedHandler::_chooseInitNondetSeed()
00292     {
00293 #ifdef __GNUC__
00294 #if( __GNUC__ <= 3)
00295     _PseedInFile = new ifstream("seeds.in",ios::in);
00296 #else
00297     _PseedInFile = new ifstream("seeds.in",ios::in|ios::nocreate);
00298 #endif
00299 #else
00300     _PseedInFile = new ifstream("seeds.in",ios::in);
00301 #endif
00302 
00303     if (!*_PseedInFile)
00304         {
00305         delete _PseedInFile;
00306         _PseedInFile=NULL;
00307         }
00308 
00309     if (_PseedInFile)
00310         {
00311         unsigned DummyInUseLine;
00312         cerr<<"File seeds.in exists and will override all seeds, including "
00313               "hardcoded ones " << endl;
00314         *_PseedInFile >> DummyInUseLine;
00315         abkwarn(!DummyInUseLine,"File seeds.in appears to come from a process "
00316                                 "that never completed\n");
00317         *_PseedInFile >> _nextSeed;
00318         //cerr << "Init nondet seed read was "<<_nextSeed << endl;
00319         abkfatal(!(_PseedInFile->fail()),"File seeds.in exists but program "
00320                                          "was unable to read initial seed "
00321                                          "therefrom.");
00322         abkwarn(_progOverrideExternalSeed==UINT_MAX,
00323             "\nThere is a programmatic override of the external seed,"
00324             " which will be ignored because seeds.in exists");
00325         }
00326     else if (_progOverrideExternalSeed==UINT_MAX)
00327         {
00328         Timer tm;
00329 
00330         char buf[255];
00331 #if defined(WIN32)
00332         int procID=_getpid();
00333         LARGE_INTEGER hiPrecTime;
00334         ::QueryPerformanceCounter(&hiPrecTime);
00335         LONGLONG hiP1=hiPrecTime.QuadPart;
00336         sprintf(buf,"%g %d %I64d",tm.getUnixTime(),procID,hiP1);
00337 #else
00338         unsigned procID=getpid();
00339         unsigned rndbuf[2];
00340         FILE *rnd=fopen("/dev/random","r");
00341         fread(rndbuf,sizeof(rndbuf),1,rnd);
00342         fclose(rnd);
00343         sprintf(buf,"%g %d %d %d",tm.getUnixTime(),procID,rndbuf[0],rndbuf[1]);
00344 #endif
00345 
00346         MD5 hash(buf);
00347         _nextSeed=hash;
00348         }
00349     else
00350         {
00351         _nextSeed=_progOverrideExternalSeed;
00352         }
00353     _externalSeed=_nextSeed;
00354     }
00355 
00356 //****************************************************************************
00357 //****************************************************************************
00358 
00359 void SeedHandler::_initializeOutFile()
00360     {
00361     unsigned inUse;
00362 
00363 #ifdef __GNUC__
00364 #if( __GNUC__ < 3)
00365     ifstream outFileAsInFile("seeds.out",ios::in|ios::nocreate);
00366 #else
00367     ifstream outFileAsInFile("seeds.out",ios::in);
00368 #endif
00369 #else
00370     ifstream outFileAsInFile("seeds.out",ios::in);
00371 #endif
00372 
00373     if (!!outFileAsInFile)
00374         {
00375 
00376         outFileAsInFile >> inUse;
00377         if (outFileAsInFile.fail())
00378             {
00379             char errtxt[1023];
00380 
00381             sprintf(errtxt,"Unable to determine whether file seeds.out is"
00382                            " in use; random seeds from "
00383                            "this process will not be logged.\n  Initial non-"
00384                            "deterministic seed is %u",_nextSeed);
00385 
00386             abkwarn(0,errtxt);
00387             _loggingOff=true;
00388             }
00389         else
00390             {
00391             if (inUse)
00392                 {
00393                 char errtxt[1023];
00394 
00395                 sprintf(errtxt,"File seeds.out is in use; random seeds from "
00396                                "this process will not be logged.\nInitial non-"
00397                                "deterministic seed is %u.\nIf there is no "
00398                                "other process running in this directory, then "
00399                                "an earlier\nprocess may have terminated\n"
00400                                "abnormally. "
00401                                "You should remove or rename seeds.out\n"
00402                                ,_nextSeed);
00403 
00404                 abkwarn(0,errtxt);
00405                 _loggingOff=true;
00406                 }
00407             }
00408         }
00409         outFileAsInFile.close();
00410 
00411         if (!_loggingOff)
00412             {
00413             _PseedOutFile=new ofstream("seeds.out",ios::out); //overwrite file
00414 
00415             if (!_PseedOutFile)
00416                 {
00417                 char errtxt[1023];
00418 
00419                 sprintf(errtxt,"Unable to create file seeds.out; random seeds from "
00420                                "this process will not be logged.\n  Initial non-"
00421                                "deterministic seed is %u",_nextSeed);
00422 
00423                 abkwarn(0,errtxt);
00424                 _loggingOff=true;
00425                 delete _PseedOutFile;_PseedOutFile=NULL;
00426                 }
00427 
00428             *_PseedOutFile << "1" << endl; //mark as in use
00429 
00430             *_PseedOutFile << _nextSeed << endl; //initial nondet seed
00431             }
00432 
00433     }
00434 
00435 //****************************************************************************
00436 //****************************************************************************
00437 //****************************************************************************
00438 //****************************************************************************
00439 
00440 
00441 

Generated on Mon Apr 25 01:09:25 2005 for Parquete by doxygen 1.3.2