From a72ab6c1879153a2b700ef70bc27446d2d58018d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Sun, 16 Oct 2022 15:03:24 -0700 Subject: [PATCH 01/16] Define C++20 concepts --- include/boost/math/ccmath/abs.hpp | 5 +- include/boost/math/concepts/concepts.hpp | 111 +++++++++++++++++++++++ test/Jamfile.v2 | 40 ++++++++ 3 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 include/boost/math/concepts/concepts.hpp diff --git a/include/boost/math/ccmath/abs.hpp b/include/boost/math/ccmath/abs.hpp index 8e9317c517..cd1e16d1f2 100644 --- a/include/boost/math/ccmath/abs.hpp +++ b/include/boost/math/ccmath/abs.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,7 @@ namespace boost::math::ccmath { namespace detail { -template +template inline constexpr T abs_impl(T x) noexcept { return boost::math::ccmath::isnan(x) ? std::numeric_limits::quiet_NaN() : @@ -32,6 +33,7 @@ inline constexpr T abs_impl(T x) noexcept } // Namespace detail template , bool> = true> + BOOST_MATH_REQUIRES(BOOST_MATH_SIGNED_ARITHMETIC, T) inline constexpr T abs(T x) noexcept { if(BOOST_MATH_IS_CONSTANT_EVALUATED(x)) @@ -48,6 +50,7 @@ inline constexpr T abs(T x) noexcept // If abs() is called with an argument of type X for which is_unsigned_v is true and if X // cannot be converted to int by integral promotion (7.3.7), the program is ill-formed. template , bool> = true> + BOOST_MATH_REQUIRES(BOOST_MATH_UNSIGNED_ARITHMETIC, T) inline constexpr T abs(T x) noexcept { if constexpr (std::is_convertible_v) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp new file mode 100644 index 0000000000..bb21b1ed0b --- /dev/null +++ b/include/boost/math/concepts/concepts.hpp @@ -0,0 +1,111 @@ +// (C) Copyright Matt Borland 2022. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_CONCEPTS_CONCEPTS_HPP +#define BOOST_MATH_CONCEPTS_CONCEPTS_HPP + +#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L +#if __has_include() +#include + +#include +#include + +namespace boost::math::concepts { + +template +concept Integral = std::is_integral_v + #ifdef __SIZEOF_INT128__ + || std::is_same_v<__int128_t, T> + || std::is_same_v<__uint128_t, T> + #endif + ; + + +template +concept Signed_integral = std::is_integral_v && std::is_signed_v + #ifdef __SIZEOF_INT128__ + || std::is_same_v<__int128_t, T> + #endif + ; + +template +concept Unsigned_integral = std::is_integral_v && std::is_unsigned_v + #ifdef __SIZEOF_INT128__ + || std::is_same_v<__uint128_t, T> + #endif + ; + +template +concept Real = std::is_floating_point_v + #ifdef BOOST_HAS_FLOAT128 + || std::is_same_v<__float128, T> + #endif + ; + +template +concept Arithmetic = Integral || Real; + +template +concept Signed_arithmetic = Arithmetic && (std::is_signed_v + #ifdef __SIZEOF_INT128__ + || std::is_same_v<__int128_t, T> + #endif + ); + +template +concept Unsigned_arithmetic = Arithmetic && (std::is_unsigned_v + #ifdef __SIZEOF_INT128__ + || std::is_same_v<__uint128_t, T> + #endif + ); + +} + +#define BOOST_MATH_INTEGRAL boost::math::concepts::Integral +#define BOOST_MATH_SIGNED_INTEGRAL boost::math::concepts::Signed_integral +#define BOOST_MATH_UNSIGNED_INTEGRAL boost::math::concepts::Unsigned_integral +#define BOOST_MATH_REAL boost::math::concepts::Real +#define BOOST_MATH_ARITHMETIC boost::math::concepts::Arithmetic +#define BOOST_MATH_SIGNED_ARITHMETIC boost::math::concepts::Signed_arithmetic +#define BOOST_MATH_UNSIGNED_ARITHMETIC boost::math::concepts::Unsigned_arithmetic +#define BOOST_MATH_REQUIRES(X, T) requires X + +#endif +#endif + +#ifndef BOOST_MATH_INTEGRAL +# define BOOST_MATH_INTEGRAL typename +#endif + +#ifndef BOOST_MATH_SIGNED_INTEGRAL +# define BOOST_MATH_SIGNED_INTEGRAL typename +#endif + +#ifndef BOOST_MATH_UNSIGNED_INTEGRAL +# define BOOST_MATH_UNSIGNED_INTEGRAL typename +#endif + +#ifndef BOOST_MATH_REAL +# define BOOST_MATH_REAL typename +#endif + +#ifndef BOOST_MATH_ARITHMETIC +# define BOOST_MATH_ARITHMETIC typename +#endif + +#ifndef BOOST_MATH_SIGNED_ARITHMETIC +# define BOOST_MATH_SIGNED_ARITHMETIC typename +#endif + +#ifndef BOOST_MATH_UNSIGNED_ARITHMETIC +# define BOOST_MATH_UNSIGNED_ARITHMETIC typename +#endif + +#ifndef BOOST_MATH_REQUIRES +# define BOOST_MATH_REQUIRES(X, T) +#endif + +#endif // BOOST_MATH_CONCEPTS_CONCEPTS_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 57295797ff..f5493aabe6 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1645,6 +1645,46 @@ alias no_eh_tests : explicit no_eh_tests ; +# alias for the ccmath tests + +alias ccmath_tests : + ccmath_abs_test + ccmath_ceil_test + ccmath_copysign_test + ccmath_div_test + ccmath_fdim_test + ccmath_floor_test + ccmath_fma_test + ccmath_fmax_test + ccmath_fmin_test + ccmath_fmod_test + ccmath_fpclassify_test + ccmath_frexp_test + ccmath_hypot_test + ccmath_ilogb_test + ccmath_isfinite_test + ccmath_isgreater_test + ccmath_isgreaterequal_test + ccmath_isinf_test + ccmath_isless_test + ccmath_islessequal_test + ccmath_isnan_test + ccmath_isnormal_test + ccmath_isunordered_test + ccmath_ldexp_test + ccmath_logb_test + ccmath_modf_test + ccmath_next_test + ccmath_remainder_test + ccmath_round_test + ccmath_scalbln_test + ccmath_scalbn_test + ccmath_signbit_test + ccmath_sqrt_test +; + +explicit ccmath_tests ; + # Some aliases which group blocks of tests for CI testing: alias github_ci_block_1 : special_fun float128_tests distribution_tests mp misc ; From c495bf73eddfabf2f03bfaa94b1231fe77010756 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 17 Oct 2022 09:05:54 -0700 Subject: [PATCH 02/16] Add intel _Quad type [ci skip] --- include/boost/math/concepts/concepts.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index bb21b1ed0b..20ac3ce0b6 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -41,8 +41,12 @@ concept Unsigned_integral = std::is_integral_v && std::is_unsigned_v template concept Real = std::is_floating_point_v #ifdef BOOST_HAS_FLOAT128 + #if defined(__INTEL_LLVM_COMPILER) || defined(__INTEL_COMPILER) + || std::is_same_v<_Quad, T> + #else || std::is_same_v<__float128, T> #endif + #endif ; template From a4cd40ff4db6afc602dde96242f182df272f69cd Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 17 Oct 2022 10:39:40 -0700 Subject: [PATCH 03/16] Add arbitrary arithmetic concepts [ci skip] --- include/boost/math/ccmath/abs.hpp | 6 +- include/boost/math/concepts/concepts.hpp | 99 ++++++++++++++++++++++-- 2 files changed, 97 insertions(+), 8 deletions(-) diff --git a/include/boost/math/ccmath/abs.hpp b/include/boost/math/ccmath/abs.hpp index cd1e16d1f2..bec9d1c49e 100644 --- a/include/boost/math/ccmath/abs.hpp +++ b/include/boost/math/ccmath/abs.hpp @@ -20,7 +20,7 @@ namespace boost::math::ccmath { namespace detail { -template +template inline constexpr T abs_impl(T x) noexcept { return boost::math::ccmath::isnan(x) ? std::numeric_limits::quiet_NaN() : @@ -33,7 +33,7 @@ inline constexpr T abs_impl(T x) noexcept } // Namespace detail template , bool> = true> - BOOST_MATH_REQUIRES(BOOST_MATH_SIGNED_ARITHMETIC, T) + BOOST_MATH_REQUIRES(BOOST_MATH_ARBITRARY_SIGNED_ARITHMETIC, T) inline constexpr T abs(T x) noexcept { if(BOOST_MATH_IS_CONSTANT_EVALUATED(x)) @@ -50,7 +50,7 @@ inline constexpr T abs(T x) noexcept // If abs() is called with an argument of type X for which is_unsigned_v is true and if X // cannot be converted to int by integral promotion (7.3.7), the program is ill-formed. template , bool> = true> - BOOST_MATH_REQUIRES(BOOST_MATH_UNSIGNED_ARITHMETIC, T) + BOOST_MATH_REQUIRES(BOOST_MATH_ARBITRARY_UNSIGNED_ARITHMETIC, T) inline constexpr T abs(T x) noexcept { if constexpr (std::is_convertible_v) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index 20ac3ce0b6..b379eabecf 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -6,15 +6,39 @@ #ifndef BOOST_MATH_CONCEPTS_CONCEPTS_HPP #define BOOST_MATH_CONCEPTS_CONCEPTS_HPP -#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L +#if (__cplusplus >= 202002L || _MSVC_LANG >= 202002L) && !defined(BOOST_MATH_DISABLE_CONCEPTS) #if __has_include() -#include +#include +#include +#include +#include #include +#include #include +#include namespace boost::math::concepts { +template +struct op_valid_impl +{ + template + static constexpr auto test(int) -> decltype(std::declval()(std::declval(), std::declval()), + void(), std::true_type()); + + template + static constexpr auto test(...) -> std::false_type; + + using type = decltype(test(0)); +}; + +template +using op_valid = typename op_valid_impl::type; + +template +inline constexpr bool op_valid_v = op_valid::value; + template concept Integral = std::is_integral_v #ifdef __SIZEOF_INT128__ @@ -66,15 +90,56 @@ concept Unsigned_arithmetic = Arithmetic && (std::is_unsigned_v #endif ); +template +concept Arbitrary_unsigned_arithmetic_type = Unsigned_arithmetic || + (op_valid_v> && + op_valid_v> && + op_valid_v> && + op_valid_v> && + op_valid_v> && + op_valid_v> && + op_valid_v> && + op_valid_v> && + op_valid_v> && + op_valid_v> && + op_valid_v>); + +template +concept Arbitrary_signed_arithmetic_type = Signed_arithmetic || + (Arbitrary_unsigned_arithmetic_type && + op_valid_v>); + +template +concept Arbitrary_arithmetic_type = Arbitrary_unsigned_arithmetic_type || + Arbitrary_signed_arithmetic_type; + +template +concept Aribitrary_unsigned_integer_type = Arbitrary_unsigned_arithmetic_type && + std::numeric_limits::is_integer; + +template +concept Aribitrary_signed_integer_type = Arbitrary_signed_arithmetic_type && + std::numeric_limits::is_integer; + +template +concept Aribitrary_integer_type = Aribitrary_unsigned_integer_type || + Aribitrary_signed_integer_type; + } -#define BOOST_MATH_INTEGRAL boost::math::concepts::Integral -#define BOOST_MATH_SIGNED_INTEGRAL boost::math::concepts::Signed_integral -#define BOOST_MATH_UNSIGNED_INTEGRAL boost::math::concepts::Unsigned_integral +#define BOOST_MATH_INTEGRAL boost::math::concepts::Integral +#define BOOST_MATH_SIGNED_INTEGRAL boost::math::concepts::Signed_integral +#define BOOST_MATH_UNSIGNED_INTEGRAL boost::math::concepts::Unsigned_integral #define BOOST_MATH_REAL boost::math::concepts::Real #define BOOST_MATH_ARITHMETIC boost::math::concepts::Arithmetic #define BOOST_MATH_SIGNED_ARITHMETIC boost::math::concepts::Signed_arithmetic #define BOOST_MATH_UNSIGNED_ARITHMETIC boost::math::concepts::Unsigned_arithmetic +#define BOOST_MATH_ARBITRARY_UNSIGNED_ARITHMETIC boost::math::concepts::Arbitrary_unsigned_arithmetic_type +#define BOOST_MATH_ARBITRARY_SIGNED_ARITHMETIC boost::math::concepts::Arbitrary_signed_arithmetic_type +#define BOOST_MATH_ARBITRARY_ARITHMETIC boost::math::concepts::Arbitrary_arithmetic_type +#define BOOST_MATH_ARBITRARY_UNSIGNED_INTEGER boost::math::concepts::Aribitrary_unsigned_integer_type +#define BOOST_MATH_ARBITRARY_SIGNED_INTEGER boost::math::concepts::Aribitrary_signed_integer_type +#define BOOST_MATH_ARBITRARY_INTEGER boost::math::concepts::Aribitrary_integer_type #define BOOST_MATH_REQUIRES(X, T) requires X #endif @@ -108,6 +173,30 @@ concept Unsigned_arithmetic = Arithmetic && (std::is_unsigned_v # define BOOST_MATH_UNSIGNED_ARITHMETIC typename #endif +#ifndef BOOST_MATH_ARBITRARY_UNSIGNED_ARITHMETIC +# define BOOST_MATH_ARBITRARY_UNSIGNED_ARITHMETIC typename +#endif + +#ifndef BOOST_MATH_ARBITRARY_SIGNED_ARITHMETIC +# define BOOST_MATH_ARBITRARY_SIGNED_ARITHMETIC typename +#endif + +#ifndef BOOST_MATH_ARBITRARY_ARITHMETIC +# define BOOST_MATH_ARBITRARY_ARITHMETIC typename +#endif + +#ifndef BOOST_MATH_ARBITRARY_UNSIGNED_INTEGER +# define BOOST_MATH_ARBITRARY_UNSIGNED_INTEGER typename +#endif + +#ifndef BOOST_MATH_ARBITRARY_SIGNED_INTEGER +# define BOOST_MATH_ARBITRARY_SIGNED_INTEGER typename +#endif + +#ifndef BOOST_MATH_ARBITRARY_INTEGER +# define BOOST_MATH_ARBITRARY_INTEGER typename +#endif + #ifndef BOOST_MATH_REQUIRES # define BOOST_MATH_REQUIRES(X, T) #endif From b5344d54100db4cdb45db98d55a0ca958dff89fe Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 17 Oct 2022 12:57:47 -0700 Subject: [PATCH 04/16] Add test on special function (beta) [ci skip] --- include/boost/math/concepts/concepts.hpp | 25 ++++++++----- include/boost/math/special_functions/beta.hpp | 35 ++++++++++--------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index b379eabecf..6b6e242d84 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -16,7 +16,6 @@ #include #include #include -#include namespace boost::math::concepts { @@ -47,20 +46,19 @@ concept Integral = std::is_integral_v #endif ; - template -concept Signed_integral = std::is_integral_v && std::is_signed_v +concept Signed_integral = std::is_integral_v && (std::is_signed_v #ifdef __SIZEOF_INT128__ || std::is_same_v<__int128_t, T> #endif - ; + ); template -concept Unsigned_integral = std::is_integral_v && std::is_unsigned_v +concept Unsigned_integral = std::is_integral_v && (std::is_unsigned_v #ifdef __SIZEOF_INT128__ || std::is_same_v<__uint128_t, T> #endif - ; + ); template concept Real = std::is_floating_point_v @@ -101,13 +99,13 @@ concept Arbitrary_unsigned_arithmetic_type = Unsigned_arithmetic || op_valid_v> && op_valid_v> && op_valid_v> && - op_valid_v> && - op_valid_v>); + op_valid_v>); template concept Arbitrary_signed_arithmetic_type = Signed_arithmetic || (Arbitrary_unsigned_arithmetic_type && - op_valid_v>); + (op_valid_v> || + std::numeric_limits::is_signed)); template concept Arbitrary_arithmetic_type = Arbitrary_unsigned_arithmetic_type || @@ -125,6 +123,10 @@ template concept Aribitrary_integer_type = Aribitrary_unsigned_integer_type || Aribitrary_signed_integer_type; +template +concept Aribitrary_real_type = Arbitrary_arithmetic_type && + !std::numeric_limits::is_integer; + } #define BOOST_MATH_INTEGRAL boost::math::concepts::Integral @@ -140,6 +142,7 @@ concept Aribitrary_integer_type = Aribitrary_unsigned_integer_type || #define BOOST_MATH_ARBITRARY_UNSIGNED_INTEGER boost::math::concepts::Aribitrary_unsigned_integer_type #define BOOST_MATH_ARBITRARY_SIGNED_INTEGER boost::math::concepts::Aribitrary_signed_integer_type #define BOOST_MATH_ARBITRARY_INTEGER boost::math::concepts::Aribitrary_integer_type +#define BOOST_MATH_ARBITRARY_REAL boost::math::concepts::Aribitrary_real_type #define BOOST_MATH_REQUIRES(X, T) requires X #endif @@ -197,6 +200,10 @@ concept Aribitrary_integer_type = Aribitrary_unsigned_integer_type || # define BOOST_MATH_ARBITRARY_INTEGER typename #endif +#ifndef BOOST_MATH_ARBITRARY_REAL +# define BOOST_MATH_ARBITRARY_REAL typename +#endif + #ifndef BOOST_MATH_REQUIRES # define BOOST_MATH_REQUIRES(X, T) #endif diff --git a/include/boost/math/special_functions/beta.hpp b/include/boost/math/special_functions/beta.hpp index f74937c1a7..980ec9d551 100644 --- a/include/boost/math/special_functions/beta.hpp +++ b/include/boost/math/special_functions/beta.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace boost{ namespace math{ @@ -30,7 +31,7 @@ namespace detail{ // // Implementation of Beta(a,b) using the Lanczos approximation: // -template +template T beta_imp(T a, T b, const Lanczos&, const Policy& pol) { BOOST_MATH_STD_USING // for ADL of std names @@ -120,7 +121,7 @@ T beta_imp(T a, T b, const Lanczos&, const Policy& pol) // Generic implementation of Beta(a,b) without Lanczos approximation support // (Caution this is slow!!!): // -template +template T beta_imp(T a, T b, const lanczos::undefined_lanczos& l, const Policy& pol) { BOOST_MATH_STD_USING @@ -203,7 +204,7 @@ T beta_imp(T a, T b, const lanczos::undefined_lanczos& l, const Policy& pol) // powers are *hard* though, and using logarithms just leads to // horrendous cancellation errors. // -template +template T ibeta_power_terms(T a, T b, T x, @@ -440,7 +441,7 @@ T ibeta_power_terms(T a, // // This version is generic, slow, and does not use the Lanczos approximation. // -template +template T ibeta_power_terms(T a, T b, T x, @@ -532,7 +533,7 @@ T ibeta_power_terms(T a, // // Series approximation to the incomplete beta: // -template +template struct ibeta_series_t { typedef T result_type; @@ -551,7 +552,7 @@ struct ibeta_series_t int n; }; -template +template T ibeta_series(T a, T b, T x, T s0, const Lanczos&, bool normalised, T* p_derivative, T y, const Policy& pol) { BOOST_MATH_STD_USING @@ -620,7 +621,7 @@ T ibeta_series(T a, T b, T x, T s0, const Lanczos&, bool normalised, T* p_deriva // // Incomplete Beta series again, this time without Lanczos support: // -template +template T ibeta_series(T a, T b, T x, T s0, const boost::math::lanczos::undefined_lanczos& l, bool normalised, T* p_derivative, T y, const Policy& pol) { BOOST_MATH_STD_USING @@ -682,7 +683,7 @@ T ibeta_series(T a, T b, T x, T s0, const boost::math::lanczos::undefined_lanczo // // Continued fraction for the incomplete beta: // -template +template struct ibeta_fraction2_t { typedef std::pair result_type; @@ -711,7 +712,7 @@ struct ibeta_fraction2_t // // Evaluate the incomplete beta via the continued fraction representation: // -template +template inline T ibeta_fraction2(T a, T b, T x, T y, const Policy& pol, bool normalised, T* p_derivative) { typedef typename lanczos::lanczos::type lanczos_type; @@ -734,7 +735,7 @@ inline T ibeta_fraction2(T a, T b, T x, T y, const Policy& pol, bool normalised, // // Computes the difference between ibeta(a,b,x) and ibeta(a+k,b,x): // -template +template T ibeta_a_step(T a, T b, T x, T y, int k, const Policy& pol, bool normalised, T* p_derivative) { typedef typename lanczos::lanczos::type lanczos_type; @@ -768,7 +769,7 @@ T ibeta_a_step(T a, T b, T x, T y, int k, const Policy& pol, bool normalised, T* // beta(a,b,x) = prefix + delta * beta(a+k,b,x) // it is currently only called for small k. // -template +template inline T rising_factorial_ratio(T a, T b, int k) { // calculate: @@ -795,7 +796,7 @@ inline T rising_factorial_ratio(T a, T b, int k) // Note that the table size should never exceed the size of our // tables of factorials. // -template +template struct Pn_size { // This is likely to be enough for ~35-50 digit accuracy @@ -825,7 +826,7 @@ struct Pn_size static_assert(::boost::math::max_factorial::value >= 100, "Type does not provide for ~35-50 digits of accuracy"); }; -template +template T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const Policy& pol, bool normalised) { typedef typename lanczos::lanczos::type lanczos_type; @@ -937,7 +938,7 @@ T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const Policy& po // For integer arguments we can relate the incomplete beta to the // complement of the binomial distribution cdf and use this finite sum. // -template +template T binomial_ccdf(T n, T k, T x, T y, const Policy& pol) { BOOST_MATH_STD_USING // ADL of std names @@ -998,7 +999,7 @@ T binomial_ccdf(T n, T k, T x, T y, const Policy& pol) // input range and select the right implementation method for // each domain: // -template +template T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised, T* p_derivative) { static const char* function = "boost::math::ibeta<%1%>(%1%, %1%, %1%)"; @@ -1398,13 +1399,13 @@ T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised, T* p_de return invert ? (normalised ? 1 : boost::math::beta(a, b, pol)) - fract : fract; } // template T ibeta_imp(T a, T b, T x, const Lanczos& l, bool inv, bool normalised) -template +template inline T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised) { return ibeta_imp(a, b, x, pol, inv, normalised, static_cast(nullptr)); } -template +template T ibeta_derivative_imp(T a, T b, T x, const Policy& pol) { static const char* function = "ibeta_derivative<%1%>(%1%,%1%,%1%)"; From 725232026f4546bb23c4ebfee40bbbf4c8402547 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 17 Oct 2022 13:18:00 -0700 Subject: [PATCH 05/16] Add policy concept [ci skip] --- include/boost/math/concepts/concepts.hpp | 51 +++++++++++------- include/boost/math/special_functions/beta.hpp | 52 +++++++++---------- 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index 6b6e242d84..cdc9a32e71 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace boost::math::concepts { @@ -39,7 +40,7 @@ template inline constexpr bool op_valid_v = op_valid::value; template -concept Integral = std::is_integral_v +concept Integral = std::numeric_limits::is_integer #ifdef __SIZEOF_INT128__ || std::is_same_v<__int128_t, T> || std::is_same_v<__uint128_t, T> @@ -47,21 +48,24 @@ concept Integral = std::is_integral_v ; template -concept Signed_integral = std::is_integral_v && (std::is_signed_v - #ifdef __SIZEOF_INT128__ - || std::is_same_v<__int128_t, T> - #endif - ); +concept Signed_integral = (std::numeric_limits::is_integer && + std::numeric_limits::is_signed) + #ifdef __SIZEOF_INT128__ + || std::is_same_v<__int128_t, T> + #endif + ; template -concept Unsigned_integral = std::is_integral_v && (std::is_unsigned_v - #ifdef __SIZEOF_INT128__ - || std::is_same_v<__uint128_t, T> - #endif - ); +concept Unsigned_integral = (std::numeric_limits::is_integer && + !std::numeric_limits::is_signed) + #ifdef __SIZEOF_INT128__ + || std::is_same_v<__uint128_t, T> + #endif + ; template -concept Real = std::is_floating_point_v +concept Real = std::numeric_limits::is_iec559 || + std::is_floating_point_v #ifdef BOOST_HAS_FLOAT128 #if defined(__INTEL_LLVM_COMPILER) || defined(__INTEL_COMPILER) || std::is_same_v<_Quad, T> @@ -75,18 +79,18 @@ template concept Arithmetic = Integral || Real; template -concept Signed_arithmetic = Arithmetic && (std::is_signed_v +concept Signed_arithmetic = (Arithmetic && std::is_signed_v) #ifdef __SIZEOF_INT128__ || std::is_same_v<__int128_t, T> #endif - ); + ; template -concept Unsigned_arithmetic = Arithmetic && (std::is_unsigned_v - #ifdef __SIZEOF_INT128__ - || std::is_same_v<__uint128_t, T> - #endif - ); +concept Unsigned_arithmetic = (Arithmetic && std::is_unsigned_v) + #ifdef __SIZEOF_INT128__ + || std::is_same_v<__uint128_t, T> + #endif + ; template concept Arbitrary_unsigned_arithmetic_type = Unsigned_arithmetic || @@ -127,6 +131,9 @@ template concept Aribitrary_real_type = Arbitrary_arithmetic_type && !std::numeric_limits::is_integer; +template +concept policy = boost::math::policies::is_policy::value; + } #define BOOST_MATH_INTEGRAL boost::math::concepts::Integral @@ -143,6 +150,7 @@ concept Aribitrary_real_type = Arbitrary_arithmetic_type && #define BOOST_MATH_ARBITRARY_SIGNED_INTEGER boost::math::concepts::Aribitrary_signed_integer_type #define BOOST_MATH_ARBITRARY_INTEGER boost::math::concepts::Aribitrary_integer_type #define BOOST_MATH_ARBITRARY_REAL boost::math::concepts::Aribitrary_real_type +#define BOOST_MATH_POLICY boost::math::concepts::policy #define BOOST_MATH_REQUIRES(X, T) requires X #endif @@ -204,6 +212,11 @@ concept Aribitrary_real_type = Arbitrary_arithmetic_type && # define BOOST_MATH_ARBITRARY_REAL typename #endif +#ifndef BOOST_MATH_POLICY +# define BOOST_MATH_POLICY typename + +#endif + #ifndef BOOST_MATH_REQUIRES # define BOOST_MATH_REQUIRES(X, T) #endif diff --git a/include/boost/math/special_functions/beta.hpp b/include/boost/math/special_functions/beta.hpp index 980ec9d551..e9bdeaf16c 100644 --- a/include/boost/math/special_functions/beta.hpp +++ b/include/boost/math/special_functions/beta.hpp @@ -31,7 +31,7 @@ namespace detail{ // // Implementation of Beta(a,b) using the Lanczos approximation: // -template +template T beta_imp(T a, T b, const Lanczos&, const Policy& pol) { BOOST_MATH_STD_USING // for ADL of std names @@ -121,7 +121,7 @@ T beta_imp(T a, T b, const Lanczos&, const Policy& pol) // Generic implementation of Beta(a,b) without Lanczos approximation support // (Caution this is slow!!!): // -template +template T beta_imp(T a, T b, const lanczos::undefined_lanczos& l, const Policy& pol) { BOOST_MATH_STD_USING @@ -204,7 +204,7 @@ T beta_imp(T a, T b, const lanczos::undefined_lanczos& l, const Policy& pol) // powers are *hard* though, and using logarithms just leads to // horrendous cancellation errors. // -template +template T ibeta_power_terms(T a, T b, T x, @@ -441,7 +441,7 @@ T ibeta_power_terms(T a, // // This version is generic, slow, and does not use the Lanczos approximation. // -template +template T ibeta_power_terms(T a, T b, T x, @@ -552,7 +552,7 @@ struct ibeta_series_t int n; }; -template +template T ibeta_series(T a, T b, T x, T s0, const Lanczos&, bool normalised, T* p_derivative, T y, const Policy& pol) { BOOST_MATH_STD_USING @@ -621,7 +621,7 @@ T ibeta_series(T a, T b, T x, T s0, const Lanczos&, bool normalised, T* p_deriva // // Incomplete Beta series again, this time without Lanczos support: // -template +template T ibeta_series(T a, T b, T x, T s0, const boost::math::lanczos::undefined_lanczos& l, bool normalised, T* p_derivative, T y, const Policy& pol) { BOOST_MATH_STD_USING @@ -712,7 +712,7 @@ struct ibeta_fraction2_t // // Evaluate the incomplete beta via the continued fraction representation: // -template +template inline T ibeta_fraction2(T a, T b, T x, T y, const Policy& pol, bool normalised, T* p_derivative) { typedef typename lanczos::lanczos::type lanczos_type; @@ -735,7 +735,7 @@ inline T ibeta_fraction2(T a, T b, T x, T y, const Policy& pol, bool normalised, // // Computes the difference between ibeta(a,b,x) and ibeta(a+k,b,x): // -template +template T ibeta_a_step(T a, T b, T x, T y, int k, const Policy& pol, bool normalised, T* p_derivative) { typedef typename lanczos::lanczos::type lanczos_type; @@ -826,7 +826,7 @@ struct Pn_size static_assert(::boost::math::max_factorial::value >= 100, "Type does not provide for ~35-50 digits of accuracy"); }; -template +template T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const Policy& pol, bool normalised) { typedef typename lanczos::lanczos::type lanczos_type; @@ -938,7 +938,7 @@ T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const Policy& po // For integer arguments we can relate the incomplete beta to the // complement of the binomial distribution cdf and use this finite sum. // -template +template T binomial_ccdf(T n, T k, T x, T y, const Policy& pol) { BOOST_MATH_STD_USING // ADL of std names @@ -999,7 +999,7 @@ T binomial_ccdf(T n, T k, T x, T y, const Policy& pol) // input range and select the right implementation method for // each domain: // -template +template T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised, T* p_derivative) { static const char* function = "boost::math::ibeta<%1%>(%1%, %1%, %1%)"; @@ -1399,13 +1399,13 @@ T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised, T* p_de return invert ? (normalised ? 1 : boost::math::beta(a, b, pol)) - fract : fract; } // template T ibeta_imp(T a, T b, T x, const Lanczos& l, bool inv, bool normalised) -template +template inline T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised) { return ibeta_imp(a, b, x, pol, inv, normalised, static_cast(nullptr)); } -template +template T ibeta_derivative_imp(T a, T b, T x, const Policy& pol) { static const char* function = "ibeta_derivative<%1%>(%1%,%1%,%1%)"; @@ -1442,7 +1442,7 @@ T ibeta_derivative_imp(T a, T b, T x, const Policy& pol) // // Some forwarding functions that dis-ambiguate the third argument type: // -template +template inline typename tools::promote_args::type beta(RT1 a, RT2 b, const Policy&, const std::true_type*) { @@ -1459,7 +1459,7 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::beta_imp(static_cast(a), static_cast(b), evaluation_type(), forwarding_policy()), "boost::math::beta<%1%>(%1%,%1%)"); } -template +template inline typename tools::promote_args::type beta(RT1 a, RT2 b, RT3 x, const std::false_type*) { @@ -1472,7 +1472,7 @@ inline typename tools::promote_args::type // which Lanczos approximation to use // and forward to the implementation functions: // -template +template inline typename tools::promote_args::type beta(RT1 a, RT2 b, A arg) { @@ -1480,14 +1480,14 @@ inline typename tools::promote_args::type return boost::math::detail::beta(a, b, arg, static_cast(nullptr)); } -template +template inline typename tools::promote_args::type beta(RT1 a, RT2 b) { return boost::math::beta(a, b, policies::policy<>()); } -template +template inline typename tools::promote_args::type beta(RT1 a, RT2 b, RT3 x, const Policy&) { @@ -1504,7 +1504,7 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), false, false), "boost::math::beta<%1%>(%1%,%1%,%1%)"); } -template +template inline typename tools::promote_args::type betac(RT1 a, RT2 b, RT3 x, const Policy&) { @@ -1520,14 +1520,14 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), true, false), "boost::math::betac<%1%>(%1%,%1%,%1%)"); } -template +template inline typename tools::promote_args::type betac(RT1 a, RT2 b, RT3 x) { return boost::math::betac(a, b, x, policies::policy<>()); } -template +template inline typename tools::promote_args::type ibeta(RT1 a, RT2 b, RT3 x, const Policy&) { @@ -1543,14 +1543,14 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), false, true), "boost::math::ibeta<%1%>(%1%,%1%,%1%)"); } -template +template inline typename tools::promote_args::type ibeta(RT1 a, RT2 b, RT3 x) { return boost::math::ibeta(a, b, x, policies::policy<>()); } -template +template inline typename tools::promote_args::type ibetac(RT1 a, RT2 b, RT3 x, const Policy&) { @@ -1566,14 +1566,14 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), true, true), "boost::math::ibetac<%1%>(%1%,%1%,%1%)"); } -template +template inline typename tools::promote_args::type ibetac(RT1 a, RT2 b, RT3 x) { return boost::math::ibetac(a, b, x, policies::policy<>()); } -template +template inline typename tools::promote_args::type ibeta_derivative(RT1 a, RT2 b, RT3 x, const Policy&) { @@ -1589,7 +1589,7 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::ibeta_derivative_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy()), "boost::math::ibeta_derivative<%1%>(%1%,%1%,%1%)"); } -template +template inline typename tools::promote_args::type ibeta_derivative(RT1 a, RT2 b, RT3 x) { From 046217c4432b38f637809dca0464eaa8a72bf918 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 17 Oct 2022 13:50:32 -0700 Subject: [PATCH 06/16] Iterator concept example in statistics --- include/boost/math/concepts/concepts.hpp | 5 ++ .../math/statistics/univariate_statistics.hpp | 83 ++++++++++--------- 2 files changed, 47 insertions(+), 41 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index cdc9a32e71..ec7d529698 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -151,6 +152,7 @@ concept policy = boost::math::policies::is_policy::value; #define BOOST_MATH_ARBITRARY_INTEGER boost::math::concepts::Aribitrary_integer_type #define BOOST_MATH_ARBITRARY_REAL boost::math::concepts::Aribitrary_real_type #define BOOST_MATH_POLICY boost::math::concepts::policy +#define BOOST_MATH_FORWARD_ITER std::forward_iterator #define BOOST_MATH_REQUIRES(X, T) requires X #endif @@ -214,7 +216,10 @@ concept policy = boost::math::policies::is_policy::value; #ifndef BOOST_MATH_POLICY # define BOOST_MATH_POLICY typename +#endif +#ifndef BOOST_MATH_FORWARD_ITER +# define BOOST_MATH_FORWARD_ITER typename #endif #ifndef BOOST_MATH_REQUIRES diff --git a/include/boost/math/statistics/univariate_statistics.hpp b/include/boost/math/statistics/univariate_statistics.hpp index 082517d650..3e4324d520 100644 --- a/include/boost/math/statistics/univariate_statistics.hpp +++ b/include/boost/math/statistics/univariate_statistics.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +26,7 @@ namespace boost::math::statistics { -template +template inline auto mean(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -61,7 +62,7 @@ inline auto mean(ExecutionPolicy&& exec, Container const & v) return mean(exec, std::cbegin(v), std::cend(v)); } -template +template inline auto mean(ForwardIterator first, ForwardIterator last) { return mean(std::execution::seq, first, last); @@ -73,7 +74,7 @@ inline auto mean(Container const & v) return mean(std::execution::seq, std::cbegin(v), std::cend(v)); } -template +template inline auto variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -110,7 +111,7 @@ inline auto variance(ExecutionPolicy&& exec, Container const & v) return variance(exec, std::cbegin(v), std::cend(v)); } -template +template inline auto variance(ForwardIterator first, ForwardIterator last) { return variance(std::execution::seq, first, last); @@ -122,7 +123,7 @@ inline auto variance(Container const & v) return variance(std::execution::seq, std::cbegin(v), std::cend(v)); } -template +template inline auto sample_variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { const auto n = std::distance(first, last); @@ -136,7 +137,7 @@ inline auto sample_variance(ExecutionPolicy&& exec, Container const & v) return sample_variance(exec, std::cbegin(v), std::cend(v)); } -template +template inline auto sample_variance(ForwardIterator first, ForwardIterator last) { return sample_variance(std::execution::seq, first, last); @@ -148,7 +149,7 @@ inline auto sample_variance(Container const & v) return sample_variance(std::execution::seq, std::cbegin(v), std::cend(v)); } -template +template inline auto mean_and_sample_variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -187,7 +188,7 @@ inline auto mean_and_sample_variance(ExecutionPolicy&& exec, Container const & v return mean_and_sample_variance(exec, std::cbegin(v), std::cend(v)); } -template +template inline auto mean_and_sample_variance(ForwardIterator first, ForwardIterator last) { return mean_and_sample_variance(std::execution::seq, first, last); @@ -199,7 +200,7 @@ inline auto mean_and_sample_variance(Container const & v) return mean_and_sample_variance(std::execution::seq, std::cbegin(v), std::cend(v)); } -template +template inline auto first_four_moments(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -242,7 +243,7 @@ inline auto first_four_moments(ExecutionPolicy&& exec, Container const & v) return first_four_moments(exec, std::cbegin(v), std::cend(v)); } -template +template inline auto first_four_moments(ForwardIterator first, ForwardIterator last) { return first_four_moments(std::execution::seq, first, last); @@ -255,7 +256,7 @@ inline auto first_four_moments(Container const & v) } // https://prod.sandia.gov/techlib-noauth/access-control.cgi/2008/086212.pdf -template +template inline auto skewness(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -304,7 +305,7 @@ inline auto skewness(ExecutionPolicy&& exec, Container & v) return skewness(exec, std::cbegin(v), std::cend(v)); } -template +template inline auto skewness(ForwardIterator first, ForwardIterator last) { return skewness(std::execution::seq, first, last); @@ -318,7 +319,7 @@ inline auto skewness(Container const & v) // Follows equation 1.6 of: // https://prod.sandia.gov/techlib-noauth/access-control.cgi/2008/086212.pdf -template +template inline auto kurtosis(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { const auto [M1, M2, M3, M4] = first_four_moments(exec, first, last); @@ -335,7 +336,7 @@ inline auto kurtosis(ExecutionPolicy&& exec, Container const & v) return kurtosis(exec, std::cbegin(v), std::cend(v)); } -template +template inline auto kurtosis(ForwardIterator first, ForwardIterator last) { return kurtosis(std::execution::seq, first, last); @@ -347,7 +348,7 @@ inline auto kurtosis(Container const & v) return kurtosis(std::execution::seq, std::cbegin(v), std::cend(v)); } -template +template inline auto excess_kurtosis(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { return kurtosis(exec, first, last) - 3; @@ -359,7 +360,7 @@ inline auto excess_kurtosis(ExecutionPolicy&& exec, Container const & v) return excess_kurtosis(exec, std::cbegin(v), std::cend(v)); } -template +template inline auto excess_kurtosis(ForwardIterator first, ForwardIterator last) { return excess_kurtosis(std::execution::seq, first, last); @@ -537,7 +538,7 @@ inline auto median_absolute_deviation(RandomAccessContainer & v, return median_absolute_deviation(std::execution::seq, std::begin(v), std::end(v), center); } -template +template auto interquartile_range(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -596,7 +597,7 @@ inline auto interquartile_range(RandomAccessContainer & v) return interquartile_range(std::execution::seq, std::begin(v), std::end(v)); } -template +template inline OutputIterator mode(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, OutputIterator output) { if(!std::is_sorted(exec, first, last)) @@ -620,7 +621,7 @@ inline OutputIterator mode(ExecutionPolicy&& exec, Container & v, OutputIterator return mode(exec, std::begin(v), std::end(v), output); } -template +template inline OutputIterator mode(ForwardIterator first, ForwardIterator last, OutputIterator output) { return mode(std::execution::seq, first, last, output); @@ -642,7 +643,7 @@ inline OutputIterator mode(Container & v, OutputIterator output) // std::list is the return type for the proposed STL stats library -template::value_type> +template::value_type> inline auto mode(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { std::list modes; @@ -656,7 +657,7 @@ inline auto mode(ExecutionPolicy&& exec, Container & v) return mode(exec, std::begin(v), std::end(v)); } -template +template inline auto mode(ForwardIterator first, ForwardIterator last) { return mode(std::execution::seq, first, last); @@ -677,7 +678,7 @@ namespace boost { namespace math { namespace statistics { template using enable_if_t = typename std::enable_if::type; -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double mean(const ForwardIterator first, const ForwardIterator last) { @@ -692,7 +693,7 @@ inline double mean(const Container& c) return mean(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real mean(const ForwardIterator first, const ForwardIterator last) { @@ -707,7 +708,7 @@ inline Real mean(const Container& c) return mean(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double variance(const ForwardIterator first, const ForwardIterator last) { @@ -721,7 +722,7 @@ inline double variance(const Container& c) return variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real variance(const ForwardIterator first, const ForwardIterator last) { @@ -736,7 +737,7 @@ inline Real variance(const Container& c) return variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double sample_variance(const ForwardIterator first, const ForwardIterator last) { @@ -752,7 +753,7 @@ inline double sample_variance(const Container& c) return sample_variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real sample_variance(const ForwardIterator first, const ForwardIterator last) { @@ -768,7 +769,7 @@ inline Real sample_variance(const Container& c) return sample_variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline std::pair mean_and_sample_variance(const ForwardIterator first, const ForwardIterator last) { @@ -783,7 +784,7 @@ inline std::pair mean_and_sample_variance(const Container& c) return mean_and_sample_variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline std::pair mean_and_sample_variance(const ForwardIterator first, const ForwardIterator last) { @@ -798,7 +799,7 @@ inline std::pair mean_and_sample_variance(const Container& c) return mean_and_sample_variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline std::tuple first_four_moments(const ForwardIterator first, const ForwardIterator last) { @@ -814,7 +815,7 @@ inline std::tuple first_four_moments(const Conta return first_four_moments(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline std::tuple first_four_moments(const ForwardIterator first, const ForwardIterator last) { @@ -830,7 +831,7 @@ inline std::tuple first_four_moments(const Container& c) return first_four_moments(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double skewness(const ForwardIterator first, const ForwardIterator last) { @@ -844,7 +845,7 @@ inline double skewness(const Container& c) return skewness(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real skewness(const ForwardIterator first, const ForwardIterator last) { @@ -858,7 +859,7 @@ inline Real skewness(const Container& c) return skewness(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double kurtosis(const ForwardIterator first, const ForwardIterator last) { @@ -881,7 +882,7 @@ inline double kurtosis(const Container& c) return kurtosis(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real kurtosis(const ForwardIterator first, const ForwardIterator last) { @@ -904,7 +905,7 @@ inline Real kurtosis(const Container& c) return kurtosis(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double excess_kurtosis(const ForwardIterator first, const ForwardIterator last) { @@ -918,7 +919,7 @@ inline double excess_kurtosis(const Container& c) return excess_kurtosis(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real excess_kurtosis(const ForwardIterator first, const ForwardIterator last) { @@ -1061,7 +1062,7 @@ inline Real median_absolute_deviation(RandomAccessContainer& c, return median_absolute_deviation(std::begin(c), std::end(c), center); } -template::value_type> +template::value_type> Real interquartile_range(ForwardIterator first, ForwardIterator last) { static_assert(!std::is_integral::value, "Integer values have not yet been implemented."); @@ -1109,7 +1110,7 @@ Real interquartile_range(Container& c) return interquartile_range(std::begin(c), std::end(c)); } -template::iterator_category(), std::random_access_iterator_tag>::value, bool> = true> inline OutputIterator mode(ForwardIterator first, ForwardIterator last, OutputIterator output) { @@ -1121,7 +1122,7 @@ inline OutputIterator mode(ForwardIterator first, ForwardIterator last, OutputIt return detail::mode_impl(first, last, output); } -template::iterator_category(), std::random_access_iterator_tag>::value, bool> = true> inline OutputIterator mode(ForwardIterator first, ForwardIterator last, OutputIterator output) { @@ -1139,7 +1140,7 @@ inline OutputIterator mode(Container& c, OutputIterator output) return mode(std::begin(c), std::end(c), output); } -template::value_type> +template::value_type> inline std::list mode(ForwardIterator first, ForwardIterator last) { std::list modes; From e9af3487f2ff89377d614395dc37ba3099b3e358 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 18 Oct 2022 08:07:59 -0700 Subject: [PATCH 07/16] Tighten definitions of built-in concepts by excluding 128 bit extensions --- include/boost/math/concepts/concepts.hpp | 44 +++---------------- include/boost/math/special_functions/beta.hpp | 27 ++++++------ 2 files changed, 20 insertions(+), 51 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index ec7d529698..279454bb9f 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -41,57 +41,25 @@ template inline constexpr bool op_valid_v = op_valid::value; template -concept Integral = std::numeric_limits::is_integer - #ifdef __SIZEOF_INT128__ - || std::is_same_v<__int128_t, T> - || std::is_same_v<__uint128_t, T> - #endif - ; +concept Integral = std::is_integral_v; template -concept Signed_integral = (std::numeric_limits::is_integer && - std::numeric_limits::is_signed) - #ifdef __SIZEOF_INT128__ - || std::is_same_v<__int128_t, T> - #endif - ; +concept Signed_integral = Integral && std::is_signed_v; template -concept Unsigned_integral = (std::numeric_limits::is_integer && - !std::numeric_limits::is_signed) - #ifdef __SIZEOF_INT128__ - || std::is_same_v<__uint128_t, T> - #endif - ; +concept Unsigned_integral = Integral && std::is_unsigned_v; template -concept Real = std::numeric_limits::is_iec559 || - std::is_floating_point_v - #ifdef BOOST_HAS_FLOAT128 - #if defined(__INTEL_LLVM_COMPILER) || defined(__INTEL_COMPILER) - || std::is_same_v<_Quad, T> - #else - || std::is_same_v<__float128, T> - #endif - #endif - ; +concept Real = std::is_floating_point_v; template concept Arithmetic = Integral || Real; template -concept Signed_arithmetic = (Arithmetic && std::is_signed_v) - #ifdef __SIZEOF_INT128__ - || std::is_same_v<__int128_t, T> - #endif - ; +concept Signed_arithmetic = Arithmetic && std::is_signed_v; template -concept Unsigned_arithmetic = (Arithmetic && std::is_unsigned_v) - #ifdef __SIZEOF_INT128__ - || std::is_same_v<__uint128_t, T> - #endif - ; +concept Unsigned_arithmetic = Arithmetic && std::is_unsigned_v; template concept Arbitrary_unsigned_arithmetic_type = Unsigned_arithmetic || diff --git a/include/boost/math/special_functions/beta.hpp b/include/boost/math/special_functions/beta.hpp index e9bdeaf16c..03f88713b7 100644 --- a/include/boost/math/special_functions/beta.hpp +++ b/include/boost/math/special_functions/beta.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace boost{ namespace math{ @@ -1442,7 +1443,7 @@ T ibeta_derivative_imp(T a, T b, T x, const Policy& pol) // // Some forwarding functions that dis-ambiguate the third argument type: // -template +template inline typename tools::promote_args::type beta(RT1 a, RT2 b, const Policy&, const std::true_type*) { @@ -1459,7 +1460,7 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::beta_imp(static_cast(a), static_cast(b), evaluation_type(), forwarding_policy()), "boost::math::beta<%1%>(%1%,%1%)"); } -template +template inline typename tools::promote_args::type beta(RT1 a, RT2 b, RT3 x, const std::false_type*) { @@ -1472,7 +1473,7 @@ inline typename tools::promote_args::type // which Lanczos approximation to use // and forward to the implementation functions: // -template +template inline typename tools::promote_args::type beta(RT1 a, RT2 b, A arg) { @@ -1480,14 +1481,14 @@ inline typename tools::promote_args::type return boost::math::detail::beta(a, b, arg, static_cast(nullptr)); } -template +template inline typename tools::promote_args::type beta(RT1 a, RT2 b) { return boost::math::beta(a, b, policies::policy<>()); } -template +template inline typename tools::promote_args::type beta(RT1 a, RT2 b, RT3 x, const Policy&) { @@ -1504,7 +1505,7 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), false, false), "boost::math::beta<%1%>(%1%,%1%,%1%)"); } -template +template inline typename tools::promote_args::type betac(RT1 a, RT2 b, RT3 x, const Policy&) { @@ -1520,14 +1521,14 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), true, false), "boost::math::betac<%1%>(%1%,%1%,%1%)"); } -template +template inline typename tools::promote_args::type betac(RT1 a, RT2 b, RT3 x) { return boost::math::betac(a, b, x, policies::policy<>()); } -template +template inline typename tools::promote_args::type ibeta(RT1 a, RT2 b, RT3 x, const Policy&) { @@ -1543,14 +1544,14 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), false, true), "boost::math::ibeta<%1%>(%1%,%1%,%1%)"); } -template +template inline typename tools::promote_args::type ibeta(RT1 a, RT2 b, RT3 x) { return boost::math::ibeta(a, b, x, policies::policy<>()); } -template +template inline typename tools::promote_args::type ibetac(RT1 a, RT2 b, RT3 x, const Policy&) { @@ -1566,14 +1567,14 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::ibeta_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy(), true, true), "boost::math::ibetac<%1%>(%1%,%1%,%1%)"); } -template +template inline typename tools::promote_args::type ibetac(RT1 a, RT2 b, RT3 x) { return boost::math::ibetac(a, b, x, policies::policy<>()); } -template +template inline typename tools::promote_args::type ibeta_derivative(RT1 a, RT2 b, RT3 x, const Policy&) { @@ -1589,7 +1590,7 @@ inline typename tools::promote_args::type return policies::checked_narrowing_cast(detail::ibeta_derivative_imp(static_cast(a), static_cast(b), static_cast(x), forwarding_policy()), "boost::math::ibeta_derivative<%1%>(%1%,%1%,%1%)"); } -template +template inline typename tools::promote_args::type ibeta_derivative(RT1 a, RT2 b, RT3 x) { From 9a0905a09f19adb8966c4aa50e668e8161a7d844 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 18 Oct 2022 11:37:19 -0700 Subject: [PATCH 08/16] Add definition for container --- include/boost/math/concepts/concepts.hpp | 99 ++++++++++++++++--- .../math/statistics/univariate_statistics.hpp | 78 +++++++-------- 2 files changed, 124 insertions(+), 53 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index 279454bb9f..7b31b27fae 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -21,6 +21,8 @@ namespace boost::math::concepts { +namespace detail { + template struct op_valid_impl { @@ -35,10 +37,50 @@ struct op_valid_impl }; template -using op_valid = typename op_valid_impl::type; +using op_valid_t = typename op_valid_impl::type; template -inline constexpr bool op_valid_v = op_valid::value; +inline constexpr bool op_valid_v = op_valid_t::value; + +// Detector for class member functions +struct nonesuch +{ + nonesuch(const nonesuch&) = delete; + ~nonesuch() = delete; + void operator=(const nonesuch&) = delete; +}; + +template typename Op, typename... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template typename Op, typename... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template typename Op, typename... Args> +using is_detected = typename detector::value_t; + +template typename Op, typename... Args> +using detected_t = typename detector::type; + +#define BOOST_MATH_HAS_MEMBER_FUNCTION(member) \ +template \ +using has_##member##_t = decltype(std::declval().member()); \ + \ +template \ +inline constexpr bool has_##member##_v = is_detected::value; + +BOOST_MATH_HAS_MEMBER_FUNCTION(begin) +BOOST_MATH_HAS_MEMBER_FUNCTION(end) + +} // Namespace detail template concept Integral = std::is_integral_v; @@ -63,21 +105,21 @@ concept Unsigned_arithmetic = Arithmetic && std::is_unsigned_v; template concept Arbitrary_unsigned_arithmetic_type = Unsigned_arithmetic || - (op_valid_v> && - op_valid_v> && - op_valid_v> && - op_valid_v> && - op_valid_v> && - op_valid_v> && - op_valid_v> && - op_valid_v> && - op_valid_v> && - op_valid_v>); + (detail::op_valid_v> && + detail::op_valid_v> && + detail::op_valid_v> && + detail::op_valid_v> && + detail::op_valid_v> && + detail::op_valid_v> && + detail::op_valid_v> && + detail::op_valid_v> && + detail::op_valid_v> && + detail::op_valid_v>); template concept Arbitrary_signed_arithmetic_type = Signed_arithmetic || (Arbitrary_unsigned_arithmetic_type && - (op_valid_v> || + (detail::op_valid_v> || std::numeric_limits::is_signed)); template @@ -103,7 +145,15 @@ concept Aribitrary_real_type = Arbitrary_arithmetic_type && template concept policy = boost::math::policies::is_policy::value; -} +template +concept is_container = detail::has_begin_v && + detail::has_end_v; + +template +concept random_access_container = is_container && + std::random_access_iterator; + +} // boost::math::concepts #define BOOST_MATH_INTEGRAL boost::math::concepts::Integral #define BOOST_MATH_SIGNED_INTEGRAL boost::math::concepts::Signed_integral @@ -121,6 +171,11 @@ concept policy = boost::math::policies::is_policy::value; #define BOOST_MATH_ARBITRARY_REAL boost::math::concepts::Aribitrary_real_type #define BOOST_MATH_POLICY boost::math::concepts::policy #define BOOST_MATH_FORWARD_ITER std::forward_iterator +#define BOOST_MATH_BIDIRECTIONAL_ITER std::bidirectional_iterator +#define BOOST_MATH_RANDOM_ACCESS_ITER std::random_access_iterator +#define BOOST_MATH_OUTPUT_ITER std::output_iterator +#define BOOST_MATH_CONTAINER boost::math::concepts::is_container +#define BOOST_MATH_RANDOM_ACCESS_CONTAINER boost::math::concepts::random_access_container #define BOOST_MATH_REQUIRES(X, T) requires X #endif @@ -190,6 +245,22 @@ concept policy = boost::math::policies::is_policy::value; # define BOOST_MATH_FORWARD_ITER typename #endif +#ifndef BOOST_MATH_BIDIRECTIONAL_ITER +# define BOOST_MATH_BIDIRECTIONAL_ITER typename +#endif + +#ifndef BOOST_MATH_RANDOM_ACCESS_ITER +# define BOOST_MATH_RANDOM_ACCESS_ITER typename +#endif + +#ifndef BOOST_MATH_CONTAINER +# define BOOST_MATH_CONTAINER typename +#endif + +#ifndef BOOST_MATH_RANDOM_ACCESS_CONTAINER +# define BOOST_MATH_RANDOM_ACCESS_CONTAINER typename +#endif + #ifndef BOOST_MATH_REQUIRES # define BOOST_MATH_REQUIRES(X, T) #endif diff --git a/include/boost/math/statistics/univariate_statistics.hpp b/include/boost/math/statistics/univariate_statistics.hpp index 3e4324d520..52f8f838a0 100644 --- a/include/boost/math/statistics/univariate_statistics.hpp +++ b/include/boost/math/statistics/univariate_statistics.hpp @@ -56,7 +56,7 @@ inline auto mean(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator } } -template +template inline auto mean(ExecutionPolicy&& exec, Container const & v) { return mean(exec, std::cbegin(v), std::cend(v)); @@ -68,7 +68,7 @@ inline auto mean(ForwardIterator first, ForwardIterator last) return mean(std::execution::seq, first, last); } -template +template inline auto mean(Container const & v) { return mean(std::execution::seq, std::cbegin(v), std::cend(v)); @@ -105,7 +105,7 @@ inline auto variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardItera } } -template +template inline auto variance(ExecutionPolicy&& exec, Container const & v) { return variance(exec, std::cbegin(v), std::cend(v)); @@ -117,7 +117,7 @@ inline auto variance(ForwardIterator first, ForwardIterator last) return variance(std::execution::seq, first, last); } -template +template inline auto variance(Container const & v) { return variance(std::execution::seq, std::cbegin(v), std::cend(v)); @@ -131,7 +131,7 @@ inline auto sample_variance(ExecutionPolicy&& exec, ForwardIterator first, Forwa return n*variance(exec, first, last)/(n-1); } -template +template inline auto sample_variance(ExecutionPolicy&& exec, Container const & v) { return sample_variance(exec, std::cbegin(v), std::cend(v)); @@ -143,7 +143,7 @@ inline auto sample_variance(ForwardIterator first, ForwardIterator last) return sample_variance(std::execution::seq, first, last); } -template +template inline auto sample_variance(Container const & v) { return sample_variance(std::execution::seq, std::cbegin(v), std::cend(v)); @@ -182,7 +182,7 @@ inline auto mean_and_sample_variance(ExecutionPolicy&& exec, ForwardIterator fir } } -template +template inline auto mean_and_sample_variance(ExecutionPolicy&& exec, Container const & v) { return mean_and_sample_variance(exec, std::cbegin(v), std::cend(v)); @@ -194,7 +194,7 @@ inline auto mean_and_sample_variance(ForwardIterator first, ForwardIterator last return mean_and_sample_variance(std::execution::seq, first, last); } -template +template inline auto mean_and_sample_variance(Container const & v) { return mean_and_sample_variance(std::execution::seq, std::cbegin(v), std::cend(v)); @@ -237,7 +237,7 @@ inline auto first_four_moments(ExecutionPolicy&& exec, ForwardIterator first, Fo } } -template +template inline auto first_four_moments(ExecutionPolicy&& exec, Container const & v) { return first_four_moments(exec, std::cbegin(v), std::cend(v)); @@ -249,7 +249,7 @@ inline auto first_four_moments(ForwardIterator first, ForwardIterator last) return first_four_moments(std::execution::seq, first, last); } -template +template inline auto first_four_moments(Container const & v) { return first_four_moments(std::execution::seq, std::cbegin(v), std::cend(v)); @@ -299,7 +299,7 @@ inline auto skewness(ExecutionPolicy&& exec, ForwardIterator first, ForwardItera } } -template +template inline auto skewness(ExecutionPolicy&& exec, Container & v) { return skewness(exec, std::cbegin(v), std::cend(v)); @@ -311,7 +311,7 @@ inline auto skewness(ForwardIterator first, ForwardIterator last) return skewness(std::execution::seq, first, last); } -template +template inline auto skewness(Container const & v) { return skewness(std::execution::seq, std::cbegin(v), std::cend(v)); @@ -330,7 +330,7 @@ inline auto kurtosis(ExecutionPolicy&& exec, ForwardIterator first, ForwardItera return M4/(M2*M2); } -template +template inline auto kurtosis(ExecutionPolicy&& exec, Container const & v) { return kurtosis(exec, std::cbegin(v), std::cend(v)); @@ -342,7 +342,7 @@ inline auto kurtosis(ForwardIterator first, ForwardIterator last) return kurtosis(std::execution::seq, first, last); } -template +template inline auto kurtosis(Container const & v) { return kurtosis(std::execution::seq, std::cbegin(v), std::cend(v)); @@ -354,7 +354,7 @@ inline auto excess_kurtosis(ExecutionPolicy&& exec, ForwardIterator first, Forwa return kurtosis(exec, first, last) - 3; } -template +template inline auto excess_kurtosis(ExecutionPolicy&& exec, Container const & v) { return excess_kurtosis(exec, std::cbegin(v), std::cend(v)); @@ -366,7 +366,7 @@ inline auto excess_kurtosis(ForwardIterator first, ForwardIterator last) return excess_kurtosis(std::execution::seq, first, last); } -template +template inline auto excess_kurtosis(Container const & v) { return excess_kurtosis(std::execution::seq, std::cbegin(v), std::cend(v)); @@ -615,7 +615,7 @@ inline OutputIterator mode(ExecutionPolicy&& exec, ForwardIterator first, Forwar return detail::mode_impl(first, last, output); } -template +template inline OutputIterator mode(ExecutionPolicy&& exec, Container & v, OutputIterator output) { return mode(exec, std::begin(v), std::end(v), output); @@ -629,7 +629,7 @@ inline OutputIterator mode(ForwardIterator first, ForwardIterator last, OutputIt // Requires enable_if_t to not clash with impl that returns std::list // Very ugly. std::is_execution_policy_v returns false for the std::execution objects and decltype of the objects (e.g. std::execution::seq) -template && +template && !std::is_convertible_v && !std::is_convertible_v #if __cpp_lib_execution > 201900 @@ -651,7 +651,7 @@ inline auto mode(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator return modes; } -template +template inline auto mode(ExecutionPolicy&& exec, Container & v) { return mode(exec, std::begin(v), std::end(v)); @@ -663,7 +663,7 @@ inline auto mode(ForwardIterator first, ForwardIterator last) return mode(std::execution::seq, first, last); } -template +template inline auto mode(Container & v) { return mode(std::execution::seq, std::begin(v), std::end(v)); @@ -686,7 +686,7 @@ inline double mean(const ForwardIterator first, const ForwardIterator last) return detail::mean_sequential_impl(first, last); } -template::value, bool> = true> inline double mean(const Container& c) { @@ -701,7 +701,7 @@ inline Real mean(const ForwardIterator first, const ForwardIterator last) return detail::mean_sequential_impl(first, last); } -template::value, bool> = true> inline Real mean(const Container& c) { @@ -715,7 +715,7 @@ inline double variance(const ForwardIterator first, const ForwardIterator last) return std::get<2>(detail::variance_sequential_impl>(first, last)); } -template::value, bool> = true> inline double variance(const Container& c) { @@ -730,7 +730,7 @@ inline Real variance(const ForwardIterator first, const ForwardIterator last) } -template::value, bool> = true> inline Real variance(const Container& c) { @@ -746,7 +746,7 @@ inline double sample_variance(const ForwardIterator first, const ForwardIterator return n*variance(first, last)/(n-1); } -template::value, bool> = true> inline double sample_variance(const Container& c) { @@ -762,7 +762,7 @@ inline Real sample_variance(const ForwardIterator first, const ForwardIterator l return n*variance(first, last)/(n-1); } -template::value, bool> = true> inline Real sample_variance(const Container& c) { @@ -777,7 +777,7 @@ inline std::pair mean_and_sample_variance(const ForwardIterator return std::make_pair(std::get<0>(results), std::get<3>(results)*std::get<2>(results)/(std::get<3>(results)-1.0)); } -template::value, bool> = true> inline std::pair mean_and_sample_variance(const Container& c) { @@ -792,7 +792,7 @@ inline std::pair mean_and_sample_variance(const ForwardIterator firs return std::make_pair(std::get<0>(results), std::get<3>(results)*std::get<2>(results)/(std::get<3>(results)-Real(1))); } -template::value, bool> = true> inline std::pair mean_and_sample_variance(const Container& c) { @@ -808,7 +808,7 @@ inline std::tuple first_four_moments(const Forwa std::get<3>(results) / std::get<4>(results)); } -template::value, bool> = true> inline std::tuple first_four_moments(const Container& c) { @@ -824,7 +824,7 @@ inline std::tuple first_four_moments(const ForwardIterat std::get<3>(results) / std::get<4>(results)); } -template::value, bool> = true> inline std::tuple first_four_moments(const Container& c) { @@ -838,7 +838,7 @@ inline double skewness(const ForwardIterator first, const ForwardIterator last) return detail::skewness_sequential_impl(first, last); } -template::value, bool> = true> inline double skewness(const Container& c) { @@ -852,7 +852,7 @@ inline Real skewness(const ForwardIterator first, const ForwardIterator last) return detail::skewness_sequential_impl(first, last); } -template::value, bool> = true> inline Real skewness(const Container& c) { @@ -875,7 +875,7 @@ inline double kurtosis(const ForwardIterator first, const ForwardIterator last) } } -template::value, bool> = true> inline double kurtosis(const Container& c) { @@ -898,7 +898,7 @@ inline Real kurtosis(const ForwardIterator first, const ForwardIterator last) } } -template::value, bool> = true> inline Real kurtosis(const Container& c) { @@ -912,7 +912,7 @@ inline double excess_kurtosis(const ForwardIterator first, const ForwardIterator return kurtosis(first, last) - 3; } -template::value, bool> = true> inline double excess_kurtosis(const Container& c) { @@ -926,7 +926,7 @@ inline Real excess_kurtosis(const ForwardIterator first, const ForwardIterator l return kurtosis(first, last) - 3; } -template::value, bool> = true> inline Real excess_kurtosis(const Container& c) { @@ -1104,7 +1104,7 @@ Real interquartile_range(ForwardIterator first, ForwardIterator last) } } -template +template Real interquartile_range(Container& c) { return interquartile_range(std::begin(c), std::end(c)); @@ -1134,7 +1134,7 @@ inline OutputIterator mode(ForwardIterator first, ForwardIterator last, OutputIt return detail::mode_impl(first, last, output); } -template +template inline OutputIterator mode(Container& c, OutputIterator output) { return mode(std::begin(c), std::end(c), output); @@ -1148,7 +1148,7 @@ inline std::list mode(ForwardIterator first, ForwardIterator last) return modes; } -template +template inline std::list mode(Container& c) { return mode(std::begin(c), std::end(c)); From b56de86efc088c04abdc04a9979d7e3a285fad12 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 18 Oct 2022 13:28:04 -0700 Subject: [PATCH 09/16] Workaround for libcpp++ partial implementation of concepts --- include/boost/math/concepts/concepts.hpp | 48 +++++++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index 7b31b27fae..2014273968 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -95,7 +95,7 @@ template concept Real = std::is_floating_point_v; template -concept Arithmetic = Integral || Real; +concept Arithmetic = std::is_arithmetic_v; template concept Signed_arithmetic = Arithmetic && std::is_signed_v; @@ -145,13 +145,38 @@ concept Aribitrary_real_type = Arbitrary_arithmetic_type && template concept policy = boost::math::policies::is_policy::value; +// Workaround for LIBCPP versions that have but have not implemented concepts in +#if defined(_LIBCPP_VERSION) && !defined(_LIBCPP___ITERATOR_CONCEPTS_H) + +template +concept forward_iterator = std::is_same_v::iterator_category(), std::forward_iterator_tag>; + +template +concept bidirectional_iterator = std::is_same_v::iterator_category(), std::bidirectional_iterator_tag>; + +template +concept random_access_iterator = std::is_same_v::iterator_category(), std::random_access_iterator_tag>; + +#else + +template +concept forward_iterator = std::forward_iterator; + +template +concept bidirectional_iterator = std::bidirectional_iterator; + +template +concept random_access_iterator = std::random_access_iterator; + +#endif + template concept is_container = detail::has_begin_v && detail::has_end_v; template concept random_access_container = is_container && - std::random_access_iterator; + boost::math::concepts::random_access_iterator; } // boost::math::concepts @@ -170,14 +195,25 @@ concept random_access_container = is_container && #define BOOST_MATH_ARBITRARY_INTEGER boost::math::concepts::Aribitrary_integer_type #define BOOST_MATH_ARBITRARY_REAL boost::math::concepts::Aribitrary_real_type #define BOOST_MATH_POLICY boost::math::concepts::policy -#define BOOST_MATH_FORWARD_ITER std::forward_iterator -#define BOOST_MATH_BIDIRECTIONAL_ITER std::bidirectional_iterator -#define BOOST_MATH_RANDOM_ACCESS_ITER std::random_access_iterator -#define BOOST_MATH_OUTPUT_ITER std::output_iterator #define BOOST_MATH_CONTAINER boost::math::concepts::is_container #define BOOST_MATH_RANDOM_ACCESS_CONTAINER boost::math::concepts::random_access_container #define BOOST_MATH_REQUIRES(X, T) requires X +// Workaround for LIBCPP versions that have but have not implemented concepts in +#if defined(_LIBCPP_VERSION) && !defined(_LIBCPP___ITERATOR_CONCEPTS_H) + +#define BOOST_MATH_FORWARD_ITER boost::math::concepts::forward_iterator +#define BOOST_MATH_BIDIRECTIONAL_ITER boost::math::concepts::bidirectional_iterator +#define BOOST_MATH_RANDOM_ACCESS_ITER boost::math::concepts::random_access_iterator + +#else + +#define BOOST_MATH_FORWARD_ITER std::forward_iterator +#define BOOST_MATH_BIDIRECTIONAL_ITER std::bidirectional_iterator +#define BOOST_MATH_RANDOM_ACCESS_ITER std::random_access_iterator + +#endif + #endif #endif From b802b7c0f12bd1a3b3ad8a23b6a1dfaede1e1309 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 18 Oct 2022 15:37:23 -0700 Subject: [PATCH 10/16] Add complex number support --- include/boost/math/concepts/concepts.hpp | 109 ++++++++++++++++------- 1 file changed, 76 insertions(+), 33 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index 2014273968..9b09563a9c 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -79,32 +80,45 @@ inline constexpr bool has_##member##_v = is_detected::value BOOST_MATH_HAS_MEMBER_FUNCTION(begin) BOOST_MATH_HAS_MEMBER_FUNCTION(end) +BOOST_MATH_HAS_MEMBER_FUNCTION(real) +BOOST_MATH_HAS_MEMBER_FUNCTION(imag) } // Namespace detail template -concept Integral = std::is_integral_v; +concept integral = std::is_integral_v; template -concept Signed_integral = Integral && std::is_signed_v; +concept signed_integral = integral && std::is_signed_v; template -concept Unsigned_integral = Integral && std::is_unsigned_v; +concept unsigned_integral = integral && std::is_unsigned_v; template -concept Real = std::is_floating_point_v; +concept real = std::is_floating_point_v; template -concept Arithmetic = std::is_arithmetic_v; +concept complex = std::is_same_v> + || std::is_same_v> + #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS + || std::is_same_v> + #endif + ; template -concept Signed_arithmetic = Arithmetic && std::is_signed_v; +concept real_or_complex = real || complex; template -concept Unsigned_arithmetic = Arithmetic && std::is_unsigned_v; +concept arithmetic = std::is_arithmetic_v; template -concept Arbitrary_unsigned_arithmetic_type = Unsigned_arithmetic || +concept signed_arithmetic = arithmetic && std::is_signed_v; + +template +concept unsigned_arithmetic = arithmetic && std::is_unsigned_v; + +template +concept arbitrary_unsigned_arithmetic_type = unsigned_arithmetic || (detail::op_valid_v> && detail::op_valid_v> && detail::op_valid_v> && @@ -117,36 +131,45 @@ concept Arbitrary_unsigned_arithmetic_type = Unsigned_arithmetic || detail::op_valid_v>); template -concept Arbitrary_signed_arithmetic_type = Signed_arithmetic || - (Arbitrary_unsigned_arithmetic_type && +concept arbitrary_signed_arithmetic_type = signed_arithmetic || + (arbitrary_unsigned_arithmetic_type && (detail::op_valid_v> || std::numeric_limits::is_signed)); template -concept Arbitrary_arithmetic_type = Arbitrary_unsigned_arithmetic_type || - Arbitrary_signed_arithmetic_type; +concept arbitrary_arithmetic_type = arbitrary_unsigned_arithmetic_type || + arbitrary_signed_arithmetic_type; template -concept Aribitrary_unsigned_integer_type = Arbitrary_unsigned_arithmetic_type && +concept arbitrary_unsigned_integer_type = arbitrary_unsigned_arithmetic_type && std::numeric_limits::is_integer; template -concept Aribitrary_signed_integer_type = Arbitrary_signed_arithmetic_type && +concept arbitrary_signed_integer_type = arbitrary_signed_arithmetic_type && std::numeric_limits::is_integer; template -concept Aribitrary_integer_type = Aribitrary_unsigned_integer_type || - Aribitrary_signed_integer_type; +concept arbitrary_integer_type = arbitrary_unsigned_integer_type || + arbitrary_signed_integer_type; template -concept Aribitrary_real_type = Arbitrary_arithmetic_type && +concept arbitrary_real_type = arbitrary_arithmetic_type && !std::numeric_limits::is_integer; +template +concept arbitrary_complex_type = complex || + (detail::has_real_v && + detail::has_imag_v); + +template +concept arbitrary_real_or_complex_type = arbitrary_real_type || + arbitrary_complex_type; + template concept policy = boost::math::policies::is_policy::value; // Workaround for LIBCPP versions that have but have not implemented concepts in -#if defined(_LIBCPP_VERSION) && !defined(_LIBCPP___ITERATOR_CONCEPTS_H) +#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 13000 template concept forward_iterator = std::is_same_v::iterator_category(), std::forward_iterator_tag>; @@ -180,27 +203,31 @@ concept random_access_container = is_container && } // boost::math::concepts -#define BOOST_MATH_INTEGRAL boost::math::concepts::Integral -#define BOOST_MATH_SIGNED_INTEGRAL boost::math::concepts::Signed_integral -#define BOOST_MATH_UNSIGNED_INTEGRAL boost::math::concepts::Unsigned_integral -#define BOOST_MATH_REAL boost::math::concepts::Real -#define BOOST_MATH_ARITHMETIC boost::math::concepts::Arithmetic -#define BOOST_MATH_SIGNED_ARITHMETIC boost::math::concepts::Signed_arithmetic -#define BOOST_MATH_UNSIGNED_ARITHMETIC boost::math::concepts::Unsigned_arithmetic -#define BOOST_MATH_ARBITRARY_UNSIGNED_ARITHMETIC boost::math::concepts::Arbitrary_unsigned_arithmetic_type -#define BOOST_MATH_ARBITRARY_SIGNED_ARITHMETIC boost::math::concepts::Arbitrary_signed_arithmetic_type -#define BOOST_MATH_ARBITRARY_ARITHMETIC boost::math::concepts::Arbitrary_arithmetic_type -#define BOOST_MATH_ARBITRARY_UNSIGNED_INTEGER boost::math::concepts::Aribitrary_unsigned_integer_type -#define BOOST_MATH_ARBITRARY_SIGNED_INTEGER boost::math::concepts::Aribitrary_signed_integer_type -#define BOOST_MATH_ARBITRARY_INTEGER boost::math::concepts::Aribitrary_integer_type -#define BOOST_MATH_ARBITRARY_REAL boost::math::concepts::Aribitrary_real_type +#define BOOST_MATH_INTEGRAL boost::math::concepts::integral +#define BOOST_MATH_SIGNED_INTEGRAL boost::math::concepts::signed_integral +#define BOOST_MATH_UNSIGNED_INTEGRAL boost::math::concepts::unsigned_integral +#define BOOST_MATH_REAL boost::math::concepts::real +#define BOOST_MATH_COMPLEX boost::math::concepts::complex +#define BOOST_MATH_REAL_OR_COMPLEX boost::math::concepts::real_or_complex +#define BOOST_MATH_ARITHMETIC boost::math::concepts::arithmetic +#define BOOST_MATH_SIGNED_ARITHMETIC boost::math::concepts::signed_arithmetic +#define BOOST_MATH_UNSIGNED_ARITHMETIC boost::math::concepts::unsigned_arithmetic +#define BOOST_MATH_ARBITRARY_UNSIGNED_ARITHMETIC boost::math::concepts::arbitrary_unsigned_arithmetic_type +#define BOOST_MATH_ARBITRARY_SIGNED_ARITHMETIC boost::math::concepts::arbitrary_signed_arithmetic_type +#define BOOST_MATH_ARBITRARY_ARITHMETIC boost::math::concepts::arbitrary_arithmetic_type +#define BOOST_MATH_ARBITRARY_UNSIGNED_INTEGER boost::math::concepts::arbitrary_unsigned_integer_type +#define BOOST_MATH_ARBITRARY_SIGNED_INTEGER boost::math::concepts::arbitrary_signed_integer_type +#define BOOST_MATH_ARBITRARY_INTEGER boost::math::concepts::arbitrary_integer_type +#define BOOST_MATH_ARBITRARY_REAL boost::math::concepts::arbitrary_real_type +#define BOOST_MATH_ARBITRARY_COMPLEX boost::math::concepts::arbitrary_complex_type +#define BOOST_MATH_ARBITRARY_REAL_OR_COMPLEX boost::math::concepts::arbitrary_real_or_complex_type #define BOOST_MATH_POLICY boost::math::concepts::policy #define BOOST_MATH_CONTAINER boost::math::concepts::is_container #define BOOST_MATH_RANDOM_ACCESS_CONTAINER boost::math::concepts::random_access_container #define BOOST_MATH_REQUIRES(X, T) requires X // Workaround for LIBCPP versions that have but have not implemented concepts in -#if defined(_LIBCPP_VERSION) && !defined(_LIBCPP___ITERATOR_CONCEPTS_H) +#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 13000 #define BOOST_MATH_FORWARD_ITER boost::math::concepts::forward_iterator #define BOOST_MATH_BIDIRECTIONAL_ITER boost::math::concepts::bidirectional_iterator @@ -233,6 +260,14 @@ concept random_access_container = is_container && # define BOOST_MATH_REAL typename #endif +#ifndef BOOST_MATH_COMPLEX +# define BOOST_MATH_COMPLEX typename +#endif + +#ifndef BOOST_MATH_REAL_OR_COMPLEX +# define BOOST_MATH_REAL_OR_COMPLEX typename +#endif + #ifndef BOOST_MATH_ARITHMETIC # define BOOST_MATH_ARITHMETIC typename #endif @@ -273,6 +308,14 @@ concept random_access_container = is_container && # define BOOST_MATH_ARBITRARY_REAL typename #endif +#ifndef BOOST_MATH_ARBITRARY_COMPLEX +# define BOOST_MATH_ARBITRARY_COMPLEX typename +#endif + +#ifndef BOOST_MATH_ARBITRARY_REAL_OR_COMPLEX +# define BOOST_MATH_ARBITRARY_REAL_OR_COMPLEX typename +#endif + #ifndef BOOST_MATH_POLICY # define BOOST_MATH_POLICY typename #endif From b03cbf5be08616f481da519520fbfa13b3cf2696 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 18 Oct 2022 15:49:13 -0700 Subject: [PATCH 11/16] Add execution policy concept --- include/boost/math/concepts/concepts.hpp | 26 +++++- .../math/statistics/univariate_statistics.hpp | 82 +++++++++---------- 2 files changed, 64 insertions(+), 44 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index 9b09563a9c..fc511ac8e1 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -239,10 +239,26 @@ concept random_access_container = is_container && #define BOOST_MATH_BIDIRECTIONAL_ITER std::bidirectional_iterator #define BOOST_MATH_RANDOM_ACCESS_ITER std::random_access_iterator -#endif +#endif // Workaround for LIBCPP -#endif -#endif +#ifdef BOOST_MATH_EXEC_COMPATIBLE +#include + +namespace boost::math::concepts { + +template +concept execution_policy = std::is_execution_policy_v>; + +} // Namespace boost::math::concepts + +#define BOOST_MATH_EXECUTION_POLICY boost::math::concepts::execution_policy + +#endif // Has + +#endif // Has +#endif // C++20 + +// If concepts are unavailable replace them with typename for compatibility #ifndef BOOST_MATH_INTEGRAL # define BOOST_MATH_INTEGRAL typename @@ -340,6 +356,10 @@ concept random_access_container = is_container && # define BOOST_MATH_RANDOM_ACCESS_CONTAINER typename #endif +#ifndef BOOST_MATH_EXECUTION_POLICY +# define BOOST_MATH_EXECUTION_POLICY typename +#endif + #ifndef BOOST_MATH_REQUIRES # define BOOST_MATH_REQUIRES(X, T) #endif diff --git a/include/boost/math/statistics/univariate_statistics.hpp b/include/boost/math/statistics/univariate_statistics.hpp index 52f8f838a0..595d08c2fe 100644 --- a/include/boost/math/statistics/univariate_statistics.hpp +++ b/include/boost/math/statistics/univariate_statistics.hpp @@ -26,7 +26,7 @@ namespace boost::math::statistics { -template +template inline auto mean(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -56,7 +56,7 @@ inline auto mean(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator } } -template +template inline auto mean(ExecutionPolicy&& exec, Container const & v) { return mean(exec, std::cbegin(v), std::cend(v)); @@ -74,7 +74,7 @@ inline auto mean(Container const & v) return mean(std::execution::seq, std::cbegin(v), std::cend(v)); } -template +template inline auto variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -105,7 +105,7 @@ inline auto variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardItera } } -template +template inline auto variance(ExecutionPolicy&& exec, Container const & v) { return variance(exec, std::cbegin(v), std::cend(v)); @@ -123,7 +123,7 @@ inline auto variance(Container const & v) return variance(std::execution::seq, std::cbegin(v), std::cend(v)); } -template +template inline auto sample_variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { const auto n = std::distance(first, last); @@ -131,7 +131,7 @@ inline auto sample_variance(ExecutionPolicy&& exec, ForwardIterator first, Forwa return n*variance(exec, first, last)/(n-1); } -template +template inline auto sample_variance(ExecutionPolicy&& exec, Container const & v) { return sample_variance(exec, std::cbegin(v), std::cend(v)); @@ -149,7 +149,7 @@ inline auto sample_variance(Container const & v) return sample_variance(std::execution::seq, std::cbegin(v), std::cend(v)); } -template +template inline auto mean_and_sample_variance(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -182,7 +182,7 @@ inline auto mean_and_sample_variance(ExecutionPolicy&& exec, ForwardIterator fir } } -template +template inline auto mean_and_sample_variance(ExecutionPolicy&& exec, Container const & v) { return mean_and_sample_variance(exec, std::cbegin(v), std::cend(v)); @@ -200,7 +200,7 @@ inline auto mean_and_sample_variance(Container const & v) return mean_and_sample_variance(std::execution::seq, std::cbegin(v), std::cend(v)); } -template +template inline auto first_four_moments(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -237,7 +237,7 @@ inline auto first_four_moments(ExecutionPolicy&& exec, ForwardIterator first, Fo } } -template +template inline auto first_four_moments(ExecutionPolicy&& exec, Container const & v) { return first_four_moments(exec, std::cbegin(v), std::cend(v)); @@ -256,7 +256,7 @@ inline auto first_four_moments(Container const & v) } // https://prod.sandia.gov/techlib-noauth/access-control.cgi/2008/086212.pdf -template +template inline auto skewness(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -299,7 +299,7 @@ inline auto skewness(ExecutionPolicy&& exec, ForwardIterator first, ForwardItera } } -template +template inline auto skewness(ExecutionPolicy&& exec, Container & v) { return skewness(exec, std::cbegin(v), std::cend(v)); @@ -319,7 +319,7 @@ inline auto skewness(Container const & v) // Follows equation 1.6 of: // https://prod.sandia.gov/techlib-noauth/access-control.cgi/2008/086212.pdf -template +template inline auto kurtosis(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { const auto [M1, M2, M3, M4] = first_four_moments(exec, first, last); @@ -330,7 +330,7 @@ inline auto kurtosis(ExecutionPolicy&& exec, ForwardIterator first, ForwardItera return M4/(M2*M2); } -template +template inline auto kurtosis(ExecutionPolicy&& exec, Container const & v) { return kurtosis(exec, std::cbegin(v), std::cend(v)); @@ -348,13 +348,13 @@ inline auto kurtosis(Container const & v) return kurtosis(std::execution::seq, std::cbegin(v), std::cend(v)); } -template +template inline auto excess_kurtosis(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { return kurtosis(exec, first, last) - 3; } -template +template inline auto excess_kurtosis(ExecutionPolicy&& exec, Container const & v) { return excess_kurtosis(exec, std::cbegin(v), std::cend(v)); @@ -373,7 +373,7 @@ inline auto excess_kurtosis(Container const & v) } -template +template auto median(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last) { const auto num_elems = std::distance(first, last); @@ -394,7 +394,7 @@ auto median(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIter } -template +template inline auto median(ExecutionPolicy&& exec, RandomAccessContainer & v) { return median(exec, std::begin(v), std::end(v)); @@ -406,13 +406,13 @@ inline auto median(RandomAccessIterator first, RandomAccessIterator last) return median(std::execution::seq, first, last); } -template +template inline auto median(RandomAccessContainer & v) { return median(std::execution::seq, std::begin(v), std::end(v)); } -template +template inline auto gini_coefficient(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last) { using Real = typename std::iterator_traits::value_type; @@ -445,7 +445,7 @@ inline auto gini_coefficient(ExecutionPolicy&& exec, RandomAccessIterator first, } } -template +template inline auto gini_coefficient(ExecutionPolicy&& exec, RandomAccessContainer & v) { return gini_coefficient(exec, std::begin(v), std::end(v)); @@ -457,20 +457,20 @@ inline auto gini_coefficient(RandomAccessIterator first, RandomAccessIterator la return gini_coefficient(std::execution::seq, first, last); } -template +template inline auto gini_coefficient(RandomAccessContainer & v) { return gini_coefficient(std::execution::seq, std::begin(v), std::end(v)); } -template +template inline auto sample_gini_coefficient(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last) { const auto n = std::distance(first, last); return n*gini_coefficient(exec, first, last)/(n-1); } -template +template inline auto sample_gini_coefficient(ExecutionPolicy&& exec, RandomAccessContainer & v) { return sample_gini_coefficient(exec, std::begin(v), std::end(v)); @@ -482,13 +482,13 @@ inline auto sample_gini_coefficient(RandomAccessIterator first, RandomAccessIter return sample_gini_coefficient(std::execution::seq, first, last); } -template +template inline auto sample_gini_coefficient(RandomAccessContainer & v) { return sample_gini_coefficient(std::execution::seq, std::begin(v), std::end(v)); } -template +template auto median_absolute_deviation(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last, typename std::iterator_traits::value_type center=std::numeric_limits::value_type>::quiet_NaN()) { @@ -517,7 +517,7 @@ auto median_absolute_deviation(ExecutionPolicy&& exec, RandomAccessIterator firs } } -template +template inline auto median_absolute_deviation(ExecutionPolicy&& exec, RandomAccessContainer & v, typename RandomAccessContainer::value_type center=std::numeric_limits::quiet_NaN()) { @@ -531,14 +531,14 @@ inline auto median_absolute_deviation(RandomAccessIterator first, RandomAccessIt return median_absolute_deviation(std::execution::seq, first, last, center); } -template +template inline auto median_absolute_deviation(RandomAccessContainer & v, typename RandomAccessContainer::value_type center=std::numeric_limits::quiet_NaN()) { return median_absolute_deviation(std::execution::seq, std::begin(v), std::end(v), center); } -template +template auto interquartile_range(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { using Real = typename std::iterator_traits::value_type; @@ -579,7 +579,7 @@ auto interquartile_range(ExecutionPolicy&& exec, ForwardIterator first, ForwardI } } -template +template inline auto interquartile_range(ExecutionPolicy&& exec, RandomAccessContainer & v) { return interquartile_range(exec, std::begin(v), std::end(v)); @@ -591,13 +591,13 @@ inline auto interquartile_range(RandomAccessIterator first, RandomAccessIterator return interquartile_range(std::execution::seq, first, last); } -template +template inline auto interquartile_range(RandomAccessContainer & v) { return interquartile_range(std::execution::seq, std::begin(v), std::end(v)); } -template +template inline OutputIterator mode(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, OutputIterator output) { if(!std::is_sorted(exec, first, last)) @@ -615,7 +615,7 @@ inline OutputIterator mode(ExecutionPolicy&& exec, ForwardIterator first, Forwar return detail::mode_impl(first, last, output); } -template +template inline OutputIterator mode(ExecutionPolicy&& exec, Container & v, OutputIterator output) { return mode(exec, std::begin(v), std::end(v), output); @@ -643,7 +643,7 @@ inline OutputIterator mode(Container & v, OutputIterator output) // std::list is the return type for the proposed STL stats library -template::value_type> +template::value_type> inline auto mode(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { std::list modes; @@ -651,7 +651,7 @@ inline auto mode(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator return modes; } -template +template inline auto mode(ExecutionPolicy&& exec, Container & v) { return mode(exec, std::begin(v), std::end(v)); @@ -953,7 +953,7 @@ Real median(RandomAccessIterator first, RandomAccessIterator last) } } -template +template inline Real median(RandomAccessContainer& c) { return median(std::begin(c), std::end(c)); @@ -971,7 +971,7 @@ inline double gini_coefficient(RandomAccessIterator first, RandomAccessIterator return detail::gini_coefficient_sequential_impl(first, last); } -template::value, bool> = true> inline double gini_coefficient(RandomAccessContainer& c) { @@ -990,7 +990,7 @@ inline Real gini_coefficient(RandomAccessIterator first, RandomAccessIterator la return detail::gini_coefficient_sequential_impl(first, last); } -template::value, bool> = true> inline Real gini_coefficient(RandomAccessContainer& c) { @@ -1005,7 +1005,7 @@ inline double sample_gini_coefficient(RandomAccessIterator first, RandomAccessIt return n*gini_coefficient(first, last)/(n-1); } -template::value, bool> = true> inline double sample_gini_coefficient(RandomAccessContainer& c) { @@ -1020,7 +1020,7 @@ inline Real sample_gini_coefficient(RandomAccessIterator first, RandomAccessIter return n*gini_coefficient(first, last)/(n-1); } -template::value, bool> = true> inline Real sample_gini_coefficient(RandomAccessContainer& c) { @@ -1055,7 +1055,7 @@ Real median_absolute_deviation(RandomAccessIterator first, RandomAccessIterator } } -template +template inline Real median_absolute_deviation(RandomAccessContainer& c, typename RandomAccessContainer::value_type center=std::numeric_limits::quiet_NaN()) { From 6bd07ec732d37e455a11fe98635fa4b7a499d5ae Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 18 Oct 2022 16:23:47 -0700 Subject: [PATCH 12/16] Add any numerical type (int, floating, complex) concept --- include/boost/math/concepts/concepts.hpp | 17 +++ .../math/statistics/univariate_statistics.hpp | 119 +++++++++--------- 2 files changed, 77 insertions(+), 59 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index fc511ac8e1..25fad1ef0b 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -111,6 +111,9 @@ concept real_or_complex = real || complex; template concept arithmetic = std::is_arithmetic_v; +template +concept numerical = arithmetic || real_or_complex; + template concept signed_arithmetic = arithmetic && std::is_signed_v; @@ -165,6 +168,10 @@ template concept arbitrary_real_or_complex_type = arbitrary_real_type || arbitrary_complex_type; +template +concept arbitrary_numerical_type = arbitrary_real_or_complex_type || + arbitrary_arithmetic_type; + template concept policy = boost::math::policies::is_policy::value; @@ -210,6 +217,7 @@ concept random_access_container = is_container && #define BOOST_MATH_COMPLEX boost::math::concepts::complex #define BOOST_MATH_REAL_OR_COMPLEX boost::math::concepts::real_or_complex #define BOOST_MATH_ARITHMETIC boost::math::concepts::arithmetic +#define BOOST_MATH_NUMERICAL boost::math::concepts::numerical #define BOOST_MATH_SIGNED_ARITHMETIC boost::math::concepts::signed_arithmetic #define BOOST_MATH_UNSIGNED_ARITHMETIC boost::math::concepts::unsigned_arithmetic #define BOOST_MATH_ARBITRARY_UNSIGNED_ARITHMETIC boost::math::concepts::arbitrary_unsigned_arithmetic_type @@ -221,6 +229,7 @@ concept random_access_container = is_container && #define BOOST_MATH_ARBITRARY_REAL boost::math::concepts::arbitrary_real_type #define BOOST_MATH_ARBITRARY_COMPLEX boost::math::concepts::arbitrary_complex_type #define BOOST_MATH_ARBITRARY_REAL_OR_COMPLEX boost::math::concepts::arbitrary_real_or_complex_type +#define BOOST_MATH_ARBITRARY_NUMERICAL boost::math::concepts::arbitrary_numerical_type #define BOOST_MATH_POLICY boost::math::concepts::policy #define BOOST_MATH_CONTAINER boost::math::concepts::is_container #define BOOST_MATH_RANDOM_ACCESS_CONTAINER boost::math::concepts::random_access_container @@ -288,6 +297,10 @@ concept execution_policy = std::is_execution_policy_v>; # define BOOST_MATH_ARITHMETIC typename #endif +#ifndef BOOST_MATH_NUMERICAL +# define BOOST_MATH_NUMERICAL typename +#endif + #ifndef BOOST_MATH_SIGNED_ARITHMETIC # define BOOST_MATH_SIGNED_ARITHMETIC typename #endif @@ -332,6 +345,10 @@ concept execution_policy = std::is_execution_policy_v>; # define BOOST_MATH_ARBITRARY_REAL_OR_COMPLEX typename #endif +#ifndef BOOST_MATH_ARBITRARY_NUMERICAL +# define BOOST_MATH_ARBITRARY_NUMERICAL typename +#endif + #ifndef BOOST_MATH_POLICY # define BOOST_MATH_POLICY typename #endif diff --git a/include/boost/math/statistics/univariate_statistics.hpp b/include/boost/math/statistics/univariate_statistics.hpp index 595d08c2fe..1bbdb43cd1 100644 --- a/include/boost/math/statistics/univariate_statistics.hpp +++ b/include/boost/math/statistics/univariate_statistics.hpp @@ -373,7 +373,7 @@ inline auto excess_kurtosis(Container const & v) } -template +template auto median(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last) { const auto num_elems = std::distance(first, last); @@ -400,7 +400,7 @@ inline auto median(ExecutionPolicy&& exec, RandomAccessContainer & v) return median(exec, std::begin(v), std::end(v)); } -template +template inline auto median(RandomAccessIterator first, RandomAccessIterator last) { return median(std::execution::seq, first, last); @@ -412,7 +412,7 @@ inline auto median(RandomAccessContainer & v) return median(std::execution::seq, std::begin(v), std::end(v)); } -template +template inline auto gini_coefficient(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last) { using Real = typename std::iterator_traits::value_type; @@ -451,7 +451,7 @@ inline auto gini_coefficient(ExecutionPolicy&& exec, RandomAccessContainer & v) return gini_coefficient(exec, std::begin(v), std::end(v)); } -template +template inline auto gini_coefficient(RandomAccessIterator first, RandomAccessIterator last) { return gini_coefficient(std::execution::seq, first, last); @@ -463,7 +463,7 @@ inline auto gini_coefficient(RandomAccessContainer & v) return gini_coefficient(std::execution::seq, std::begin(v), std::end(v)); } -template +template inline auto sample_gini_coefficient(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last) { const auto n = std::distance(first, last); @@ -476,7 +476,7 @@ inline auto sample_gini_coefficient(ExecutionPolicy&& exec, RandomAccessContaine return sample_gini_coefficient(exec, std::begin(v), std::end(v)); } -template +template inline auto sample_gini_coefficient(RandomAccessIterator first, RandomAccessIterator last) { return sample_gini_coefficient(std::execution::seq, first, last); @@ -488,7 +488,7 @@ inline auto sample_gini_coefficient(RandomAccessContainer & v) return sample_gini_coefficient(std::execution::seq, std::begin(v), std::end(v)); } -template +template auto median_absolute_deviation(ExecutionPolicy&& exec, RandomAccessIterator first, RandomAccessIterator last, typename std::iterator_traits::value_type center=std::numeric_limits::value_type>::quiet_NaN()) { @@ -524,7 +524,7 @@ inline auto median_absolute_deviation(ExecutionPolicy&& exec, RandomAccessContai return median_absolute_deviation(exec, std::begin(v), std::end(v), center); } -template +template inline auto median_absolute_deviation(RandomAccessIterator first, RandomAccessIterator last, typename RandomAccessIterator::value_type center=std::numeric_limits::quiet_NaN()) { @@ -585,7 +585,7 @@ inline auto interquartile_range(ExecutionPolicy&& exec, RandomAccessContainer & return interquartile_range(exec, std::begin(v), std::end(v)); } -template +template inline auto interquartile_range(RandomAccessIterator first, RandomAccessIterator last) { return interquartile_range(std::execution::seq, first, last); @@ -643,10 +643,11 @@ inline OutputIterator mode(Container & v, OutputIterator output) // std::list is the return type for the proposed STL stats library -template::value_type> +template::value_type> inline auto mode(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last) { - std::list modes; + std::list modes; mode(exec, first, last, std::inserter(modes, modes.begin())); return modes; } @@ -678,7 +679,7 @@ namespace boost { namespace math { namespace statistics { template using enable_if_t = typename std::enable_if::type; -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double mean(const ForwardIterator first, const ForwardIterator last) { @@ -686,14 +687,14 @@ inline double mean(const ForwardIterator first, const ForwardIterator last) return detail::mean_sequential_impl(first, last); } -template::value, bool> = true> inline double mean(const Container& c) { return mean(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real mean(const ForwardIterator first, const ForwardIterator last) { @@ -701,28 +702,28 @@ inline Real mean(const ForwardIterator first, const ForwardIterator last) return detail::mean_sequential_impl(first, last); } -template::value, bool> = true> inline Real mean(const Container& c) { return mean(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double variance(const ForwardIterator first, const ForwardIterator last) { return std::get<2>(detail::variance_sequential_impl>(first, last)); } -template::value, bool> = true> inline double variance(const Container& c) { return variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real variance(const ForwardIterator first, const ForwardIterator last) { @@ -730,14 +731,14 @@ inline Real variance(const ForwardIterator first, const ForwardIterator last) } -template::value, bool> = true> inline Real variance(const Container& c) { return variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double sample_variance(const ForwardIterator first, const ForwardIterator last) { @@ -746,14 +747,14 @@ inline double sample_variance(const ForwardIterator first, const ForwardIterator return n*variance(first, last)/(n-1); } -template::value, bool> = true> inline double sample_variance(const Container& c) { return sample_variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real sample_variance(const ForwardIterator first, const ForwardIterator last) { @@ -762,14 +763,14 @@ inline Real sample_variance(const ForwardIterator first, const ForwardIterator l return n*variance(first, last)/(n-1); } -template::value, bool> = true> inline Real sample_variance(const Container& c) { return sample_variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline std::pair mean_and_sample_variance(const ForwardIterator first, const ForwardIterator last) { @@ -777,14 +778,14 @@ inline std::pair mean_and_sample_variance(const ForwardIterator return std::make_pair(std::get<0>(results), std::get<3>(results)*std::get<2>(results)/(std::get<3>(results)-1.0)); } -template::value, bool> = true> inline std::pair mean_and_sample_variance(const Container& c) { return mean_and_sample_variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline std::pair mean_and_sample_variance(const ForwardIterator first, const ForwardIterator last) { @@ -792,14 +793,14 @@ inline std::pair mean_and_sample_variance(const ForwardIterator firs return std::make_pair(std::get<0>(results), std::get<3>(results)*std::get<2>(results)/(std::get<3>(results)-Real(1))); } -template::value, bool> = true> inline std::pair mean_and_sample_variance(const Container& c) { return mean_and_sample_variance(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline std::tuple first_four_moments(const ForwardIterator first, const ForwardIterator last) { @@ -808,14 +809,14 @@ inline std::tuple first_four_moments(const Forwa std::get<3>(results) / std::get<4>(results)); } -template::value, bool> = true> inline std::tuple first_four_moments(const Container& c) { return first_four_moments(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline std::tuple first_four_moments(const ForwardIterator first, const ForwardIterator last) { @@ -824,42 +825,42 @@ inline std::tuple first_four_moments(const ForwardIterat std::get<3>(results) / std::get<4>(results)); } -template::value, bool> = true> inline std::tuple first_four_moments(const Container& c) { return first_four_moments(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double skewness(const ForwardIterator first, const ForwardIterator last) { return detail::skewness_sequential_impl(first, last); } -template::value, bool> = true> inline double skewness(const Container& c) { return skewness(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real skewness(const ForwardIterator first, const ForwardIterator last) { return detail::skewness_sequential_impl(first, last); } -template::value, bool> = true> inline Real skewness(const Container& c) { return skewness(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double kurtosis(const ForwardIterator first, const ForwardIterator last) { @@ -875,14 +876,14 @@ inline double kurtosis(const ForwardIterator first, const ForwardIterator last) } } -template::value, bool> = true> inline double kurtosis(const Container& c) { return kurtosis(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real kurtosis(const ForwardIterator first, const ForwardIterator last) { @@ -898,42 +899,42 @@ inline Real kurtosis(const ForwardIterator first, const ForwardIterator last) } } -template::value, bool> = true> inline Real kurtosis(const Container& c) { return kurtosis(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double excess_kurtosis(const ForwardIterator first, const ForwardIterator last) { return kurtosis(first, last) - 3; } -template::value, bool> = true> inline double excess_kurtosis(const Container& c) { return excess_kurtosis(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real excess_kurtosis(const ForwardIterator first, const ForwardIterator last) { return kurtosis(first, last) - 3; } -template::value, bool> = true> inline Real excess_kurtosis(const Container& c) { return excess_kurtosis(std::begin(c), std::end(c)); } -template::value_type> +template::value_type> Real median(RandomAccessIterator first, RandomAccessIterator last) { const auto num_elems = std::distance(first, last); @@ -953,13 +954,13 @@ Real median(RandomAccessIterator first, RandomAccessIterator last) } } -template +template inline Real median(RandomAccessContainer& c) { return median(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double gini_coefficient(RandomAccessIterator first, RandomAccessIterator last) { @@ -971,14 +972,14 @@ inline double gini_coefficient(RandomAccessIterator first, RandomAccessIterator return detail::gini_coefficient_sequential_impl(first, last); } -template::value, bool> = true> inline double gini_coefficient(RandomAccessContainer& c) { return gini_coefficient(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real gini_coefficient(RandomAccessIterator first, RandomAccessIterator last) { @@ -990,14 +991,14 @@ inline Real gini_coefficient(RandomAccessIterator first, RandomAccessIterator la return detail::gini_coefficient_sequential_impl(first, last); } -template::value, bool> = true> inline Real gini_coefficient(RandomAccessContainer& c) { return gini_coefficient(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline double sample_gini_coefficient(RandomAccessIterator first, RandomAccessIterator last) { @@ -1005,14 +1006,14 @@ inline double sample_gini_coefficient(RandomAccessIterator first, RandomAccessIt return n*gini_coefficient(first, last)/(n-1); } -template::value, bool> = true> inline double sample_gini_coefficient(RandomAccessContainer& c) { return sample_gini_coefficient(std::begin(c), std::end(c)); } -template::value_type, +template::value_type, enable_if_t::value, bool> = true> inline Real sample_gini_coefficient(RandomAccessIterator first, RandomAccessIterator last) { @@ -1020,14 +1021,14 @@ inline Real sample_gini_coefficient(RandomAccessIterator first, RandomAccessIter return n*gini_coefficient(first, last)/(n-1); } -template::value, bool> = true> inline Real sample_gini_coefficient(RandomAccessContainer& c) { return sample_gini_coefficient(std::begin(c), std::end(c)); } -template::value_type> +template::value_type> Real median_absolute_deviation(RandomAccessIterator first, RandomAccessIterator last, typename std::iterator_traits::value_type center=std::numeric_limits::value_type>::quiet_NaN()) { @@ -1055,14 +1056,14 @@ Real median_absolute_deviation(RandomAccessIterator first, RandomAccessIterator } } -template +template inline Real median_absolute_deviation(RandomAccessContainer& c, typename RandomAccessContainer::value_type center=std::numeric_limits::quiet_NaN()) { return median_absolute_deviation(std::begin(c), std::end(c), center); } -template::value_type> +template::value_type> Real interquartile_range(ForwardIterator first, ForwardIterator last) { static_assert(!std::is_integral::value, "Integer values have not yet been implemented."); @@ -1104,7 +1105,7 @@ Real interquartile_range(ForwardIterator first, ForwardIterator last) } } -template +template Real interquartile_range(Container& c) { return interquartile_range(std::begin(c), std::end(c)); @@ -1140,7 +1141,7 @@ inline OutputIterator mode(Container& c, OutputIterator output) return mode(std::begin(c), std::end(c), output); } -template::value_type> +template::value_type> inline std::list mode(ForwardIterator first, ForwardIterator last) { std::list modes; @@ -1148,7 +1149,7 @@ inline std::list mode(ForwardIterator first, ForwardIterator last) return modes; } -template +template inline std::list mode(Container& c) { return mode(std::begin(c), std::end(c)); From 5b81a37d4b8c92a827dc9e48c75248dee95a230a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 19 Oct 2022 10:01:24 -0700 Subject: [PATCH 13/16] Remove libc++ workaround --- include/boost/math/concepts/concepts.hpp | 48 ++++++++----------- .../math/statistics/univariate_statistics.hpp | 4 ++ 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index 25fad1ef0b..85d6ccb0ce 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -175,30 +175,18 @@ concept arbitrary_numerical_type = arbitrary_real_or_complex_type || template concept policy = boost::math::policies::is_policy::value; -// Workaround for LIBCPP versions that have but have not implemented concepts in -#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 13000 - -template -concept forward_iterator = std::is_same_v::iterator_category(), std::forward_iterator_tag>; - -template -concept bidirectional_iterator = std::is_same_v::iterator_category(), std::bidirectional_iterator_tag>; - template -concept random_access_iterator = std::is_same_v::iterator_category(), std::random_access_iterator_tag>; - -#else +concept forward_iterator = std::derived_from::iterator_category, std::forward_iterator_tag>; template -concept forward_iterator = std::forward_iterator; +concept bidirectional_iterator = std::derived_from::iterator_category, std::bidirectional_iterator_tag>; template -concept bidirectional_iterator = std::bidirectional_iterator; +concept random_access_iterator = std::derived_from::iterator_category, std::random_access_iterator_tag>; -template -concept random_access_iterator = std::random_access_iterator; - -#endif +template +concept output_iterator = std::derived_from::iterator_category, std::input_iterator_tag> && + std::derived_from::iterator_category, std::output_iterator_tag>; template concept is_container = detail::has_begin_v && @@ -230,25 +218,19 @@ concept random_access_container = is_container && #define BOOST_MATH_ARBITRARY_COMPLEX boost::math::concepts::arbitrary_complex_type #define BOOST_MATH_ARBITRARY_REAL_OR_COMPLEX boost::math::concepts::arbitrary_real_or_complex_type #define BOOST_MATH_ARBITRARY_NUMERICAL boost::math::concepts::arbitrary_numerical_type + #define BOOST_MATH_POLICY boost::math::concepts::policy + #define BOOST_MATH_CONTAINER boost::math::concepts::is_container #define BOOST_MATH_RANDOM_ACCESS_CONTAINER boost::math::concepts::random_access_container -#define BOOST_MATH_REQUIRES(X, T) requires X - -// Workaround for LIBCPP versions that have but have not implemented concepts in -#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 13000 #define BOOST_MATH_FORWARD_ITER boost::math::concepts::forward_iterator #define BOOST_MATH_BIDIRECTIONAL_ITER boost::math::concepts::bidirectional_iterator #define BOOST_MATH_RANDOM_ACCESS_ITER boost::math::concepts::random_access_iterator +#define BOOST_MATH_OUTPUT_ITER(I, T) boost::math::concepts::output_iterator +#define BOOST_MATH_REQUIRES_ITER(X) requires X -#else - -#define BOOST_MATH_FORWARD_ITER std::forward_iterator -#define BOOST_MATH_BIDIRECTIONAL_ITER std::bidirectional_iterator -#define BOOST_MATH_RANDOM_ACCESS_ITER std::random_access_iterator - -#endif // Workaround for LIBCPP +#define BOOST_MATH_REQUIRES(X, T) requires X #ifdef BOOST_MATH_EXEC_COMPATIBLE #include @@ -365,6 +347,14 @@ concept execution_policy = std::is_execution_policy_v>; # define BOOST_MATH_RANDOM_ACCESS_ITER typename #endif +#ifndef BOOST_MATH_OUTPUT_ITER +# define BOOST_MATH_OUTPUT_ITER(I, T) +#endif + +#ifndef BOOST_MATH_REQUIRES_ITER +# define BOOST_MATH_REQUIRES_ITER(X) +#endif + #ifndef BOOST_MATH_CONTAINER # define BOOST_MATH_CONTAINER typename #endif diff --git a/include/boost/math/statistics/univariate_statistics.hpp b/include/boost/math/statistics/univariate_statistics.hpp index 1bbdb43cd1..35a0b25ac6 100644 --- a/include/boost/math/statistics/univariate_statistics.hpp +++ b/include/boost/math/statistics/univariate_statistics.hpp @@ -598,6 +598,7 @@ inline auto interquartile_range(RandomAccessContainer & v) } template + BOOST_MATH_REQUIRES_ITER(BOOST_MATH_OUTPUT_ITER(ForwardIterator, OutputIterator)) inline OutputIterator mode(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last, OutputIterator output) { if(!std::is_sorted(exec, first, last)) @@ -616,12 +617,14 @@ inline OutputIterator mode(ExecutionPolicy&& exec, ForwardIterator first, Forwar } template + BOOST_MATH_REQUIRES_ITER(BOOST_MATH_OUTPUT_ITER(typename Container::iterator, OutputIterator)) inline OutputIterator mode(ExecutionPolicy&& exec, Container & v, OutputIterator output) { return mode(exec, std::begin(v), std::end(v), output); } template + BOOST_MATH_REQUIRES_ITER(BOOST_MATH_OUTPUT_ITER(ForwardIterator, OutputIterator)) inline OutputIterator mode(ForwardIterator first, ForwardIterator last, OutputIterator output) { return mode(std::execution::seq, first, last, output); @@ -636,6 +639,7 @@ template #endif , bool> = true> + BOOST_MATH_REQUIRES_ITER(BOOST_MATH_OUTPUT_ITER(typename Container::iterator, OutputIterator)) inline OutputIterator mode(Container & v, OutputIterator output) { return mode(std::execution::seq, std::begin(v), std::end(v), output); From 3420530786df95b5587cf62e947a78b67999d972 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 19 Oct 2022 12:26:52 -0700 Subject: [PATCH 14/16] Define our own derived_from as std not available on all platforms --- include/boost/math/concepts/concepts.hpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/include/boost/math/concepts/concepts.hpp b/include/boost/math/concepts/concepts.hpp index 85d6ccb0ce..e0ee3646ea 100644 --- a/include/boost/math/concepts/concepts.hpp +++ b/include/boost/math/concepts/concepts.hpp @@ -175,18 +175,22 @@ concept arbitrary_numerical_type = arbitrary_real_or_complex_type || template concept policy = boost::math::policies::is_policy::value; +template +concept derived_from = std::is_base_of_v && + std::is_convertible_v; + template -concept forward_iterator = std::derived_from::iterator_category, std::forward_iterator_tag>; +concept forward_iterator = derived_from::iterator_category, std::forward_iterator_tag>; template -concept bidirectional_iterator = std::derived_from::iterator_category, std::bidirectional_iterator_tag>; +concept bidirectional_iterator = derived_from::iterator_category, std::bidirectional_iterator_tag>; template -concept random_access_iterator = std::derived_from::iterator_category, std::random_access_iterator_tag>; +concept random_access_iterator = derived_from::iterator_category, std::random_access_iterator_tag>; template -concept output_iterator = std::derived_from::iterator_category, std::input_iterator_tag> && - std::derived_from::iterator_category, std::output_iterator_tag>; +concept output_iterator = derived_from::iterator_category, std::input_iterator_tag> && + derived_from::iterator_category, std::output_iterator_tag>; template concept is_container = detail::has_begin_v && From 7fa561dd59f71cef96b1ec46fe7ec97087e6185b Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Fri, 11 Nov 2022 18:38:31 +0000 Subject: [PATCH 15/16] Update log1p for concept tests. --- .../boost/math/special_functions/log1p.hpp | 23 ++++++++++--------- .../boost/math/special_functions/math_fwd.hpp | 9 ++++---- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/include/boost/math/special_functions/log1p.hpp b/include/boost/math/special_functions/log1p.hpp index 8121a573cd..b3ecf4cbaa 100644 --- a/include/boost/math/special_functions/log1p.hpp +++ b/include/boost/math/special_functions/log1p.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #if defined(__GNUC__) && defined(BOOST_MATH_USE_FLOAT128) // @@ -293,7 +294,7 @@ const typename log1p_initializer::init log1p_initializer +template inline typename tools::promote_args::type log1p(T x, const Policy&) { typedef typename tools::promote_args::type result_type; @@ -327,7 +328,7 @@ inline typename tools::promote_args::type log1p(T x, const Policy&) #if defined(BOOST_HAS_LOG1P) && !(defined(__osf__) && defined(__DECCXX_VER)) # ifdef BOOST_MATH_USE_C99 -template +template inline float log1p(float x, const Policy& pol) { if(x < -1) @@ -339,7 +340,7 @@ inline float log1p(float x, const Policy& pol) return ::log1pf(x); } #ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS -template +template inline long double log1p(long double x, const Policy& pol) { if(x < -1) @@ -352,7 +353,7 @@ inline long double log1p(long double x, const Policy& pol) } #endif #else -template +template inline float log1p(float x, const Policy& pol) { if(x < -1) @@ -364,7 +365,7 @@ inline float log1p(float x, const Policy& pol) return ::log1p(x); } #endif -template +template inline double log1p(double x, const Policy& pol) { if(x < -1) @@ -381,7 +382,7 @@ inline double log1p(double x, const Policy& pol) // that your compilers optimizer won't mess this code up!! // Currently tested with VC8 and Intel 9.1. // -template +template inline double log1p(double x, const Policy& pol) { if(x < -1) @@ -396,7 +397,7 @@ inline double log1p(double x, const Policy& pol) else return ::log(u)*(x/(u-1.0)); } -template +template inline float log1p(float x, const Policy& pol) { return static_cast(boost::math::log1p(static_cast(x), pol)); @@ -406,7 +407,7 @@ inline float log1p(float x, const Policy& pol) // For some reason this fails to compile under WinCE... // Needs more investigation. // -template +template inline long double log1p(long double x, const Policy& pol) { if(x < -1) @@ -424,7 +425,7 @@ inline long double log1p(long double x, const Policy& pol) #endif #endif -template +template inline typename tools::promote_args::type log1p(T x) { return boost::math::log1p(x, policies::policy<>()); @@ -432,7 +433,7 @@ inline typename tools::promote_args::type log1p(T x) // // Compute log(1+x)-x: // -template +template inline typename tools::promote_args::type log1pmx(T x, const Policy& pol) { @@ -464,7 +465,7 @@ inline typename tools::promote_args::type return result; } -template +template inline typename tools::promote_args::type log1pmx(T x) { return log1pmx(x, policies::policy<>()); diff --git a/include/boost/math/special_functions/math_fwd.hpp b/include/boost/math/special_functions/math_fwd.hpp index 6f9d739e1e..1ee35473f4 100644 --- a/include/boost/math/special_functions/math_fwd.hpp +++ b/include/boost/math/special_functions/math_fwd.hpp @@ -29,6 +29,7 @@ #include #include // for argument promotion. #include +#include #define BOOST_NO_MACRO_EXPAND /**/ @@ -567,17 +568,17 @@ namespace boost typename tools::promote_args::type cbrt(RT z, const Policy&); // log1p is log(x + 1) - template + template typename tools::promote_args::type log1p(T); - template + template typename tools::promote_args::type log1p(T, const Policy&); // log1pmx is log(x + 1) - x - template + template typename tools::promote_args::type log1pmx(T); - template + template typename tools::promote_args::type log1pmx(T, const Policy&); // Exp (x) minus 1 functions. From 2f889d47e153125fb83aadc5212e284b90665fb4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Sat, 19 Nov 2022 11:52:29 -0800 Subject: [PATCH 16/16] Change concept to allow integer promotion to double a la STL --- include/boost/math/special_functions/log1p.hpp | 8 ++++---- include/boost/math/special_functions/math_fwd.hpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/boost/math/special_functions/log1p.hpp b/include/boost/math/special_functions/log1p.hpp index b3ecf4cbaa..877ec214d9 100644 --- a/include/boost/math/special_functions/log1p.hpp +++ b/include/boost/math/special_functions/log1p.hpp @@ -294,7 +294,7 @@ const typename log1p_initializer::init log1p_initializer +template inline typename tools::promote_args::type log1p(T x, const Policy&) { typedef typename tools::promote_args::type result_type; @@ -425,7 +425,7 @@ inline long double log1p(long double x, const Policy& pol) #endif #endif -template +template inline typename tools::promote_args::type log1p(T x) { return boost::math::log1p(x, policies::policy<>()); @@ -433,7 +433,7 @@ inline typename tools::promote_args::type log1p(T x) // // Compute log(1+x)-x: // -template +template inline typename tools::promote_args::type log1pmx(T x, const Policy& pol) { @@ -465,7 +465,7 @@ inline typename tools::promote_args::type return result; } -template +template inline typename tools::promote_args::type log1pmx(T x) { return log1pmx(x, policies::policy<>()); diff --git a/include/boost/math/special_functions/math_fwd.hpp b/include/boost/math/special_functions/math_fwd.hpp index 1ee35473f4..0ba43b5ae5 100644 --- a/include/boost/math/special_functions/math_fwd.hpp +++ b/include/boost/math/special_functions/math_fwd.hpp @@ -568,17 +568,17 @@ namespace boost typename tools::promote_args::type cbrt(RT z, const Policy&); // log1p is log(x + 1) - template + template typename tools::promote_args::type log1p(T); - template + template typename tools::promote_args::type log1p(T, const Policy&); // log1pmx is log(x + 1) - x - template + template typename tools::promote_args::type log1pmx(T); - template + template typename tools::promote_args::type log1pmx(T, const Policy&); // Exp (x) minus 1 functions.