Free cookie consent management tool by TermsFeed Policy Generator

source: branches/XmlReaderWriterBranch/HeuristicLab.Random/MersenneTwister.cs @ 125

Last change on this file since 125 was 125, checked in by gkronber, 16 years ago

created a branch that combines the XmlReader and XmlWriter branches

File size: 8.3 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;
39
40namespace HeuristicLab.Random {
41  public class MersenneTwister : ItemBase, IRandom {
42    private const int n = 624, m = 397;
43
44    private object locker = new object();
45    private uint[] state = new uint[n];
46    private int p = 0;
47    private bool init = false;
48
49    public MersenneTwister() {
50      if(!init) seed((uint)DateTime.Now.Ticks);
51      init = true;
52    }
53    public MersenneTwister(uint s) {
54      seed(s);
55      init = true;
56    }
57    public MersenneTwister(uint[] array) {
58      seed(array);
59      init = true;
60    }
61
62    public override object Clone(IDictionary<Guid, object> clonedObjects) {
63      MersenneTwister clone = new MersenneTwister();
64      clonedObjects.Add(Guid, clone);
65      clone.state = (uint[])state.Clone();
66      clone.p = p;
67      clone.init = init;
68      return clone;
69    }
70
71    public void Reset() {
72      lock(locker)
73        seed((uint)DateTime.Now.Ticks);
74    }
75    public void Reset(int s) {
76      lock(locker)
77        seed((uint)s);
78    }
79
80    public int Next() {
81      lock(locker) {
82        return (int)(rand_int32() >> 1);
83      }
84    }
85    public int Next(int maxVal) {
86      lock(locker) {
87        if(maxVal <= 0)
88          throw new ArgumentException("The interval [0, " + maxVal + ") is empty");
89        int limit = (Int32.MaxValue / maxVal) * maxVal;
90        int value = Next();
91        while(value >= limit) value = Next();
92        return value % maxVal;
93      }
94    }
95    public int Next(int minVal, int maxVal) {
96      lock(locker) {
97        if(maxVal <= minVal)
98          throw new ArgumentException("The interval [" + minVal + ", " + maxVal + ") is empty");
99        return Next(maxVal - minVal) + minVal;
100      }
101    }
102    public double NextDouble() {
103      lock(locker) {
104        return rand_double53();
105      }
106    }
107
108    #region Persistence Methods
109    //public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid,IStorable> persistedObjects) {
110    //  XmlNode node = base.GetXmlNode(name, document, persistedObjects);
111
112    //  StringBuilder builder = new StringBuilder();
113    //  builder.Append(state[0]);
114    //  for (int i = 1; i < state.Length; i++) {
115    //    builder.Append(';');
116    //    builder.Append(state[i]);
117    //  }
118    //  XmlNode stateNode = document.CreateNode(XmlNodeType.Element, "State", null);
119    //  stateNode.InnerText = builder.ToString();
120    //  node.AppendChild(stateNode);
121
122    //  XmlNode pNode = document.CreateNode(XmlNodeType.Element, "P", null);
123    //  pNode.InnerText = p.ToString();
124    //  node.AppendChild(pNode);
125
126    //  XmlNode initNode = document.CreateNode(XmlNodeType.Element, "Init", null);
127    //  initNode.InnerText = init.ToString();
128    //  node.AppendChild(initNode);
129
130    //  return node;
131    //}
132    public override void Persist(string name, XmlWriter writer, IDictionary<Guid, IStorable> persistedObjects) {
133      base.Persist(name, writer, persistedObjects);
134      StringBuilder builder = new StringBuilder();
135      builder.Append(state[0]);
136      for(int i = 1; i < state.Length; i++) {
137        builder.Append(';');
138        builder.Append(state[i]);
139      }
140      writer.WriteStartElement("State");
141      writer.WriteValue(builder.ToString());
142      writer.WriteEndElement(); // </State>
143      writer.WriteStartElement("P");
144      writer.WriteValue(p.ToString());
145      writer.WriteEndElement(); // </P>
146      writer.WriteStartElement("Init");
147      writer.WriteValue(init.ToString());
148      writer.WriteEndElement(); // </Init>
149    }
150    //public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
151    //  base.Populate(node, restoredObjects);
152
153    //  string stateString = node.SelectSingleNode("State").InnerText;
154    //  string[] tokens = stateString.Split(';');
155    //  for(int i = 0; i < tokens.Length; i++)
156    //    state[i] = uint.Parse(tokens[i]);
157    //  p = int.Parse(node.SelectSingleNode("P").InnerText);
158    //  init = bool.Parse(node.SelectSingleNode("Init").InnerText);
159    //}
160    public override void Populate(XmlReader reader, IDictionary<Guid, IStorable> restoredObjects) {
161      base.Populate(reader, restoredObjects);
162      reader.Read();
163      string stateString = reader.ReadElementString("State");
164      string[] tokens = stateString.Split(';');
165      for(int i = 0; i < tokens.Length; i++)
166        state[i] = uint.Parse(tokens[i]);
167      p = int.Parse(reader.ReadElementString("P"));
168      init = bool.Parse(reader.ReadElementString("Init"));
169    }
170    #endregion
171
172    #region Seed Methods
173    public void seed(uint s) {
174      state[0] = s & 0xFFFFFFFFU;
175      for(int i = 1; i < n; ++i) {
176        state[i] = 1812433253U * (state[i - 1] ^ (state[i - 1] >> 30)) + (uint)i;
177        state[i] &= 0xFFFFFFFFU;
178      }
179      p = n;
180    }
181    public void seed(uint[] array) {
182      seed(19650218U);
183      int i = 1, j = 0;
184      for(int k = ((n > array.Length) ? n : array.Length); k > 0; --k) {
185        state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525U))
186          + array[j] + (uint)j;
187        state[i] &= 0xFFFFFFFFU;
188        ++j;
189        j %= array.Length;
190        if((++i) == n) { state[0] = state[n - 1]; i = 1; }
191      }
192      for(int k = n - 1; k > 0; --k) {
193        state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941U)) - (uint)i;
194        state[i] &= 0xFFFFFFFFU;
195        if((++i) == n) { state[0] = state[n - 1]; i = 1; }
196      }
197      state[0] = 0x80000000U;
198      p = n;
199    }
200    #endregion
201
202    #region Random Number Generation Methods
203    private uint rand_int32() {
204      if(p == n) gen_state();
205      uint x = state[p++];
206      x ^= (x >> 11);
207      x ^= (x << 7) & 0x9D2C5680U;
208      x ^= (x << 15) & 0xEFC60000U;
209      return x ^ (x >> 18);
210    }
211    private double rand_double() { // interval [0, 1)
212      return ((double)rand_int32()) * (1.0 / 4294967296.0);
213    }
214    private double rand_double_closed() { // interval [0, 1]
215      return ((double)rand_int32()) * (1.0 / 4294967295.0);
216    }
217    private double rand_double_open() { // interval (0, 1)
218      return (((double)rand_int32()) + 0.5) * (1.0 / 4294967296.0);
219    }
220    private double rand_double53() { // 53 bit resolution, interval [0, 1)
221      return (((double)(rand_int32() >> 5)) * 67108864.0 +
222        ((double)(rand_int32() >> 6))) * (1.0 / 9007199254740992.0);
223    }
224    #endregion
225
226    #region Private Helper Methods
227    private uint twiddle(uint u, uint v) {
228      return (((u & 0x80000000U) | (v & 0x7FFFFFFFU)) >> 1)
229        ^ (((v & 1U) != 0) ? 0x9908B0DFU : 0x0U);
230    }
231    private void gen_state() {
232      for(int i = 0; i < (n - m); ++i)
233        state[i] = state[i + m] ^ twiddle(state[i], state[i + 1]);
234      for(int i = n - m; i < (n - 1); ++i)
235        state[i] = state[i + m - n] ^ twiddle(state[i], state[i + 1]);
236      state[n - 1] = state[m - 1] ^ twiddle(state[n - 1], state[0]);
237      p = 0; // reset position
238    }
239    #endregion
240  }
241}
Note: See TracBrowser for help on using the repository browser.