Free cookie consent management tool by TermsFeed Policy Generator

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

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

Operator architecture refactoring (#95)

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