diff options
Diffstat (limited to 'src/boost/libs/random/test/test_qrng_functions.hpp')
-rw-r--r-- | src/boost/libs/random/test/test_qrng_functions.hpp | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/src/boost/libs/random/test/test_qrng_functions.hpp b/src/boost/libs/random/test/test_qrng_functions.hpp new file mode 100644 index 000000000..effc96007 --- /dev/null +++ b/src/boost/libs/random/test/test_qrng_functions.hpp @@ -0,0 +1,278 @@ +// Copyright Justinas Vygintas Daugmaudis, 2010-2018. +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) + +#ifndef TEST_QRNG_FUNCTIONS_HPP_INCLUDED +#define TEST_QRNG_FUNCTIONS_HPP_INCLUDED + +#include <boost/random/uniform_real.hpp> +#include <boost/test/floating_point_comparison.hpp> + +#include <sstream> + +namespace test { + +// Invokes operator() precisely n times. This is to check that +// Engine::discard(n) actually has the same effect. +template<typename Engine> +inline void trivial_discard(Engine& eng, boost::uintmax_t n) +{ + for( ; n != 0; --n ) eng(); +} + + +template<typename Engine, typename T, std::size_t Dimension> +inline void match_vector(Engine& eng, T (&pt)[Dimension]) +{ + BOOST_REQUIRE_EQUAL( eng.dimension(), Dimension ); // paranoid check + + boost::uniform_real<T> dist; + + for( std::size_t i = 0; i != eng.dimension(); ++i ) + { + T val = dist(eng); + // We want to check that quasi-random number generator values differ no + // more than 0.0006% of their value. + BOOST_CHECK_CLOSE(pt[i], val, 0.0006); + } +} + + +template<typename Engine, typename T, std::size_t Dimension, std::size_t N> +inline void expected_values(T (&pt)[N][Dimension], std::size_t skip) +{ + Engine eng(Dimension); + + eng.seed(skip); + + for( std::size_t i = 0; i != N; ++i ) + match_vector(eng, pt[i]); +} + +template<typename Engine, typename T> +inline void test_zero_seed(std::size_t dimension) +{ + Engine eng(dimension); + + Engine other(dimension); + other.seed(0); + + // Check that states are equal after zero seed. + boost::uniform_real<T> dist; + BOOST_CHECK( eng == other ); + for( std:: size_t i = 0; i != dimension; ++i ) + { + T q_val = dist(eng); + T t_val = dist(other); + BOOST_CHECK_CLOSE(q_val, t_val, 0.0001); + } +} + +template<typename Engine, typename T, std::size_t Dimension, std::size_t N> +inline void seed_function(T (&pt)[N][Dimension], std::size_t skip) +{ + // Test zero seed before doing other tests. + test_zero_seed<Engine, T>(Dimension); + + Engine eng(Dimension); + for( std::size_t i = 0; i != N; ++i ) + { + // For all N seeds an engine + // and checks if the expected values match. + eng.seed(skip + i); + match_vector(eng, pt[i]); + } +} + +template<typename Engine, typename T, std::size_t Dimension, std::size_t N> +inline void discard_function(T (&pt)[N][Dimension], std::size_t skip) +{ + Engine eng(Dimension), trivial(Dimension), streamed(Dimension), initial_state(Dimension); + boost::uniform_real<T> dist; + + const std::size_t element_count = N * Dimension; + const T* pt_array = reinterpret_cast<T *>(boost::addressof(pt)); + + std::stringstream ss; + + initial_state.seed(skip); + for (std::size_t step = 0; step != element_count; ++step) + { + // Init to the same state + eng = initial_state; + trivial = initial_state; + + // Discards have to have the same effect + eng.discard(step); + trivial_discard(trivial, step); + + // test serialization to stream + ss.str(std::string()); // clear stream + ss << eng; + ss >> streamed; + + // Therefore, states are equal + BOOST_CHECK( eng == trivial ); + BOOST_CHECK( eng == streamed ); + + // Now, let's check whether they really produce the same sequence + T q_val = dist(eng); + T t_val = dist(trivial); + T s_val = dist(streamed); + BOOST_CHECK_CLOSE(q_val, t_val, 0.0001); + BOOST_CHECK_CLOSE(q_val, s_val, 0.0001); + // ~ BOOST_CHECK(q_val == t_val), but those are floating point values, + // so strict equality check may fail unnecessarily + + // States remain equal! + BOOST_CHECK( eng == trivial ); + BOOST_CHECK( eng == streamed ); + + // We want to check that quasi-random number generator values differ no + // more than 0.0006% of their value. + BOOST_CHECK_CLOSE(pt_array[step], q_val, 0.0006); + } +} + +inline bool accept_all_exceptions(const std::exception& e) +{ + BOOST_TEST_MESSAGE( e.what() ); + return true; +} + +template<typename Engine> +void test_max_seed(std::size_t dim) +{ + typedef typename Engine::size_type size_type; + static const size_type maxseed = Engine::max(); + + Engine eng(dim); + eng.seed(maxseed-1); // must succeed + eng(); // skip one element + BOOST_REQUIRE_EXCEPTION( eng.seed(maxseed), std::range_error, accept_all_exceptions ); + + Engine other(dim); + other.seed(maxseed-1); // must succeed + other(); // skip one element, too + + // States remain the same even after unsuccessful seeding for eng. + BOOST_CHECK( eng == other ); + BOOST_CHECK( eng() == other() ); +} + +template<typename Generator> +void test_max_discard(std::size_t dim) +{ + typedef typename Generator::type engine_type; + + static const boost::uintmax_t maxdiscard = dim * engine_type::max(); + + // Max discard limit + { + engine_type eng(dim); + eng.discard(maxdiscard-1); // must succeed + eng(); // the very last element + + BOOST_REQUIRE_EXCEPTION( eng(), std::range_error, accept_all_exceptions ); + + engine_type other(dim); + + BOOST_CHECK( eng != other ); // test that comparison does not overflow + + other(); // the very first element + other.discard(maxdiscard-1); // must succeed + + BOOST_CHECK( eng == other ); + + BOOST_REQUIRE_EXCEPTION( other(), std::range_error, accept_all_exceptions ); + } + + // Overdiscarding + { + engine_type eng(dim); + eng.discard(maxdiscard); // must succeed, since it's maxdiscard operator() invocations + + // must fail because after discarding the whole sequence + // we can't put the eng to any valid sequence producing state + BOOST_REQUIRE_EXCEPTION( eng(), std::range_error, accept_all_exceptions ); + + // Plain overdiscarding by 1 + engine_type other(dim); + BOOST_REQUIRE_EXCEPTION( other.discard(maxdiscard+1), std::range_error, accept_all_exceptions ); + } + + // Test wraparound + { + engine_type eng(dim); + + // must fail either because seq_count overflow check is triggered, + // or because this discard violates seeding bitcount constraint + BOOST_REQUIRE_EXCEPTION( eng.discard(maxdiscard*2), std::range_error, accept_all_exceptions ); + } +} + +} // namespace test + + +#define QRNG_VALIDATION_TEST_FUNCTIONS(QRNG) \ +\ +typedef boost::random::QRNG engine_t; \ +\ +template<typename T, std::size_t Dimension, std::size_t N> \ +inline void test_##QRNG##_values(T (&pt)[N][Dimension], std::size_t skip) \ +{ \ + test::expected_values<engine_t>(pt, skip); \ +} \ +\ +template<typename T, std::size_t Dimension, std::size_t N> \ +inline void test_##QRNG##_seed(T (&pt)[N][Dimension], std::size_t skip) \ +{ \ + test::seed_function<engine_t>(pt, skip); \ +} \ +\ +template<typename T, std::size_t Dimension, std::size_t N> \ +inline void test_##QRNG##_discard(T (&pt)[N][Dimension], std::size_t skip) \ +{ \ + test::discard_function<engine_t>(pt, skip); \ +} \ +inline void test_##QRNG##_max_seed() \ +{ \ + test::test_max_seed<engine_t>(2); \ +} \ +inline void test_##QRNG##_max_dimension(std::size_t dim) \ +{ \ + engine_t eng(dim); /*must succeed*/ \ + BOOST_REQUIRE_EXCEPTION( engine_t(dim+1), std::invalid_argument, test::accept_all_exceptions ); \ +} \ +\ +BOOST_AUTO_TEST_CASE( test_##QRNG##_zero_dimension_fails ) \ +{ \ + BOOST_REQUIRE_EXCEPTION( engine_t(0), std::invalid_argument, test::accept_all_exceptions ); \ +} \ +/**/ + +#define QRNG_VALIDATION_TEST_DISCARD(QRNG) \ +\ +template <typename IntType, unsigned w> \ +struct gen_engine \ +{ \ + typedef boost::random::QRNG##_engine<IntType, w> type; \ +}; \ +\ +inline void test_##QRNG##_max_discard() \ +{ \ + static const std::size_t dim = 2;\ + \ + /* test full 8 bits */ \ + test::test_max_discard<gen_engine<boost::uint8_t, 8u> >(dim); \ + \ + /* test 7 bits */ \ + test::test_max_discard<gen_engine<boost::uint8_t, 7u> >(dim); \ + \ + /* test 6 bits for a good measure */ \ + test::test_max_discard<gen_engine<boost::uint8_t, 6u> >(dim); \ +} \ +/**/ + +#endif // TEST_QRNG_FUNCTIONS_HPP_INCLUDED |