/*******************************************************************************
+
+  LEDA 3.5
+
+  random.h
+
+  This file is part of the LEDA research version (LEDA-R) that can be 
+  used free of charge in academic research and teaching. Any commercial
+  use of this software requires a license which is distributed by the
+  LEDA Software GmbH, Postfach 151101, 66041 Saarbruecken, FRG
+  (fax +49 681 31104).
+
+  Copyright (c) 1991-1997  by  Max-Planck-Institut fuer Informatik
+  Im Stadtwald, 66123 Saarbruecken, Germany     
+  All rights reserved.
+ 
*******************************************************************************/
#ifndef LEDA_RANDOM_H
#define LEDA_RANDOM_H

#if !defined(LEDA_ROOT_INCL_ID)
#define LEDA_ROOT_INCL_ID 350105
#include <LEDA/REDEFINE_NAMES.h>
#endif



//------------------------------------------------------------------------------
// random numbers
//------------------------------------------------------------------------------

#include <LEDA/basic.h>


/*{\Manpage {random_source} {} {Random Sources} }*/


class bsd_random {

  int* degrees;
  int* seps;
  long* randtbl;

  long *fptr;
  long *rptr;
  
  long* state;
  int   rand_type;
  int   rand_deg;
  int   rand_sep;
  long* end_ptr;
  
public:

   bsd_random();
  ~bsd_random();

  void  set_random(unsigned x);
  char* initstate(unsigned seed, char* arg_state, int n);
  char* setstate(char* arg_state);
  unsigned long get_random();
  
};



class random_source : public bsd_random {

/*{\Mdefinition 
An instance of type |\Mname| is a random source. It allows to generate
uniformly distributed random bits, characters, integers, and doubles.
It can be in  either of two modes: In bit mode it generates a random bit string
of some given length $p$ ($1 \le p \le 31$) and in integer mode it generates a random
integer in some given range $[ low .. high]$  ($low \le high < low + 2^{31}$). The mode can be changed any time, either globally or for a single operation. The output of the random
source can be converted to a number of formats (using standard conversions).}*/

  unsigned long pat;
  int prec;
  int low;
  int diff;
  bool bit_mode;

static leda_mutex random_mutex_count;

static int count;

public:

/*{\Mcreation S }*/

random_source();
/*{\Mcreate  creates an instance |\Mvar| of type |\Mname|, 
             puts it into bit mode, and 
             sets the precision to 31. }*/

random_source(int p);
/*{\Mcreate  creates an instance |\Mvar| of type |\Mname|, 
             puts it into bit mode, and 
             sets the precision to $p$ ($1 \le p \le 31$). }*/

random_source(int low, int high);
/*{\Mcreate  creates an instance |\Mvar| of type |\Mname|, 
             puts it into integer mode, and 
             sets the range to $[ low .. high]$. }*/


/*{\Moperations 3.2 5 }*/

void set_seed(int s) { set_random(s); }
/*{\Mop         resets the seed of the random number generator to $s$. }*/

void set_range(int low, int high);
/*{\Mopl        sets the mode to integer mode and 
                changes the range to $[ low .. high]$. }*/

int set_precision(int p);
/*{\Mop         sets the mode to bit mode, changes the precision 
                to $p$ bits and returns previous precision. }*/

int get_precision() { return prec; }
/*{\Mop         returns current precision of |\Mvar|. }*/


// extract random numbers with precision or range specified in constructor

random_source& operator>>(char& x);
/*{\Mbinop      extracts a character $x$ of default precision or range
                and returns |\Mvar|, i.e., it first generates an unsigned
                integer of the desired precision or in the desired range
                and then converts it to a character (by standard conversion).
                 }*/

random_source& operator>>(unsigned char& x);
/*{\Mbinop      extracts an unsigned character $x$ of default precision or 
                range and returns |\Mvar|. }*/

random_source& operator>>(int& x);
/*{\Mbinop      extracts an integer $x$ of default precision or range and 
                returns |\Mvar|. }*/

random_source& operator>>(long& x);
/*{\Mbinop      extracts a long integer $x$ of default precision or range and 
                returns |\Mvar|. }*/


random_source& operator>>(unsigned int& x);
/*{\Mbinop      extracts an unsigned integer $x$ of default precision or
                range and returns |\Mvar|. }*/

random_source& operator>>(unsigned long& x);
/*{\Mbinop      extracts a long unsigned integer $x$ of default precision or 
                range and returns |\Mvar|. }*/
       


random_source& operator>>(double& x);
/*{\Mbinop      extracts a double precision floating point number $x$ in 
                $[0,1]$, i.e, $u/(2^{31} -1)$ where $u$ is a random integer 
                in $[0..2^{31}-1]$, and returns |\Mvar|.}*/

random_source& operator>>(float& x);
/*{\Mbinop      extracts a single precision floating point number $x$ in 
                $[0,1]$, i.e, $u/(2^{31} -1)$ where $u$ is a random integer 
                in $[0..2^{31}-1]$, and returns |\Mvar|.}*/


#ifdef __HAS_BUILTIN_BOOL__
random_source& operator>>(bool& b);
/*{\Mbinop      extracts a random boolean value (true or false). }*/

#endif

// raw read (31 bit)

unsigned get() { return unsigned(get_random()); }
/*{\Mop            returns an unsigned integer of maximal precision (31 bits). }*/

// operator()

int operator()();    
/*{\Mfunop         returns an integer of default precision or range.}*/

int operator()(int prec);
/*{\Mfunop         returns an integer of supplied precision $prec$. }*/

int operator()(int low, int high);
/*{\Mfunop         returns an integer from the supplied range $[low..high]$. }*/


};

extern random_source rand_int;   // standard random input stream


#if LEDA_ROOT_INCL_ID == 350105
#undef LEDA_ROOT_INCL_ID
#include <LEDA/UNDEFINE_NAMES.h>
#endif

#endif
