/*========================================================================= 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 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; }; 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 #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 == false) { vtkWarningMacro(<< "Initializing process "<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(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 "<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); }