/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2016-2017 Danny Robson */ #ifndef CRUFT_UTIL_RANDOM_HPP #define CRUFT_UTIL_RANDOM_HPP #include "coord/traits.hpp" #include #include #include #include #include namespace util::random { template struct state_size; template < class UIntType, size_t w, size_t n, size_t m, size_t r, UIntType a, size_t u, UIntType d, size_t s, UIntType b, size_t t, UIntType c, size_t l, UIntType f > struct state_size> { static constexpr auto value = n * sizeof (UIntType); }; template struct state_size> { static constexpr auto value = sizeof (UIntType); }; template constexpr auto state_size_v = state_size::value; /////////////////////////////////////////////////////////////////////////// /// return correctly initialised thread-local generator of an unspecified, /// but not entirely useless, type. ie, not LCG. inline auto& generator (void) { using generator_t = std::default_random_engine; static thread_local generator_t gen = [] () { std::array / 4> seed; std::generate (seed.begin (), seed.end (), std::random_device ()); std::seed_seq seq (seed.begin (), seed.end ()); return generator_t (seq); } (); return gen; } /////////////////////////////////////////////////////////////////////////// /// select a value uniformly from the range [lo, hi) template std::enable_if_t,T> uniform (T lo, T hi) { return std::uniform_real_distribution { lo, hi } (generator ()); } template std::enable_if_t,T> uniform (void) { return uniform (0, 1); } ///------------------------------------------------------------------------ /// select a value uniformly from the range [lo, hi) using a supplied /// generator template < typename T, typename GeneratorT, typename = std::enable_if_t> > T uniform (T lo, T hi, GeneratorT &&gen) { return std::uniform_int_distribution { lo, hi } (gen); } ///------------------------------------------------------------------------ /// select a value uniformly from the range [lo, hi) template std::enable_if_t,T> uniform (T lo, T hi) { return uniform (lo, hi, generator ()); } //------------------------------------------------------------------------- template std::enable_if_t,T> uniform (void) { return uniform ( std::numeric_limits::min (), std::numeric_limits::max () ); } //------------------------------------------------------------------------- template < typename T, typename = std::enable_if_t< is_coord_v && std::is_floating_point_v > > T uniform (void) { T res {}; std::fill (res.begin (), res.end (), uniform ()); return res; } /////////////////////////////////////////////////////////////////////////// /// choose a value at random from an array template T& choose (T (&t)[N]) { std::uniform_int_distribution dist (0, N - 1); return t[dist (generator ())]; } }; #endif