mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-01-19 03:57:14 +01:00
259 lines
11 KiB
C++
259 lines
11 KiB
C++
|
/**
|
||
|
* \file RandomMixer.hpp
|
||
|
* \brief Header for Mixer classes.
|
||
|
*
|
||
|
* Mixer classes convert a seed vector into a random generator state. An
|
||
|
* important property of this method is that "close" seeds should produce
|
||
|
* "widely separated" states. This allows the seeds to be set is some
|
||
|
* systematic fashion to produce a set of uncorrelated random number
|
||
|
* sequences.
|
||
|
*
|
||
|
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
|
||
|
* under the MIT/X11 License. For more information, see
|
||
|
* http://randomlib.sourceforge.net/
|
||
|
**********************************************************************/
|
||
|
|
||
|
#if !defined(RANDOMLIB_RANDOMMIXER_HPP)
|
||
|
#define RANDOMLIB_RANDOMMIXER_HPP 1
|
||
|
|
||
|
#include <vector>
|
||
|
#include <string>
|
||
|
#include <RandomLib/RandomSeed.hpp>
|
||
|
|
||
|
namespace RandomLib {
|
||
|
|
||
|
/**
|
||
|
* \brief The original %MT19937 mixing functionality
|
||
|
*
|
||
|
* This implements the functionality of init_by_array in MT19937
|
||
|
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c
|
||
|
* and init_by_array64 in MT19937_64
|
||
|
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c
|
||
|
* with the following changes:
|
||
|
* - in the case of an zero-length seed array, behave in the same way if
|
||
|
* MT19937 and MT19937_64 are called without initialization in which case,
|
||
|
* e.g., init_genrand(5489UL) is called. (init_by_array does not allow
|
||
|
* calling with a zero-length seed.)
|
||
|
* - init_by_array64 accepts a seed array of 64-bit unsigned ints. Here with
|
||
|
* seed is an array of 32-bit unsigned ints and these are repacked into
|
||
|
* 64-bit quantities internally using a LSB convention. Thus, to mimic the
|
||
|
* MT19937_64 sample invocation with a seed array {0x12345ULL, 0x23456ULL,
|
||
|
* 0x34567ULL, 0x45678ULL}, MixerMT0<Random_u64>::SeedToState needs to
|
||
|
* be invoked with a seed vector [0x12345UL, 0, 0x23456UL, 0, 0x34567UL, 0,
|
||
|
* 0x45678UL, 0]. (Actually the last 0 is unnecessary.)
|
||
|
*
|
||
|
* The template parameter \e RandomType switches between the 32-bit and
|
||
|
* 64-bit versions.
|
||
|
*
|
||
|
* MixerMT0 is specific to the MT19937 generators and should not be used
|
||
|
* for other generators (e.g., SFMT19937). In addition, MixerMT0 has
|
||
|
* known defects and should only be used to check the operation of the
|
||
|
* MT19937 engines against the original implementation. These defects are
|
||
|
* described in the MixerMT1 which is a modification of MixerMT0
|
||
|
* which corrects these defects. For production use MixerMT1 or,
|
||
|
* preferably, MixerSFMT should be used.
|
||
|
*
|
||
|
* @tparam RandomType the type of the results, either Random_u32 or
|
||
|
* Random_u64.
|
||
|
**********************************************************************/
|
||
|
template<class RandomType> class RANDOMLIB_EXPORT MixerMT0 {
|
||
|
public:
|
||
|
/**
|
||
|
* The RandomType controlling the output of MixerMT0::SeedToState
|
||
|
**********************************************************************/
|
||
|
typedef RandomType mixer_t;
|
||
|
/**
|
||
|
* A version number which should be unique to this RandomMixer. This
|
||
|
* prevents RandomEngine::Load from loading a saved generator with a
|
||
|
* different RandomMixer. Here the version is "MxMT" or "MxMU".
|
||
|
**********************************************************************/
|
||
|
static const unsigned version = 0x4d784d54UL + (mixer_t::width == 64);
|
||
|
private:
|
||
|
/**
|
||
|
* The unsigned type corresponding to mixer_t.
|
||
|
**********************************************************************/
|
||
|
typedef typename mixer_t::type mixer_type;
|
||
|
/**
|
||
|
* The mask for mixer_t.
|
||
|
**********************************************************************/
|
||
|
static const mixer_type mask = mixer_t::mask;
|
||
|
public:
|
||
|
/**
|
||
|
* Mix the seed vector, \e seed, into the state array, \e state, of size \e
|
||
|
* n.
|
||
|
*
|
||
|
* @param[in] seed the input seed vector.
|
||
|
* @param[out] state the generator state.
|
||
|
* @param[in] n the size of the state.
|
||
|
**********************************************************************/
|
||
|
static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
|
||
|
mixer_type state[], unsigned n) throw();
|
||
|
/**
|
||
|
* Return the name of this class.
|
||
|
*
|
||
|
* @return the name.
|
||
|
**********************************************************************/
|
||
|
static std::string Name() {
|
||
|
return "MixerMT0<Random_u" +
|
||
|
std::string(mixer_t::width == 32 ? "32" : "64") + ">";
|
||
|
}
|
||
|
private:
|
||
|
static const mixer_type a0 = 5489ULL;
|
||
|
static const mixer_type a1 = 19650218ULL;
|
||
|
static const mixer_type
|
||
|
b = mixer_t::width == 32 ? 1812433253ULL : 6364136223846793005ULL;
|
||
|
static const mixer_type
|
||
|
c = mixer_t::width == 32 ? 1664525ULL : 3935559000370003845ULL;
|
||
|
static const mixer_type
|
||
|
d = mixer_t::width == 32 ? 1566083941ULL : 2862933555777941757ULL;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* \brief The modified %MT19937 mixing functionality
|
||
|
*
|
||
|
* MixerMT0 has two defects
|
||
|
* - The zeroth word of the state is set to a constant (independent of the
|
||
|
* seed). This is a relatively minor defect which halves the accessible
|
||
|
* state space for MT19937 (but the resulting state space is still huge).
|
||
|
* (Actually, for the 64-bit version, it reduces the accessible states by
|
||
|
* 2<sup>33</sup>. On the other hand the 64-bit has better mixing
|
||
|
* properties.)
|
||
|
* - Close seeds, for example, [1] and [1,0], result in the same state. This
|
||
|
* is a potentially serious flaw which might result is identical random
|
||
|
* number sequences being generated instead of independent sequences.
|
||
|
*
|
||
|
* MixerMT1 fixes these defects in a straightforward manner. The
|
||
|
* resulting algorithm was included in one of the proposals for Random Number
|
||
|
* Generation for C++0X, see Brown, et al.,
|
||
|
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2079.pdf
|
||
|
*
|
||
|
* The template parameter \e RandomType switches between the 32-bit and
|
||
|
* 64-bit versions.
|
||
|
*
|
||
|
* MixerMT1 still has a weakness in that it doesn't thoroughly mix the
|
||
|
* state. This is illustrated by an example given to me by Makoto Matsumoto:
|
||
|
* Consider a seed of length \e N and suppose we consider all \e
|
||
|
* W<sup><i>N</i>/2</sup> values for the first half of the seed (here \e W =
|
||
|
* 2<sup><i>width</i></sup>). MixerMT1 has a bottleneck in the way that
|
||
|
* the state is initialized which results in the second half of the state
|
||
|
* only taking on \e W<sup>2</sup> possible values. MixerSFMT mixes the
|
||
|
* seed into the state much more thoroughly.
|
||
|
*
|
||
|
* @tparam RandomType the type of the results, either Random_u32 or
|
||
|
* Random_u64.
|
||
|
**********************************************************************/
|
||
|
template<class RandomType> class RANDOMLIB_EXPORT MixerMT1 {
|
||
|
public:
|
||
|
/**
|
||
|
* The RandomType controlling the output of MixerMT1::SeedToState
|
||
|
**********************************************************************/
|
||
|
typedef RandomType mixer_t;
|
||
|
/**
|
||
|
* A version number which should be unique to this RandomMixer. This
|
||
|
* prevents RandomEngine::Load from loading a saved generator with a
|
||
|
* different RandomMixer. Here the version is "MxMV" or "MxMW".
|
||
|
**********************************************************************/
|
||
|
static const unsigned version = 0x4d784d56UL + (mixer_t::width == 64);
|
||
|
private:
|
||
|
/**
|
||
|
* The unsigned type corresponding to mixer_t.
|
||
|
**********************************************************************/
|
||
|
typedef typename mixer_t::type mixer_type;
|
||
|
/**
|
||
|
* The mask for mixer_t.
|
||
|
**********************************************************************/
|
||
|
static const mixer_type mask = mixer_t::mask;
|
||
|
public:
|
||
|
/**
|
||
|
* Mix the seed vector, \e seed, into the state array, \e state, of size \e
|
||
|
* n.
|
||
|
*
|
||
|
* @param[in] seed the input seed vector.
|
||
|
* @param[out] state the generator state.
|
||
|
* @param[in] n the size of the state.
|
||
|
**********************************************************************/
|
||
|
static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
|
||
|
mixer_type state[], unsigned n) throw();
|
||
|
/**
|
||
|
* Return the name of this class.
|
||
|
*
|
||
|
* @return the name.
|
||
|
**********************************************************************/
|
||
|
static std::string Name() {
|
||
|
return "MixerMT1<Random_u" +
|
||
|
std::string(mixer_t::width == 32 ? "32" : "64") + ">";
|
||
|
}
|
||
|
private:
|
||
|
static const mixer_type a = 5489ULL;
|
||
|
static const mixer_type
|
||
|
b = mixer_t::width == 32 ? 1812433253ULL : 6364136223846793005ULL;
|
||
|
static const mixer_type
|
||
|
c = mixer_t::width == 32 ? 1664525ULL : 3935559000370003845ULL;
|
||
|
static const mixer_type
|
||
|
d = mixer_t::width == 32 ? 1566083941ULL : 2862933555777941757ULL;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* \brief The SFMT mixing functionality
|
||
|
*
|
||
|
* MixerSFMT is adapted from SFMT's init_by_array Mutsuo Saito given in
|
||
|
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/SFMT-src-1.2.tar.gz
|
||
|
* and is part of the C++11 standard; see P. Becker, Working Draft, Standard
|
||
|
* for Programming Language C++, Oct. 2007, Sec. 26.4.7.1,
|
||
|
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf
|
||
|
*
|
||
|
* MixerSFMT contains a single change is to allow it to function properly
|
||
|
* when the size of the state is small.
|
||
|
*
|
||
|
* MixerSFMT mixes the seed much more thoroughly than MixerMT1 and, in
|
||
|
* particular, it removes the mixing bottleneck present in MixerMT1.
|
||
|
* Thus it is the recommended mixing scheme for all production work.
|
||
|
**********************************************************************/
|
||
|
class RANDOMLIB_EXPORT MixerSFMT {
|
||
|
public:
|
||
|
/**
|
||
|
* The RandomType controlling the output of MixerSFMT::SeedToState
|
||
|
**********************************************************************/
|
||
|
typedef Random_u32 mixer_t;
|
||
|
/**
|
||
|
* A version number which should be unique to this RandomMixer. This
|
||
|
* prevents RandomEngine::Load from loading a saved generator with a
|
||
|
* different RandomMixer. Here the version is "MxSM".
|
||
|
**********************************************************************/
|
||
|
static const unsigned version = 0x4d78534dUL;
|
||
|
private:
|
||
|
/**
|
||
|
* The unsigned type corresponding to mixer_t.
|
||
|
**********************************************************************/
|
||
|
typedef mixer_t::type mixer_type;
|
||
|
/**
|
||
|
* The mask for mixer_t.
|
||
|
**********************************************************************/
|
||
|
static const mixer_type mask = mixer_t::mask;
|
||
|
public:
|
||
|
/**
|
||
|
* Mix the seed vector, \e seed, into the state array, \e state, of size \e
|
||
|
* n.
|
||
|
*
|
||
|
* @param[in] seed the input seed vector.
|
||
|
* @param[out] state the generator state.
|
||
|
* @param[in] n the size of the state.
|
||
|
**********************************************************************/
|
||
|
static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
|
||
|
mixer_type state[], unsigned n) throw();
|
||
|
/**
|
||
|
* Return the name of this class.
|
||
|
*
|
||
|
* @return the name.
|
||
|
**********************************************************************/
|
||
|
static std::string Name() { return "MixerSFMT"; }
|
||
|
private:
|
||
|
static const mixer_type a = 0x8b8b8b8bUL;
|
||
|
static const mixer_type b = 1664525UL;
|
||
|
static const mixer_type c = 1566083941UL;
|
||
|
};
|
||
|
|
||
|
} // namespace RandomLib
|
||
|
|
||
|
#endif // RANDOMLIB_RANDOMMIXER_HPP
|