Author: psteitz Date: Wed Jun 1 20:06:45 2005 New Revision: 179494 URL: http://svn.apache.org/viewcvs?rev=179494&view=rev Log: Added RandomAdaptor to complete PRNG pluggability framework, updated User Guide.
Added: jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/random/RandomAdaptor.java jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/random/RandomAdaptorTest.java Modified: jakarta/commons/proper/math/trunk/xdocs/userguide/index.xml jakarta/commons/proper/math/trunk/xdocs/userguide/random.xml Added: jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/random/RandomAdaptor.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/random/RandomAdaptor.java?rev=179494&view=auto ============================================================================== --- jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/random/RandomAdaptor.java (added) +++ jakarta/commons/proper/math/trunk/src/java/org/apache/commons/math/random/RandomAdaptor.java Wed Jun 1 20:06:45 2005 @@ -0,0 +1,121 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.random; + +import java.util.Random; + +/** + * Extension of <code>java.util.Random</code> wrapping a + * [EMAIL PROTECTED] RandomGenerator}. + * + * @since 1.1 + * @version $Revision:$ $Date$ + */ +public class RandomAdaptor extends Random implements RandomGenerator { + + /** Wrapped randomGenerator instance */ + private RandomGenerator randomGenerator = null; + + /** + * Prevent instantiation without a generator argument + */ + private RandomAdaptor() { } + + /** + * Construct a RandomAdaptor wrapping the supplied RandomGenerator. + * + * @param randomGenerator the wrapped generator + */ + public RandomAdaptor(RandomGenerator randomGenerator) { + this.randomGenerator = randomGenerator; + } + + /** + * Factory method to create a <code>Random</code> using the supplied + * <code>RandomGenerator</code>. + * + * @param randomGenerator + * @return a Random instance wrapping the RandomGenerator + */ + public static Random createAdaptor(RandomGenerator randomGenerator) { + return new RandomAdaptor(randomGenerator); + } + + /* (non-Javadoc) + * @see java.util.Random#nextBoolean() + */ + public boolean nextBoolean() { + return randomGenerator.nextBoolean(); + } + + /* (non-Javadoc) + * @see java.util.Random#nextBytes(byte[]) + */ + public void nextBytes(byte[] bytes) { + randomGenerator.nextBytes(bytes); + } + + /* (non-Javadoc) + * @see java.util.Random#nextDouble() + */ + public double nextDouble() { + return randomGenerator.nextDouble(); + } + + /* (non-Javadoc) + * @see java.util.Random#nextFloat() + */ + public float nextFloat() { + return randomGenerator.nextFloat(); + } + + /* (non-Javadoc) + * @see java.util.Random#nextGaussian() + */ + public double nextGaussian() { + return randomGenerator.nextGaussian(); + } + + /* (non-Javadoc) + * @see java.util.Random#nextInt() + */ + public int nextInt() { + return randomGenerator.nextInt(); + } + + /* (non-Javadoc) + * @see java.util.Random#nextInt(int) + */ + public int nextInt(int n) { + return randomGenerator.nextInt(n); + } + + /* (non-Javadoc) + * @see java.util.Random#nextLong() + */ + public long nextLong() { + return randomGenerator.nextLong(); + } + + /* (non-Javadoc) + * @see java.util.Random#setSeed(long) + */ + public void setSeed(long seed) { + if (randomGenerator != null) { // required to avoid NPE in constructor + randomGenerator.setSeed(seed); + } + } +} Added: jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/random/RandomAdaptorTest.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/random/RandomAdaptorTest.java?rev=179494&view=auto ============================================================================== --- jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/random/RandomAdaptorTest.java (added) +++ jakarta/commons/proper/math/trunk/src/test/org/apache/commons/math/random/RandomAdaptorTest.java Wed Jun 1 20:06:45 2005 @@ -0,0 +1,103 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.random; +import junit.framework.Test; +import junit.framework.TestSuite; +import java.util.Random; + +/** + * Test cases for the RandomAdaptor class + * + * @version $Revision:$ $Date$ + */ + +public class RandomAdaptorTest extends RandomDataTest { + + public RandomAdaptorTest(String name) { + super(name); + } + + public static Test suite() { + TestSuite suite = new TestSuite(RandomAdaptorTest.class); + suite.setName("RandomAdaptor Tests"); + return suite; + } + + public void testAdaptor() { + ConstantGenerator generator = new ConstantGenerator(); + Random random = RandomAdaptor.createAdaptor(generator); + checkConstant(random); + RandomAdaptor randomAdaptor = new RandomAdaptor(generator); + checkConstant(randomAdaptor); + } + + private void checkConstant(Random random) { + byte[] bytes = new byte[] {0}; + random.nextBytes(bytes); + assertEquals(0, bytes[0]); + assertEquals(false, random.nextBoolean()); + assertEquals(0, random.nextDouble(), 0); + assertEquals(0, random.nextFloat(), 0); + assertEquals(0, random.nextGaussian(), 0); + assertEquals(0, random.nextInt()); + assertEquals(0, random.nextInt(1)); + assertEquals(0, random.nextLong()); + random.setSeed(100); + assertEquals(0, random.nextDouble(), 0); + } + + /* + * "Constant" generator to test Adaptor delegation. + * "Powered by Eclipse ;-)" + * + */ + private class ConstantGenerator implements RandomGenerator { + + public boolean nextBoolean() { + return false; + } + + public void nextBytes(byte[] bytes) { + } + + public double nextDouble() { + return 0; + } + + public float nextFloat() { + return 0; + } + + public double nextGaussian() { + return 0; + } + + public int nextInt() { + return 0; + } + + public int nextInt(int n) { + return 0; + } + + public long nextLong() { + return 0; + } + + public void setSeed(long seed) { + } + } +} Modified: jakarta/commons/proper/math/trunk/xdocs/userguide/index.xml URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/xdocs/userguide/index.xml?rev=179494&r1=179493&r2=179494&view=diff ============================================================================== --- jakarta/commons/proper/math/trunk/xdocs/userguide/index.xml (original) +++ jakarta/commons/proper/math/trunk/xdocs/userguide/index.xml Wed Jun 1 20:06:45 2005 @@ -50,7 +50,8 @@ <li><a href="random.html#2.2 Random numbers">2.2 Random numbers</a></li> <li><a href="random.html#2.3 Random Strings">2.3 Random Strings</a></li> <li><a href="random.html#2.4 Random permutations, combinations, sampling">2.4 Random permutations, combinations, sampling</a></li> - <li><a href="random.html#2.5 Generating data &apos;like&apos; an input file">2.5 Generating data 'like' an input file</a></li> + <li><a href="random.html#2.5 Generating data 'like' an input file">2.5 Generating data 'like' an input file</a></li> + <li><a href="random.html#2.6 PRNG Pluggability">2.6 PRNG Pluggability</a></li> </ul></li> <li><a href="linear.html">3. Linear Algebra</a> <ul> Modified: jakarta/commons/proper/math/trunk/xdocs/userguide/random.xml URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/math/trunk/xdocs/userguide/random.xml?rev=179494&r1=179493&r2=179494&view=diff ============================================================================== --- jakarta/commons/proper/math/trunk/xdocs/userguide/random.xml (original) +++ jakarta/commons/proper/math/trunk/xdocs/userguide/random.xml Wed Jun 1 20:06:45 2005 @@ -34,95 +34,130 @@ <ul> <li>generating random numbers</li> <li>generating random strings</li> - <li>generating cryptographically secure sequences of random numbers or strings</li> + <li>generating cryptographically secure sequences of random numbers or + strings</li> <li>generating random samples and permuations</li> - <li>analyzing distributions of values in an input file and generating values "like" - the values in the file</li> - <li>generating data for grouped frequency distributions or histograms</li> - </ul></p> + <li>analyzing distributions of values in an input file and generating + values "like" the values in the file</li> + <li>generating data for grouped frequency distributions or + histograms</li> + </ul></p> + <p> + The source of random data used by the data generation utilities is + pluggable. By default, the JDK-supplied PseudoRandom Number Generator + (PRNG) is used, but alternative generators can be "plugged in" using an + adaptor framework, which provides a generic facility for replacing + <code>java.util.Random</code> with an alternative PRNG. + </p> + <p> + Sections 2.3-2.5 below show how to use the commons math API to generate + different kinds of random data. The examples all use the default + JDK-supplied PRNG. PRNG pluggability is covered in 2.6. The only + modification required to the examples to use alternative PRNGs is to + replace the argumentless constructor calls with invocations including + a <code>RandomGenerator</code> instance as a parameter. + </p> </subsection> <subsection name="2.2 Random numbers" href="deviates"> <p> The <a href="../apidocs/org/apache/commons/math/random/RandomData.html"> - org.apache.commons.math.RandomData</a> interface defines methods for generating - random sequences of numbers. The API contracts of these methods use the following concepts: + org.apache.commons.math.RandomData</a> interface defines methods for + generating random sequences of numbers. The API contracts of these methods + use the following concepts: <dl> <dt>Random sequence of numbers from a probability distribution</dt> - <dd>There is no such thing as a single "random number." What can be generated - are <i>sequences</i> of numbers that appear to be random. When using the - built-in JDK function <code>Math.random(),</code> sequences of values generated - follow the <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3662.htm"> - Uniform Distribution</a>, which means that the values are evenly spread over the interval - between 0 and 1, with no sub-interval having a greater probability of containing generated - values than any other interval of the same length. The mathematical concept of a <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda36.htm"> - probability distribution</a> basically amounts to asserting that different ranges in the set - of possible values for of a random variable have different probabilities of containing the value. - Commons Math supports generating random sequences from the following probability distributions. The - javadoc for the <code>nextXxx</code> methods in <code>RandomDataImpl</code> describes the algorithms used - to generate random deviates from each of these distributions. + <dd>There is no such thing as a single "random number." What can be + generated are <i>sequences</i> of numbers that appear to be random. When + using the built-in JDK function <code>Math.random(),</code> sequences of + values generated follow the + <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3662.htm"> + Uniform Distribution</a>, which means that the values are evenly spread + over the interval between 0 and 1, with no sub-interval having a greater + probability of containing generated values than any other interval of the + same length. The mathematical concept of a + <a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda36.htm"> + probability distribution</a> basically amounts to asserting that different + ranges in the set of possible values for of a random variable have + different probabilities of containing the value. Commons Math supports + generating random sequences from the following probability distributions. + The javadoc for the <code>nextXxx</code> methods in + <code>RandomDataImpl</code> describes the algorithms used to generate + random deviates from each of these distributions. <ul> - <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3662.htm">uniform distribution</a></li> - <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3667.htm">exponential distribution</a></li> - <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda366j.htm">poisson distribution</a></li> - <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm">Gaussian distribution</a></li> + <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3662.htm"> + uniform distribution</a></li> + <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3667.htm"> + exponential distribution</a></li> + <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda366j.htm"> + poisson distribution</a></li> + <li><a href="http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm"> + Gaussian distribution</a></li> </ul> </dd> <dt>Cryptographically secure random sequences</dt> - <dd>It is possible for a sequence of numbers to appear random, but nonetheless to be - predictable based on the algorithm used to generate the sequence. If in addition to - randomness, strong unpredictability is required, it is best to use a + <dd>It is possible for a sequence of numbers to appear random, but + nonetheless to be predictable based on the algorithm used to generate the + sequence. If in addition to randomness, strong unpredictability is + required, it is best to use a <a href="http://www.wikipedia.org/wiki/Cryptographically_secure_pseudo-random_number_generator"> - secure random number generator</a> to generate values (or strings). The nextSecureXxx methods - in the <code>RandomDataImpl</code> implementation of the <code>RandomData</code> interface use the - JDK <code>SecureRandom</code> pseudo-random number generator (PRNG) - to generate cryptographically secure sequences. The <code>setSecureAlgorithm</code> method - allows you to change the underlying PRNG. These methods are <strong>much slower</strong> than - the corresponding "non-secure" versions, so they should only be used when cryptographic security - is required.</dd> + secure random number generator</a> to generate values (or strings). The + nextSecureXxx methods in the <code>RandomDataImpl</code> implementation of + the <code>RandomData</code> interface use the JDK <code>SecureRandom</code> + PRNG to generate cryptographically secure sequences. The + <code>setSecureAlgorithm</code> method allows you to change the underlying + PRNG. These methods are <strong>much slower</strong> than the corresponding + "non-secure" versions, so they should only be used when cryptographic + security is required.</dd> <dt>Seeding pseudo-random number generators</dt> - <dd>By default, the implementation provided in <code>RandomDataImpl</code> uses the JDK-provided - PRNG. Like other PRNGs, the JDK generator generates sequences of random numbers based on an initial - "seed value". For the non-secure methods, starting with the same seed always produces the same - sequence of values. Secure sequences started with the same seeds will diverge. When a new - <code>RandomDataImpl</code> is created, the underlying random number generators are - <strong>not</strong> intialized. The first call to a data generation method, or to a - <code>reSeed()</code> method initializes the appropriate generator. If you do not explicitly - seed the generator, it is by default seeded with the current time in milliseconds. Therefore, - to generate sequences of random data values, you should always instantiate <strong>one</strong> - <code>RandomDataImpl</code> and use it repeatedly instead of creating new instances for - subsequent values in the sequence. For example, the following will generate a random sequence - of 50 long integers between 1 and 1,000,000, using the current time in milliseconds as the seed - for the JDK PRNG: + <dd>By default, the implementation provided in <code>RandomDataImpl</code> + uses the JDK-provided PRNG. Like most other PRNGs, the JDK generator + generates sequences of random numbers based on an initial "seed value". + For the non-secure methods, starting with the same seed always produces the + same sequence of values. Secure sequences started with the same seeds will + diverge. When a new <code>RandomDataImpl</code> is created, the underlying + random number generators are <strong>not</strong> intialized. The first + call to a data generation method, or to a <code>reSeed()</code> method + initializes the appropriate generator. If you do not explicitly seed the + generator, it is by default seeded with the current time in milliseconds. + Therefore, to generate sequences of random data values, you should always + instantiate <strong>one</strong> <code>RandomDataImpl</code> and use it + repeatedly instead of creating new instances for subsequent values in the + sequence. For example, the following will generate a random sequence of 50 + long integers between 1 and 1,000,000, using the current time in + milliseconds as the seed for the JDK PRNG: <source> - RandomDataImpl randomData = new RandomDataImpl(); - for (int i = 0; i < 1000; i++) { - value = randomData.nextLong(1, 1000000); - } +RandomDataImpl randomData = new RandomDataImpl(); +for (int i = 0; i < 1000; i++) { + value = randomData.nextLong(1, 1000000); +} </source> - The following will not in general produce a good random sequence, since the PRNG is reseeded - each time through the loop with the current time in milliseconds: + The following will not in general produce a good random sequence, since the + PRNG is reseeded each time through the loop with the current time in + milliseconds: <source> - for (int i = 0; i < 1000; i++) { - RandomDataImpl randomData = new RandomDataImpl(); - value = randomData.nextLong(1, 1000000); - } +for (int i = 0; i < 1000; i++) { + RandomDataImpl randomData = new RandomDataImpl(); + value = randomData.nextLong(1, 1000000); +} </source> - The following will produce the same random sequence each time it is executed: + The following will produce the same random sequence each time it is + executed: <source> - RandomDataImpl randomData = new RandomDataImpl(); - randomData.reSeed(1000); - for (int i = 0; i = 1000; i++) { - value = randomData.nextLong(1, 1000000); - } +RandomDataImpl randomData = new RandomDataImpl(); +randomData.reSeed(1000); +for (int i = 0; i = 1000; i++) { + value = randomData.nextLong(1, 1000000); +} </source> - The following will produce a different random sequence each time it is executed. + The following will produce a different random sequence each time it is + executed. <source> - RandomDataImpl randomData = new RandomDataImpl(); - randomData.reSeedSecure(1000); - for (int i = 0; i < 1000; i++) { - value = randomData.nextSecureLong(1, 1000000); - } +RandomDataImpl randomData = new RandomDataImpl(); +randomData.reSeedSecure(1000); +for (int i = 0; i < 1000; i++) { + value = randomData.nextSecureLong(1, 1000000); +} </source> </dd></dl> </p> @@ -226,6 +261,87 @@ </dd> </dl> </p> +</subsection> + +<subsection name="2.6 PRNG Pluggability" href="pluggability"> + <p> + To enable alternative PRNGs to be "plugged in" to the commons-math data + generation utilities and to provide a generic means to replace + <code>java.util.Random</code> in applications, a random generator + adaptor framework has been added to commons-math. The + <a href="../apidocs/org/apache/commons/math/random/RandomGenerator.html"> + org.apache.commons.math.RandomGenerator</a> interface abstracts the public + interface of <code>java.util.Random</code> and any implementation of this + interface can be used as the source of random data for the commons-math + data generation classes. An abstract superclass, + <a href="../apidocs/org/apache/commons/math/random/AbstractRandomGenerator.html"> + org.apache.commons.math.AbstractRandomGenerator</a> is provided to make + implementation easier. This class provides default implementations of + "derived" data generation methods based on the primitive, + <code>nextDouble().</code> To support generic replacement of + <code>java.util.Random</code>, the + <a href="../apidocs/org/apache/commons/math/random/RandomAdaptor.html"> + org.apache.commons.math.RandomAdaptor</a> class is provided, which + extends <code>java.util.Random</code> and wraps and delegates calls to + a <code>RandomGenerator</code> instance. + </p> + <p> + Examples: + <dl> + <dt>Create a RandomGenerator based on RngPack's Mersenne Twister</dt> + <dd>To create a RandomGenerator using the RngPack Mersenne Twister PRNG + as the source of randomness, extend <code>AbstractRandomGenerator</code> + overriding the derived methods that the RngPack implementation provides: + <source> +import edu.cornell.lassp.houle.RngPack.RanMT; +/** + * AbstractRandomGenerator based on RngPack RanMT generator. + */ +public class RngPackGenerator extends AbstractRandomGenerator { + + private RanMT random = new RanMT(); + + public void setSeed(long seed) { + random = new RanMT(seed); + } + + public double nextDouble() { + return random.raw(); + } + + public double nextGaussian() { + return random.gaussian(); + } + + public int nextInt(int n) { + return random.choose(n); + } + + public boolean nextBoolean() { + return random.coin(); + } +} + </source> + </dd> + <dt>Use the Mersenne Twister RandomGenerator in place of + <code>java.util.Random</code> in <code>RandomData</code></dt> + <dd> + <source> +RandomData randomData = new RandomDataImpl(new RngPackGenerator()); + </source> + </dd> + <dt>Create an adaptor instance based on the Mersenne Twister generator + that can be used in place of a <code>Random</code></dt> + <dd> + <source> + RandomGenerator generator = new RngPackGenerator(); + Random random = RandomAdaptor.createAdaptor(generator); + // random can now be used in place of a Random instance, data generation + // calls will be delegated to the wrapped Mersenne Twister + </source> + </dd> + </dl> + </p> </subsection> </section> --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]