Random contains a variety of random number distributions as static
instance variables as well as a few next* methods for returning the
next psuedo-random value from a distribution. Before using any of the
instance variable distributions, these distributions must be created via
the appropriate create* method. For example,
This creates a uniform distribution from which to draw random numbers.
You can then draw random numbers from this distribution using
the the appropriate methods. See the cern.jet.random package in the
colt documentation for the details
of these methods. The actual random number generator is seeded on
first use with the current timestamp. See below for more details on
seeding the generator.
// initialize Random.uniform
Random.createUniform();
// Random.uniform is now initialized and can be used.
int index = Random.uniform.getNextIntFromTo(0, 100);
Once created a distribution can be used anywhere in your code through the
use of Random's static instance variables. So for example, if you create
the Uniform distribution in your model's begin() method, you can access the
same Uniform distribution in your model's agent code with
Random.uniform. This instance variable should always be
referenced as such, that is, as Random._distribution_name_, and not as
the right hand side of an assignment. Assigning a variable in this way
can lead to unpredictable results when setting the random seed.
In short, code like this:
and never like this:
int index = Random.uniform.nextIntFromTo(0, 10);
All but one of the distributions in Random are from the
colt library. The instance variable name is the same as
the corresponding colt object with the first
character in lower case. For example, the cern.jet.Random.Zeta distribution
is Random.zeta. See the cern.jet.random package in the
colt library documentation
for more information about these distributions, and how to
draw random numbers from them.
The next* methods can be used as is, without creating a distribution
before hand. For example,
Uniform myUniform = Random.uniform; // This is dangerous. Don't do it!!!
...
int index = myUniform.nextIntFromTo(0, 10);
Draws the next value from a Cauchy distribution.
double s = Random.nextCauchy();
In all cases, the distributions use a MersenneTwister as the
source for psuedo-random numbers. The MersenneTwister is a
particularly good generator for simulations as it has an
extremely large period. This generator is seeded on first use
with the current timestamp. However, Random also allows you to set and
get the random seed as well as the random number generator associated
with that seed. Setting a new seed with Random.setSeed
will create a new MersenneTwister with the specified seed and
invalidate any previously created distributions. If you wish to use
a distribution after the seed has been set, you must create it as
described above. Consequently, the following is correct code:
but this is not:
Random.createUniform();
int index = Random.uniform.nextIntFromTo(1, 10);
...
Random.setSeed(1L);
Random.createUniform();
...
int index = Random.uniform.nextIntFromTo(1, 10);
Calling a Repast model's setRngSeed method will also set Random's seed,
as will setting the seed through the parameter's panel of a gui model.
Once the seed has been set all the distributions will
use the same random number stream and repeatable randomness can be
easily achieved.
Random.createUniform();
int index = Random.uniform.nextIntFromTo(1, 10);
...
Random.setSeed(1L);
...
int index = Random.uniform.nextIntFromTo(1, 10); // This won't work
Note that Random creates a default random number generator using the current timestamp as the seed. If you do not explicitly set your own seed, the distributions created via the create* calls will use this default generator.
The normal pattern of use then is to create the distributions you want,
and having done so draw randon numbers from those distributions
througout your code via Random's instance variables. For
example:
For more information see the doc for cern.jet.random in the
colt library documentation.
Custom Random Number Generation
Random.createUniform();
Random.createNormal(.5, .3);
...
int index = Random.uniform.nextIntFromTo(0, 10);
double val = Random.normal.nextDouble();
Custom random number generation still uses the colt library but
bypasses Repast's Random class. You'll need to do this if you
want to use distributions with independent random number streams (random
number generators). The general idea here is to define some
instance variables in your model of the appropriate distribution
types, create your random number generators and then associate these
generators with the distributions you want to use. For example:
The important part here is the creation of two different
MersenneTwisters. This will provide two different random number
streams to the distributions. You can parameterize the seeds
to these distributions and make them available to be set via the
user interface or through a parameter file, by providing get
and set methods for two seed values. You would then use the seed variables
to seed the MersenneTwisters in place of "123" and "321" above.
If the seeds are user specifiable, its also important to create
the distributions in the begin() method rather than the setup() method.
Any parameter changes will occur after setup() has been called and
so creating your distributions there will ignore any parameter changes.
import cern.jet.random.*;
import cern.jet.random.engine.MersenneTwister;
...
public class MyModel extends SimModelImpl {
Normal myNormalDist;
Uniform myUniformDist;
...
public void begin() {
MersenneTwister generator1 = new MersenneTwister(123);
MersenneTwister generator2 = new MersenneTwister(321);
myNormalDist = new Normal(1.0, 1.0, generator1);
myUniformDist = new Uniform(generator2);
}
...
public void someMethod() {
int index = myUniformDist.nextIntFromTo(0, 10);
doubl val = myNormalDist.nextDouble();
}
}