//  Swarm library. Copyright (C) 1996 Santa Fe Institute.
// This library is distributed without any warranty; 
// without even the implied warranty of merchantability 
// or fitness for a particular purpose.
// See file LICENSE for details and terms of copying.

/*
Name:            LCG2gen.m
Description:     Linear Congruential Generator
Library:         random
Original Author: Nelson Minar
Date:            1996-09-09
Modified by:     Sven Thommesen
Date:            1997-01-15
*/

/*
123456789|123456789|123456789|123456789|123456789|123456789|123456789|123456789|
*/

// LCG1: Linear Congruential generator
//   X_n+1 = (a * X_n + c) mod 2^32

// Nelson's comments about LCG:

// Algorithm taken from Knuth "Art of Computer Programming" vol. II.
// Should have period 2^32 and be reasonably random and efficient.
// However, the low order bits are poor.

// Knuth claims that the adder c does not really matter as long as it
// doesn't have factors in common with the modulus (2^32). I'm taking this
// recommendation from Numerical Recipes, in turn from H.W. Lewis.

// Note: this code relies on controlled overflow at 32 bits. This requires
// that unsigned be a 32 bit value that follows ANSI C rules.

#import <collections.h>
#import <random/LCG2gen.h>

@implementation LCG2

// This struct is used by getState and setState
// to pass our state data to/from other objects:

typedef struct {
// Generator identification:
  unsigned magic;
// RandomNumberGenerator data:
  unsigned stateSize;
  unsigned unsignedMax;
  unsigned initialSeed;
  unsigned currentCount;
// generator specific data:
  unsigned a;
  unsigned c;
  unsigned state;
} state_struct_t;

-resetState {				// Override RandomNumberGenerator method

// Called by setStateFromSeed in the superclass.

// If initialSeed needs to be tested for sanity, do it here:
   // seed==4x+1? seed isOdd?

// Load the state vector from the starting seed:

  state = initialSeed;

  return self;
}


-initState {				// Override RandomNumberGenerator method

// Called by createBegin in the superclass.

// Math is modulo 2^32, so max value is 2^32-1
   unsignedMax =  0xffffffffU;

// State size for getState and setState:
   stateSize = sizeof(state_struct_t);

// Set the 'personality' of this generator:
// ( Reference: Knuth p. 26 )

  a = LCG2MULTIPLIER;
  c = LCG2ADDER;

// The state vector is allocated as an instance variable.
// It is initialized in resetState above.

   return self;
}


// ----- protocol RandomNumberGenerator: -----

-(unsigned) getUnsignedSample {		// Override RandomNumberGenerator method

// Generate the next 'random' value from the state.
// The math is implicitly modulo 2^32.

// Algorithm for LCG:
//   new = (a * old + c) mod 2^32

// NOTE: no check is made that the state has been properly initialized.
// Responsibility for doing so rests with the RandomNumberGenerator class.

// Update count of variates delivered:

  currentCount++;

// Calculate next variate:

  state = a * state + c;		// implicitly modulo 2^32

  return state;
}

// ----- protocol InternalState: -----

-(void) getState: (void *) stateBuf {	// Override RandomNumberGenerator method
   state_struct_t * internalState;

// Recast the caller's pointer:
internalState = (state_struct_t *) (stateBuf) ;

// Fill the external buffer with current values:
  // Generator identification:
  internalState->magic = LCG2MAGIC;
  // RandomNumberGenerator variables:
  internalState->unsignedMax = unsignedMax;
  internalState->stateSize = stateSize;
  internalState->initialSeed = initialSeed;
  internalState->currentCount = currentCount;
  // generator specific variables:
  internalState->a = a;
  internalState->c = c;
  internalState->state = state;

  // nothing returned from a (void) function
}

-(void) setState: (void *) stateBuf {	// Override RandomNumberGenerator method
   state_struct_t * internalState;

// Recast the caller's pointer:
internalState = (state_struct_t *) (stateBuf) ;

// TEST the integrity of the external data:
if (     (internalState->magic     != LCG2MAGIC)
      || (internalState->stateSize != stateSize)
      || (internalState->a         != a)
      || (internalState->c         != c) 
   )
[InvalidCombination raiseEvent:
 "LCG2 generator: your are passing bad data to setState!\n %u %u %u %u\n",
  internalState->magic, internalState->stateSize, 
  internalState->a, internalState->c ];

// Place external data into internal variables:
  // RandomNumberGenerator variables:
    // stateSize = internalState->stateSize;
    // unsignedMax = internalState->unsignedMax;
  initialSeed = internalState->initialSeed;
  currentCount = internalState->currentCount;
  // generator specific variables:
    // a = internalState->a;
    // c = internalState->c;
  state = internalState->state;

  // nothing returned from a (void) function
}

// ----- temporary methods: -----

- (void) describe: outStream {	// Extend RandomNumberGenerator method
  char buffer[200];
  //  int i;

  (void)sprintf(buffer,"LCG2 describe: outStream: \n");
  (void)sprintf(buffer,"            a = %u\n", a);
  (void)sprintf(buffer,"            c = %u\n", c);
  (void)sprintf(buffer,"        state = %u\n", state);

  [super describe: outStream];			// Print RandomNumberGenerator data
  [outStream catC: buffer];
  [outStream catC: "\n"];

  //return self;
}

-(int) verifySelf {
   const unsigned testValue = 87216529U;
   unsigned bitbucket;
   int i;

   [self setStateFromSeed: 1];

   for (i = 0; i < 10000; i++)
     bitbucket = [self getUnsignedSample];

   if (bitbucket == testValue) {
     printf("    LCG2: Verify passed. Actual value = Expected value = %u\n",
       testValue);
     return 1;
   } else {
     printf("    LCG2: Verify failed! Actual value = %u, Expected value = %u\n",
       testValue, bitbucket);
     return 0;
   } 

}

@end
