Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Random/3.3/MersenneTwister.cs @ 4412

Last change on this file since 4412 was 4258, checked in by swagner, 14 years ago

Worked in integration of FastRandom PRNG (#1114)

File size: 8.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22/*
23 * C# port of the freeware implementation of the Mersenne Twister
24 * originally developed by M. Matsumoto and T. Nishimura
25 *
26 * M. Matsumoto and T. Nishimura,
27 * "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform
28 * Pseudo-Random Number Generator",
29 * ACM Transactions on Modeling and Computer Simulation,
30 * Vol. 8, No. 1, January 1998, pp 3-30.
31 *
32 */
33
34using System;
35using HeuristicLab.Common;
36using HeuristicLab.Core;
37using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
38
39namespace HeuristicLab.Random {
40  /// <summary>
41  /// A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number Generator.
42  /// </summary>
43  [Item("MersenneTwister", "A high-quality pseudo random number generator which creates uniformly distributed random numbers.")]
44  [StorableClass]
45  public sealed class MersenneTwister : Item, IRandom {
46    private const int n = 624, m = 397;
47
48    private object locker = new object();
49    [Storable]
50    private uint[] state = new uint[n];
51    [Storable]
52    private int p = 0;
53    [Storable]
54    private bool init = false;
55
56    /// <summary>
57    /// Initializes a new instance of <see cref="MersenneTwister"/>.
58    /// </summary>
59    public MersenneTwister() {
60      if (!init) seed((uint)DateTime.Now.Ticks);
61      init = true;
62    }
63    /// <summary>
64    /// Initializes a new instance of <see cref="MersenneTwister"/>
65    /// with the given seed <paramref name="s"/>.
66    /// </summary>
67    /// <param name="s">The seed with which to initialize the random number generator.</param>
68    public MersenneTwister(uint s) {
69      seed(s);
70      init = true;
71    }
72    /// <summary>
73    /// Initializes a new instance of <see cref="MersenneTwister"/> with the given seed array.
74    /// </summary>
75    /// <param name="array">The seed array with which to initialize the random number generator.</param>
76    public MersenneTwister(uint[] array) {
77      seed(array);
78      init = true;
79    }
80    /// <summary>
81    /// Used by HeuristicLab.Persistence to initialize new instances during deserialization.
82    /// </summary>
83    /// <param name="deserializing">true, if the constructor is called during deserialization.</param>
84    [StorableConstructor]
85    private MersenneTwister(bool deserializing) : base(deserializing) { }
86
87    /// <summary>
88    /// Clones the current instance (deep clone).
89    /// </summary>
90    /// <param name="clonedObjects">Dictionary of all already cloned objects. (Needed to avoid cycles.)</param>
91    /// <returns>The cloned object as <see cref="MersenneTwister"/>.</returns>
92    public override IDeepCloneable Clone(Cloner cloner) {
93      MersenneTwister clone = (MersenneTwister)base.Clone(cloner);
94      clone.state = (uint[])state.Clone();
95      clone.p = p;
96      clone.init = init;
97      return clone;
98    }
99
100    /// <summary>
101    /// Resets the current random number generator.
102    /// </summary>
103    public void Reset() {
104      lock (locker)
105        seed((uint)DateTime.Now.Ticks);
106    }
107    /// <summary>
108    /// Resets the current random number generator with the given seed <paramref name="s"/>.
109    /// </summary>
110    /// <param name="s">The seed with which to reset the current instance.</param>
111    public void Reset(int s) {
112      lock (locker)
113        seed((uint)s);
114    }
115
116    /// <summary>
117    /// Gets a new random number.
118    /// </summary>
119    /// <returns>A new int random number.</returns>
120    public int Next() {
121      lock (locker) {
122        return (int)(rand_int32() >> 1);
123      }
124    }
125    /// <summary>
126    /// Gets a new random number being smaller than the given <paramref name="maxVal"/>.
127    /// </summary>
128    /// <exception cref="ArgumentException">Thrown when the given maximum value is
129    /// smaller or equal to zero.</exception>
130    /// <param name="maxVal">The maximum value of the generated random number.</param>
131    /// <returns>A new int random number.</returns>
132    public int Next(int maxVal) {
133      lock (locker) {
134        if (maxVal <= 0)
135          throw new ArgumentException("The interval [0, " + maxVal + ") is empty");
136        int limit = (Int32.MaxValue / maxVal) * maxVal;
137        int value = Next();
138        while (value >= limit) value = Next();
139        return value % maxVal;
140      }
141    }
142    /// <summary>
143    /// Gets a new random number being in the given interval <paramref name="minVal"/> and
144    /// <paramref name="maxVal"/>.
145    /// </summary>
146    /// <param name="minVal">The minimum value of the generated random number.</param>
147    /// <param name="maxVal">The maximum value of the generated random number.</param>
148    /// <returns>A new int random number.</returns>
149    public int Next(int minVal, int maxVal) {
150      lock (locker) {
151        if (maxVal <= minVal)
152          throw new ArgumentException("The interval [" + minVal + ", " + maxVal + ") is empty");
153        return Next(maxVal - minVal) + minVal;
154      }
155    }
156    /// <summary>
157    /// Gets a new double random variable.
158    /// </summary>
159    /// <returns></returns>
160    public double NextDouble() {
161      lock (locker) {
162        return rand_double53();
163      }
164    }
165
166    #region Seed Methods
167    /// <summary>
168    /// Initializes current instance with random seed.
169    /// </summary>
170    /// <param name="s">A starting seed.</param>
171    public void seed(uint s) {
172      state[0] = s & 0xFFFFFFFFU;
173      for (int i = 1; i < n; ++i) {
174        state[i] = 1812433253U * (state[i - 1] ^ (state[i - 1] >> 30)) + (uint)i;
175        state[i] &= 0xFFFFFFFFU;
176      }
177      p = n;
178    }
179    /// <summary>
180    /// Initializes current instance with random seed.
181    /// </summary>
182    /// <param name="array">A starting seed array.</param>
183    public void seed(uint[] array) {
184      seed(19650218U);
185      int i = 1, j = 0;
186      for (int k = ((n > array.Length) ? n : array.Length); k > 0; --k) {
187        state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525U))
188          + array[j] + (uint)j;
189        state[i] &= 0xFFFFFFFFU;
190        ++j;
191        j %= array.Length;
192        if ((++i) == n) { state[0] = state[n - 1]; i = 1; }
193      }
194      for (int k = n - 1; k > 0; --k) {
195        state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941U)) - (uint)i;
196        state[i] &= 0xFFFFFFFFU;
197        if ((++i) == n) { state[0] = state[n - 1]; i = 1; }
198      }
199      state[0] = 0x80000000U;
200      p = n;
201    }
202    #endregion
203
204    #region Random Number Generation Methods
205    private uint rand_int32() {
206      if (p == n) gen_state();
207      uint x = state[p++];
208      x ^= (x >> 11);
209      x ^= (x << 7) & 0x9D2C5680U;
210      x ^= (x << 15) & 0xEFC60000U;
211      return x ^ (x >> 18);
212    }
213    private double rand_double() { // interval [0, 1)
214      return ((double)rand_int32()) * (1.0 / 4294967296.0);
215    }
216    private double rand_double_closed() { // interval [0, 1]
217      return ((double)rand_int32()) * (1.0 / 4294967295.0);
218    }
219    private double rand_double_open() { // interval (0, 1)
220      return (((double)rand_int32()) + 0.5) * (1.0 / 4294967296.0);
221    }
222    private double rand_double53() { // 53 bit resolution, interval [0, 1)
223      return (((double)(rand_int32() >> 5)) * 67108864.0 +
224        ((double)(rand_int32() >> 6))) * (1.0 / 9007199254740992.0);
225    }
226    #endregion
227
228    #region Private Helper Methods
229    private uint twiddle(uint u, uint v) {
230      return (((u & 0x80000000U) | (v & 0x7FFFFFFFU)) >> 1)
231        ^ (((v & 1U) != 0) ? 0x9908B0DFU : 0x0U);
232    }
233    private void gen_state() {
234      for (int i = 0; i < (n - m); ++i)
235        state[i] = state[i + m] ^ twiddle(state[i], state[i + 1]);
236      for (int i = n - m; i < (n - 1); ++i)
237        state[i] = state[i + m - n] ^ twiddle(state[i], state[i + 1]);
238      state[n - 1] = state[m - 1] ^ twiddle(state[n - 1], state[0]);
239      p = 0; // reset position
240    }
241    #endregion
242  }
243}
Note: See TracBrowser for help on using the repository browser.