Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3051 was 3017, checked in by epitzer, 15 years ago

Merge StorableClassType.Empty into StorableClassType.MarkedOnly and make it the default if not specified (#548)

File size: 8.3 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.Core;
36using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
37
38namespace HeuristicLab.Random {
39  /// <summary>
40  /// A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number Generator.
41  /// </summary>
42  [Item("MersenneTwister", "A high-quality pseudo random number generator which creates uniformly distributed random numbers.")]
43  [StorableClass]
44  public class MersenneTwister : Item, IRandom {
45    private const int n = 624, m = 397;
46
47    private object locker = new object();
48    [Storable]
49    private uint[] state = new uint[n];
50    [Storable]
51    private int p = 0;
52    [Storable]
53    private bool init = false;
54
55    /// <summary>
56    /// Initializes a new instance of <see cref="MersenneTwister"/>.
57    /// </summary>
58    public MersenneTwister() {
59      if (!init) seed((uint)DateTime.Now.Ticks);
60      init = true;
61    }
62    /// <summary>
63    /// Initializes a new instance of <see cref="MersenneTwister"/>
64    /// with the given seed <paramref name="s"/>.
65    /// </summary>
66    /// <param name="s">The seed with which to initialize the random number generator.</param>
67    public MersenneTwister(uint s) {
68      seed(s);
69      init = true;
70    }
71    /// <summary>
72    /// Initializes a new instance of <see cref="MersenneTwister"/> with the given seed array.
73    /// </summary>
74    /// <param name="array">The seed array with which to initialize the random number generator.</param>
75    public MersenneTwister(uint[] array) {
76      seed(array);
77      init = true;
78    }
79
80    /// <summary>
81    /// Clones the current instance (deep clone).
82    /// </summary>
83    /// <param name="clonedObjects">Dictionary of all already cloned objects. (Needed to avoid cycles.)</param>
84    /// <returns>The cloned object as <see cref="MersenneTwister"/>.</returns>
85    public override IDeepCloneable Clone(Cloner cloner) {
86      MersenneTwister clone = new MersenneTwister();
87      cloner.RegisterClonedObject(this, clone);
88      clone.state = (uint[])state.Clone();
89      clone.p = p;
90      clone.init = init;
91      return clone;
92    }
93
94    /// <summary>
95    /// Resets the current random number generator.
96    /// </summary>
97    public void Reset() {
98      lock (locker)
99        seed((uint)DateTime.Now.Ticks);
100    }
101    /// <summary>
102    /// Resets the current random number generator with the given seed <paramref name="s"/>.
103    /// </summary>
104    /// <param name="s">The seed with which to reset the current instance.</param>
105    public void Reset(int s) {
106      lock (locker)
107        seed((uint)s);
108    }
109
110    /// <summary>
111    /// Gets a new random number.
112    /// </summary>
113    /// <returns>A new int random number.</returns>
114    public int Next() {
115      lock (locker) {
116        return (int)(rand_int32() >> 1);
117      }
118    }
119    /// <summary>
120    /// Gets a new random number being smaller than the given <paramref name="maxVal"/>.
121    /// </summary>
122    /// <exception cref="ArgumentException">Thrown when the given maximum value is
123    /// smaller or equal to zero.</exception>
124    /// <param name="maxVal">The maximum value of the generated random number.</param>
125    /// <returns>A new int random number.</returns>
126    public int Next(int maxVal) {
127      lock (locker) {
128        if (maxVal <= 0)
129          throw new ArgumentException("The interval [0, " + maxVal + ") is empty");
130        int limit = (Int32.MaxValue / maxVal) * maxVal;
131        int value = Next();
132        while (value >= limit) value = Next();
133        return value % maxVal;
134      }
135    }
136    /// <summary>
137    /// Gets a new random number being in the given interval <paramref name="minVal"/> and
138    /// <paramref name="maxVal"/>.
139    /// </summary>
140    /// <param name="minVal">The minimum value of the generated random number.</param>
141    /// <param name="maxVal">The maximum value of the generated random number.</param>
142    /// <returns>A new int random number.</returns>
143    public int Next(int minVal, int maxVal) {
144      lock (locker) {
145        if (maxVal <= minVal)
146          throw new ArgumentException("The interval [" + minVal + ", " + maxVal + ") is empty");
147        return Next(maxVal - minVal) + minVal;
148      }
149    }
150    /// <summary>
151    /// Gets a new double random variable.
152    /// </summary>
153    /// <returns></returns>
154    public double NextDouble() {
155      lock (locker) {
156        return rand_double53();
157      }
158    }
159
160    #region Seed Methods
161    /// <summary>
162    /// Initializes current instance with random seed.
163    /// </summary>
164    /// <param name="s">A starting seed.</param>
165    public void seed(uint s) {
166      state[0] = s & 0xFFFFFFFFU;
167      for (int i = 1; i < n; ++i) {
168        state[i] = 1812433253U * (state[i - 1] ^ (state[i - 1] >> 30)) + (uint)i;
169        state[i] &= 0xFFFFFFFFU;
170      }
171      p = n;
172    }
173    /// <summary>
174    /// Initializes current instance with random seed.
175    /// </summary>
176    /// <param name="array">A starting seed array.</param>
177    public void seed(uint[] array) {
178      seed(19650218U);
179      int i = 1, j = 0;
180      for (int k = ((n > array.Length) ? n : array.Length); k > 0; --k) {
181        state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525U))
182          + array[j] + (uint)j;
183        state[i] &= 0xFFFFFFFFU;
184        ++j;
185        j %= array.Length;
186        if ((++i) == n) { state[0] = state[n - 1]; i = 1; }
187      }
188      for (int k = n - 1; k > 0; --k) {
189        state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941U)) - (uint)i;
190        state[i] &= 0xFFFFFFFFU;
191        if ((++i) == n) { state[0] = state[n - 1]; i = 1; }
192      }
193      state[0] = 0x80000000U;
194      p = n;
195    }
196    #endregion
197
198    #region Random Number Generation Methods
199    private uint rand_int32() {
200      if (p == n) gen_state();
201      uint x = state[p++];
202      x ^= (x >> 11);
203      x ^= (x << 7) & 0x9D2C5680U;
204      x ^= (x << 15) & 0xEFC60000U;
205      return x ^ (x >> 18);
206    }
207    private double rand_double() { // interval [0, 1)
208      return ((double)rand_int32()) * (1.0 / 4294967296.0);
209    }
210    private double rand_double_closed() { // interval [0, 1]
211      return ((double)rand_int32()) * (1.0 / 4294967295.0);
212    }
213    private double rand_double_open() { // interval (0, 1)
214      return (((double)rand_int32()) + 0.5) * (1.0 / 4294967296.0);
215    }
216    private double rand_double53() { // 53 bit resolution, interval [0, 1)
217      return (((double)(rand_int32() >> 5)) * 67108864.0 +
218        ((double)(rand_int32() >> 6))) * (1.0 / 9007199254740992.0);
219    }
220    #endregion
221
222    #region Private Helper Methods
223    private uint twiddle(uint u, uint v) {
224      return (((u & 0x80000000U) | (v & 0x7FFFFFFFU)) >> 1)
225        ^ (((v & 1U) != 0) ? 0x9908B0DFU : 0x0U);
226    }
227    private void gen_state() {
228      for (int i = 0; i < (n - m); ++i)
229        state[i] = state[i + m] ^ twiddle(state[i], state[i + 1]);
230      for (int i = n - m; i < (n - 1); ++i)
231        state[i] = state[i + m - n] ^ twiddle(state[i], state[i + 1]);
232      state[n - 1] = state[m - 1] ^ twiddle(state[n - 1], state[0]);
233      p = 0; // reset position
234    }
235    #endregion
236  }
237}
Note: See TracBrowser for help on using the repository browser.