// Swarm library. Copyright (C) 1996 Santa Fe Institute.
//  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:            UniformDouble.m
Description:     Uniform distribution returning double values
Library:         random
Original Author: Sven Thommesen
Date:            1997-01-15
*/

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

// 
// Methods to generate the next pseudo-random number in a stream:
// 
// // Using the bit generator to create Uniform numbers.
//
// // Bit generators return values in the interval [0,maxValue].
// // For the implemented generators, maxValue is:
// //    PMMLCG:  2,147,483,645 = 2^31 - 3
// //    SWB:     4,294,967,295 = 2^32 - 1
// //    LCG:     4,294,967,295 = 2^32 - 1
// //    ACG:     4,294,967,295 = 2^32 - 1
// //    SCG:       999,999,999 = 10^9 - 1 (29.9 bits)
// 


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


@implementation UniformDouble

// data struct used by getState and setState:
//
typedef struct {
   // Object identification:
   unsigned magic;
   // unsigned generator_magic;	// later
   // ProbabilityDistribution variables:
   unsigned stateSize;
   BOOL optionsInitialized;
   unsigned currentCount;
   unsigned generatorMax;
   double maxDivisor;
   double duuMask;
   // Distribution specific data:
   double doubleMin;
   double doubleMax;
   double doubleRange;
} state_struct_t;

// ----- internal methods -----

-resetState {

// Called by setGenerator in the superclass
// and by setMax:Min: below.

   currentCount = 0;

   return self;
}

-initState {
   UnsignedOverlayDouble duuTemp;
   // volatile double x;
   // double y;

// Called by createBegin in the superclass.

   stateSize = sizeof(state_struct_t);

   doubleMin   = 0.0;
   doubleMax   = 0.0;
   doubleRange = 0.0;
   currentCount = 0;

// State variables are allocated as instance variables
// and initialized in resetState above.

// ----------------------------

   // Now for the libg++ magic:

   if ( sizeof(double) != 2*sizeof(unsigned) )
   [InvalidCombination raiseEvent:
   " double <> 2 unsigneds: math will fail!!! \n"];

// #if_IEEE == 1
// #ifdef _IEEE

   //   printf(" initState: IEEE is defined \n");
   duuTemp.d = 1.5;
   if (duuTemp.u[1] == 0) {	// sun word order?
     //printf(" initState: sun word order \n");
     duuTemp.u[0] = 0x3fffffff;
     duuTemp.u[1] = 0xffffffff;
   } else {			// encore word order?
     //printf(" initState: encore word order \n");
     duuTemp.u[0] = 0xffffffff;
     duuTemp.u[1] = 0x3fffffff;
   }

/*
#else IEEE

   printf(" initState: IEEE is *not* defined \n");

   x = 1.0;
   y = 0.5;

   do {
     duuTemp.d = x;
     x += y;
     y *= 0.5;
   } while ( x != duuTemp.d && x < 2.0);

#endif IEEE
*/

   duuMask.d = 1.0;
   duuMask.u[0] ^= duuTemp.u[0];
   duuMask.u[1] ^= duuTemp.u[1];

// ----------------------------

   return self;
}

// This method returns values in the interval [0.0,1.0):

-(double) rDouble {
  double rdValue;
  unsigned bitValue;

  bitValue = [randomGenerator getUnsignedSample];
  rdValue = (double) (bitValue / maxDivisor);

  return rdValue;
}

// This method returns values in the interval (0.0,1.0):

-(double) nzrDouble {
  double rdValue;
  unsigned bitValue;

  do { bitValue = [randomGenerator getUnsignedSample]; }
  while (bitValue == 0);		// So we don't return 0.0

  rdValue = (double) (bitValue / maxDivisor);

  return rdValue;
}

// This method fills each double with two successive generator 
// values (64 bits). It will never return 0.0.

-(double) duuDouble {
   unsigned bitValue0, bitValue1;
   UnsignedOverlayDouble duuValue;

   bitValue0 = [randomGenerator getUnsignedSample];
   bitValue1 = [randomGenerator getUnsignedSample];

//   printf(" duuValue: generator inputs were %u and %u \n", 
//	bitValue0, bitValue1);

   duuValue.d = 1.0;
   duuValue.u[0] |= (bitValue0 & duuMask.u[0]);
   duuValue.u[1] |= (bitValue1 & duuMask.u[1]);
   duuValue.d -= 1.0;

   if ((duuValue.d >= 1.0) || (duuValue.d < 0))
   [InvalidCombination raiseEvent:
   "duuDouble: result was not in [0.0,1.0) -- sigh... \n"];

//   printf(" duuValue: d0=%60.50f\n", duuValue.d);

   return duuValue.d;
}

// ----- protocol UniformDouble -----

+create: (id) aZone setGenerator: (id) generator
	setDoubleMin: (double) minValue setMax: (double) maxValue {
   UniformDouble * aDistribution;
   double tmpMin, tmpMax, tmpRange;

   aDistribution = [ super create: aZone setGenerator: generator ];

   if (minValue == maxValue)
   [InvalidCombination raiseEvent:
   "UniformDouble: setting minValue = maxValue not allowed!\n"];

   // Ensure that doubleMax > doubleMin:

   if (maxValue > minValue) {
     tmpMax = maxValue;
     tmpMin = minValue;
   } else {
     tmpMax = minValue;
     tmpMin = maxValue;
   }
   tmpRange = tmpMax - tmpMin;

   aDistribution->doubleMax   = tmpMax;
   aDistribution->doubleMin   = tmpMin;
   aDistribution->doubleRange = tmpRange;

   // This object is now fixed:

   aDistribution->optionsInitialized = YES;

   [ aDistribution resetState ];

   return aDistribution;
}

