Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3345 was 3317, checked in by swagner, 15 years ago

Implemented ReadOnlyView property for items (#969).

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 = (MersenneTwister)base.Clone(cloner);
87      clone.state = (uint[])state.Clone();
88      clone.p = p;
89      clone.init = init;
90      return clone;
91    }
92
93    /// <summary>
94    /// Resets the current random number generator.
95    /// </summary>
96    public void Reset() {
97      lock (locker)
98        seed((uint)DateTime.Now.Ticks);
99    }
100    /// <summary>
101    /// Resets the current random number generator with the given seed <paramref name="s"/>.
102    /// </summary>
103    /// <param name="s">The seed with which to reset the current instance.</param>
104    public void Reset(int s) {
105      lock (locker)
106        seed((uint)s);
107    }
108
109    /// <summary>
110    /// Gets a new random number.
111    /// </summary>
112    /// <returns>A new int random number.</returns>
113    public int Next() {
114      lock (locker) {
115        return (int)(rand_int32() >> 1);
116      }
117    }
118    /// <summary>
119    /// Gets a new random number being smaller than the given <paramref name="maxVal"/>.
120    /// </summary>
121    /// <exception cref="ArgumentException">Thrown when the given maximum value is
122    /// smaller or equal to zero.</exception>
123    /// <param name="maxVal">The maximum value of the generated random number.</param>
124    /// <returns>A new int random number.</returns>
125    public int Next(int maxVal) {
126      lock (locker) {
127        if (maxVal <= 0)
128          throw new ArgumentException("The interval [0, " + maxVal + ") is empty");
129        int limit = (Int32.MaxValue / maxVal) * maxVal;
130        int value = Next();
131        while (value >= limit) value = Next();
132        return value % maxVal;
133      }
134    }
135    /// <summary>
136    /// Gets a new random number being in the given interval <paramref name="minVal"/> and
137    /// <paramref name="maxVal"/>.
138    /// </summary>
139    /// <param name="minVal">The minimum value of the generated random number.</param>
140    /// <param name="maxVal">The maximum value of the generated random number.</param>
141    /// <returns>A new int random number.</returns>
142    public int Next(int minVal, int maxVal) {
143      lock (locker) {
144        if (maxVal <= minVal)
145          throw new ArgumentException("The interval [" + minVal + ", " + maxVal + ") is empty");
146        return Next(maxVal - minVal) + minVal;
147      }
148    }
149    /// <summary>
150    /// Gets a new double random variable.
151    /// </summary>
152    /// <returns></returns>
153    public double NextDouble() {
154      lock (locker) {
155        return rand_double53();
156      }
157    }
158
159    #region Seed Methods
160    /// <summary>
161    /// Initializes current instance with random seed.
162    /// </summary>
163    /// <param name="s">A starting seed.</param>
164    public void seed(uint s) {
165      state[0] = s & 0xFFFFFFFFU;
166      for (int i = 1; i < n; ++i) {
167        state[i] = 1812433253U * (state[i - 1] ^ (state[i - 1] >> 30)) + (uint)i;
168        state[i] &= 0xFFFFFFFFU;
169      }
170      p = n;
171    }
172    /// <summary>
173    /// Initializes current instance with random seed.
174    /// </summary>
175    /// <param name="array">A starting seed array.</param>
176    public void seed(uint[] array) {
177      seed(19650218U);
178      int i = 1, j = 0;
179      for (int k = ((n > array.Length) ? n : array.Length); k > 0; --k) {
180        state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525U))
181          + array[j] + (uint)j;
182        state[i] &= 0xFFFFFFFFU;
183        ++j;
184        j %= array.Length;
185        if ((++i) == n) { state[0] = state[n - 1]; i = 1; }
186      }
187      for (int k = n - 1; k > 0; --k) {
188        state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941U)) - (uint)i;
189        state[i] &= 0xFFFFFFFFU;
190        if ((++i) == n) { state[0] = state[n - 1]; i = 1; }
191      }
192      state[0] = 0x80000000U;
193      p = n;
194    }
195    #endregion
196
197    #region Random Number Generation Methods
198    private uint rand_int32() {
199      if (p == n) gen_state();
200      uint x = state[p++];
201      x ^= (x >> 11);
202      x ^= (x << 7) & 0x9D2C5680U;
203      x ^= (x << 15) & 0xEFC60000U;
204      return x ^ (x >> 18);
205    }
206    private double rand_double() { // interval [0, 1)
207      return ((double)rand_int32()) * (1.0 / 4294967296.0);
208    }
209    private double rand_double_closed() { // interval [0, 1]
210      return ((double)rand_int32()) * (1.0 / 4294967295.0);
211    }
212    private double rand_double_open() { // interval (0, 1)
213      return (((double)rand_int32()) + 0.5) * (1.0 / 4294967296.0);
214    }
215    private double rand_double53() { // 53 bit resolution, interval [0, 1)
216      return (((double)(rand_int32() >> 5)) * 67108864.0 +
217        ((double)(rand_int32() >> 6))) * (1.0 / 9007199254740992.0);
218    }
219    #endregion
220
221    #region Private Helper Methods
222    private uint twiddle(uint u, uint v) {
223      return (((u & 0x80000000U) | (v & 0x7FFFFFFFU)) >> 1)
224        ^ (((v & 1U) != 0) ? 0x9908B0DFU : 0x0U);
225    }
226    private void gen_state() {
227      for (int i = 0; i < (n - m); ++i)
228        state[i] = state[i + m] ^ twiddle(state[i], state[i + 1]);
229      for (int i = n - m; i < (n - 1); ++i)
230        state[i] = state[i + m - n] ^ twiddle(state[i], state[i + 1]);
231      state[n - 1] = state[m - 1] ^ twiddle(state[n - 1], state[0]);
232      p = 0; // reset position
233    }
234    #endregion
235  }
236}
Note: See TracBrowser for help on using the repository browser.