#region License Information /* HeuristicLab * Copyright (C) 2002-2008 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 System.Collections.Generic; using System.Text; using System.Xml; using HeuristicLab.Core; namespace HeuristicLab.Random { public class MersenneTwister : ItemBase, IRandom { private const int n = 624, m = 397; private object locker = new object(); private uint[] state = new uint[n]; private int p = 0; private bool init = false; public MersenneTwister() { if (!init) seed((uint)DateTime.Now.Ticks); init = true; } public MersenneTwister(uint s) { seed(s); init = true; } public MersenneTwister(uint[] array) { seed(array); init = true; } public override object Clone(IDictionary clonedObjects) { MersenneTwister clone = new MersenneTwister(); clonedObjects.Add(Guid, clone); clone.state = (uint[])state.Clone(); clone.p = p; clone.init = init; return clone; } public void Reset() { lock (locker) seed((uint)DateTime.Now.Ticks); } public void Reset(int s) { lock (locker) seed((uint)s); } public int Next() { lock (locker) { return (int)(rand_int32() >> 1); } } 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; } } 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; } } public double NextDouble() { lock (locker) { return rand_double53(); } } #region Persistence Methods public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary persistedObjects) { XmlNode node = base.GetXmlNode(name, document, persistedObjects); StringBuilder builder = new StringBuilder(); builder.Append(state[0]); for (int i = 1; i < state.Length; i++) { builder.Append(';'); builder.Append(state[i]); } XmlNode stateNode = document.CreateNode(XmlNodeType.Element, "State", null); stateNode.InnerText = builder.ToString(); node.AppendChild(stateNode); XmlNode pNode = document.CreateNode(XmlNodeType.Element, "P", null); pNode.InnerText = p.ToString(); node.AppendChild(pNode); XmlNode initNode = document.CreateNode(XmlNodeType.Element, "Init", null); initNode.InnerText = init.ToString(); node.AppendChild(initNode); return node; } public override void Populate(XmlNode node, IDictionary restoredObjects) { base.Populate(node, restoredObjects); string stateString = node.SelectSingleNode("State").InnerText; string[] tokens = stateString.Split(';'); for (int i = 0; i < tokens.Length; i++) state[i] = uint.Parse(tokens[i]); p = int.Parse(node.SelectSingleNode("P").InnerText); init = bool.Parse(node.SelectSingleNode("Init").InnerText); } #endregion #region Seed Methods 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; } 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 } }