/* * 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. * * 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