DEFINITION MODULE RandomLib;

  (*------------------------------------------------------------------------*)
  (* Dieses Modul stellt verschiedene uniforme Pseudozufallszahlen-         *)
  (* generatoren zur Verfuegung.                                            *)
  (* This module providing several uniform pseudorandom number generators.  *)
  (*------------------------------------------------------------------------*)
  (* Implementation : Michael Riedl                                         *)
  (* Licence        : GNU Lesser General Public License (LGPL)              *)
  (*------------------------------------------------------------------------*)

  (* $Id: RandomLib.def,v 1.5 2016/01/24 09:19:45 mriedl Exp $ *)

TYPE SeedVektor = ARRAY [1..25] OF INTEGER; (* Fuer RanLux *)

PROCEDURE Random(a,b : LONGREAL) : LONGREAL;

          (*----------------------------------------------------------------*)
          (* ACM Algorithm 133                                              *)
          (*                                                                *)
          (* Produces pseudo random numbers in the interval [a,b].          *)
          (*                                                                *)
          (* Very simple random number generator, do not use for production *)
          (* code as randomness is weak. Code is only of historical         *)
          (* interrest.                                                     *)
          (*----------------------------------------------------------------*)

PROCEDURE InitRandom();

          (*----------------------------------------------------------------*)
          (* Initialisiert Random neu mit Systemzeit oder selbstgenerierten *)
          (* Zufallszahlen.                                                 *)
          (*                                                                *)
          (* Initializes Random with values form the system clock. If that  *)
          (* is not possible a fixed seed is used                           *)
          (*----------------------------------------------------------------*)

