/*========================================================================= 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. */ // NOLINTNEXTLINE(bugprone-suspicious-include) #include "vtkMersenneTwister_Private.cxx" #include "vtkMultiThreader.h" #include "vtkNew.h" #include namespace { class MersenneTwister { public: typedef std::map 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(nullptr)); 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(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; }; const int NMersenneExponents = 15; const int MersenneExponents[NMersenneExponents] = { 521, 607, 1279, 2203, 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497 }; const int* MersenneExponentsEnd = MersenneExponents + NMersenneExponents; } #include #include "vtkMersenneTwister.h" #include "vtkObjectFactory.h" class vtkMersenneTwisterInternals : public MersenneTwister { public: typedef std::map 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) { vtkWarningMacro(<< "Initializing process " << id << " which is already " << "initialized. This may break sequence encapsulation."); } this->Internal->InitializeSequence(id, seed, periodExp); // Start the sequence since the initial value =0.0. this->Next(id); } //------------------------------------------------------------------------------ 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.)); // Start the sequence since the initial value =0.0. this->Next(id); 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(std::numeric_limits::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); }