Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pack (type erase) a random number generator

Tags:

c++

random

c++11

The C++11 std library has several random number generators (RNG), each implementing the concept UniformRandomNumberGenerator. These can then be used as argument for random distributions, see also this documentation for an overview.

The advantage of this design is that the choice of the underlying RNG engine is de-coupled from its application. However, the design also requires the definition (not merely the declarations) of all calls to the RNG to be available (if the RNG type is to remain unspecified as template parameter). Thus, in

struct complicated_random_distribution
{
  /*
     some data and auxiliary methods here
  */
  // complicated; may call RNG::operator() many times
  template<typename RNG>
  some_type operator()(RNG&gen) const;
};

the member operator() cannot be straightforwardly implemented in a separate compilation unit (CU), but must be available in the same header file (or one #included from it).

For a separate implementation, one ideally would want some way to pack a RNG in the same way as std::function<> packs any callable object. (Simply using std::function and providing the values for RNG::min() and RNG::max() as arguments to a function defined in a separate CU is restrictive and will not allow to use, say, std::uniform_real_distribution<> inside).

How can this be done? Are implementations for this available? Will the std library provide this in the future? Or am I after a red herring?


Edit Random number generators are required to have static members min() and max(), making type-erasure hard or impossible (GNU's libstdc++ doesn't make this assumption and a type erasure with non-static members min() and max() works, but not with LLVM's libc++, which uses the standard required static members). Is there a way to still solve this problem? If not, doesn't this imply that the C++ standard has a botched interface for random number generators?

like image 360
Walter Avatar asked Jun 01 '15 10:06

Walter


People also ask

Can you trick a random number generator?

It is possible to hack into the Random Number Generators used in casinos and other fields. But, it is a difficult venture that even the best hackers find challenging. With high-quality RNGs and security protocols, this possibility can be reduced to the minimum.

Does Google have a random number generator?

The RAND function in Google Sheets generates a random number between 0 and 1 and can be used as a random number generator in Google Sheets. The RAND function outputs a decimal number between 0 and 1, for example, 0.2760773217.

Does Excel have a random number generator?

The RAND function in Excel is one of the two functions specially designed for generating random numbers. It returns a random decimal number (real number) between 0 and 1. RAND() is a volatile function, meaning that a new random number is generated every time the worksheet is calculated.


2 Answers

Adapt the RNG with an independent_bits_engine, and type erase the adapted RNG. You have full knowledge of what the independent_bits_engine's min() and max() are.

Here's a sketch:

struct RNG_wrapper {
    using result_type = std::uint32_t;
    static constexpr result_type min() { return 0; }
    static constexpr result_type max() { return 0xFFFFFFFF; }

    template<class RNG>
    using my_engine_type = std::independent_bits_engine<RNG, 32, result_type>;

    template<class RNG,
             class = std::enable_if_t<!std::is_same<std::decay_t<RNG>, RNG_wrapper>{}>>
    RNG_wrapper(RNG&& r)
        : rng(my_engine_type<std::decay_t<RNG>>(std::forward<RNG>(r))) {}

    result_type operator()() { return rng(); }
    std::function<result_type()> rng;
};
like image 56
T.C. Avatar answered Oct 24 '22 01:10

T.C.


This works in clang and gcc (with libstdc++), but this is not strictly a UniformRandomNumberGenerator, for the noted reason that min and max are not static.

#include <cassert>
#include <random>
#include <functional>
#include <iostream>

template<typename T>
class AnyUniformRandomNumberGenerator
{
    T mMin;
    T mMax;
    std::function<T()> mValue;
public:

    using result_type = T;

    template<typename UniformRandomNumberGenerator>
    AnyUniformRandomNumberGenerator(UniformRandomNumberGenerator uniformRandomNumberGenerator) :
    mMin(UniformRandomNumberGenerator::min()),
    mMax(UniformRandomNumberGenerator::max()),
    mValue([=]() mutable { return uniformRandomNumberGenerator(); })
    {}

    T operator()()
    {
        return mValue();
    }

    T min()
    {
        return mMin;
    }

    T max()
    {
        return mMax;
    }
};

int main()
{
    std::default_random_engine rng;
    AnyUniformRandomNumberGenerator<decltype(rng())> any{rng};

    assert(any() <= any.max());
    assert(any() >= any.min());

    std::uniform_int_distribution<> dist{1, 6};

    std::cout << dist(any);
}

GCC: http://rextester.com/ANAP79935

clang http://rextester.com/YCIIR21607

like image 27
tahsmith Avatar answered Oct 23 '22 23:10

tahsmith