forked from Kitware/VTK
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vtkMersenneTwister.cxx
225 lines (193 loc) · 7.62 KB
/
vtkMersenneTwister.cxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/*=========================================================================
Program: Visualization Toolkit
Module: vtkMersenneTwister.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
/* Many thanks to M. Matsumoto, T. Nishimura and M. Saito for the */
/* implementation of their algorithm, the Mersenne Twister, taken from */
/* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/DC/dc.html */
/* Dynamic Creation (DC) of Mersenne Twister generators */
/* */
/* Reference: */
/* Makoto Matsumoto and Takuji Nishimura, */
/* "Dynamic Creation of Pseudorandom Number Generators", */
/* Monte Carlo and Quasi-Monte Carlo Methods 1998, */
/* Springer, 2000, pp 56--69. */
#include "vtkMersenneTwister_Private.cxx"
#include <map>
namespace
{
class MersenneTwister
{
public:
typedef std::map<uint32_t, mt_struct*> mt_parameter_map;
typedef mt_parameter_map::value_type mt_parameter;
typedef mt_parameter_map::iterator mt_parameter_it;
~MersenneTwister()
{
// Free the initialized MT states.
for (mt_parameter_it it = this->Parameters.begin();
it != this->Parameters.end(); ++it)
{
free_mt_struct(it->second);
}
}
void InitializeSequence(uint32_t key, uint32_t seed, int periodExp=521)
{
mt_parameter_it it = this->Parameters.find(key);
if (it != this->Parameters.end())
{
// If a sequence already exists with this id, free its contents...
free_mt_struct(it->second);
}
else
{
//...otherwise, add a key/value pair for this sequence id
mt_parameter parameter(key, static_cast<mt_struct*>(0));
it = this->Parameters.insert(parameter).first;
}
// Instantiate the sequence.
it->second = get_mt_parameter_id_st(32, periodExp, key, seed);
sgenrand_mt(seed, it->second);
}
uint32_t InitializeNewSequence(uint32_t seed, int periodExp=521)
{
// Identify an id that has not yet been used...
uint32_t key = static_cast<uint32_t>(this->Parameters.size());
while (this->Parameters.find(key) != this->Parameters.end())
{
++key;
}
//...and use it to instantiate a sequence.
mt_parameter parameter(key, get_mt_parameter_id_st(32,periodExp,key,seed));
sgenrand_mt(seed, parameter.second);
// Here and throughout, we use insert() with a hint to mitigate the cost of
// using a map to associate keys with MT states (the upshot is we get to use
// whatever ids we want to grab MT states).
this->Parameters.insert(
(this->Parameters.begin() == this->Parameters.end() ?
this->Parameters.begin() : --this->Parameters.end()), parameter);
return key;
}
uint32_t Random32(uint32_t sequenceId)
{
mt_parameter_it it = this->Parameters.find(sequenceId);
if (it == this->Parameters.end())
{
mt_parameter parameter(sequenceId,
get_mt_parameter_id_st(32, 521, sequenceId, 0));
sgenrand_mt(0, parameter.second);
it = this->Parameters.insert(--it, parameter);
}
return genrand_mt(it->second);
}
vtkTypeUInt64 Random64(uint32_t sequenceId)
{
vtkTypeUInt64 value = this->Random32(sequenceId);
return (value << 32) + this->Random32(sequenceId);
}
protected:
mt_parameter_map Parameters;
};
static const int NMersenneExponents = 15;
static const int MersenneExponents[NMersenneExponents] = {521, 607, 1279,
2203, 2281, 3217,
4253, 4423, 9689,
9941, 11213, 19937,
21701, 23209, 44497};
static const int* MersenneExponentsEnd = MersenneExponents + NMersenneExponents;
}
#include <algorithm>
#include "vtkMersenneTwister.h"
#include "vtkObjectFactory.h"
class vtkMersenneTwisterInternals : public MersenneTwister
{
public:
typedef std::map<uint32_t, double> ValueMap;
typedef ValueMap::iterator ValueIt;
typedef ValueMap::value_type Value;
ValueMap Values;
};
vtkStandardNewMacro(vtkMersenneTwister);
// ----------------------------------------------------------------------------
vtkMersenneTwister::vtkMersenneTwister()
{
this->Internal = new vtkMersenneTwisterInternals();
}
// ----------------------------------------------------------------------------
vtkMersenneTwister::~vtkMersenneTwister()
{
delete this->Internal;
}
// ----------------------------------------------------------------------------
void vtkMersenneTwister::InitializeSequence(vtkMersenneTwister::SequenceId id,
vtkTypeUInt32 seed, int periodExp)
{
if (std::find(MersenneExponents, MersenneExponentsEnd, periodExp) ==
MersenneExponentsEnd)
{
periodExp = MersenneExponents[periodExp%15];
}
if (this->Internal->Values.insert(
vtkMersenneTwisterInternals::Value(id, 0.)).second == false)
{
vtkWarningMacro(<< "Initializing process "<<id<<" which is already "
<< "initialized. This may break sequence encapsulation.");
}
this->Internal->InitializeSequence(id, seed, periodExp);
}
// ----------------------------------------------------------------------------
vtkMersenneTwister::SequenceId
vtkMersenneTwister::InitializeNewSequence(vtkTypeUInt32 seed, int periodExp)
{
if (std::find(MersenneExponents, MersenneExponentsEnd, periodExp) ==
MersenneExponentsEnd)
{
periodExp = MersenneExponents[periodExp%15];
}
SequenceId id = this->Internal->InitializeNewSequence(seed, periodExp);
this->Internal->Values.insert(
(this->Internal->Values.begin() == this->Internal->Values.end() ?
this->Internal->Values.begin() : --this->Internal->Values.end()),
vtkMersenneTwisterInternals::Value(id, 0.));
return id;
}
// ----------------------------------------------------------------------------
double vtkMersenneTwister::GetValue(vtkMersenneTwister::SequenceId id)
{
vtkMersenneTwisterInternals::ValueIt it = this->Internal->Values.find(id);
if (it == this->Internal->Values.end())
{
this->Next(id);
}
return this->Internal->Values.find(id)->second;
}
// ----------------------------------------------------------------------------
void vtkMersenneTwister::Next(vtkMersenneTwister::SequenceId id)
{
static const double norm =
1./static_cast<double>(std::numeric_limits<vtkTypeUInt64>::max());
vtkMersenneTwisterInternals::ValueIt it = this->Internal->Values.find(id);
if (it == this->Internal->Values.end())
{
vtkWarningMacro(<< "Using an ininitialized vtkMersenneTwister process. "
<< "Initializing process "<<id<<" with default values.");
vtkMersenneTwisterInternals::Value value(id, 0.);
it = this->Internal->Values.insert(
(this->Internal->Values.begin() == this->Internal->Values.end() ?
this->Internal->Values.begin() : --this->Internal->Values.end()),
value);
this->Internal->InitializeSequence(id, 0);
}
it->second = this->Internal->Random64(id)*norm;
}
// ----------------------------------------------------------------------------
void vtkMersenneTwister::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}