From 3801c0f6759593c897833004f1be1d6e8a655780 Mon Sep 17 00:00:00 2001 From: Alex Rozgo Date: Sat, 24 Jun 2017 17:07:39 -0700 Subject: [PATCH] Fix #34 - deterministic_randomness test failures adds deterministic distribution functions for randutils fixes shuffle to do deterministic shuffling adds deterministic_distributions tests --- .../include/eos/utilities/randutils.hpp | 24 +++++++----- tests/tests/misc_tests.cpp | 37 +++++++++++++++++-- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/libraries/utilities/include/eos/utilities/randutils.hpp b/libraries/utilities/include/eos/utilities/randutils.hpp index 0d0ae008a06..2c8c00eaa14 100644 --- a/libraries/utilities/include/eos/utilities/randutils.hpp +++ b/libraries/utilities/include/eos/utilities/randutils.hpp @@ -102,6 +102,9 @@ #include #include +#include +#include + // Ugly platform-specific code for auto_seeded #if !defined(RANDUTILS_CPU_ENTROPY) && defined(__has_builtin) @@ -572,8 +575,8 @@ using auto_seed_256 = auto_seeded; template using uniform_distribution = typename std::conditional< std::is_integral::value, - std::uniform_int_distribution, - std::uniform_real_distribution >::type; + boost::random::uniform_int_distribution, + boost::random::uniform_real_distribution >::type; @@ -730,16 +733,19 @@ class random_generator { std::forward(params)...); } - template - void shuffle(Iter first, Iter last) - { - std::shuffle(first, last, engine_); - } - template void shuffle(Range&& range) { - shuffle(std::begin(range), std::end(range)); + // Fisher-Yates shuffle algorithm + int idx_count = range.size(); + for (auto idx = range.rbegin(); idx != range.rend() - 1; ++idx , --idx_count) + { + int rand_idx = uniform(0, idx_count - 1); + if (*idx != range.at(rand_idx)) + { + std::swap(range.at(rand_idx), *idx); + } + } } diff --git a/tests/tests/misc_tests.cpp b/tests/tests/misc_tests.cpp index 4bb8ad3c64a..9f9daaf5271 100644 --- a/tests/tests/misc_tests.cpp +++ b/tests/tests/misc_tests.cpp @@ -49,12 +49,43 @@ BOOST_AUTO_TEST_CASE(deterministic_randomness) vector words = {"infamy", "invests", "estimated", "potters", "memorizes", "hal9000"}; rng.shuffle(words); BOOST_CHECK_EQUAL(fc::json::to_string(words), - fc::json::to_string(vector{"potters","hal9000","memorizes","infamy","invests","estimated"})); + fc::json::to_string(vector{"hal9000","infamy","estimated","memorizes","invests","potters"})); rng.shuffle(words); - BOOST_CHECK_EQUAL(fc::json::to_string(words), - fc::json::to_string(vector{"memorizes","hal9000","infamy","invests","estimated","potters"})); + BOOST_CHECK_EQUAL(fc::json::to_string(words), + fc::json::to_string(vector{"hal9000","estimated","infamy","memorizes","potters","invests"})); +} FC_LOG_AND_RETHROW() } + +BOOST_AUTO_TEST_CASE(deterministic_distributions) +{ try { + randutils::seed_seq_fe<1> seed({123454321}); + randutils::random_generator rng(seed); + + std::vector nums = {0, 1, 2}; + + BOOST_CHECK_EQUAL(rng.uniform(0.0, 1.0), 0.52802440151572227); + BOOST_CHECK_EQUAL(rng.uniform(0.0, 1.0), 0.36562641779892147); + BOOST_CHECK_EQUAL(rng.uniform(0.0, 1.0), 0.44247416267171502); + + BOOST_CHECK_EQUAL(rng.pick(nums), 2); + BOOST_CHECK_EQUAL(rng.pick(nums), 0); + BOOST_CHECK_EQUAL(rng.pick(nums), 2); + + rng.shuffle(nums); + std::vector a{0, 1, 2}; + BOOST_CHECK(std::equal(nums.begin(), nums.end(), a.begin())); + rng.shuffle(nums); + std::vector b{0, 2, 1}; + BOOST_CHECK(std::equal(nums.begin(), nums.end(), b.begin())); + rng.shuffle(nums); + std::vector c{1, 0, 2}; + BOOST_CHECK(std::equal(nums.begin(), nums.end(), c.begin())); + + BOOST_CHECK_EQUAL(rng.uniform(0, 9), 2); + BOOST_CHECK_EQUAL(rng.uniform(0, 9), 9); + BOOST_CHECK_EQUAL(rng.uniform(0, 9), 0); } FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() } // namespace eos