// --------------------------------------------
//
// Swarm rel. 1.0 (random rel. 0.6)
//
// Notes on the use of the distribution objects
//
// Sven Thommesen <sthomme@humsci.auburn.edu>
//
// 1997-01-15
//
// --------------------------------------------

USAGE notes:
------------

This library (random) implements all the distributions that were in
previous objects, but somewhat rearranged. They are now standard Swarm
objects that inherit from SwarmObject. There are now 3 uniform
distribution objects: UniformInteger, UniformUnsigned, and UniformDouble,
which return results of the specified type over some range. There is a
random-bit object, which returns a stream of random coin tosses as 
boolean or integer values.

In addition, there are now objects which return variates drawn from the
Normal, the LogNormal, the Exponential, and the Gamma distributions.

Improvements over previous versions of the random library:

(a) the UniformInteger and UniformUnsigned objects now have code added
that prevents bias from creeping in when converting from the full range
of a random generator value. Thanks due to Barry McMullin!

(b) every distribution that returns a floating point double value now
uses TWO unsigned (32-bit) generator values to create a uniform [0.0,1.0)
value, which is the universal intermediate result. We therefore now have
full precision; all bits of the mantissa are significant. The code to do
this was borrowed from the libg++ library.


// -----

More distributions will be added to this library in the future.
Please let me know if there is one whose absence is particularly keenly felt.

These objects were designed in a minimalist fashion; extraneous
functionality was avoided. However, you the user call the shots!
If you think of functionality that you feel is missing from this
release of the random library, please e-mail me with your suggestions.

// -----

COMMON FUNCTIONALITY:

Each distribution object must be assigned a pre-created random generator
on creation. You may not re-assign generators to a distribution after it
has been created.

Each distribution has its own set of (1-2) parameters. You may deal with 
these parameters in two different ways: (1) you assign a set of parameter
values to the object on creation, and all subsequent draws from this 
distribution are made using those parameters; or (2) you do not assign
parameter values to the object on creation -- instead, you must specify
(possibly different) parameter values to the object every time you want
to obtain a random number from it.

Just like the generator objects, the distribution objects allow you to 
save and later restore their internal state.

// -----

Where I use NormalDistribution in examples below, substitute any other
distribution and its parameters as needed.

You CREATE a distribution in one of several ways:

(a) the hard way:

	aDistribution = [ NormalDistribution
			createBegin: [self getZone] ];
	[ aDistribution setGenerator: aGenerator ];	// created earlier
	aDistribution = [ aDistribution createEnd ];

(b) the easier way:

	aDistribution = [ NormalDistribution
			create: [self getZone]
			setGenerator: aGenerator ];	// created earlier

You CANNOT use the following idiom (it generates an error & halts):

	aDistribution = [ NormalDistribution create: [self getZone ]];
	[ aDistribution setGenerator: aGenerator ];

Note that a (pre-created) generator MUST be supplied when a distribution 
object is created. The distribution is 'wedded' to this generator for 
the rest of its life. You cannot later assign a different generator 
to a distribution.

(However, it IS possible to assign the SAME generator to DIFFERENT 
distribution objects. The statistical advisability of doing so, versus
the advisability of assigning different generators of the same kind to
each distribution object, is your call. But note: if you choose the 
latter path, you better use different seeds for each generator ...)


Every distribution has a small number of parameters that govern its output.
Swarm distribution objects allow you to deal with these parameters in two
different ways. You may think of these objects as being of two kinds, the
'frozen' kind and the variable kind.

(c) frozen objects:

With the 'frozen' kind, you assign values to the parameters when the object
is created, and those parameters govern the object's operation for the rest
of its life.

You do this by adding the following call to the creation sequences above:

	[ aDistribution setMean: meanValue
			setVariance: varianceValue ];

You may then obtain successive random values from the chosen distribution by
calling

	dValue = [ aDistribution getDoubleSample ];

