Free cookie consent management tool by TermsFeed Policy Generator

source: branches/XmlTextReaderBranch/HeuristicLab.Random/MersenneTwister.cs @ 121

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

created a branch that uses XmlTextReader instead of XMLDocument to load documents. Investigating ticket #103. (...work in progress!)

File size: 7.6 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 Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
133    //  base.Populate(node, restoredObjects);
134
135    //  string stateString = node.SelectSingleNode("State").InnerText;
136    //  string[] tokens = stateString.Split(';');
137    //  for(int i = 0; i < tokens.Length; i++)
138    //    state[i] = uint.Parse(tokens[i]);
139    //  p = int.Parse(node.SelectSingleNode("P").InnerText);
140    //  init = bool.Parse(node.SelectSingleNode("Init").InnerText);
141    //}
142    public override void Populate(XmlReader reader, IDictionary<Guid, IStorable> restoredObjects) {
143      base.Populate(reader, restoredObjects);
144
145      reader.ReadStartElement("State");
146      string stateString = reader.ReadString();
147      reader.ReadEndElement();
148      string[] tokens = stateString.Split(';');
149      for(int i = 0; i < tokens.Length; i++)
150        state[i] = uint.Parse(tokens[i]);
151      reader.ReadStartElement("P");
152      p = int.Parse(reader.ReadString());
153      reader.ReadEndElement();
154      reader.ReadStartElement("Init");
155      init = bool.Parse(reader.ReadString());
156      reader.ReadEndElement();
157    }
158    #endregion
159
160    #region Seed Methods
161    public void seed(uint s) {
162      state[0] = s & 0xFFFFFFFFU;
163      for (int i = 1; i < n; ++i) {
164        state[i] = 1812433253U * (state[i - 1] ^ (state[i - 1] >> 30)) + (uint)i;
165        state[i] &= 0xFFFFFFFFU;
166      }
167      p = n;
168    }
169    public void seed(uint[] array) {
170      seed(19650218U);
171      int i = 1, j = 0;
172      for (int k = ((n > array.Length) ? n : array.Length); k > 0; --k) {
173        state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525U))
174          + array[j] + (uint)j;
175        state[i] &= 0xFFFFFFFFU;
176        ++j;
177        j %= array.Length;
178        if ((++i) == n) { state[0] = state[n - 1]; i = 1; }
179      }
180      for (int k = n - 1; k > 0; --k) {
181        state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941U)) - (uint)i;
182        state[i] &= 0xFFFFFFFFU;
183        if ((++i) == n) { state[0] = state[n - 1]; i = 1; }
184      }
185      state[0] = 0x80000000U;
186      p = n;
187    }
188    #endregion
189
190    #region Random Number Generation Methods
191    private uint rand_int32() {
192      if (p == n) gen_state();
193      uint x = state[p++];
194      x ^= (x >> 11);
195      x ^= (x << 7) & 0x9D2C5680U;
196      x ^= (x << 15) & 0xEFC60000U;
197      return x ^ (x >> 18);
198    }
199    private double rand_double() { // interval [0, 1)
200      return ((double)rand_int32()) * (1.0 / 4294967296.0);
201    }
202    private double rand_double_closed() { // interval [0, 1]
203      return ((double)rand_int32()) * (1.0 / 4294967295.0);
204    }
205    private double rand_double_open() { // interval (0, 1)
206      return (((double)rand_int32()) + 0.5) * (1.0 / 4294967296.0);
207    }
208    private double rand_double53() { // 53 bit resolution, interval [0, 1)
209      return (((double)(rand_int32() >> 5)) * 67108864.0 +
210        ((double)(rand_int32() >> 6))) * (1.0 / 9007199254740992.0);
211    }
212    #endregion
213
214    #region Private Helper Methods
215    private uint twiddle(uint u, uint v) {
216      return (((u & 0x80000000U) | (v & 0x7FFFFFFFU)) >> 1)
217        ^ (((v & 1U) != 0) ? 0x9908B0DFU : 0x0U);
218    }
219    private void gen_state() {
220      for (int i = 0; i < (n - m); ++i)
221        state[i] = state[i + m] ^ twiddle(state[i], state[i + 1]);
222      for (int i = n - m; i < (n - 1); ++i)
223        state[i] = state[i + m - n] ^ twiddle(state[i], state[i + 1]);
224      state[n - 1] = state[m - 1] ^ twiddle(state[n - 1], state[0]);
225      p = 0; // reset position
226    }
227    #endregion
228  }
229}
Note: See TracBrowser for help on using the repository browser.