diff --git a/CMakeLists.txt b/CMakeLists.txt index 07081f4..582202b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,9 @@ PROJECT (SampleFlow ######################################### ### Set up compiler flags and input paths +message(STATUS "Using compiler ${CMAKE_CXX_COMPILER_ID}, version ${CMAKE_CXX_COMPILER_VERSION}") + + ######################################### # Also make sure we link with the threads library in question. # We need this when linking C++ stuff that uses threads. @@ -114,13 +117,19 @@ INSTALL(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}config.cmake" # Now also define a library that consists of the C++20 modules, # assuming the compiler and generator supports this: -if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" - AND - ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL 16 +if (((${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" + AND + ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL 16) + OR + (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" + AND + ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL 14)) # does not actually work in practice AND ${CMAKE_GENERATOR} STREQUAL "Ninja") message(STATUS "Enabling the use of C++20-style modules") set(SAMPLEFLOW_BUILD_MODULE "ON") +else() + message(STATUS "Not using C++20-style modules") endif() if (SAMPLEFLOW_BUILD_MODULE) diff --git a/tests/adaptive_mh_01.cc b/tests/adaptive_mh_01.cc index 9208a14..e3547e7 100644 --- a/tests/adaptive_mh_01.cc +++ b/tests/adaptive_mh_01.cc @@ -25,6 +25,8 @@ #include +#include "tests.h" + #ifndef SAMPLEFLOW_TEST_WITH_MODULE # include # include @@ -78,7 +80,7 @@ std::pair perturb_adaptive (const SampleType &x, SampleType random_vector; for (unsigned int i=0; i(0,1)(rng); + SampleFlow::Testing::NormalDistribution(0,1)(rng); const SampleType y = x + LLt.matrixL() * random_vector; diff --git a/tests/auto_covariance_matrix_05.cc b/tests/auto_covariance_matrix_05.cc index 06bd2c6..7db96ed 100644 --- a/tests/auto_covariance_matrix_05.cc +++ b/tests/auto_covariance_matrix_05.cc @@ -29,6 +29,8 @@ #include +#include "tests.h" + #ifndef SAMPLEFLOW_TEST_WITH_MODULE # include # include @@ -64,7 +66,7 @@ std::pair perturb (const SampleType &x) // Perturb the current sample using a Gaussian distribution // around the current point with standard deviation 1.5. static std::mt19937 rng; - std::normal_distribution distribution(0., 1.5); + SampleFlow::Testing::NormalDistribution distribution(0., 1.5); SampleType y = x; for (auto &el : y) diff --git a/tests/auto_covariance_trace_05.cc b/tests/auto_covariance_trace_05.cc index a60a834..36c1268 100644 --- a/tests/auto_covariance_trace_05.cc +++ b/tests/auto_covariance_trace_05.cc @@ -29,6 +29,8 @@ #include +#include "tests.h" + #ifndef SAMPLEFLOW_TEST_WITH_MODULE # include # include @@ -53,7 +55,7 @@ std::pair perturb (const SampleType &x) // Perturb the current sample using a Gaussian distribution // around the current point with standard deviation 1.5. static std::mt19937 rng; - std::normal_distribution distribution(0., 1.5); + SampleFlow::Testing::NormalDistribution distribution(0., 1.5); SampleType y = x; for (auto &el : y) diff --git a/tests/covariance_matrix_11.cc b/tests/covariance_matrix_11.cc index 26fbef7..975e41f 100644 --- a/tests/covariance_matrix_11.cc +++ b/tests/covariance_matrix_11.cc @@ -31,6 +31,8 @@ #include +#include "tests.h" + #ifndef SAMPLEFLOW_TEST_WITH_MODULE # include # include @@ -65,7 +67,7 @@ std::pair perturb (const SampleType &x) static std::mt19937 rng; SampleType random_vector; for (unsigned int i=0; i(0,1)(rng); + random_vector(i) = SampleFlow::Testing::NormalDistribution(0,1)(rng); const SampleType y = (LLt.matrixL()) * random_vector + x; diff --git a/tests/delayed_rejection_mh_producer_03.cc b/tests/delayed_rejection_mh_producer_03.cc index d2d4814..c3e8d4f 100644 --- a/tests/delayed_rejection_mh_producer_03.cc +++ b/tests/delayed_rejection_mh_producer_03.cc @@ -22,6 +22,8 @@ #include #include +#include "tests.h" + #ifndef SAMPLEFLOW_TEST_WITH_MODULE # include # include @@ -43,7 +45,7 @@ double log_likelihood (const SampleType &x) std::pair perturb (const SampleType &x, const std::vector &) { static std::mt19937 rng; - std::normal_distribution distribution(0, 1); + SampleFlow::Testing::NormalDistribution distribution(0, 1); const double perturbation = distribution(rng); const SampleType x_tilde = x + perturbation; return {x_tilde, 1.0}; diff --git a/tests/my_triangle.h b/tests/my_triangle.h index 9651a25..2370602 100644 --- a/tests/my_triangle.h +++ b/tests/my_triangle.h @@ -20,6 +20,7 @@ #include #include +#include "tests.h" /** * A class that serves as a custom sample class that is not a vector @@ -54,11 +55,12 @@ std::ostream &operator<<(std::ostream &os, const MyTriangle &tri) } + inline std::pair perturb(const MyTriangle &sample) { static std::mt19937 gen; - std::normal_distribution<> d {0, 1}; + SampleFlow::Testing::NormalDistribution<> d {0, 1}; double side_a = sample.side_lengths[0] + d(gen); double side_b = sample.side_lengths[1] + d(gen); double side_c = sample.side_lengths[2] + d(gen); diff --git a/tests/tests.h b/tests/tests.h new file mode 100644 index 0000000..a50ee0b --- /dev/null +++ b/tests/tests.h @@ -0,0 +1,106 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2020 by the SampleFlow authors. +// +// This file is part of the SampleFlow library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE.md at +// the top level directory of deal.II. +// +// --------------------------------------------------------------------- + + +#ifndef SAMPLEFLOW_TESTS_H +#define SAMPLEFLOW_TESTS_H + + +namespace SampleFlow +{ + namespace Testing + { + /** + * Whereas the random number generators are portable between + * compilers, the random number distributions are not. This class + * makes sure we remain compatible at least between GCC and Clang + * by creating a class that, given a random number generator, + * returns normally distributed random floating point numbers. + * + * The class is a drop-in replacement for std::normal_distribution. + */ + template + class NormalDistribution + { + static_assert(std::is_floating_point_v, + "result_type must be a floating point type"); + + public: + using result_type = RealType; + + + public: + explicit + NormalDistribution(result_type mu, + result_type sigma) + : mean(mu), stddev(sigma) + { } + + template + result_type + operator()(RNG &rng); + + private: + result_type mean, stddev; + result_type saved_value = 0; + bool saved_value_available = false; + }; + + + + template + template + typename NormalDistribution::result_type + NormalDistribution:: + operator()(RNG &rng) + { + result_type ret; + + auto get_real = [&rng]() + { + return std::generate_canonical::digits, + RNG>(rng); + }; + + if (saved_value_available) + { + saved_value_available = false; + ret = saved_value; + } + else + { + result_type x, y, r2; + do + { + x = result_type(2.0) * get_real() - 1.0; + y = result_type(2.0) * get_real() - 1.0; + r2 = x * x + y * y; + } + while (r2 > 1.0 || r2 == 0.0); + + const result_type mult = std::sqrt(-2 * std::log(r2) / r2); + ret = y * mult; + saved_value = x * mult; + saved_value_available = true; + + } + return ret * stddev + mean; + } + } +} + + +#endif