PROCEDURE RanMarInit(ij,kl : CARDINAL);

          (*----------------------------------------------------------------*)
          (* Initialisierungsroutine f\"ur den Zufallszahlengenerator       *)
          (* RanMar()                                                       *)
          (* Hinweis : Die Initialisierungsvariablen m\"ussen in dem        *)
          (*           Bereich 0 <= ij <= 31328 und 0 <= kl <= 30081        *)
          (*           liegen.                                              *)
          (*                                                                *)
          (* The random number sequences created by these two seeds are     *)
          (* of sufficient length to complete an entire calculation with.   *)
          (* For example, if sveral different groups are working on         *)
          (* different parts of the same calculation, each group could be   *)
          (* assigned its own ij seed. This would leave each group with     *)
          (* 30000 choices for the second seed. That is to say, this random *)
          (* number generator can create 900 million different subsequences *)
          (* with each subsequence having a length of approximately 1.0E+30 *)
          (*                                                                *)
          (* Use ij = 1802 & kl = 9373 to test the random number generator  *)
          (* The subroutine RanMar should be used to generate 20000 random  *)
          (* numbers. Then display the next six random numbers generated    *)
          (* multiplied by 4096*4096. If the random number generator is     *)
          (* working properly, the random numbers should be :               *)
          (*                                                                *)
          (*       6533892.0  14220222.0   7275067.0                        *)
          (*       6172232.0   8354498.0  10633180.0                        *)
          (*                                                                *)
          (* Anpassung an Modula-2 von M.Riedl am 03.06.1993                *)
          (*                                                                *)
          (* Um eine zufaellige Initialisierung zu erziehlen kann folgendes *)
          (* Codesegment benutzt werden:                                    *)
          (*                                                                *)
          (* VAR x : LONGREAL; i : CARDINAL;                                *)
          (* BEGIN                                                          *)
          (*   InitZufallSysT;                                              *)
          (*   FOR i:=1 TO 31328+30081 DO x:=Zufall(); END;                 *)
          (*   RanMarInit(IRandom(0,31328),IRandom(0,30081));               *)
          (*   ...                                                          *)
          (*----------------------------------------------------------------*)

PROCEDURE RanMar() : LONGREAL;

          (*----------------------------------------------------------------*)
          (* Zufallszahlengenarator nach dem Algorithmus von                *)
          (* George Marsaglia,                                              *)
          (* Florida State University Report: FSU-SCRI-87-50                *)
          (*                                                                *)
          (* This random number generator originally appeared in            *)
          (* "Toward a Universal Random Number Generator" by                *)
          (* George Marsaglia and Arif Zaman.                               *)
          (* Florida State University Report: FSU-SCRI-87-50 (1987)         *)
          (*                                                                *)
          (* It was later modified by F. James and published in             *)
          (* "A Review of Pseudorandom Number Generators"                   *)
          (*                                                                *)
          (* THIS IS THE BEST KNOWN RANDOM NUMBER GENERATOR AVAILABLE.      *)
          (* (However, a newly discovered technique can yield a period      *)
          (*  of 10^600. But that is still in the development stage.)       *)
          (*                                                                *)
          (* It passes ALL of the tests for random number generators and    *)
          (* has a period of 2^144, is completely portable (gives bit       *)
          (* identical results on all machines with at least 24-bit         *)
          (* mantissas in the floating point representation).               *)
          (*                                                                *)
          (* The algorithm is a combination of a Fibonacci sequence (with   *)
          (* lags of 97 and 33, and operation "subtraction plus one,        *)
          (* modulo one") and an "arithmetic sequence" (using subtraction). *)
          (*                                                                *)
          (* On a Vax 11/780, this random number generator can produce a    *)
          (* number in 13 microseconds.                                     *)
          (*                                                                *)
          (* Auf einem 386/387-64 (16MHz) werden, bei leicht ge\"andertem   *)
          (* Algorithmus (1 Zufallszahl je Ausfruf statt eines Feldes von   *)
          (* Zufallszahlen), 85 Mikrosekunden ben\"otigt.                   *)
          (*                                                                *)
          (* Anpassung an Modula-2 von M.Riedl, 03.06.1993                  *)
          (*----------------------------------------------------------------*)

PROCEDURE InitZufall;

          (*----------------------------------------------------------------*)
          (* Initialisiert den Zufallszahlengenerator Zufall().             *)
          (*                                                                *)
          (* Initializes Zufall with the original seed                      *)
          (*----------------------------------------------------------------*)

PROCEDURE InitZufallSysT;

          (*----------------------------------------------------------------*)
          (* Initialisiert den Zufallszahlengenerator Zufall() mit Werten   *)
          (* die von der Systemzeit abhaengen (nicht/schwer reproduzierbar) *)
          (*                                                                *)
          (* Initializes the random number generator Zufall() with values   *)
          (* dependent on the system clock (not/difficult to reproduce)     *)
          (*----------------------------------------------------------------*)

PROCEDURE Zufall() : LONGREAL;

          (*----------------------------------------------------------------*)
          (* Berechnet Zufallszahlen im Intervall [0,1) nach dem Additive   *)
          (* Congruential Random Number (ACORN) Algorithmus.                *) 
          (*                                                                *)
          (* Wikramaratna, R.S. "ACORN — A new method for generating        *)
          (* sequences of uniformly distributed Pseudo-random Numbers",     *)
          (* J. Comp. Phys. 83,1 pp 16-31 (1989)                            *)
          (*----------------------------------------------------------------*)

PROCEDURE IRandom(a,b : CARDINAL) : CARDINAL;

          (*----------------------------------------------------------------*)
          (* Berechne eine Zufallszahl im Intervall [a,b]                   *)
          (* Calculate a random number in the intervall [a,b]               *)
          (* Benutzt / uses : Zufall                                        *)
          (*----------------------------------------------------------------*)

PROCEDURE RLuxGo(Lux,InS,K1,K2: INTEGER);

          (*----------------------------------------------------------------*)
          (* Origin : CERN Program Library (SUBROUTINE RANLUX)              *)
          (*                                                                *)
          (* Entry to initialize from one or three integers                 *)
          (* Initializes the generator from one 32-bit integer InS and sets *)
          (* Luxury Level Lux which is integer between zero and MAXLEV, or  *)
          (* if Lux .GT. 24, it sets p=Lux directly. K1 and K2 should be    *)
          (* set to zero unless restarting at a break point given by output *)
          (* of RLuxAt (see RLuxAt). RanLux will then skip over             *)
          (* K1 + 10**9*K2 numbers to reach the break point. This can be    *)
          (* rather time consuming - see RLuxUt/RLuxIn for an alternative   *)
          (* to restart RanLux.                                             *)
          (*----------------------------------------------------------------*)

PROCEDURE RLuxAt(VAR Lout,InOut,K1,K2 : INTEGER);

          (*----------------------------------------------------------------*)
          (* Origin : CERN Program Library (SUBROUTINE RANLUX)              *)
          (*                                                                *)
          (* Entry to output the "convenient" restart point                 *)
          (* gets the values of four integers which can be used to restart  *)
          (* the RanLux generator at the current point by calling RLuxGo.   *)
          (* K1 and K2 specify how many numbers were generated since the    *)
          (* initialization with LUX and INT. The restarting skips over     *)
          (* K1+K2*E9 numbers, so it can be long.                           *)
          (*----------------------------------------------------------------*)

PROCEDURE RLuxUt(VAR ISDext : SeedVektor);

          (*----------------------------------------------------------------*)
          (* Origin : CERN Program Library (SUBROUTINE RANLUX)              *)
          (*                                                                *)
          (* Entry to ouput seeds as integers                               *)
          (* Outputs the current values of the 25 ++ 32-bit integer seeds,  *)
          (* to be used for restarting.  Argument must be dimensioned 25 in *)
          (* the calling program.                                           *)
          (*----------------------------------------------------------------*)

PROCEDURE RLuxIn(VAR ISDext : SeedVektor);

          (*----------------------------------------------------------------*)
          (* Origin : CERN Program Library (SUBROUTINE RANLUX)              *)
          (*                                                                *)
          (* Entry to input and float integer seeds from previous run       *)
          (* more efficient but less convenient way of restarting is by     *)
          (* RLuxIn(ISDext). It restarts the generator from vector          *)
          (* ISVEC of 25 32-bit integers (see RLuxUt)                       *)
          (*                                                                *)
          (* HINT : If seed or luxlevel had been chenge in between they     *)
          (* need to be re-set by RLuxGo(originalLuxlevel,originalSeed,0,0) *)
          (* before the call to RLuxIn !!!                                  *)
          (*----------------------------------------------------------------*)

PROCEDURE RanLux(VAR RVec : ARRAY OF LONGREAL;
                     LenV : INTEGER);

          (*----------------------------------------------------------------*)
          (* Origin : CERN Program Library (SUBROUTINE RANLUX)              *)
          (*                                                                *)
          (* Returns a vector RVec of LenV of 32-bit random floating point  *)
          (* numbers between zero (not included) and one (also not incl.).  *)
          (* Subtract-and-borrow random number generator proposed by        *)
          (* Marsaglia and Zaman, implemented by F. James with the name     *)
          (* RCARRY in 1991, and later improved by Martin Luescher in 1993  *)
          (* to produce "Luxury Pseudorandom Numbers".                      *)
          (*                                                                *)
          (* The available luxury levels are:                               *)
          (*                                                                *)
          (* 0 : p=24: equivalent to the original RCARRY of Marsaglia       *)
          (*     and Zaman, very long period, but fails many tests.         *)
          (* 1 : p=48: considerable improvement in quality over level 0,    *)
          (*     now passes the gap test, but still fails spectral test.    *)
          (* 2 : p=97: passes all known tests, but theoretically still      *)
          (*     defective.                                                 *)
          (* 3 : p=223: DEFAULT VALUE. Any theoretically possible           *)
          (*     correlations have very small chance of being observed.     *)
          (* 4 : p=389: highest possible luxury, all 24 bits chaotic.       *)
          (*                                                                *)
          (* The level can be change via routine RLuxGo                     *)
          (*----------------------------------------------------------------*)

END RandomLib.
