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]