There is a comprehensive creation method that sets all parameters in one call:

	aDistribution = [ NormalDistribution
			create: [self getZone]
			setGenerator: aGenerator
			setMean: meanValue
			setVariance: varianceValue ];

(d) non-frozen objects:

If you do NOT set the parameters (here, mean and variance) when creating the
distribution object (methods a and b above), you may supply different 
parameters for every time you want to obtain a random value:

	dValue = [ aDistribution getSampleWithMean: meanValue
					withVariance: varianceValue ];


NOTE: you may 'freeze' a non-frozen distribution at any time by calling
setMean:setVariance:. It will remain frozen thereafter.

NOTE: you must of course create any generators before assigning them to
a distribution. Or, you may do the all-in-one act of creation:

	aDistribution = [ NormalDistribution
			create: [self getZone]
			setGenerator: [ SWB1 create: [self getZone]
					setStateFromSeed: seedValue ]
			setMean: meanValue
			setVariance: varianceValue ];

You may find out if a distribution object has been 'frozen' by calling

	boolValue = [ aDistribution getOptionsInitialized ];

And you may obtain the values for the parameters (mean, variance, standard
deviation) by method calls named in obvious ways.

NOTE: ABOMINABLE BEHAVIOR: it IS possible to reset the state of a 
generator ('behind the distribution's back', as it were) using

	[ [ aDistribution getGenerator] setStateFromSeed: seedValue ];

However, keep in mind that for distribution objects that keep an internal
state (such as Normal and LogNormal), the next number drawn from the 
distribution may not yet have been drawn from the reset generator. You 
might wish to avoid doing such a thing, unless you have inspected the
source code and know it to be safe!


You may SAVE AND RESTORE THE INTERNAL STATE of a distribution object in a 
manner analogous to that of the generator objects (see README.Generators).

PLEASE NOTE: the state of a distribution object is saved independently
of that of the generator attached to it. You, the user, must keep track of 
what generator state goes with what distribution state. While the distribution
objects perform some checks on the state data given to them, it is probably
possible to mess up if you are not careful.

(The important thing is that if you save the state of a NormalDistribution
object which has a PMMLCG1 generator attached to it, you must later create
a NormalDistribution object with a PMMLCG1 generator before you use setState
on them. Any attempt to feed ExponentialDistribution data to a Normal-
Distribution object will be detected and rejected, as will attempts to feed
PMMLCG2 data to a PMMLCG1 generator.)

NOTE: if you discover any malfunction in any of these distribution objects,
kindly e-mail me soonest so the problem can be rectified.


PROGRAMMING notes:
------------------

Every distribution object is subclassed from the RandomDistribution object,
which is a subclass of SwarmObject. Code and data common to all distributions
is in RandomDistribution, and the subclassed distributions add their own data
and override RandomDistribution methods as needed.

RandomDistribution is not functional as a standalone object.

Each distribution object implements:

-initState;		// called by createBegin; initializes fixed
			// (unchanging) parameters for the distribution

-resetState;		// called by setGenerator and by the method that
			// sets parameters; it initializes (resets) 
			// parameters that depend on the values supplied,
			// and other variable working data (state data).

-getStateSize;		// obtain the required buffer size for getState
-getState;		// extract object's internal state into user's buffer
-setState;		// set object's internal state from user's buffer

Depending on the type of value returned, each FROZEN distribution implements:

-(double)   getDoubleSample;    or
-(unsigned) getUnsignedSample;  or
-(int)      getIntegerSample.

Each UNFROZEN distribution will also have a method call returning successive
random numbers, of the following type:

-(double)   getSampleWithParam1: (double)   p1 withParam2: (double)   p2;
-(unsigned) getSampleWithParam1: (unsigned) p1 withParam2: (unsigned) p2;
-(int)      getSampleWithParam1: (int)      p1 withParam2: (int)      p2;

where 'Param1' and 'Param2' are replaced by the names of the actual parameters.

// -----

