View Javadoc
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    *      https://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  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.random;
23  
24  import java.io.Serializable;
25  
26  import org.hipparchus.util.FastMath;
27  
28  
29  /**
30   * This abstract class implements the WELL class of pseudo-random number generator
31   * from François Panneton, Pierre L'Ecuyer and Makoto Matsumoto.
32   * <p>
33   * This generator is described in a paper by Fran&ccedil;ois Panneton,
34   * Pierre L'Ecuyer and Makoto Matsumoto
35   * <a href="http://www.iro.umontreal.ca/~lecuyer/myftp/papers/wellrng.pdf">
36   * Improved Long-Period Generators Based on Linear Recurrences Modulo 2</a>
37   * ACM Transactions on Mathematical Software, 32, 1 (2006). The errata for the paper
38   * are in <a href="http://www.iro.umontreal.ca/~lecuyer/myftp/papers/wellrng-errata.txt">
39   * wellrng-errata.txt</a>.
40   *
41   * @see <a href="http://www.iro.umontreal.ca/~panneton/WELLRNG.html">WELL Random number generator</a>
42   */
43  public abstract class AbstractWell extends IntRandomGenerator implements Serializable {
44  
45      /** Serializable version identifier. */
46      private static final long serialVersionUID = 20150223L;
47  
48      /** Current index in the bytes pool. */
49      protected int index;
50  
51      /** Bytes pool. */
52      protected final int[] v;
53  
54      /** Creates a new random number generator.
55       * <p>The instance is initialized using the current time plus the
56       * system identity hash code of this instance as the seed.</p>
57       * @param k number of bits in the pool (not necessarily a multiple of 32)
58       */
59      protected AbstractWell(final int k) {
60          this(k, null);
61      }
62  
63      /** Creates a new random number generator using a single int seed.
64       * @param k number of bits in the pool (not necessarily a multiple of 32)
65       * @param seed the initial seed (32 bits integer)
66       */
67      protected AbstractWell(final int k, final int seed) {
68          this(k, new int[] { seed });
69      }
70  
71      /**
72       * Creates a new random number generator using an int array seed.
73       * @param k number of bits in the pool (not necessarily a multiple of 32)
74       * @param seed the initial seed (32 bits integers array), if null
75       * the seed of the generator will be related to the current time
76       */
77      protected AbstractWell(final int k, final int[] seed) {
78  
79          final int r = calculateBlockCount(k);
80          this.v      = new int[r];
81          this.index  = 0;
82  
83          // initialize the pool content
84          setSeed(seed);
85      }
86  
87      /**
88       * Creates a new random number generator using a single long seed.
89       * @param k number of bits in the pool (not necessarily a multiple of 32)
90       * @param seed the initial seed (64 bits integer)
91       */
92      protected AbstractWell(final int k, final long seed) {
93          this(k, new int[] { (int) (seed >>> 32), (int) (seed & 0xffffffffl) });
94      }
95  
96      /**
97       * Reinitialize the generator as if just built with the given int array seed.
98       * <p>
99       * The state of the generator is exactly the same as a new
100      * generator built with the same seed.
101      *
102      * @param seed the initial seed (32 bits integers array). If null
103      * the seed of the generator will be the system time plus the system identity
104      * hash code of the instance.
105      */
106     @Override
107     public void setSeed(final int[] seed) {
108         if (seed == null) {
109             setSeed(System.currentTimeMillis() + System.identityHashCode(this));
110             return;
111         }
112 
113         System.arraycopy(seed, 0, v, 0, FastMath.min(seed.length, v.length));
114 
115         if (seed.length < v.length) {
116             for (int i = seed.length; i < v.length; ++i) {
117                 final long l = v[i - seed.length];
118                 v[i] = (int) ((1812433253l * (l ^ (l >> 30)) + i) & 0xffffffffL);
119             }
120         }
121 
122         index = 0;
123         clearCache(); // Clear normal deviate cache
124     }
125 
126     /**
127      * Calculate the number of 32-bits blocks.
128      * @param k number of bits in the pool (not necessarily a multiple of 32)
129      * @return the number of 32-bits blocks
130      */
131     private static int calculateBlockCount(final int k) {
132         // the bits pool contains k bits, k = r w - p where r is the number
133         // of w bits blocks, w is the block size (always 32 in the original paper)
134         // and p is the number of unused bits in the last block
135         final int w = 32;
136         return (k + w - 1) / w;
137     }
138 
139     /**
140      * Inner class used to store the indirection index table which is fixed
141      * for a given type of WELL class of pseudo-random number generator.
142      */
143     protected static final class IndexTable {
144         /**
145          * Index indirection table giving for each index its predecessor
146          * taking table size into account.
147          */
148         private final int[] iRm1;
149 
150         /**
151          * Index indirection table giving for each index its second predecessor
152          * taking table size into account.
153          */
154         private final int[] iRm2;
155 
156         /**
157          * Index indirection table giving for each index the value index + m1
158          * taking table size into account.
159          */
160         private final int[] i1;
161 
162         /**
163          * Index indirection table giving for each index the value index + m2
164          * taking table size into account.
165          */
166         private final int[] i2;
167 
168         /**
169          * Index indirection table giving for each index the value index + m3
170          * taking table size into account.
171          */
172         private final int[] i3;
173 
174         /**
175          * Creates a new pre-calculated indirection index table.
176          * @param k number of bits in the pool (not necessarily a multiple of 32)
177          * @param m1 first parameter of the algorithm
178          * @param m2 second parameter of the algorithm
179          * @param m3 third parameter of the algorithm
180          */
181         public IndexTable(final int k, final int m1, final int m2, final int m3) {
182 
183             final int r = calculateBlockCount(k);
184 
185             // precompute indirection index tables. These tables are used for optimizing access
186             // they allow saving computations like "(j + r - 2) % r" with costly modulo operations
187             iRm1 = new int[r];
188             iRm2 = new int[r];
189             i1   = new int[r];
190             i2   = new int[r];
191             i3   = new int[r];
192             for (int j = 0; j < r; ++j) {
193                 iRm1[j] = (j + r - 1) % r;
194                 iRm2[j] = (j + r - 2) % r;
195                 i1[j]   = (j + m1)    % r;
196                 i2[j]   = (j + m2)    % r;
197                 i3[j]   = (j + m3)    % r;
198             }
199         }
200 
201         /**
202          * Returns the predecessor of the given index modulo the table size.
203          * @param index the index to look at
204          * @return (index - 1) % table size
205          */
206         public int getIndexPred(final int index) {
207             return iRm1[index];
208         }
209 
210         /**
211          * Returns the second predecessor of the given index modulo the table size.
212          * @param index the index to look at
213          * @return (index - 2) % table size
214          */
215         public int getIndexPred2(final int index) {
216             return iRm2[index];
217         }
218 
219         /**
220          * Returns index + M1 modulo the table size.
221          * @param index the index to look at
222          * @return (index + M1) % table size
223          */
224         public int getIndexM1(final int index) {
225             return i1[index];
226         }
227 
228         /**
229          * Returns index + M2 modulo the table size.
230          * @param index the index to look at
231          * @return (index + M2) % table size
232          */
233         public int getIndexM2(final int index) {
234             return i2[index];
235         }
236 
237         /**
238          * Returns index + M3 modulo the table size.
239          * @param index the index to look at
240          * @return (index + M3) % table size
241          */
242         public int getIndexM3(final int index) {
243             return i3[index];
244         }
245     }
246 }