#region License Information /* HeuristicLab * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion /* * C# port of the freeware implementation of the Mersenne Twister * originally developed by M. Matsumoto and T. Nishimura * * M. Matsumoto and T. Nishimura, * "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform * Pseudo-Random Number Generator", * ACM Transactions on Modeling and Computer Simulation, * Vol. 8, No. 1, January 1998, pp 3-30. * */ using System; using HeuristicLab.Core; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Random { /// /// A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number Generator. /// [Item("MersenneTwister", "A high-quality pseudo random number generator which creates uniformly distributed random numbers.")] [StorableClass] public class MersenneTwister : Item, IRandom { private const int n = 624, m = 397; private object locker = new object(); [Storable] private uint[] state = new uint[n]; [Storable] private int p = 0; [Storable] private bool init = false; /// /// Initializes a new instance of . /// public MersenneTwister() { if (!init) seed((uint)DateTime.Now.Ticks); init = true; } /// /// Initializes a new instance of /// with the given seed . /// /// The seed with which to initialize the random number generator. public MersenneTwister(uint s) { seed(s); init = true; } /// /// Initializes a new instance of with the given seed array. /// /// The seed array with which to initialize the random number generator. public MersenneTwister(uint[] array) { seed(array); init = true; } /// /// Clones the current instance (deep clone). /// /// Dictionary of all already cloned objects. (Needed to avoid cycles.) /// The cloned object as . public override IDeepCloneable Clone(Cloner cloner) { MersenneTwister clone = new MersenneTwister(); cloner.RegisterClonedObject(this, clone); clone.state = (uint[])state.Clone(); clone.p = p; clone.init = init; return clone; } /// /// Resets the current random number generator. /// public void Reset() { lock (locker) seed((uint)DateTime.Now.Ticks); } /// /// Resets the current random number generator with the given seed . /// /// The seed with which to reset the current instance. public void Reset(int s) { lock (locker) seed((uint)s); } /// /// Gets a new random number. /// /// A new int random number. public int Next() { lock (locker) { return (int)(rand_int32() >> 1); } } /// /// Gets a new random number being smaller than the given . /// /// Thrown when the given maximum value is /// smaller or equal to zero. /// The maximum value of the generated random number. /// A new int random number. public int Next(int maxVal) { lock (locker) { if (maxVal <= 0) throw new ArgumentException("The interval [0, " + maxVal + ") is empty"); int limit = (Int32.MaxValue / maxVal) * maxVal; int value = Next(); while (value >= limit) value = Next(); return value % maxVal; } } /// /// Gets a new random number being in the given interval and /// . /// /// The minimum value of the generated random number. /// The maximum value of the generated random number. /// A new int random number. public int Next(int minVal, int maxVal) { lock (locker) { if (maxVal <= minVal) throw new ArgumentException("The interval [" + minVal + ", " + maxVal + ") is empty"); return Next(maxVal - minVal) + minVal; } } /// /// Gets a new double random variable. /// /// public double NextDouble() { lock (locker) { return rand_double53(); } } #region Seed Methods /// /// Initializes current instance with random seed. /// /// A starting seed. public void seed(uint s) { state[0] = s & 0xFFFFFFFFU; for (int i = 1; i < n; ++i) { state[i] = 1812433253U * (state[i - 1] ^ (state[i - 1] >> 30)) + (uint)i; state[i] &= 0xFFFFFFFFU; } p = n; } /// /// Initializes current instance with random seed. /// /// A starting seed array. public void seed(uint[] array) { seed(19650218U); int i = 1, j = 0; for (int k = ((n > array.Length) ? n : array.Length); k > 0; --k) { state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525U)) + array[j] + (uint)j; state[i] &= 0xFFFFFFFFU; ++j; j %= array.Length; if ((++i) == n) { state[0] = state[n - 1]; i = 1; } } for (int k = n - 1; k > 0; --k) { state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941U)) - (uint)i; state[i] &= 0xFFFFFFFFU; if ((++i) == n) { state[0] = state[n - 1]; i = 1; } } state[0] = 0x80000000U; p = n; } #endregion #region Random Number Generation Methods private uint rand_int32() { if (p == n) gen_state(); uint x = state[p++]; x ^= (x >> 11); x ^= (x << 7) & 0x9D2C5680U; x ^= (x << 15) & 0xEFC60000U; return x ^ (x >> 18); } private double rand_double() { // interval [0, 1) return ((double)rand_int32()) * (1.0 / 4294967296.0); } private double rand_double_closed() { // interval [0, 1] return ((double)rand_int32()) * (1.0 / 4294967295.0); } private double rand_double_open() { // interval (0, 1) return (((double)rand_int32()) + 0.5) * (1.0 / 4294967296.0); } private double rand_double53() { // 53 bit resolution, interval [0, 1) return (((double)(rand_int32() >> 5)) * 67108864.0 + ((double)(rand_int32() >> 6))) * (1.0 / 9007199254740992.0); } #endregion #region Private Helper Methods private uint twiddle(uint u, uint v) { return (((u & 0x80000000U) | (v & 0x7FFFFFFFU)) >> 1) ^ (((v & 1U) != 0) ? 0x9908B0DFU : 0x0U); } private void gen_state() { for (int i = 0; i < (n - m); ++i) state[i] = state[i + m] ^ twiddle(state[i], state[i + 1]); for (int i = n - m; i < (n - 1); ++i) state[i] = state[i + m - n] ^ twiddle(state[i], state[i + 1]); state[n - 1] = state[m - 1] ^ twiddle(state[n - 1], state[0]); p = 0; // reset position } #endregion } }