1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package org.apache.commons.math.random;
18 
19 import java.io.Serializable;
20 
21 
22 /** This abstract class implements the WELL class of pseudo-random number generator
23  * from François Panneton, Pierre L'Ecuyer and Makoto Matsumoto.
24 
25  * <p>This generator is described in a paper by Fran&ccedil;ois Panneton,
26  * Pierre L'Ecuyer and Makoto Matsumoto <a
27  * href="http://www.iro.umontreal.ca/~lecuyer/myftp/papers/wellrng.pdf">Improved
28  * Long-Period Generators Based on Linear Recurrences Modulo 2</a> ACM
29  * Transactions on Mathematical Software, 32, 1 (2006). The errata for the paper
30  * are in <a href="http://www.iro.umontreal.ca/~lecuyer/myftp/papers/wellrng-errata.txt">wellrng-errata.txt</a>.</p>
31 
32  * @see <a href="http://www.iro.umontreal.ca/~panneton/WELLRNG.html">WELL Random number generator</a>
33  * @version $Revision: 1003892 $ $Date: 2010-10-02 23:28:56 +0200 (sam. 02 oct. 2010) $
34  * @since 2.2
35 
36  */
37 public abstract class AbstractWell extends BitsStreamGenerator implements Serializable {
38 
39     /** Serializable version identifier. */
40     private static final long serialVersionUID = -817701723016583596L;
41 
42     /** Current index in the bytes pool. */
43     protected int index;
44 
45     /** Bytes pool. */
46     protected final int[] v;
47 
48     /** Index indirection table giving for each index its predecessor taking table size into account. */
49     protected final int[] iRm1;
50 
51     /** Index indirection table giving for each index its second predecessor taking table size into account. */
52     protected final int[] iRm2;
53 
54     /** Index indirection table giving for each index the value index + m1 taking table size into account. */
55     protected final int[] i1;
56 
57     /** Index indirection table giving for each index the value index + m2 taking table size into account. */
58     protected final int[] i2;
59 
60     /** Index indirection table giving for each index the value index + m3 taking table size into account. */
61     protected final int[] i3;
62 
63     /** Creates a new random number generator.
64      * <p>The instance is initialized using the current time as the
65      * seed.</p>
66      * @param k number of bits in the pool (not necessarily a multiple of 32)
67      * @param m1 first parameter of the algorithm
68      * @param m2 second parameter of the algorithm
69      * @param m3 third parameter of the algorithm
70      */
AbstractWell(final int k, final int m1, final int m2, final int m3)71     protected AbstractWell(final int k, final int m1, final int m2, final int m3) {
72         this(k, m1, m2, m3, System.currentTimeMillis());
73     }
74 
75     /** Creates a new random number generator using a single int seed.
76      * @param k number of bits in the pool (not necessarily a multiple of 32)
77      * @param m1 first parameter of the algorithm
78      * @param m2 second parameter of the algorithm
79      * @param m3 third parameter of the algorithm
80      * @param seed the initial seed (32 bits integer)
81      */
AbstractWell(final int k, final int m1, final int m2, final int m3, final int seed)82     protected AbstractWell(final int k, final int m1, final int m2, final int m3, final int seed) {
83         this(k, m1, m2, m3, new int[] { seed });
84     }
85 
86     /** Creates a new random number generator using an int array seed.
87      * @param k number of bits in the pool (not necessarily a multiple of 32)
88      * @param m1 first parameter of the algorithm
89      * @param m2 second parameter of the algorithm
90      * @param m3 third parameter of the algorithm
91      * @param seed the initial seed (32 bits integers array), if null
92      * the seed of the generator will be related to the current time
93      */
AbstractWell(final int k, final int m1, final int m2, final int m3, final int[] seed)94     protected AbstractWell(final int k, final int m1, final int m2, final int m3, final int[] seed) {
95 
96         // the bits pool contains k bits, k = r w - p where r is the number
97         // of w bits blocks, w is the block size (always 32 in the original paper)
98         // and p is the number of unused bits in the last block
99         final int w = 32;
100         final int r = (k + w - 1) / w;
101         this.v      = new int[r];
102         this.index  = 0;
103 
104         // precompute indirection index tables. These tables are used for optimizing access
105         // they allow saving computations like "(j + r - 2) % r" with costly modulo operations
106         iRm1 = new int[r];
107         iRm2 = new int[r];
108         i1   = new int[r];
109         i2   = new int[r];
110         i3   = new int[r];
111         for (int j = 0; j < r; ++j) {
112             iRm1[j] = (j + r - 1) % r;
113             iRm2[j] = (j + r - 2) % r;
114             i1[j]   = (j + m1)    % r;
115             i2[j]   = (j + m2)    % r;
116             i3[j]   = (j + m3)    % r;
117         }
118 
119         // initialize the pool content
120         setSeed(seed);
121 
122     }
123 
124     /** Creates a new random number generator using a single long seed.
125      * @param k number of bits in the pool (not necessarily a multiple of 32)
126      * @param m1 first parameter of the algorithm
127      * @param m2 second parameter of the algorithm
128      * @param m3 third parameter of the algorithm
129      * @param seed the initial seed (64 bits integer)
130      */
AbstractWell(final int k, final int m1, final int m2, final int m3, final long seed)131     protected AbstractWell(final int k, final int m1, final int m2, final int m3, final long seed) {
132         this(k, m1, m2, m3, new int[] { (int) (seed >>> 32), (int) (seed & 0xffffffffl) });
133     }
134 
135     /** Reinitialize the generator as if just built with the given int seed.
136      * <p>The state of the generator is exactly the same as a new
137      * generator built with the same seed.</p>
138      * @param seed the initial seed (32 bits integer)
139      */
140     @Override
setSeed(final int seed)141     public void setSeed(final int seed) {
142         setSeed(new int[] { seed });
143     }
144 
145     /** Reinitialize the generator as if just built with the given int array seed.
146      * <p>The state of the generator is exactly the same as a new
147      * generator built with the same seed.</p>
148      * @param seed the initial seed (32 bits integers array), if null
149      * the seed of the generator will be related to the current time
150      */
151     @Override
setSeed(final int[] seed)152     public void setSeed(final int[] seed) {
153 
154         if (seed == null) {
155             setSeed(System.currentTimeMillis());
156             return;
157         }
158 
159         System.arraycopy(seed, 0, v, 0, Math.min(seed.length, v.length));
160 
161         if (seed.length < v.length) {
162             for (int i = seed.length; i < v.length; ++i) {
163                 final long l = v[i - seed.length];
164                 v[i] = (int) ((1812433253l * (l ^ (l >> 30)) + i) & 0xffffffffL);
165             }
166         }
167 
168         index = 0;
169 
170     }
171 
172     /** Reinitialize the generator as if just built with the given long seed.
173      * <p>The state of the generator is exactly the same as a new
174      * generator built with the same seed.</p>
175      * @param seed the initial seed (64 bits integer)
176      */
177     @Override
setSeed(final long seed)178     public void setSeed(final long seed) {
179         setSeed(new int[] { (int) (seed >>> 32), (int) (seed & 0xffffffffl) });
180     }
181 
182     /** {@inheritDoc} */
183     @Override
next(final int bits)184     protected abstract int next(final int bits);
185 
186 }
187