-(void) setDoubleMin: (double) minValue setMax: (double) maxValue {

   if (optionsInitialized)
   [InvalidCombination raiseEvent:
   "UniformDouble: setting parameters more than once not allowed\n"];

   if (minValue == maxValue)
   [InvalidCombination raiseEvent:
   "UniformDouble: setting minValue = maxValue not allowed!\n"];

   // Ensure that doubleMax > doubleMin:

   if (maxValue > minValue) {
     doubleMax = maxValue;
     doubleMin = minValue;
   } else {
     doubleMax = minValue;
     doubleMin = maxValue;
   }
   doubleRange = doubleMax - doubleMin;

   // This object is now fixed:

   optionsInitialized = YES;

   [ self resetState ];

   //   return self;
}

-(double) getDoubleMin {
   return doubleMin;
}

-(double) getDoubleMax {
   return doubleMax;
}

// ---------------------------------------------------

-(double) getDoubleWithMin: (double) minValue withMax: (double) maxValue {
   double tmpMin, tmpMax, tmpRange;
   double rdValue;

   if (optionsInitialized)
   [InvalidCombination raiseEvent:
   "UniformDouble: getDoubleWithMin:withMax: options already initialized\n"];

   if (minValue == maxValue)
   [InvalidCombination raiseEvent:
   "UniformDouble: setting minValue = maxValue not allowed!\n"];

   currentCount++ ;

   // Ensure tmpMax > tmpMin:

   if (maxValue > minValue) {
     tmpMax = maxValue;
     tmpMin = minValue;
   } else {
     tmpMax = minValue;
     tmpMin = maxValue;
   }
   tmpRange = tmpMax - tmpMin;

   // Generate a value in [0.0,1.0)
   // rdValue = [self rDouble];

   rdValue = [self duuDouble];

   // Generate a value in [minValue,maxValue)
   // (using the values supplied for this call only)

   rdValue = rdValue*tmpRange + tmpMin;

   return rdValue;
}

// ----- protocol DoubleDistribution -----

-(double) getDoubleSample {
   double rdValue;

   if (!optionsInitialized)
   [InvalidCombination raiseEvent:
   "UniformDouble: getDoubleSample: options have not been initialized\n"];

   currentCount++ ;

   // Generate a value in [0.0,1.0)
   // rdValue = [self rDouble];

   rdValue = [self duuDouble];

   // Generate a value in [doubleMin, doubleMax)
   // (using fixed values set at creation)

   rdValue = rdValue*doubleRange + doubleMin;

   return rdValue;
}

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

-(void) getState: (void *) stateBuf {		// override superclass method
   state_struct_t * internalState;
   // unsigned generator_magic;

  // obtain my generator's magic number:
  // (no way to do that yet)

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

  // fill the caller's buffer with state data:
  // object identification:
  internalState->magic = UNIFORMDOUBLEMAGIC;
  // internalState->generator_magic = generator_magic;
  // ProbabilityDistribution data:
  internalState->stateSize = stateSize;
  internalState->optionsInitialized = optionsInitialized;
  internalState->currentCount = currentCount;
  internalState->generatorMax = generatorMax;
  internalState->maxDivisor = maxDivisor;
  internalState->duuMask = duuMask.d;
  // distribution specific data:
  internalState->doubleMin = doubleMin;
  internalState->doubleMax = doubleMax;
  internalState->doubleRange = doubleRange;

  // nothing is returned from a (void) function

}

-(void) setState: (void *) stateBuf {		// override superclass method
   state_struct_t * internalState;

  // obtain my generator's magic number:
  // (no way to do that yet)

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

  // TEST the integrity of the external data:
  if (    (internalState->magic     != UNIFORMDOUBLEMAGIC)
       || (internalState->stateSize != stateSize)
//     || (internalState->generator_magic != generator_magic)
     )
  [InvalidCombination raiseEvent:
  "UniformDouble: you are passing bad data to setState!\n %u %u\n",
   internalState->magic, internalState->stateSize];

  // set internal state from data in caller's buffer:
  // ProbabilityDistribution data:
    // stateSize = internalState->stateSize;
  optionsInitialized = internalState->optionsInitialized;
  currentCount = internalState->currentCount;
    // generatorMax = internalState->generatorMax;
    // maxDivisor = internalState->maxDivisor;
    // duuMask.d = internalState->duuMask;
  // distribution specific data:
  doubleMin   = internalState->doubleMin;
  doubleMax   = internalState->doubleMax;
  doubleRange = internalState->doubleRange;

  // nothing is returned from a (void) function

}

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

- (void) describe: outStream {
  char buffer[200];

  (void)sprintf(buffer," UniformDouble describe: outStream: \n");
  (void)sprintf(buffer,"      doubleMin = %f\n", doubleMin);
  (void)sprintf(buffer,"      doubleMax = %f\n", doubleMax);
  (void)sprintf(buffer,"    doubleRange = %f\n", doubleRange);

  [ super describe: outStream ];
  [outStream catC: buffer];
  [outStream catC: "\n"];

  //  return self;
}

-(int) verifySelf {

   return 1;
}

@end
