Skip to content

Uniformize Interface of Random Generators in Math #12410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions math/mathcore/inc/Math/MersenneTwisterEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace ROOT {
@ingroup Random
*/

class MersenneTwisterEngine : public TRandomEngine {
class MersenneTwisterEngine final : public TRandomEngine {


public:
Expand All @@ -56,6 +56,9 @@ namespace ROOT {
typedef uint32_t Result_t;
typedef uint32_t StateInt_t;

// number of random bits generated
static constexpr uint32_t kNumberOfBits = 32;


MersenneTwisterEngine(uint32_t seed=4357) {
SetSeed(seed);
Expand All @@ -75,9 +78,9 @@ namespace ROOT {
}

/// minimum integer taht can be generated
static unsigned int MinInt() { return 0; }
static constexpr unsigned int MinInt() { return 0; }
/// maximum integer that can be generated
static unsigned int MaxInt() { return 0xffffffff; } // 2^32 -1
static constexpr unsigned int MaxInt() { return 0xffffffff; } // 2^32 -1

static int Size() { return kSize; }

Expand Down
10 changes: 7 additions & 3 deletions math/mathcore/inc/Math/MixMaxEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "Math/TRandomEngine.h"



// struct rng_state_st; /// forward declare generator state

// typedef struct rng_state_st rng_state_t;
Expand Down Expand Up @@ -99,7 +100,7 @@ Chaos, Solitons & Fractals, Volume 91, (2016) pp. 33–38
*/

template<int N, int SkipNumber>
class MixMaxEngine : public TRandomEngine {
class MixMaxEngine final : public TRandomEngine {

public:

Expand All @@ -113,6 +114,9 @@ Chaos, Solitons & Fractals, Volume 91, (2016) pp. 33–38
#endif
typedef uint64_t Result_t;

// number of random bits generated
static constexpr uint32_t kNumberOfBits = 61;


MixMaxEngine(uint64_t seed=1);

Expand All @@ -123,10 +127,10 @@ Chaos, Solitons & Fractals, Volume 91, (2016) pp. 33–38
static int Size();

/// maximum integer that can be generated. For MIXMAX is 2^61-1
static uint64_t MaxInt();
static constexpr uint64_t MaxInt() { return 2305843009213693951ULL;}

/// minimum integer that can be generated. For MIXMAX is 0
static uint64_t MinInt();
static constexpr uint64_t MinInt() { return 0;}

/// set the generator seed
void SetSeed(Result_t seed);
Expand Down
12 changes: 0 additions & 12 deletions math/mathcore/inc/Math/MixMaxEngine.icc
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,6 @@ namespace Math {
return fRng->IntRndm();
}

template<int N, int S>
uint64_t MixMaxEngine<N,S>::MaxInt() {
//return mixmax::mixmax_engine<N>::max();
return 2305843009213693951ULL;
}

template<int N, int S>
uint64_t MixMaxEngine<N,S>::MinInt() {
//return mixmax::mixmax_engine<N>::min();
return 0;
}

template<int N, int S>
void MixMaxEngine<N,S>::RndmArray(int n, double *array){
// Return an array of n random numbers uniformly distributed in ]0,1]
Expand Down
13 changes: 13 additions & 0 deletions math/mathcore/inc/Math/RanluxppEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ class RanluxppEngine final : public TRandomEngine {
RanluxppEngine(uint64_t seed = 314159265);
~RanluxppEngine() override;

typedef TRandomEngine BaseType;

typedef uint64_t Result_t;

// number of random bits generated
static constexpr uint32_t kNumberOfBits = 48;

/// minimum integer taht can be generated
static constexpr uint64_t MinInt() { return 0; }

/// maximum integer taht can be generated
static constexpr uint64_t MaxInt() { return (1ULL<<48) - 1; } // 2^48 -1

/// Generate a double-precision random number with 48 bits of randomness
double Rndm() override;
/// Generate a double-precision random number (non-virtual method)
Expand Down
193 changes: 93 additions & 100 deletions math/mathcore/inc/Math/StdEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,107 +17,100 @@

namespace ROOT {

namespace Math {


class StdRandomEngine {};

template<class Generator>
struct StdEngineType {
static const char * Name() { return "std_random_eng";}
};
template<>
struct StdEngineType<std::minstd_rand> {
static const char * Name() { return "std_minstd_rand";}
};
template<>
struct StdEngineType<std::mt19937> {
static const char * Name() { return "std_mt19937";}
};
template<>
struct StdEngineType<std::mt19937_64> {
static const char * Name() { return "std_mt19937_64";}
};
template<>
struct StdEngineType<std::ranlux24> {
static const char * Name() { return "std_ranlux24";}
};
template<>
struct StdEngineType<std::ranlux48> {
static const char * Name() { return "std_ranlux48";}
};
template<>
struct StdEngineType<std::knuth_b> {
static const char * Name() { return "std_knuth_b";}
};
template<>
struct StdEngineType<std::random_device> {
static const char * Name() { return "std_random_device";}
};


/**
@ingroup Random
Class to wrap engines fron the C++ standard random library in
the ROOT Random interface.
These cases are then used by the generic TRandomGen class
to provide TRandom interrace generators for the C++ random generators.

See for examples the TRandomMT64 and TRandomRanlux48 generators
which are typede's to TRandomGen instantiated with some
random engine from the C++ standard library.

*/

template <class Generator>
class StdEngine {


public:

typedef StdRandomEngine BaseType;
typedef typename Generator::result_type Result_t;

StdEngine() : fGen() {
fCONS = 1./fGen.max();
}


void SetSeed(Result_t seed) { fGen.seed(seed);}

double Rndm() {
Result_t rndm = fGen(); // generate integer number according to the type
if (rndm != 0) return fCONS*rndm;
return Rndm();
}

Result_t IntRndm() {
return fGen();
}

double operator() () {
return Rndm();
}

static const char * Name() {
return StdEngineType<Generator>::Name();
}

static uint64_t MaxInt() { return Generator::max(); }


private:
Generator fGen;
double fCONS; //! cached value of maximum integer value generated
};


extern template class StdEngine<std::mt19937_64>;
extern template class StdEngine<std::ranlux48>;

} // end namespace Math
namespace Math {

class StdRandomEngine {};

template <class Generator>
struct StdEngineType {
static const char *Name() { return "std_random_eng"; }
};
template <>
struct StdEngineType<std::minstd_rand> {
static const char *Name() { return "std_minstd_rand"; }
};
template <>
struct StdEngineType<std::mt19937> {
static const char *Name() { return "std_mt19937"; }
};
template <>
struct StdEngineType<std::mt19937_64> {
static const char *Name() { return "std_mt19937_64"; }
};
template <>
struct StdEngineType<std::ranlux24> {
static const char *Name() { return "std_ranlux24"; }
};
template <>
struct StdEngineType<std::ranlux48> {
static const char *Name() { return "std_ranlux48"; }
};
template <>
struct StdEngineType<std::knuth_b> {
static const char *Name() { return "std_knuth_b"; }
};
template <>
struct StdEngineType<std::random_device> {
static const char *Name() { return "std_random_device"; }
};

/**
@ingroup Random
Class to wrap engines fron the C++ standard random library in
the ROOT Random interface.
These cases are then used by the generic TRandomGen class
to provide TRandom interrace generators for the C++ random generators.

See for examples the TRandomMT64 and TRandomRanlux48 generators
which are typede's to TRandomGen instantiated with some
random engine from the C++ standard library.

*/

template <class Generator>
class StdEngine {

public:
typedef StdRandomEngine BaseType;
typedef typename Generator::result_type Result_t;

StdEngine() : fGen() { fCONS = 1. / fGen.max(); }

void SetSeed(Result_t seed) { fGen.seed(seed); }

double Rndm()
{
Result_t rndm = fGen(); // generate integer number according to the type
if (rndm != 0)
return fCONS * rndm;
return Rndm();
}

Result_t IntRndm() { return fGen(); }

double operator()() { return Rndm(); }

static const char *Name() { return StdEngineType<Generator>::Name(); }

static constexpr uint64_t MinInt() { return Generator::min(); }
static constexpr uint64_t MaxInt() { return Generator::max(); }

#ifdef _WIN64
static constexpr uint64_t kNumberOfBits = _popcount64(Generator::max());
#else
static constexpr uint64_t kNumberOfBits = __builtin_popcountll(Generator::max());
#endif
Comment on lines +98 to +102
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not particularly happy about using builtins in the header. Is there no other way to get this information from the C++ type?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in c++20 there is a std:;popcount.
There are generators that return 48 or 61 bits. so it is not just numeric_limits<Return_type>::bits()

p.s. I agree that mixing clang-format and changes is not ideal and I do try to avoid it.
I did not expect it to make so many changes.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may argue that kNumberOfBits is redundant and could be defined in the user code (if needed)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine with me. Also, there may be generators that don't have a max() that falls on a power-of-two (LCGs come to mind)


private:
Generator fGen;
double fCONS; //! cached value of maximum integer value generated
};

extern template class StdEngine<std::mt19937_64>;
extern template class StdEngine<std::ranlux48>;

} // end namespace Math

} // end namespace ROOT


#endif /* ROOT_Math_StdEngine */
11 changes: 7 additions & 4 deletions math/mathcore/src/MersenneTwisterEngine.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ namespace Math {

/// generate a random double number
double MersenneTwisterEngine::Rndm_impl() {
auto y = IntRndm_impl();
// 2.3283064365386963e-10 == 1./(max<UINt_t>+1) -> then returned value cannot be = 1.0
if (y) return ( (double) y * 2.3283064365386963e-10); // * Power(2,-32)
return Rndm_impl();
}

uint32_t MersenneTwisterEngine::IntRndm_impl() {

uint32_t y;

Expand Down Expand Up @@ -71,10 +77,7 @@ namespace Math {
y ^= ((y << 15) & kTemperingMaskC );
y ^= (y >> 18);

// 2.3283064365386963e-10 == 1./(max<UINt_t>+1) -> then returned value cannot be = 1.0
if (y) return ( (double) y * 2.3283064365386963e-10); // * Power(2,-32)
return Rndm_impl();

return y;
}

} // namespace Math
Expand Down
Loading