123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- // 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
|