/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkMersenneTwisterRandomVariateGenerator_h #define itkMersenneTwisterRandomVariateGenerator_h #include "itkMacro.h" #include "itkObjectFactory.h" #include "itkRandomVariateGeneratorBase.h" #include "itkIntTypes.h" #include "itkMath.h" #include "itkSingletonMacro.h" #include #include #include #include namespace itk { namespace Statistics { /** \class MersenneTwisterRandomVariateGenerator * \brief MersenneTwisterRandom random variate generator * * It is recommended to create a separate object in each thread. By * default, each instantiated class will have a different seed created * by the GetNextSeed method. The creation of the initial seeds are * initialized once from the time. For deterministic behavior, the * individual instances' seeds should be manual set to separate * values in each thread. * * It is no longer recommended to use this class using a * "Singleton-like" GetInstance method for the global instance of this * class. This usage may result in unsafe concurrent access to * the global instance. * * \warning This class's instance methods are NEITHER reentrant * nor concurrent thread-safe, except where marked as * thread-safe. That is to say you can still use separate objects * concurrently. * * This notice was included with the original implementation. * The only changes made were to obfuscate the author's email addresses. * * MersenneTwister.h * Mersenne Twister random number generator -- a C++ class MTRand * Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus * Richard J. Wagner v1.0 15 May 2003 rjwagner at writeme dot com * * The Mersenne Twister is an algorithm for generating random numbers. It * was designed with consideration of the flaws in various other generators. * The period, 2^19937-1, and the order of equidistribution, 623 dimensions, * are far greater. The generator is also fast; it avoids multiplication and * division, and it benefits from caches and pipelines. For more information * see the inventors' web page at http:*www.math.keio.ac.jp/~matumoto/emt.html * * Reference * M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally * Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on * Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30. * * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, * Copyright (C) 2000 - 2003, Richard J. Wagner * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The names of its contributors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The original code included the following notice: * * When you use this, send an email to: matumoto at math dot keio dot ac dot jp * with an appropriate reference to your work. * * It would be nice to CC: * rjwagner at writeme dot com and Cokus at math dot washington dot edu * when you write. * * \ingroup Common * \ingroup ITKCommon * * \sphinx * \sphinxexample{Core/Common/MersenneTwisterRandomNumberGenerator,Mersenne Twister Random Number Generator} * \endsphinx */ struct MersenneTwisterGlobals; class ITKCommon_EXPORT MersenneTwisterRandomVariateGenerator : public RandomVariateGeneratorBase { public: /** Standard class type aliases. */ using Self = MersenneTwisterRandomVariateGenerator; using Superclass = RandomVariateGeneratorBase; using Pointer = SmartPointer; using ConstPointer = SmartPointer; using IntegerType = uint32_t; /** \see LightObject::GetNameOfClass() */ itkOverrideGetNameOfClassMacro(MersenneTwisterRandomVariateGenerator); /** \brief Method for creation through the object factory. * * This method allocates a new instance of a Mersenne Twister, * and initializes it with the next seed from the global instance's * seed. * * \note This method is thread-safe. */ static Pointer New(); /** Return the global Mersenne Twister instance. * * This method returns a Singleton of the Mersenne Twister. * The seed is initialized from the wall clock at first use, but can * be globally set using the resulting instance's SetSeed(). * * \note This method is thread-safe. */ static Pointer GetInstance(); /** Resets the internal data that is used to calculate the next seed. (Does not reset the initial seed.) Allows * generating a reproducible sequence of pseudo-random numbers. */ static void ResetNextSeed(); /** Length of state vector */ static constexpr IntegerType StateVectorLength = 624; /** Initialize with a simple IntegerType */ void Initialize(const IntegerType seed); /* Initialize with clock time */ void Initialize(); /** Get a random variate in the range [0, 1] */ double GetVariateWithClosedRange(); /** Get a random variate in the range [0, n] */ double GetVariateWithClosedRange(const double n); /** Get a range variate in the range [0, 1) */ double GetVariateWithOpenUpperRange(); /** Get a range variate in the range [0, n) */ double GetVariateWithOpenUpperRange(const double n); /** Get a range variate in the range (0, 1) */ double GetVariateWithOpenRange(); /** Get a range variate in the range (0, n) */ double GetVariateWithOpenRange(const double n); /** Get an integer variate in [0, 2^32-1] */ IntegerType GetIntegerVariate(); /** Get an integer variate in [0, n] for n < 2^32 */ IntegerType GetIntegerVariate(const IntegerType & n); /** Access to 53-bit random numbers (capacity of IEEE double precision) * in the range [0,1) */ double Get53BitVariate(); /* Access to a normal random number distribution * TODO: Compare with vnl_sample_normal */ double GetNormalVariate(const double mean = 0.0, const double variance = 1.0); /* Access to a uniform random number distribution in the range [a, b) * TODO: Compare with vnl_sample_uniform */ double GetUniformVariate(const double a, const double b); /** Get a variate in the range [0, 1] * Do NOT use for CRYPTOGRAPHY without securely hashing several returned * values together, otherwise the generator state can be learned after * reading 624 consecutive values. */ double GetVariate() override; /** Same as GetVariate() */ double operator()(); /** Re-seeding functions with same behavior as initializers * * \note This method is thread-safe. */ inline void SetSeed(const IntegerType oneSeed); inline void SetSeed(); /** Return the current seed * * \note This method is thread-safe. */ IntegerType GetSeed() const; /** Return the next seed, derived as a sequence from the seed of the * singleton instance. * * \note This method is thread-safe. */ static IntegerType GetNextSeed(); /* // Saving and loading generator state void save( IntegerType* saveArray ) const; // to array of size SAVE void load( IntegerType *const loadArray ); // from such array */ protected: MersenneTwisterRandomVariateGenerator(); ~MersenneTwisterRandomVariateGenerator() override; void PrintSelf(std::ostream & os, Indent indent) const override; /** Period parameter */ static constexpr unsigned int M = 397; /** Reload array with N new values. */ void reload(); IntegerType hiBit(const IntegerType & u) const { return u & 0x80000000; } IntegerType loBit(const IntegerType & u) const { return u & 0x00000001; } IntegerType loBits(const IntegerType & u) const { return u & 0x7fffffff; } IntegerType mixBits(const IntegerType & u, const IntegerType & v) const { return hiBit(u) | loBits(v); } IntegerType twist(const IntegerType & m, const IntegerType & s0, const IntegerType & s1) const { return m ^ (mixBits(s0, s1) >> 1) ^ (-static_cast(loBit(s1)) & 0x9908b0df); } static IntegerType hash(time_t t, clock_t c); // Internal state IntegerType state[StateVectorLength]; // Next value to get from state IntegerType * m_PNext{}; // Number of values left before reload is needed int m_Left{}; // Seed value std::atomic m_Seed{}; private: /** Only used to synchronize the global variable across static libraries.*/ itkGetGlobalDeclarationMacro(MersenneTwisterGlobals, PimplGlobals); /** Internal method to actually create a new object. */ static Pointer CreateInstance(); // Local lock to enable concurrent access to singleton std::mutex m_InstanceMutex{}; // Static/Global Variable need to be thread-safely accessed static MersenneTwisterGlobals * m_PimplGlobals; }; // end of class // Declare inlined functions.... (must be declared in the header) inline void MersenneTwisterRandomVariateGenerator::Initialize(const IntegerType seed) { const std::lock_guard lockGuard(m_InstanceMutex); this->m_Seed = seed; // Initialize generator state with seed // See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier. // In previous versions, most significant bits (MSBs) of the seed affect // only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto. IntegerType * s = state; IntegerType * r = state; IntegerType i = 1; *s++ = seed & 0xffffffffUL; for (i = 1; i < MersenneTwisterRandomVariateGenerator::StateVectorLength; ++i) { *s++ = (1812433253UL * (*r ^ (*r >> 30)) + i) & 0xffffffffUL; ++r; } reload(); } inline void MersenneTwisterRandomVariateGenerator::reload() { // Generate N new values in state // Made clearer and faster by Matthew Bellew // matthew dot bellew at home dot com // get rid of VS warning constexpr auto index = int{ M } - int{ MersenneTwisterRandomVariateGenerator::StateVectorLength }; IntegerType * p = state; int i; for (i = MersenneTwisterRandomVariateGenerator::StateVectorLength - M; i--; ++p) { *p = twist(p[M], p[0], p[1]); } for (i = M; --i; ++p) { *p = twist(p[index], p[0], p[1]); } *p = twist(p[index], p[0], state[0]); m_Left = MersenneTwisterRandomVariateGenerator::StateVectorLength; m_PNext = state; } inline void MersenneTwisterRandomVariateGenerator::Initialize() { SetSeed(); } inline void MersenneTwisterRandomVariateGenerator::SetSeed(const IntegerType oneSeed) { // Seed the generator with a simple IntegerType Initialize(oneSeed); } inline void MersenneTwisterRandomVariateGenerator::SetSeed() { // use time() and clock() to generate a unlikely-to-repeat seed. SetSeed(hash(time(nullptr), clock())); } inline MersenneTwisterRandomVariateGenerator::IntegerType MersenneTwisterRandomVariateGenerator::GetSeed() const { return this->m_Seed; } /** Get an integer variate in [0, 2^32-1] */ inline MersenneTwisterRandomVariateGenerator::IntegerType MersenneTwisterRandomVariateGenerator::GetIntegerVariate() { if (m_Left == 0) { reload(); } --m_Left; IntegerType s1 = *m_PNext++; s1 ^= (s1 >> 11); s1 ^= (s1 << 7) & 0x9d2c5680; s1 ^= (s1 << 15) & 0xefc60000; return (s1 ^ (s1 >> 18)); } inline double MersenneTwisterRandomVariateGenerator::GetVariateWithClosedRange() { return static_cast(GetIntegerVariate()) * (1.0 / 4294967295.0); } /** Get a random variate in the range [0, n] */ inline double MersenneTwisterRandomVariateGenerator::GetVariateWithClosedRange(const double n) { return GetVariateWithClosedRange() * n; } /** Get a range variate in the range [0, 1) */ inline double MersenneTwisterRandomVariateGenerator::GetVariateWithOpenUpperRange() { return static_cast(GetIntegerVariate()) * (1.0 / 4294967296.0); } /** Get a range variate in the range [0, n) */ inline double MersenneTwisterRandomVariateGenerator::GetVariateWithOpenUpperRange(const double n) { return GetVariateWithOpenUpperRange() * n; } /** Get a range variate in the range (0, 1) */ inline double MersenneTwisterRandomVariateGenerator::GetVariateWithOpenRange() { return (static_cast(GetIntegerVariate()) + 0.5) * (1.0 / 4294967296.0); } /** Get a range variate in the range (0, n) */ inline double MersenneTwisterRandomVariateGenerator::GetVariateWithOpenRange(const double n) { return GetVariateWithOpenRange() * n; } inline MersenneTwisterRandomVariateGenerator::IntegerType MersenneTwisterRandomVariateGenerator::GetIntegerVariate(const IntegerType & n) { // Find which bits are used in n IntegerType used = n; used |= used >> 1; used |= used >> 2; used |= used >> 4; used |= used >> 8; used |= used >> 16; // Draw numbers until one is found in [0,n] IntegerType i; do { i = GetIntegerVariate() & used; // toss unused bits to shorten search } while (i > n); return i; } /** Access to 53-bit random numbers (capacity of IEEE double precision) * in the range [0,1) */ inline double MersenneTwisterRandomVariateGenerator::Get53BitVariate() { IntegerType a = GetIntegerVariate() >> 5, b = GetIntegerVariate() >> 6; return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); // by Isaku // Wada } /** Access to a normal random number distribution. */ // TODO: Compare with vnl_sample_normal inline double MersenneTwisterRandomVariateGenerator::GetNormalVariate(const double mean, const double variance) { // Return a real number from a normal (Gaussian) distribution with given // mean and variance by Box-Muller method double r = std::sqrt(-2.0 * std::log(1.0 - GetVariateWithOpenRange()) * variance); double phi = 2.0 * itk::Math::pi * GetVariateWithOpenUpperRange(); return mean + r * std::cos(phi); } /** Access to a uniform random number distribution */ // TODO: Compare with vnl_sample_uniform inline double MersenneTwisterRandomVariateGenerator::GetUniformVariate(const double a, const double b) { double u = GetVariateWithOpenUpperRange(); return ((1.0 - u) * a + u * b); } inline double MersenneTwisterRandomVariateGenerator::GetVariate() { return GetVariateWithClosedRange(); } inline double MersenneTwisterRandomVariateGenerator::operator()() { return GetVariate(); } /* Change log from MTRand.h */ // Change log: // // v0.1 - First release on 15 May 2000 // - Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus // - Translated from C to C++ // - Made completely ANSI compliant // - Designed convenient interface for initialization, seeding, and // obtaining numbers in default or user-defined ranges // - Added automatic seeding from /dev/urandom or time() and clock() // - Provided functions for saving and loading generator state // // v0.2 - Fixed bug which reloaded generator one step too late // // v0.3 - Switched to clearer, faster reload() code from Matthew Bellew // // v0.4 - Removed trailing newline in saved generator format to be consistent // with output format of built-in types // // v0.5 - Improved portability by replacing static const int's with enum's and // clarifying return values in seed(); suggested by Eric Heimburg // - Removed MAXINT constant; use 0xffffffffUL instead // // v0.6 - Eliminated seed overflow when uint32 is larger than 32 bits // - Changed integer [0,n] generator to give better uniformity // // v0.7 - Fixed operator precedence ambiguity in reload() // - Added access for real numbers in (0,1) and (0,n) // // v0.8 - Included time.h header to properly support time_t and clock_t // // v1.0 - Revised seeding to match 26 Jan 2002 update of Nishimura and Matsumoto // - Allowed for seeding with arrays of any length // - Added access for real numbers in [0,1) with 53-bit resolution // - Added access for real numbers from normal (Gaussian) distributions // - Increased overall speed by optimizing twist() // - Doubled speed of integer [0,n] generation // - Fixed out-of-range number generation on 64-bit machines // - Improved portability by substituting literal constants for long enum's // - Changed license from GNU LGPL to BSD } // end namespace Statistics } // end namespace itk #endif