// file: $isip/class/system/Random/Random.h
// version: $Id: Random.h 10636 2007-01-26 22:18:09Z tm334 $
//

// make sure definitions are only made once
//
#ifndef ISIP_RANDOM
#define ISIP_RANDOM

// isip include files:
//
#ifndef ISIP_SYS_STRING
#include <SysString.h>
#endif

#ifndef ISIP_MEMORY_MANAGER
#include <MemoryManager.h>
#endif

// Random: a class that implements some standard random number generation
// algorithms. this class is introduced at this level because it is used by
// many classes to produce random valued objects. it is implemented in
// a way that allows the flexibility of parallel random generators
// or a single global generator.
//
class Random {

  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const SysString CLASS_NAME;
  
  // define algorithm choices
  //
  enum ALGORITHM { UNIFORM = 0, GAUSSIAN,
		   DEF_ALGORITHM = UNIFORM };

  // define implementations
  //
  enum IMPLEMENTATION { SUBTRACTIVE = 0, CONGRUENTIAL, TRANSFORMATION,
			DEF_IMPLEMENTATION = SUBTRACTIVE };
  
  //----------------------------------------
  //
  // other important constants
  //
  //----------------------------------------

  // define global random number generators
  //
  static Random GLOBAL_UNIFORM;
  static Random GLOBAL_GAUSSIAN;

  // define default values to seed random number generators and the
  // size of the generator's array
  //
  static const long US_MBIG = 1000000000;
  static const long US_MSEED = 161803398;
  static const long US_MZ = 0;
  static const long US_MDIM = 56;
  static const long US_CONST = 30;
  static const double US_FAC = (1.0 / 1000000000);

  // define default values to scale random numbers
  //
  static const double INV_RAND_MAX = 1.0 / RAND_MAX;

  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // define the default value(s) of the class data
  //
  
  // default arguments to methods
  //
  
  // define a default value for the random number generator
  //
  static const long DEF_SEED = 27;

  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 1900;

  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // this section contains data common to all algorithms
  //

  // algorithm name
  //
  ALGORITHM algorithm_d;
  
  // implementation name
  //
  IMPLEMENTATION implementation_d;
  
  // define a seed:
  //  most random numbers use a concept of a seed. typically, this is a
  //  large, odd, positive integer value.
  //
  long seed_d;

  // declare a static debug level for all class instantiations
  //
  static Integral::DEBUG debug_level_d;

  // static memory manager
  //
  static MemoryManager mgr_d;

  // initialization flag
  //
  boolean is_valid_d;

  // this section contains data for a specific algorithm
  //

  // algorithm: UNIFORM*
  // implementation: SUBTRACTIVE
  //
  // define some registers to maintain history
  //
  long us_inext_d;
  long us_inextp_d;
  long us_ma_d[US_MDIM];

  // algorithm: GAUSSIAN
  // implementation: TRANSFORMATION
  //
  // define two registers to maintain previously computed values
  //
  boolean gt_iset_d;
  double gt_gset_d;

  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:

  // method: name
  //
  static const SysString& name() {
    return CLASS_NAME;
  }
  
  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);
  
  // method: setDebug
  //
  static boolean setDebug(Integral::DEBUG level) {
    debug_level_d = level;
    return true;
  }
  
  // other debug methods
  //
  boolean debug(const unichar* message) const;

  // method: copy constructor
  //
  Random(const Random& arg) {
    assign(arg);
  }

  // method: destructor
  //
  ~Random() {}

  // other constructor(s)
  //
  Random(long seed = DEF_SEED);

  // assign methods:
  //
  boolean assign(const Random& arg);

  // method: operator=
  //
  Random& operator=(const Random& arg) {
    assign(arg);
    return *this;
  }
    
  // i/o methods:
  //  these methods are omitted
  //
  
  // equality methods:
  //
  boolean eq(const Random& arg) const;
  
  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }

  // other memory management methods
  // 
  boolean clear(Integral::CMODE ctype_a = Integral::DEF_CMODE);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  extensions to required methods
  //
  //---------------------------------------------------------------------------
  
  // method: constructor
  //
  //  we need a constructor with configuration information to make it easy
  //  for math scalar classes to use this class.
  //
  Random(ALGORITHM alg, IMPLEMENTATION impl, long seed = DEF_SEED) {
    setAlgorithm(alg);
    setImplementation(impl);
    seed_d = seed;
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  set and get methods
  //
  //---------------------------------------------------------------------------
  
  // method: setAlgorithm
  //
  boolean setAlgorithm(ALGORITHM algorithm) {
    algorithm_d = algorithm;
    return (!(is_valid_d = false));
  }
  
  // method: setImplementation
  //
  boolean setImplementation(IMPLEMENTATION implementation) {
    implementation_d = implementation;
    return (!(is_valid_d = false));
  }

  // method: getAlgorithm
  //
  ALGORITHM getAlgorithm() const {
    return algorithm_d;
  }

  // method: getImplementation
  //
  IMPLEMENTATION getImplementation() const {
    return implementation_d;
  }

  // method: seed
  //
  boolean seed(long value = DEF_SEED) {
    seed_d = value;
    is_valid_d = false;
    return true;
  }

  // method: get
  //
  double get() {
    return compute();
  }

  // method: cast (double) conversion operator
  //  a simple way to get a random number
  //
  operator double() {
    return compute();
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  initialization and computation methods
  //
  //---------------------------------------------------------------------------
  
  // initialization methods:
  //  these methods initialize the various class constants
  //
  boolean init();
  
  // computational methods:
  //  these methods compute a new random number
  //
  double compute();

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // algorithm-specific computation methods:
  //  uniform random numbers using a subtractive method
  //
  boolean initUniformSubtractive();
  double computeUniformSubtractive();

  // algorithm-specific computation methods:
  //  uniform random numbers using a multiplicative congruential method
  //
  boolean initUniformCongruential();
  double computeUniformCongruential();

  // algorithm-specific computation methods:
  //  Gaussian random numbers using a transformation method
  //
  boolean initGaussianTransform();
  double computeGaussianTransform();
};

// end of include file
//
#endif
