diff --git a/doc/math.qbk b/doc/math.qbk index e807897f93..b406259026 100644 --- a/doc/math.qbk +++ b/doc/math.qbk @@ -767,6 +767,7 @@ and as a CD ISBN 0-9504833-2-X 978-0-9504833-2-0, Classification 519.2-dc22. [endmathpart] [mathpart quadrature Quadrature and Differentiation] +[include quadrature/van_den_bos_unit_square.qbk] [include quadrature/trapezoidal.qbk] [include quadrature/gauss.qbk] [include quadrature/gauss_kronrod.qbk] diff --git a/doc/quadrature/van_den_bos_unit_square.qbk b/doc/quadrature/van_den_bos_unit_square.qbk new file mode 100644 index 0000000000..251dfa68ce --- /dev/null +++ b/doc/quadrature/van_den_bos_unit_square.qbk @@ -0,0 +1,105 @@ +[/ +Copyright (c) 2026 Nicholas Thompson and Matt Borland +Use, modification and distribution are subject to the +Boost Software License, Version 1.0. (See accompanying file +LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[section:van_den_bos_unit_square Van den Bos Unit-Square Quadrature] + +[heading Synopsis] + + #include + namespace boost { namespace math { namespace quadrature { + + template + auto van_den_bos_unit_square( + F const& f, + double tolerance, + double* error_estimate = nullptr, + double* L1 = nullptr, + std::size_t* evaluations = nullptr); + + }}} // namespaces + +[heading Description] + +`van_den_bos_unit_square` computes an adaptive positive cubature of a +real- or complex-valued function over the reference square [0,1]^2. The +integrand receives the two coordinates as separate `double` arguments. For a +physical domain, map the coordinates and include the Jacobian in the +integrand. + +The precomputed rules form a nested hierarchy. After the first level, +only points newly introduced by the next level are evaluated. The routine +requires two consecutive adjacent-level differences to satisfy `tolerance` +before stopping, which avoids accepting an isolated cancellation. If the +maximum level is reached first, the last rule is returned and its difference +is used as the final `error_estimate` (subject to the roundoff floor). + +The optional `L1` output is the weighted sum of the absolute integrand values. +`evaluations` reports the number of function calls, including calls reused by +all subsequent levels. The supported result types are `float` and `double`, +including complex values with `float` or `double` components. Higher-precision +return types do not increase the precision of the nodes or weights and are not +supported. + +The header and generated tables require C++17. Table construction is +performed offline in `cpp_bin_float_quad`; emitted nodes and weights are +rounded once to binary64 hexadecimal literals. The reproducible generator is +`tools/dump_van_den_bos_unit_square.cpp`. No rules are constructed at runtime. +If the requested tolerance is not reached by the final precomputed level, the +routine returns that level's result and error estimate; it does not compute +additional levels. + +Positive cubature rules satisfying the same moment conditions are not unique. +The stored nodes and weights are one reproducible construction; different +candidate sets or valid reduction paths can produce different positive nested +rules with the same polynomial exactness. + +[heading Dilogarithm example] + +For a smooth special-function example, consider +[$\int_0^1\!\int_0^1 (1-xy/2)^{-1}\,dx\,dy += \pi^2/6-\log^2 2]. + + using boost::math::quadrature::van_den_bos_unit_square; + + double error = 0; + double value = van_den_bos_unit_square( + [](double x, double y) + { + return 1 / (1 - x * y / 2); + }, + 1e-10, + &error); + +[heading Square-lattice Green function] + +The resolvent of the nearest-neighbor square lattice gives the genuinely +two-dimensional periodic integral +[$G(z)=\int_0^1\!\int_0^1 +(z-\cos(2\pi x)-\cos(2\pi y))^{-1}\,dx\,dy]. For [^z > 2], its +closed form is [$G(z)=2K(2/z)/(\pi z)], where [^K] is the complete elliptic +integral of the first kind. For example, [^z = 3] can be computed with + + double const z = 3; + double const two_pi = 2 * boost::math::constants::pi(); + double value = van_den_bos_unit_square( + [=](double x, double y) + { + return 1 / (z - std::cos(two_pi * x) + - std::cos(two_pi * y)); + }, + 1e-6); + +The lattice value [^z = 2], and the parameter value [^z = 1] in the +dilogarithm family [$(1-zxy)^{-1}], give improper integrals. Singular +integrands generally require special treatment and should not be expected to +have reliable adjacent-level error estimates from this routine. + +The construction follows the positive, nested reduction approach of +[@https://arxiv.org/abs/1809.09842 van den Bos et al.], adapted here to the +uniform measure on the unit square. + +[endsect] [/section:van_den_bos_unit_square Van den Bos Unit-Square Quadrature] diff --git a/include/boost/math/quadrature/detail/van_den_bos_unit_square_tables.hpp b/include/boost/math/quadrature/detail/van_den_bos_unit_square_tables.hpp new file mode 100644 index 0000000000..46f8844f28 --- /dev/null +++ b/include/boost/math/quadrature/detail/van_den_bos_unit_square_tables.hpp @@ -0,0 +1,5049 @@ +/* + * Copyright 2026 Nicholas Thompson and Matt Borland + * Distributed under the Boost Software License, Version 1.0. + * + * Generated by tools/dump_van_den_bos_unit_square.cpp. + * + * The Clenshaw-Curtis candidates, moment matrices, support reductions, nodes, + * and weights were all computed in cpp_bin_float_quad. Nodes and weights + * were rounded once, at emission, to IEEE-754 binary64. + * + * Every hexadecimal floating-point literal exactly represents its intended + * IEEE-754 binary64 value. C++17 or later is therefore required. + */ +#ifndef BOOST_MATH_QUADRATURE_DETAIL_VAN_DEN_BOS_UNIT_SQUARE_TABLES_HPP +#define BOOST_MATH_QUADRATURE_DETAIL_VAN_DEN_BOS_UNIT_SQUARE_TABLES_HPP + +#include +#include +#include + +namespace boost { namespace math { namespace quadrature { namespace detail { + +inline constexpr unsigned van_den_bos_unit_square_level_0_degree = 4; +inline constexpr std::size_t van_den_bos_unit_square_level_0_order = 4; + +inline constexpr std::array van_den_bos_unit_square_level_0_weights{{ + 0x1.23456789abcdfp-10, + 0x1.23456789abcdfp-7, + 0x1.b4e81b4e81b4fp-7, + 0x1.23456789abcdfp-7, + 0x1.23456789abcdfp-10, + 0x1.23456789abcdfp-7, + 0x1.23456789abcdfp-4, + 0x1.b4e81b4e81b4fp-4, + 0x1.23456789abcdfp-4, + 0x1.23456789abcdfp-7, + 0x1.b4e81b4e81b4fp-7, + 0x1.b4e81b4e81b4fp-4, + 0x1.47ae147ae147bp-3, + 0x1.b4e81b4e81b4fp-4, + 0x1.b4e81b4e81b4fp-7, + 0x1.23456789abcdfp-7, + 0x1.23456789abcdfp-4, + 0x1.b4e81b4e81b4fp-4, + 0x1.23456789abcdfp-4, + 0x1.23456789abcdfp-7, + 0x1.23456789abcdfp-10, + 0x1.23456789abcdfp-7, + 0x1.b4e81b4e81b4fp-7, + 0x1.23456789abcdfp-7, + 0x1.23456789abcdfp-10 +}}; + +inline constexpr unsigned van_den_bos_unit_square_level_1_degree = 6; +inline constexpr std::size_t van_den_bos_unit_square_level_1_order = 8; + +inline constexpr std::array van_den_bos_unit_square_level_1_weights{{ + 0x1.0831051872093p-14, + 0x1.229c5267b0a3bp-10, + 0x1.997f2e4c4a5bp-10, + 0x1.229c5267b0a3bp-10, + 0x1.0831051872093p-14, + 0x1.229c5267b0a3bp-10, + 0x1.3fabf43edbe74p-6, + 0x1.c2724c871e975p-6, + 0x1.3fabf43edbe74p-6, + 0x1.229c5267b0a3bp-10, + 0x1.997f2e4c4a5bp-10, + 0x1.c2724c871e975p-6, + 0x1.3d5c2a47ecd35p-5, + 0x1.c2724c871e975p-6, + 0x1.997f2e4c4a5bp-10, + 0x1.229c5267b0a3bp-10, + 0x1.3fabf43edbe74p-6, + 0x1.c2724c871e975p-6, + 0x1.3fabf43edbe74p-6, + 0x1.229c5267b0a3bp-10, + 0x1.0831051872093p-14, + 0x1.229c5267b0a3bp-10, + 0x1.997f2e4c4a5bp-10, + 0x1.229c5267b0a3bp-10, + 0x1.0831051872093p-14, + 0x1.d95bb582ba519p-7, + 0x1.798807bed465bp-6, + 0x1.2d7b9efb07858p-5, + 0x1.c2f876913cd12p-8, + 0x1.2776a5350db12p-5, + 0x1.b76b7ca86e27dp-6, + 0x1.2a0e07a775482p-6, + 0x1.779ad067b2381p-5, + 0x1.4ee2bcb6a08d9p-4, + 0x1.613d9df6c52e8p-5, + 0x1.13d912acabcb2p-7, + 0x1.27a707f0ec9fp-7, + 0x1.0d96ba27e3be7p-4, + 0x1.1b92816d2a71p-7, + 0x1.9a183931ecbb1p-6, + 0x1.14f1bb02330c3p-6, + 0x1.40dde6e8e3d63p-4, + 0x1.02f3ff02fedaep-5, + 0x1.2f7024b09cbbp-5, + 0x1.1835cc24d43b7p-6, + 0x1.77117d76daa75p-5, + 0x1.00f221177610ep-7, + 0x1.bb0520e17574dp-7, + 0x1.db60de4d1efb2p-7, + 0x1.26d2545629399p-6, + 0x1.0a770332b14fp-8, + 0x1.f180d2d0baba3p-7, + 0x1.081d5ed8af461p-7 +}}; + +inline constexpr unsigned van_den_bos_unit_square_level_2_degree = 9; +inline constexpr std::size_t van_den_bos_unit_square_level_2_order = 16; + +inline constexpr std::array van_den_bos_unit_square_level_2_weights{{ + 0x1.0203040506071p-18, + 0x1.1db2e8620e89dp-13, + 0x1.93d34c2435225p-13, + 0x1.1db2e8620e89dp-13, + 0x1.0203040506071p-18, + 0x1.1db2e8620e89dp-13, + 0x1.3c5b659d417ffp-8, + 0x1.bf28dd075b924p-8, + 0x1.3c5b659d417ffp-8, + 0x1.1db2e8620e89dp-13, + 0x1.93d34c2435225p-13, + 0x1.bf28dd075b924p-8, + 0x1.3c05b3a1a4465p-7, + 0x1.bf28dd075b924p-8, + 0x1.93d34c2435225p-13, + 0x1.1db2e8620e89dp-13, + 0x1.3c5b659d417ffp-8, + 0x1.bf28dd075b924p-8, + 0x1.3c5b659d417ffp-8, + 0x1.1db2e8620e89dp-13, + 0x1.0203040506071p-18, + 0x1.1db2e8620e89dp-13, + 0x1.93d34c2435225p-13, + 0x1.1db2e8620e89dp-13, + 0x1.0203040506071p-18, + 0x1.756591f7bbbb7p-10, + 0x1.c0dbb1326564ep-9, + 0x1.c0dbb1326564ep-9, + 0x1.57b214c166d6fp-9, + 0x1.9d279480768a3p-8, + 0x1.57b214c166d6fp-9, + 0x1.c0dbb1326564ep-9, + 0x1.9d279480768a3p-8, + 0x1.23fd64f652465p-7, + 0x1.9d279480768a3p-8, + 0x1.e5cd4271d9a42p-9, + 0x1.23fd64f652465p-7, + 0x1.23fd64f652465p-7, + 0x1.e5cd4271d9a42p-9, + 0x1.c0dbb1326564ep-9, + 0x1.9d279480768a3p-8, + 0x1.0dc8f3221cdp-7, + 0x1.0dc8f3221cdp-7, + 0x1.c0dbb1326564ep-9, + 0x1.9d279480768a3p-8, + 0x1.9d279480768a3p-8, + 0x1.3663596fe5502p-14, + 0x1.57b214c166d6fp-9, + 0x1.c0dbb1326564ep-9, + 0x1.e5cd4271d9a42p-9, + 0x1.c0dbb1326564ep-9, + 0x1.57b214c166d6fp-9, + 0x1.756591f7bbbb7p-10, + 0x1.03baa9c9bd389p-7, + 0x1.4c6422d754962p-8, + 0x1.51fea421588a1p-8, + 0x1.2754534864422p-8, + 0x1.2480fe920110bp-6, + 0x1.68f799da7f959p-7, + 0x1.fd77f924ba78p-12, + 0x1.f4bcfeef78e4ep-7, + 0x1.3ee43431bc1d6p-6, + 0x1.526da04f4e11cp-7, + 0x1.29e17eaa8d4afp-6, + 0x1.a83aa9550849ep-7, + 0x1.316d6849781ep-6, + 0x1.63d81dce90fb8p-7, + 0x1.3984bd7e72baap-6, + 0x1.f3e0821c9f17p-6, + 0x1.aaaed22c67be9p-8, + 0x1.a6d1b45c859f8p-7, + 0x1.08024b6b17887p-5, + 0x1.1500b2e8af7d4p-5, + 0x1.2a6c0cbe96cbbp-7, + 0x1.2067fb9e55a16p-6, + 0x1.2d9abc71cf0adp-5, + 0x1.114a2ba765fc1p-6, + 0x1.23a03cbc51375p-6, + 0x1.155868d79886bp-7, + 0x1.eb6b85f311ceep-6, + 0x1.d9e50da8b0bedp-6, + 0x1.6100c1c731a7ep-5, + 0x1.955573daf4871p-6, + 0x1.90f8abf8e30f1p-6, + 0x1.aedf83928e205p-10, + 0x1.6bcaaa3a65c95p-6, + 0x1.30a1fe5cfe75cp-6, + 0x1.087a7152794c6p-5, + 0x1.fcd389912425bp-6, + 0x1.db46fe40b8714p-6, + 0x1.fdc7b2a7e43afp-8, + 0x1.27df6cb827f9bp-6, + 0x1.787b53803bbe3p-13, + 0x1.09aa7ce06b358p-8, + 0x1.933509ed2678bp-8, + 0x1.283db310e49edp-6, + 0x1.daf6a0d1588c9p-7, + 0x1.8241615ab57f7p-11, + 0x1.4cdcf3bf246dbp-7, + 0x1.82a678fd9152dp-8, + 0x1.6ea5038f8e1f8p-8, + 0x1.2710494d48c78p-8, + 0x1.bf389312de584p-8, + 0x1.64c6ccf3cc75dp-8, + 0x1.f82f2b92a75d1p-9, + 0x1.68cd12230e8dcp-8, + 0x1.f9b5440bf489fp-8, + 0x1.09011f2a1ab8cp-9 +}}; + +inline constexpr unsigned van_den_bos_unit_square_level_3_degree = 13; +inline constexpr std::size_t van_den_bos_unit_square_level_3_order = 16; + +inline constexpr std::array van_den_bos_unit_square_level_3_weights{{ + 0x1.0203040506071p-18, + 0x1.1db2e8620e89dp-13, + 0x1.93d34c2435225p-13, + 0x1.1db2e8620e89dp-13, + 0x1.0203040506071p-18, + 0x1.1db2e8620e89dp-13, + 0x1.3c5b659d417ffp-8, + 0x1.bf28dd075b924p-8, + 0x1.3c5b659d417ffp-8, + 0x1.1db2e8620e89dp-13, + 0x1.93d34c2435225p-13, + 0x1.bf28dd075b924p-8, + 0x1.3c05b3a1a4465p-7, + 0x1.bf28dd075b924p-8, + 0x1.93d34c2435225p-13, + 0x1.1db2e8620e89dp-13, + 0x1.3c5b659d417ffp-8, + 0x1.bf28dd075b924p-8, + 0x1.3c5b659d417ffp-8, + 0x1.1db2e8620e89dp-13, + 0x1.0203040506071p-18, + 0x1.1db2e8620e89dp-13, + 0x1.93d34c2435225p-13, + 0x1.1db2e8620e89dp-13, + 0x1.0203040506071p-18, + 0x1.756591f7bbbb7p-10, + 0x1.c0dbb1326564ep-9, + 0x1.c0dbb1326564ep-9, + 0x1.57b214c166d6fp-9, + 0x1.9d279480768a3p-8, + 0x1.57b214c166d6fp-9, + 0x1.c0dbb1326564ep-9, + 0x1.9d279480768a3p-8, + 0x1.23fd64f652465p-7, + 0x1.9d279480768a3p-8, + 0x1.e5cd4271d9a42p-9, + 0x1.23fd64f652465p-7, + 0x1.23fd64f652465p-7, + 0x1.e5cd4271d9a42p-9, + 0x1.c0dbb1326564ep-9, + 0x1.9d279480768a3p-8, + 0x1.0dc8f3221cdp-7, + 0x1.0dc8f3221cdp-7, + 0x1.c0dbb1326564ep-9, + 0x1.9d279480768a3p-8, + 0x1.9d279480768a3p-8, + 0x1.3663596fe5502p-14, + 0x1.57b214c166d6fp-9, + 0x1.c0dbb1326564ep-9, + 0x1.e5cd4271d9a42p-9, + 0x1.c0dbb1326564ep-9, + 0x1.57b214c166d6fp-9, + 0x1.756591f7bbbb7p-10, + 0x1.544dc1da4e54cp-10, + 0x1.d7772e6015462p-10, + 0x1.0ab58d4e665cdp-10, + 0x1.71b6355cbfe18p-11, + 0x1.dc2a2de884883p-9, + 0x1.939793399b1ccp-9, + 0x1.71b6355cbfe18p-11, + 0x1.23267f8e262bep-8, + 0x1.57810f435c178p-8, + 0x1.0d5e174645a35p-9, + 0x1.efe1e74e71b76p-9, + 0x1.b64a05b80c835p-8, + 0x1.737d37b261333p-8, + 0x1.939793399b1ccp-9, + 0x1.b43aade8ee34p-8, + 0x1.0155d610e966dp-7, + 0x1.737d37b261333p-8, + 0x1.939793399b1ccp-9, + 0x1.1e32900a5ffebp-7, + 0x1.e527e3619b644p-8, + 0x1.dc2a2de884883p-9, + 0x1.b64a05b80c835p-8, + 0x1.1e32900a5ffebp-7, + 0x1.2f9bc8961ab38p-7, + 0x1.dc2a2de884883p-9, + 0x1.e101e9fff9f2dp-10, + 0x1.068b20e69244ap-7, + 0x1.b64a05b80c835p-8, + 0x1.35c0d307b5328p-7, + 0x1.2f9bc8961ab38p-7, + 0x1.57810f435c178p-8, + 0x1.d7772e6015462p-10, + 0x1.e527e3619b644p-8, + 0x1.939793399b1ccp-9, + 0x1.0155d610e966dp-7, + 0x1.e527e3619b644p-8, + 0x1.737d37b261333p-8, + 0x1.4f7cf53ac2232p-13, + 0x1.737d37b261333p-8, + 0x1.efe1e74e71b76p-9, + 0x1.0d5e174645a35p-9, + 0x1.84a468af0bc61p-9, + 0x1.57810f435c178p-8, + 0x1.57810f435c178p-8, + 0x1.23267f8e262bep-8, + 0x1.efe1e74e71b76p-9, + 0x1.0d5e174645a35p-9, + 0x1.756591f7bbbb7p-10, + 0x1.939793399b1ccp-9, + 0x1.dc2a2de884883p-9, + 0x1.0d5e174645a35p-9, + 0x1.544dc1da4e54cp-10, + 0x1.bc6daea8921a9p-10, + 0x1.bc6daea8921a9p-10, + 0x1.71b6355cbfe18p-11, + 0x1.a084b3fba91d3p-12, + 0x1.1bc9955ae8804p-10, + 0x1.3f118ab38bb0cp-9, + 0x1.d82116d437844p-9, + 0x1.2996b3cc6eb43p-8, + 0x1.a835ee429a063p-9, + 0x1.dfb6015d1234cp-12, + 0x1.45242b9c70aaap-11, + 0x1.c52d344ddc5b2p-9, + 0x1.5f6b0403b9358p-8, + 0x1.8fcf631ea5161p-8, + 0x1.298f70758feebp-9, + 0x1.1479036e60399p-9, + 0x1.de17fae05169cp-9, + 0x1.7c234e4548e51p-8, + 0x1.799d103dd1819p-7, + 0x1.26beaebbe1a52p-9, + 0x1.68b226d0849c2p-8, + 0x1.89289aebdfd46p-8, + 0x1.ce186f9159f48p-9, + 0x1.f9a6276d56244p-10, + 0x1.fe188bb0004fcp-10, + 0x1.607263d074c34p-7, + 0x1.550e308bdbd1cp-7, + 0x1.1bb3c5de4b256p-7, + 0x1.13241e1b3b7dep-9, + 0x1.28e590fad1bb1p-7, + 0x1.23464ad2bcc01p-12, + 0x1.fb36bce228211p-7, + 0x1.1b99372221774p-10, + 0x1.ae19dd4425604p-7, + 0x1.a884f1975de2dp-8, + 0x1.04d417fe54fe8p-9, + 0x1.1297e1ed6fa8ap-9, + 0x1.56a1080f6ecc6p-6, + 0x1.e81af1a721e9dp-10, + 0x1.13ef3bc228b6fp-6, + 0x1.4030945963724p-7, + 0x1.d31d0042d2f85p-11, + 0x1.153617c17774cp-8, + 0x1.bc5e9a9427053p-10, + 0x1.180f9a80244a9p-7, + 0x1.29215e6a7120fp-6, + 0x1.86b4a8e989b6bp-8, + 0x1.14571f9d0a652p-6, + 0x1.5da3295f4e5abp-8, + 0x1.7febf23b1edbbp-8, + 0x1.729e3f9693b5cp-8, + 0x1.a9bafca27d1c8p-7, + 0x1.907257d655abbp-7, + 0x1.f00669631062ep-8, + 0x1.994a4bd4c9ae7p-9, + 0x1.ececb3a2216a2p-10, + 0x1.1ed45c1e28cb6p-9, + 0x1.99b2368af64ccp-8, + 0x1.9f52430050a2fp-7, + 0x1.779da1c558aep-7, + 0x1.64aa94cbe9e4ep-7, + 0x1.29191a5c54c22p-7, + 0x1.ed34d79c76101p-10, + 0x1.0729c55e36ab9p-8, + 0x1.100111aea6983p-9, + 0x1.b2644a6cf8e6ap-6, + 0x1.053c0da9a2dbcp-6, + 0x1.0298761850ad6p-8, + 0x1.38048a2aaed9ap-8, + 0x1.7ffeef2c10632p-9, + 0x1.8280f9e36ffd8p-7, + 0x1.5bb09438c0e56p-8, + 0x1.e65ebefac6d2p-7, + 0x1.10ee4e69c702ap-7, + 0x1.c5740b6d271bcp-9, + 0x1.32af1610a3be3p-8, + 0x1.090ddc1d02bcap-8, + 0x1.419a16b80510dp-10, + 0x1.7f7fcd019eb6dp-10, + 0x1.5e8d4e1bd1c21p-10, + 0x1.13cff68fad674p-7, + 0x1.594131199ebffp-7, + 0x1.a0f7a59bdb0e6p-8, + 0x1.01a7b957a4592p-9, + 0x1.52b6e4e180f3fp-9, + 0x1.6cfce187c2e8bp-9, + 0x1.69d110b5807c9p-8, + 0x1.9c4c234974981p-8, + 0x1.225864456368ep-10, + 0x1.0c8d6e16adb8fp-8, + 0x1.ee49cc0faddcdp-9, + 0x1.955f9f16f8dbcp-9, + 0x1.078004b762d8ap-11, + 0x1.e1d9698eaa1c7p-12, + 0x1.64bc626afe3d4p-8, + 0x1.c35f44434871dp-9, + 0x1.f299d91f90638p-11, + 0x1.0aa96ab3cd3ap-9, + 0x1.161df7d5a94bp-10, + 0x1.c50e1d16780c4p-10, + 0x1.137c4651f34d2p-9, + 0x1.72f3036f0f27p-10, + 0x1.d56eb3013a725p-10, + 0x1.b1d3e316f5222p-11, + 0x1.d845a3cbb9c89p-10, + 0x1.e4dadc0e05d5dp-11, + 0x1.14a201bedd532p-11, + 0x1.c1580728e7e05p-11 +}}; + +inline constexpr unsigned van_den_bos_unit_square_level_4_degree = 19; +inline constexpr std::size_t van_den_bos_unit_square_level_4_order = 32; + +inline constexpr std::array van_den_bos_unit_square_level_4_weights{{ + 0x1.0080301005018p-22, + 0x1.1ca740bc8e85ap-16, + 0x1.9288556131555p-16, + 0x1.1ca740bc8e85ap-16, + 0x1.0080301005018p-22, + 0x1.1ca740bc8e85ap-16, + 0x1.3be556eda6f68p-10, + 0x1.beb68c4dc15e6p-10, + 0x1.3be556eda6f68p-10, + 0x1.1ca740bc8e85ap-16, + 0x1.9288556131555p-16, + 0x1.beb68c4dc15e6p-10, + 0x1.3bda120a5cf85p-9, + 0x1.beb68c4dc15e6p-10, + 0x1.9288556131555p-16, + 0x1.1ca740bc8e85ap-16, + 0x1.3be556eda6f68p-10, + 0x1.beb68c4dc15e6p-10, + 0x1.3be556eda6f68p-10, + 0x1.1ca740bc8e85ap-16, + 0x1.0080301005018p-22, + 0x1.1ca740bc8e85ap-16, + 0x1.9288556131555p-16, + 0x1.1ca740bc8e85ap-16, + 0x1.0080301005018p-22, + 0x1.727f46940b171p-12, + 0x1.bef5d78784ae7p-11, + 0x1.bef5d78784ae7p-11, + 0x1.561be2fb423efp-11, + 0x1.9cb69c379ef84p-10, + 0x1.561be2fb423efp-11, + 0x1.bef5d78784ae7p-11, + 0x1.9cb69c379ef84p-10, + 0x1.23cfe2c64c5bap-9, + 0x1.9cb69c379ef84p-10, + 0x1.e3c808942545p-11, + 0x1.23cfe2c64c5bap-9, + 0x1.23cfe2c64c5bap-9, + 0x1.e3c808942545p-11, + 0x1.bef5d78784ae7p-11, + 0x1.9cb69c379ef84p-10, + 0x1.0d9a1a1ff9a32p-9, + 0x1.0d9a1a1ff9a32p-9, + 0x1.bef5d78784ae7p-11, + 0x1.9cb69c379ef84p-10, + 0x1.9cb69c379ef84p-10, + 0x1.34461e28acc74p-17, + 0x1.561be2fb423efp-11, + 0x1.bef5d78784ae7p-11, + 0x1.e3c808942545p-11, + 0x1.bef5d78784ae7p-11, + 0x1.561be2fb423efp-11, + 0x1.727f46940b171p-12, + 0x1.5e104e1e56a12p-12, + 0x1.e58502fa773d2p-12, + 0x1.1312fa9e16003p-12, + 0x1.7b1cad2b49c44p-13, + 0x1.da7c9bbb33fcfp-11, + 0x1.9242cb83a2515p-11, + 0x1.7b1cad2b49c44p-13, + 0x1.23ded247e160bp-10, + 0x1.58469085c37e8p-10, + 0x1.0cd2cbb398f8ep-11, + 0x1.f07385b5c0da1p-11, + 0x1.b6217070ba929p-10, + 0x1.73705a419753cp-10, + 0x1.9242cb83a2515p-11, + 0x1.b4bf73af838d6p-10, + 0x1.0195395acd626p-9, + 0x1.73705a419753cp-10, + 0x1.9242cb83a2515p-11, + 0x1.1e34a3faa3adcp-9, + 0x1.e5478afb27b96p-10, + 0x1.da7c9bbb33fcfp-11, + 0x1.b6217070ba929p-10, + 0x1.1e34a3faa3adcp-9, + 0x1.2fd4f3ba63935p-9, + 0x1.da7c9bbb33fcfp-11, + 0x1.ef07c3758ab74p-12, + 0x1.06a0ef19addb5p-9, + 0x1.b6217070ba929p-10, + 0x1.35c89691a11d1p-9, + 0x1.2fd4f3ba63935p-9, + 0x1.58469085c37e8p-10, + 0x1.e58502fa773d2p-12, + 0x1.e5478afb27b96p-10, + 0x1.9242cb83a2515p-11, + 0x1.0195395acd626p-9, + 0x1.e5478afb27b96p-10, + 0x1.73705a419753cp-10, + 0x1.4eb3fc7fcf9b6p-16, + 0x1.73705a419753cp-10, + 0x1.f07385b5c0da1p-11, + 0x1.0cd2cbb398f8ep-11, + 0x1.861a5f252b352p-11, + 0x1.58469085c37e8p-10, + 0x1.58469085c37e8p-10, + 0x1.23ded247e160bp-10, + 0x1.f07385b5c0da1p-11, + 0x1.0cd2cbb398f8ep-11, + 0x1.727f46940b171p-12, + 0x1.9242cb83a2515p-11, + 0x1.da7c9bbb33fcfp-11, + 0x1.0cd2cbb398f8ep-11, + 0x1.5e104e1e56a12p-12, + 0x1.c95a6496b4578p-12, + 0x1.c95a6496b4578p-12, + 0x1.7b1cad2b49c44p-13, + 0x1.3b7121bc27283p-18, + 0x1.bf59ffdb6e65cp-17, + 0x1.1312fa9e16003p-12, + 0x1.c95a6496b4578p-12, + 0x1.ef07c3758ab74p-12, + 0x1.9b9d45550268bp-12, + 0x1.83ed5b814caf5p-14, + 0x1.34461e28acc74p-17, + 0x1.561be2fb423efp-11, + 0x1.9242cb83a2515p-11, + 0x1.da7c9bbb33fcfp-11, + 0x1.0cd2cbb398f8ep-11, + 0x1.727f46940b171p-12, + 0x1.0cd2cbb398f8ep-11, + 0x1.861a5f252b352p-11, + 0x1.58469085c37e8p-10, + 0x1.5f0503fbb6d0bp-10, + 0x1.444d9bb40391bp-10, + 0x1.23ded247e160bp-10, + 0x1.f07385b5c0da1p-11, + 0x1.1312fa9e16003p-12, + 0x1.5e104e1e56a12p-12, + 0x1.73705a419753cp-10, + 0x1.b6217070ba929p-10, + 0x1.f07385b5c0da1p-11, + 0x1.9b9d45550268bp-12, + 0x1.23ded247e160bp-10, + 0x1.73705a419753cp-10, + 0x1.0195395acd626p-9, + 0x1.06a0ef19addb5p-9, + 0x1.e5478afb27b96p-10, + 0x1.b4bf73af838d6p-10, + 0x1.9b9d45550268bp-12, + 0x1.c95a6496b4578p-12, + 0x1.e5478afb27b96p-10, + 0x1.0d9a1a1ff9a32p-9, + 0x1.1e34a3faa3adcp-9, + 0x1.444d9bb40391bp-10, + 0x1.bef5d78784ae7p-11, + 0x1.c95a6496b4578p-12, + 0x1.e58502fa773d2p-12, + 0x1.58469085c37e8p-10, + 0x1.2fd4f3ba63935p-9, + 0x1.1e34a3faa3adcp-9, + 0x1.0195395acd626p-9, + 0x1.58469085c37e8p-10, + 0x1.5f0503fbb6d0bp-10, + 0x1.06a0ef19addb5p-9, + 0x1.35c89691a11d1p-9, + 0x1.35c89691a11d1p-9, + 0x1.5f0503fbb6d0bp-10, + 0x1.ef07c3758ab74p-12, + 0x1.e58502fa773d2p-12, + 0x1.da7c9bbb33fcfp-11, + 0x1.58469085c37e8p-10, + 0x1.0195395acd626p-9, + 0x1.1e34a3faa3adcp-9, + 0x1.1e34a3faa3adcp-9, + 0x1.b6217070ba929p-10, + 0x1.da7c9bbb33fcfp-11, + 0x1.c95a6496b4578p-12, + 0x1.1e34a3faa3adcp-9, + 0x1.23cfe2c64c5bap-9, + 0x1.e5478afb27b96p-10, + 0x1.9cb69c379ef84p-10, + 0x1.444d9bb40391bp-10, + 0x1.c95a6496b4578p-12, + 0x1.23ded247e160bp-10, + 0x1.73705a419753cp-10, + 0x1.e5478afb27b96p-10, + 0x1.0195395acd626p-9, + 0x1.b4bf73af838d6p-10, + 0x1.23ded247e160bp-10, + 0x1.9242cb83a2515p-11, + 0x1.5e104e1e56a12p-12, + 0x1.561be2fb423efp-11, + 0x1.f07385b5c0da1p-11, + 0x1.b6217070ba929p-10, + 0x1.b6217070ba929p-10, + 0x1.73705a419753cp-10, + 0x1.561be2fb423efp-11, + 0x1.5e104e1e56a12p-12, + 0x1.1312fa9e16003p-12, + 0x1.f07385b5c0da1p-11, + 0x1.23ded247e160bp-10, + 0x1.444d9bb40391bp-10, + 0x1.5f0503fbb6d0bp-10, + 0x1.444d9bb40391bp-10, + 0x1.861a5f252b352p-11, + 0x1.1312fa9e16003p-12, + 0x1.0cd2cbb398f8ep-11, + 0x1.da7c9bbb33fcfp-11, + 0x1.9242cb83a2515p-11, + 0x1.7b1cad2b49c44p-13, + 0x1.7b1cad2b49c44p-13, + 0x1.1312fa9e16003p-12, + 0x1.9b9d45550268bp-12, + 0x1.e58502fa773d2p-12, + 0x1.ef07c3758ab74p-12, + 0x1.e58502fa773d2p-12, + 0x1.9b9d45550268bp-12, + 0x1.5e104e1e56a12p-12, + 0x1.1312fa9e16003p-12, + 0x1.83ed5b814caf5p-14, + 0x1.73e53a138ba16p-16, + 0x1.924c1839ef84p-11, + 0x1.2a853c8f0a716p-12, + 0x1.135eb79bafb5p-11, + 0x1.cd9e50c840ce3p-11, + 0x1.0fc875b9b8393p-10, + 0x1.551dc9038d129p-12, + 0x1.90f54cfa7a769p-10, + 0x1.24163db086481p-9, + 0x1.723bdf91690fdp-9, + 0x1.d9ff4206d2419p-10, + 0x1.140e1d2dd08e8p-10, + 0x1.7cfa05128de39p-10, + 0x1.c1ade3ae1be3bp-11, + 0x1.1c409dee2a9a9p-10, + 0x1.f69401b013dep-9, + 0x1.ed1509f783668p-10, + 0x1.c9a44bc94b9bdp-12, + 0x1.4bd0daf69320bp-9, + 0x1.620bf3e5d9008p-9, + 0x1.75b00197b5b29p-8, + 0x1.3c65daab70a6ep-9, + 0x1.c3a457ca7a522p-9, + 0x1.9d6139e69c1a4p-10, + 0x1.8e3ba871f7293p-9, + 0x1.90196193329bcp-9, + 0x1.2182c7c351767p-9, + 0x1.add0a5a73ba56p-9, + 0x1.4c2db75e6f6d2p-9, + 0x1.4d87e169420cdp-10, + 0x1.f2dd78b42c0cp-12, + 0x1.c088d1b6ccae8p-10, + 0x1.f42961f227684p-11, + 0x1.b3f5778d20e0fp-8, + 0x1.db2beb2da8ec6p-8, + 0x1.4fdcf0310d846p-8, + 0x1.497eb936d5d78p-10, + 0x1.b34f054613b49p-8, + 0x1.85ede767dbe87p-8, + 0x1.add26f9603306p-8, + 0x1.715bbf8d0087ep-8, + 0x1.0db4071c3e6e6p-9, + 0x1.02abf6f6bd276p-10, + 0x1.179f8a32afeb5p-8, + 0x1.4a1cb0791a04dp-7, + 0x1.911abbe5c85b7p-8, + 0x1.931cbbb085fd5p-10, + 0x1.497a166a30a5ap-9, + 0x1.a3e1f2daf7c79p-8, + 0x1.4af463f2ac01bp-8, + 0x1.611c060c5fd0bp-7, + 0x1.4634c01cf8a5fp-10, + 0x1.e9bf618dda5aap-8, + 0x1.2a4dbdf677287p-9, + 0x1.69131e54aad78p-12, + 0x1.2e50a7a25fa8dp-8, + 0x1.fd04f4bd5899cp-8, + 0x1.ea3658e4411adp-10, + 0x1.3c2c8590b3d62p-8, + 0x1.50cd7e3b6649ep-8, + 0x1.40acee5d2ccbdp-11, + 0x1.a2e8f7ab9106ep-8, + 0x1.ec1f4121b8f83p-11, + 0x1.70ddd5a03bc41p-7, + 0x1.fb237f9bc8d06p-8, + 0x1.9be986e09aa7dp-8, + 0x1.e1cd7e36b59acp-8, + 0x1.3c0f600ae2b66p-9, + 0x1.1aaa9b196b0fbp-11, + 0x1.b42f5b546e2b1p-9, + 0x1.337b9886e16ccp-10, + 0x1.208d7527858b5p-7, + 0x1.0f32c6ba079f8p-7, + 0x1.3219bb0e87e8bp-11, + 0x1.90b638d12e637p-8, + 0x1.7cc3838a407a3p-7, + 0x1.9e50620e4d88p-7, + 0x1.9611dbe8428e3p-8, + 0x1.f0d747bc7f243p-8, + 0x1.a281f9caddcfep-8, + 0x1.82790ce19554p-9, + 0x1.8d3e5c774491fp-9, + 0x1.b13c3a0aa5464p-8, + 0x1.905493742d9e5p-9, + 0x1.9dedd0bf8e2afp-8, + 0x1.1ebb4cc228e2fp-11, + 0x1.9d26da5a38accp-10, + 0x1.04be18066a24fp-7, + 0x1.e82f74cbd78bp-8, + 0x1.dd29a443d7c23p-7, + 0x1.9b1f694365e9ep-8, + 0x1.331ec5cf26c3ap-7, + 0x1.1803f0564e899p-7, + 0x1.bb2697679d4cap-8, + 0x1.ae0516ca675f6p-9, + 0x1.0f8648cf9a95ap-9, + 0x1.067d0fa71d1fp-10, + 0x1.9217c6924bd86p-8, + 0x1.1c5056d7eac03p-9, + 0x1.f64ad922b66ep-11, + 0x1.becc8dffff8bap-12, + 0x1.1e204c2ddb337p-7, + 0x1.abe7917a11191p-9, + 0x1.3a1faefe7cce1p-7, + 0x1.7fedf5d4b4e58p-7, + 0x1.6154970065d54p-8, + 0x1.3c6ac0f058279p-8, + 0x1.01a42ab5f3482p-7, + 0x1.66569eeaf1f92p-7, + 0x1.336500dddfa1fp-12, + 0x1.8b9b30f6eeb21p-7, + 0x1.425b4f4f4378bp-9, + 0x1.bcee64ce44c5cp-9, + 0x1.126b6243508a5p-10, + 0x1.5adafd15f4dbdp-9, + 0x1.042e5c8e6428fp-8, + 0x1.df4ff2d8d3638p-8, + 0x1.a8cc6b3416f16p-8, + 0x1.15bfdf5272c36p-7, + 0x1.66901eef01f73p-7, + 0x1.6a312c2d1840bp-8, + 0x1.5641288231675p-8, + 0x1.4890a7a104a92p-7, + 0x1.5a793feb755dbp-8, + 0x1.109df1aeb141bp-9, + 0x1.8b98b9d61602ep-10, + 0x1.ed2e013f493a3p-9, + 0x1.d8f4ec180dd41p-8, + 0x1.20e23fb7ba4fap-7, + 0x1.97402dbb2936dp-8, + 0x1.88ff27766ece6p-8, + 0x1.be744cebdf0acp-8, + 0x1.330eb3380a1aap-9, + 0x1.0c8b47367965p-9, + 0x1.1feb9ac208444p-8, + 0x1.1c59aaf1fffd8p-10, + 0x1.96f5f665273a5p-8, + 0x1.036ed89d772a3p-7, + 0x1.4f381eb25918bp-8, + 0x1.65ea04167bf66p-11, + 0x1.6a7aa3ffbf3b7p-9, + 0x1.a682cec227cffp-9, + 0x1.05ec0a03d545ep-7, + 0x1.12b7145fe5996p-8, + 0x1.8638f4c0adf6dp-9, + 0x1.e18215ef4a553p-8, + 0x1.8bdc3ee10505dp-9, + 0x1.8bb0b20d5666ap-8, + 0x1.216f5d93a6bf2p-10, + 0x1.fc8b541d8603bp-10, + 0x1.709dec5030cebp-8, + 0x1.7e4315ee8c6b1p-8, + 0x1.da0120a5d77c2p-9, + 0x1.31479f22a7181p-11, + 0x1.5e524d2fa20f1p-10, + 0x1.a75088abff587p-9, + 0x1.f1847023ac7p-9, + 0x1.e013ee04bbd8ep-9, + 0x1.1ee3b77903845p-7, + 0x1.557d1db57c085p-8, + 0x1.3d98ed0e0a087p-10, + 0x1.3199ff9d76cadp-8, + 0x1.28ecb11a0c4afp-10, + 0x1.acc487e18a9b9p-12, + 0x1.c3a59d7f46219p-9, + 0x1.f1c9e13782f82p-10, + 0x1.24430c2ddfaf2p-8, + 0x1.d5abacef724f6p-13, + 0x1.ebcb82f3ab00ep-10, + 0x1.a0f2a0c5e4622p-9, + 0x1.98d7759fe5beep-8, + 0x1.4cbef0e3e51b3p-9, + 0x1.2ba0a66f0dff5p-8, + 0x1.ff70b89cd6b77p-9, + 0x1.d2541581e57b4p-10, + 0x1.4b0b450a77122p-9, + 0x1.5ada36525dc7cp-11, + 0x1.c913253e4b93dp-10, + 0x1.df94ed52161dbp-10, + 0x1.0aca38027bdd1p-9, + 0x1.a57065940e972p-12, + 0x1.280739f93ef9dp-12, + 0x1.cada541f48326p-12, + 0x1.18f840eb00c02p-10, + 0x1.4de72a2b21692p-11, + 0x1.7a48e09563ae6p-9, + 0x1.e428c7d134a84p-11, + 0x1.0fca3c6fb1f79p-8, + 0x1.1d927853aeed6p-10, + 0x1.0fe7fbbd25066p-9, + 0x1.1c95cded52d21p-9, + 0x1.bb15690bf3679p-14, + 0x1.1ce63d874e7fap-14, + 0x1.bb32e67e9fae5p-10, + 0x1.d486e0ee0d89p-10, + 0x1.ef3673312e7abp-12, + 0x1.c24509d205078p-12, + 0x1.54a2ae57941c1p-14, + 0x1.c86c8b35bfbedp-13, + 0x1.354ec8b24479p-11, + 0x1.089d5150952aap-11, + 0x1.ac770eb1fa585p-11, + 0x1.f1ef2103fe6b7p-13, + 0x1.4304f4c74013ep-11, + 0x1.d7e2d5562d199p-12, + 0x1.6f1c1c65240b3p-12, + 0x1.b5b80b1309129p-12, + 0x1.d767df20659d4p-12, + 0x1.3064dc6d5ad3ep-14, + 0x1.7d799e224635dp-14, + 0x1.6cc0dc43e70dp-12 +}}; + +inline constexpr unsigned van_den_bos_unit_square_level_5_degree = 27; +inline constexpr std::size_t van_den_bos_unit_square_level_5_order = 32; + +inline constexpr std::array van_den_bos_unit_square_level_5_weights{{ + 0x1.0080301005018p-22, + 0x1.1ca740bc8e85ap-16, + 0x1.9288556131555p-16, + 0x1.1ca740bc8e85ap-16, + 0x1.0080301005018p-22, + 0x1.1ca740bc8e85ap-16, + 0x1.3be556eda6f68p-10, + 0x1.beb68c4dc15e6p-10, + 0x1.3be556eda6f68p-10, + 0x1.1ca740bc8e85ap-16, + 0x1.9288556131555p-16, + 0x1.beb68c4dc15e6p-10, + 0x1.3bda120a5cf85p-9, + 0x1.beb68c4dc15e6p-10, + 0x1.9288556131555p-16, + 0x1.1ca740bc8e85ap-16, + 0x1.3be556eda6f68p-10, + 0x1.beb68c4dc15e6p-10, + 0x1.3be556eda6f68p-10, + 0x1.1ca740bc8e85ap-16, + 0x1.0080301005018p-22, + 0x1.1ca740bc8e85ap-16, + 0x1.9288556131555p-16, + 0x1.1ca740bc8e85ap-16, + 0x1.0080301005018p-22, + 0x1.727f46940b171p-12, + 0x1.bef5d78784ae7p-11, + 0x1.bef5d78784ae7p-11, + 0x1.561be2fb423efp-11, + 0x1.9cb69c379ef84p-10, + 0x1.561be2fb423efp-11, + 0x1.bef5d78784ae7p-11, + 0x1.9cb69c379ef84p-10, + 0x1.23cfe2c64c5bap-9, + 0x1.9cb69c379ef84p-10, + 0x1.e3c808942545p-11, + 0x1.23cfe2c64c5bap-9, + 0x1.23cfe2c64c5bap-9, + 0x1.e3c808942545p-11, + 0x1.bef5d78784ae7p-11, + 0x1.9cb69c379ef84p-10, + 0x1.0d9a1a1ff9a32p-9, + 0x1.0d9a1a1ff9a32p-9, + 0x1.bef5d78784ae7p-11, + 0x1.9cb69c379ef84p-10, + 0x1.9cb69c379ef84p-10, + 0x1.34461e28acc74p-17, + 0x1.561be2fb423efp-11, + 0x1.bef5d78784ae7p-11, + 0x1.e3c808942545p-11, + 0x1.bef5d78784ae7p-11, + 0x1.561be2fb423efp-11, + 0x1.727f46940b171p-12, + 0x1.5e104e1e56a12p-12, + 0x1.e58502fa773d2p-12, + 0x1.1312fa9e16003p-12, + 0x1.7b1cad2b49c44p-13, + 0x1.da7c9bbb33fcfp-11, + 0x1.9242cb83a2515p-11, + 0x1.7b1cad2b49c44p-13, + 0x1.23ded247e160bp-10, + 0x1.58469085c37e8p-10, + 0x1.0cd2cbb398f8ep-11, + 0x1.f07385b5c0da1p-11, + 0x1.b6217070ba929p-10, + 0x1.73705a419753cp-10, + 0x1.9242cb83a2515p-11, + 0x1.b4bf73af838d6p-10, + 0x1.0195395acd626p-9, + 0x1.73705a419753cp-10, + 0x1.9242cb83a2515p-11, + 0x1.1e34a3faa3adcp-9, + 0x1.e5478afb27b96p-10, + 0x1.da7c9bbb33fcfp-11, + 0x1.b6217070ba929p-10, + 0x1.1e34a3faa3adcp-9, + 0x1.2fd4f3ba63935p-9, + 0x1.da7c9bbb33fcfp-11, + 0x1.ef07c3758ab74p-12, + 0x1.06a0ef19addb5p-9, + 0x1.b6217070ba929p-10, + 0x1.35c89691a11d1p-9, + 0x1.2fd4f3ba63935p-9, + 0x1.58469085c37e8p-10, + 0x1.e58502fa773d2p-12, + 0x1.e5478afb27b96p-10, + 0x1.9242cb83a2515p-11, + 0x1.0195395acd626p-9, + 0x1.e5478afb27b96p-10, + 0x1.73705a419753cp-10, + 0x1.4eb3fc7fcf9b6p-16, + 0x1.73705a419753cp-10, + 0x1.f07385b5c0da1p-11, + 0x1.0cd2cbb398f8ep-11, + 0x1.861a5f252b352p-11, + 0x1.58469085c37e8p-10, + 0x1.58469085c37e8p-10, + 0x1.23ded247e160bp-10, + 0x1.f07385b5c0da1p-11, + 0x1.0cd2cbb398f8ep-11, + 0x1.727f46940b171p-12, + 0x1.9242cb83a2515p-11, + 0x1.da7c9bbb33fcfp-11, + 0x1.0cd2cbb398f8ep-11, + 0x1.5e104e1e56a12p-12, + 0x1.c95a6496b4578p-12, + 0x1.c95a6496b4578p-12, + 0x1.7b1cad2b49c44p-13, + 0x1.3b7121bc27283p-18, + 0x1.bf59ffdb6e65cp-17, + 0x1.1312fa9e16003p-12, + 0x1.c95a6496b4578p-12, + 0x1.ef07c3758ab74p-12, + 0x1.9b9d45550268bp-12, + 0x1.83ed5b814caf5p-14, + 0x1.34461e28acc74p-17, + 0x1.561be2fb423efp-11, + 0x1.9242cb83a2515p-11, + 0x1.da7c9bbb33fcfp-11, + 0x1.0cd2cbb398f8ep-11, + 0x1.727f46940b171p-12, + 0x1.0cd2cbb398f8ep-11, + 0x1.861a5f252b352p-11, + 0x1.58469085c37e8p-10, + 0x1.5f0503fbb6d0bp-10, + 0x1.444d9bb40391bp-10, + 0x1.23ded247e160bp-10, + 0x1.f07385b5c0da1p-11, + 0x1.1312fa9e16003p-12, + 0x1.5e104e1e56a12p-12, + 0x1.73705a419753cp-10, + 0x1.b6217070ba929p-10, + 0x1.f07385b5c0da1p-11, + 0x1.9b9d45550268bp-12, + 0x1.23ded247e160bp-10, + 0x1.73705a419753cp-10, + 0x1.0195395acd626p-9, + 0x1.06a0ef19addb5p-9, + 0x1.e5478afb27b96p-10, + 0x1.b4bf73af838d6p-10, + 0x1.9b9d45550268bp-12, + 0x1.c95a6496b4578p-12, + 0x1.e5478afb27b96p-10, + 0x1.0d9a1a1ff9a32p-9, + 0x1.1e34a3faa3adcp-9, + 0x1.444d9bb40391bp-10, + 0x1.bef5d78784ae7p-11, + 0x1.c95a6496b4578p-12, + 0x1.e58502fa773d2p-12, + 0x1.58469085c37e8p-10, + 0x1.2fd4f3ba63935p-9, + 0x1.1e34a3faa3adcp-9, + 0x1.0195395acd626p-9, + 0x1.58469085c37e8p-10, + 0x1.5f0503fbb6d0bp-10, + 0x1.06a0ef19addb5p-9, + 0x1.35c89691a11d1p-9, + 0x1.35c89691a11d1p-9, + 0x1.5f0503fbb6d0bp-10, + 0x1.ef07c3758ab74p-12, + 0x1.e58502fa773d2p-12, + 0x1.da7c9bbb33fcfp-11, + 0x1.58469085c37e8p-10, + 0x1.0195395acd626p-9, + 0x1.1e34a3faa3adcp-9, + 0x1.1e34a3faa3adcp-9, + 0x1.b6217070ba929p-10, + 0x1.da7c9bbb33fcfp-11, + 0x1.c95a6496b4578p-12, + 0x1.1e34a3faa3adcp-9, + 0x1.23cfe2c64c5bap-9, + 0x1.e5478afb27b96p-10, + 0x1.9cb69c379ef84p-10, + 0x1.444d9bb40391bp-10, + 0x1.c95a6496b4578p-12, + 0x1.23ded247e160bp-10, + 0x1.73705a419753cp-10, + 0x1.e5478afb27b96p-10, + 0x1.0195395acd626p-9, + 0x1.b4bf73af838d6p-10, + 0x1.23ded247e160bp-10, + 0x1.9242cb83a2515p-11, + 0x1.5e104e1e56a12p-12, + 0x1.561be2fb423efp-11, + 0x1.f07385b5c0da1p-11, + 0x1.b6217070ba929p-10, + 0x1.b6217070ba929p-10, + 0x1.73705a419753cp-10, + 0x1.561be2fb423efp-11, + 0x1.5e104e1e56a12p-12, + 0x1.1312fa9e16003p-12, + 0x1.f07385b5c0da1p-11, + 0x1.23ded247e160bp-10, + 0x1.444d9bb40391bp-10, + 0x1.5f0503fbb6d0bp-10, + 0x1.444d9bb40391bp-10, + 0x1.861a5f252b352p-11, + 0x1.1312fa9e16003p-12, + 0x1.0cd2cbb398f8ep-11, + 0x1.da7c9bbb33fcfp-11, + 0x1.9242cb83a2515p-11, + 0x1.7b1cad2b49c44p-13, + 0x1.7b1cad2b49c44p-13, + 0x1.1312fa9e16003p-12, + 0x1.9b9d45550268bp-12, + 0x1.e58502fa773d2p-12, + 0x1.ef07c3758ab74p-12, + 0x1.e58502fa773d2p-12, + 0x1.9b9d45550268bp-12, + 0x1.5e104e1e56a12p-12, + 0x1.1312fa9e16003p-12, + 0x1.83ed5b814caf5p-14, + 0x1.73e53a138ba16p-16, + 0x1.371fb680b26adp-16, + 0x1.7ae50b15f297bp-15, + 0x1.c7aa0c1e13b1ep-14, + 0x1.e12365b24b5b6p-13, + 0x1.cea569c39608ep-13, + 0x1.7ae50b15f297bp-15, + 0x1.39fc1cea9fcefp-12, + 0x1.9b9d45550268bp-12, + 0x1.d9acd8389ec44p-12, + 0x1.ec9baea809463p-12, + 0x1.5e104e1e56a12p-12, + 0x1.d286dea8d846cp-13, + 0x1.a898a1f0622ccp-13, + 0x1.1b0c9faf9f991p-11, + 0x1.52564a4f59518p-11, + 0x1.3080354ac8a59p-11, + 0x1.7248e820e39adp-14, + 0x1.c7ecf3da5ae4cp-12, + 0x1.aa9dd2dc26fd1p-11, + 0x1.e16a0af655191p-11, + 0x1.e16a0af655191p-11, + 0x1.32d9934b9b426p-11, + 0x1.1874dd49b4c72p-12, + 0x1.799a495a46c6bp-11, + 0x1.cc23ff193f912p-11, + 0x1.13027d5a689efp-10, + 0x1.1cd305db9aae1p-10, + 0x1.ef036b7290ab3p-11, + 0x1.1886a551271c9p-11, + 0x1.c7aa0c1e13b1ep-14, + 0x1.96fbfeb9d65cp-12, + 0x1.4acee1fa0c71fp-11, + 0x1.4fe07e82d133ep-10, + 0x1.5d4d52efadd62p-10, + 0x1.0f4f05df7c97dp-10, + 0x1.39fc1cea9fcefp-12, + 0x1.1b56a47561f6cp-10, + 0x1.61541c786de08p-10, + 0x1.722d734128f13p-10, + 0x1.bd48fe6a78441p-11, + 0x1.32d9934b9b426p-11, + 0x1.39fc1cea9fcefp-12, + 0x1.a4fddd680c5eap-11, + 0x1.bc86fd5646eeep-10, + 0x1.89eda40c9bb23p-10, + 0x1.7e9decc3bc229p-12, + 0x1.35afccdf6baep-10, + 0x1.ae8f805f06c1ep-10, + 0x1.d330ebc9ba3fep-10, + 0x1.dedf94c559c54p-10, + 0x1.d330ebc9ba3fep-10, + 0x1.59458f39a73b5p-10, + 0x1.7e9decc3bc229p-12, + 0x1.3080354ac8a59p-11, + 0x1.ef036b7290ab3p-11, + 0x1.95fad4845fcf8p-10, + 0x1.0557f6466b0c8p-9, + 0x1.95fad4845fcf8p-10, + 0x1.ef036b7290ab3p-11, + 0x1.aa5f382d90894p-13, + 0x1.eb3c7a35cd927p-10, + 0x1.0154ad8ca9a3fp-9, + 0x1.112dbfc7f78c1p-9, + 0x1.152ac71a54f9fp-9, + 0x1.0154ad8ca9a3fp-9, + 0x1.eb3c7a35cd927p-10, + 0x1.aa9dd2dc26fd1p-11, + 0x1.b48946f608fecp-12, + 0x1.52564a4f59518p-11, + 0x1.13027d5a689efp-10, + 0x1.722d734128f13p-10, + 0x1.722d734128f13p-10, + 0x1.cea569c39608ep-13, + 0x1.d330ebc9ba3fep-10, + 0x1.17393aa418907p-9, + 0x1.2e39ed875cecdp-9, + 0x1.286b7619c3109p-9, + 0x1.17393aa418907p-9, + 0x1.f6992266b314cp-10, + 0x1.1cd305db9aae1p-10, + 0x1.d9acd8389ec44p-12, + 0x1.23f2496e7293dp-10, + 0x1.112dbfc7f78c1p-9, + 0x1.b6217070ba929p-10, + 0x1.e58502fa773d2p-12, + 0x1.ec9baea809463p-12, + 0x1.bc86fd5646eeep-10, + 0x1.0557f6466b0c8p-9, + 0x1.34448ca2f8cafp-9, + 0x1.38c4b9efb8188p-9, + 0x1.2cbf5af9fe242p-9, + 0x1.e5dd6935429b9p-10, + 0x1.2835761ed9b2fp-10, + 0x1.6e35aaa2736d6p-11, + 0x1.2e39ed875cecdp-9, + 0x1.3a4e6e3253ef2p-9, + 0x1.1687aafb21d73p-9, + 0x1.6e35aaa2736d6p-11, + 0x1.e3810a62e23dap-13, + 0x1.e12365b24b5b6p-13, + 0x1.5d4d52efadd62p-10, + 0x1.e5dd6935429b9p-10, + 0x1.152ac71a54f9fp-9, + 0x1.3a4e6e3253ef2p-9, + 0x1.34448ca2f8cafp-9, + 0x1.22625bbd89de8p-9, + 0x1.8eb67078149bap-10, + 0x1.286b7619c3109p-9, + 0x1.34448ca2f8cafp-9, + 0x1.0195395acd626p-9, + 0x1.23f2496e7293dp-10, + 0x1.672c814638e8dp-11, + 0x1.cea569c39608ep-13, + 0x1.5e696470d3528p-11, + 0x1.1cd305db9aae1p-10, + 0x1.ab7139c87e334p-10, + 0x1.f6992266b314cp-10, + 0x1.2cbf5af9fe242p-9, + 0x1.213042aed4789p-9, + 0x1.7f6373b299f75p-10, + 0x1.17393aa418907p-9, + 0x1.22625bbd89de8p-9, + 0x1.c317aae994f35p-10, + 0x1.13027d5a689efp-10, + 0x1.beb440978dc6dp-13, + 0x1.aa9dd2dc26fd1p-11, + 0x1.61541c786de08p-10, + 0x1.eb3c7a35cd927p-10, + 0x1.112dbfc7f78c1p-9, + 0x1.0a83b18207048p-9, + 0x1.eb3c7a35cd927p-10, + 0x1.cf3106df6ac62p-10, + 0x1.61541c786de08p-10, + 0x1.aa9dd2dc26fd1p-11, + 0x1.9207c3cc139fep-13, + 0x1.95fad4845fcf8p-10, + 0x1.06a0ef19addb5p-9, + 0x1.4d2830cef9fb4p-10, + 0x1.7e9decc3bc229p-12, + 0x1.75ec22a0e7289p-11, + 0x1.0f4f05df7c97dp-10, + 0x1.c317aae994f35p-10, + 0x1.dedf94c559c54p-10, + 0x1.e84101077195bp-10, + 0x1.dedf94c559c54p-10, + 0x1.c317aae994f35p-10, + 0x1.796119f39aa83p-10, + 0x1.75ec22a0e7289p-11, + 0x1.7e9decc3bc229p-12, + 0x1.59458f39a73b5p-10, + 0x1.89eda40c9bb23p-10, + 0x1.a4fddd680c5eap-11, + 0x1.32ac8be120a64p-13, + 0x1.d08deef7d8de5p-12, + 0x1.bd48fe6a78441p-11, + 0x1.4d2830cef9fb4p-10, + 0x1.722d734128f13p-10, + 0x1.8eb67078149bap-10, + 0x1.88f9a9396ad55p-10, + 0x1.722d734128f13p-10, + 0x1.fc45e699008d6p-11, + 0x1.39fc1cea9fcefp-12, + 0x1.4acee1fa0c71fp-11, + 0x1.bd48fe6a78441p-11, + 0x1.358acd20a1dffp-10, + 0x1.0f4f05df7c97dp-10, + 0x1.0cab58d321192p-13, + 0x1.591fa0c288c8dp-12, + 0x1.ef036b7290ab3p-11, + 0x1.1cd305db9aae1p-10, + 0x1.29aa521d00eb7p-10, + 0x1.23f2496e7293dp-10, + 0x1.13027d5a689efp-10, + 0x1.4acee1fa0c71fp-11, + 0x1.c7ecf3da5ae4cp-12, + 0x1.c7ecf3da5ae4cp-12, + 0x1.32d9934b9b426p-11, + 0x1.aa9dd2dc26fd1p-11, + 0x1.75ec22a0e7289p-11, + 0x1.1874dd49b4c72p-12, + 0x1.7248e820e39adp-14, + 0x1.184bb564455d8p-14, + 0x1.1874dd49b4c72p-12, + 0x1.96fbfeb9d65cp-12, + 0x1.1b0c9faf9f991p-11, + 0x1.672c814638e8dp-11, + 0x1.6e35aaa2736d6p-11, + 0x1.52564a4f59518p-11, + 0x1.3080354ac8a59p-11, + 0x1.d08deef7d8de5p-12, + 0x1.1efa4b4a03a1p-13, + 0x1.b48946f608fecp-12, + 0x1.d9acd8389ec44p-12, + 0x1.d9acd8389ec44p-12, + 0x1.d286dea8d846cp-13, + 0x1.1efa4b4a03a1p-13, + 0x1.7ae50b15f297bp-15, + 0x1.7ae50b15f297bp-15, + 0x1.32ac8be120a64p-13, + 0x1.9207c3cc139fep-13, + 0x1.beb440978dc6dp-13, + 0x1.e12365b24b5b6p-13, + 0x1.e12365b24b5b6p-13, + 0x1.beb440978dc6dp-13, + 0x1.9207c3cc139fep-13, + 0x1.75b54380ce6e3p-13, + 0x1.0cab58d321192p-13, + 0x1.c7aa0c1e13b1ep-14, + 0x1.7ae50b15f297bp-15, + 0x1.7b5ae265be486p-17, + 0x1.8b6c4f77b24dep-15, + 0x1.e1940ec5ec0a9p-14, + 0x1.ed0fa48304231p-16, + 0x1.046913977a3f9p-13, + 0x1.41d689d1b32a5p-12, + 0x1.2c01c5ed7bc91p-12, + 0x1.a27bcb1c644a3p-12, + 0x1.d2b86d95d623dp-12, + 0x1.60d219dc7361dp-11, + 0x1.f3216657d6453p-13, + 0x1.289d68c5da3a2p-12, + 0x1.5f3e146e3de21p-14, + 0x1.e4d893a98d146p-12, + 0x1.f8f798a4659e2p-12, + 0x1.23870624a1dabp-12, + 0x1.3d2d30b6ca761p-12, + 0x1.d6d31726a3d3cp-14, + 0x1.885898b8a53ep-13, + 0x1.4ab649d864475p-12, + 0x1.2ba167cf9512p-11, + 0x1.13a5331414f3ep-11, + 0x1.c2ae4049182b9p-13, + 0x1.2c2a144e90fe7p-10, + 0x1.f8509e1286f5ap-13, + 0x1.04a1591be2a3ep-11, + 0x1.1a04fb3ce1cffp-12, + 0x1.7766c9cbfa525p-13, + 0x1.2c9b39bff3aa5p-13, + 0x1.5298aa1d21f69p-13, + 0x1.6a28e1bb5a93cp-11, + 0x1.bdc7fd242689ap-11, + 0x1.3a569cd4799e9p-11, + 0x1.21de9a33def5cp-10, + 0x1.8a0caff17919ap-10, + 0x1.ff00c10e28991p-10, + 0x1.d230af8adebc1p-10, + 0x1.423b8d977d16fp-10, + 0x1.921eb395a5fb7p-11, + 0x1.45e37fee92808p-11, + 0x1.c1d62513a7fedp-11, + 0x1.3173fef7aecbbp-11, + 0x1.244b5ba070665p-14, + 0x1.518261dbb6249p-10, + 0x1.933c607ffa6fap-11, + 0x1.1db72fddf2153p-10, + 0x1.7cb5d938762d1p-10, + 0x1.c4a15da6b2d7p-11, + 0x1.5f1df191927fbp-11, + 0x1.64b016635611ap-13, + 0x1.18495d3fe24abp-11, + 0x1.d8d19dcb5c2f7p-12, + 0x1.21110393c93b5p-10, + 0x1.4ccc2526db43ep-11, + 0x1.c2258f14d0c36p-10, + 0x1.afc3da6d0ff5p-11, + 0x1.0b386338e76f1p-9, + 0x1.89ae151ce0685p-9, + 0x1.f7a72e9382795p-10, + 0x1.504bc18ead502p-10, + 0x1.6ff624e84ba05p-10, + 0x1.c86965f5c84e6p-11, + 0x1.a8b007a72d79fp-10, + 0x1.6a9a889f6e9f6p-11, + 0x1.ea8727989671fp-13, + 0x1.1676614d0e181p-12, + 0x1.4dfd9971f88f3p-9, + 0x1.db806b45eddf5p-12, + 0x1.6c29416b2667fp-9, + 0x1.59c9b8c9d234bp-10, + 0x1.f2210a5aad29fp-10, + 0x1.e96aca35bd66p-11, + 0x1.0e1dc6d9d5b31p-11, + 0x1.4d73d071be94dp-11, + 0x1.a9221452d9b91p-13, + 0x1.7bcafd957ec0ap-11, + 0x1.aad6b833c798p-11, + 0x1.955b6d9ffec87p-10, + 0x1.2e91deddebceap-10, + 0x1.2c6aa2f5327e7p-9, + 0x1.915d1033c3a12p-10, + 0x1.7fac99ba602b9p-9, + 0x1.709cedbc5ffa2p-9, + 0x1.2fb953a2bc52cp-9, + 0x1.54b3597cf9509p-9, + 0x1.370b4bfe2504fp-9, + 0x1.9c1f50f6466aep-10, + 0x1.4796da6d1d8eap-9, + 0x1.333b4bd66199p-11, + 0x1.7f51fa66bfdf6p-12, + 0x1.e18607864b0b4p-12, + 0x1.dba9a5429f573p-11, + 0x1.8f91f1cb855bep-12, + 0x1.31591a60b43c3p-9, + 0x1.72065ab039b49p-11, + 0x1.2f4a0e0f42f38p-9, + 0x1.2ba749e03375p-9, + 0x1.9d5049607de52p-11, + 0x1.1f443ba4c0411p-9, + 0x1.82d339febb445p-10, + 0x1.6c4240d5665b5p-11, + 0x1.1d0b7c852f984p-12, + 0x1.45088a7970933p-11, + 0x1.b69f75003aa94p-11, + 0x1.6715bb94ad4f6p-11, + 0x1.6b1f647d523fbp-10, + 0x1.033841555c875p-9, + 0x1.0962a87e78eb4p-9, + 0x1.4775d4ecd150bp-9, + 0x1.0b9e93f7c317ap-8, + 0x1.2d49bfd4840d7p-9, + 0x1.377a90ea74073p-8, + 0x1.6ec91ab79b21ap-9, + 0x1.2cb7e016c360ep-11, + 0x1.5877ca49003cdp-9, + 0x1.8881f7ef9a7f3p-10, + 0x1.f7eb8112c7f7fp-12, + 0x1.39aee083b179bp-12, + 0x1.25d1ead2ad234p-10, + 0x1.5242bdd6a8e6dp-9, + 0x1.6a3e452f75933p-9, + 0x1.5e087e6ae3f5ap-9, + 0x1.25b15eb00148cp-10, + 0x1.80d945f679e65p-9, + 0x1.0de695d6c09fp-13, + 0x1.c4749bf4b11bdp-12, + 0x1.1cd2caec60af5p-12, + 0x1.28ebc5cecccd8p-10, + 0x1.da06f75cdbfb9p-10, + 0x1.4c13e4e6b10d4p-9, + 0x1.1e8432430c43dp-8, + 0x1.a412570798343p-9, + 0x1.d47c788e56421p-10, + 0x1.f0f36c5a16212p-10, + 0x1.acdcf4e7e6a82p-11, + 0x1.4a8576fd24f28p-8, + 0x1.7056971c69f01p-9, + 0x1.cb54f3df47b84p-9, + 0x1.a9302376979dcp-10, + 0x1.620de7f428d35p-10, + 0x1.2c748224ad38p-12, + 0x1.ac999f947348ap-10, + 0x1.0748148a7928fp-8, + 0x1.22c0a98962e79p-9, + 0x1.ddc2d544e1ce5p-9, + 0x1.839dd4d773a7dp-11, + 0x1.3b160239e3828p-9, + 0x1.0b070613cf849p-9, + 0x1.bc65576f54d1fp-10, + 0x1.85af71aef8ba8p-12, + 0x1.f00248a09bc14p-12, + 0x1.ebfe316e7dce9p-10, + 0x1.4a3959e2411eep-9, + 0x1.d154a1e8b8b55p-9, + 0x1.3c4d080811116p-9, + 0x1.f5ed25200233dp-9, + 0x1.6939426c09de3p-9, + 0x1.6679d0db9ecdp-9, + 0x1.44f211bd0146fp-8, + 0x1.a8448e165221ep-9, + 0x1.a1d6597a55bc9p-9, + 0x1.ddf5b26f1ec63p-10, + 0x1.86be69cc4f8bfp-12, + 0x1.a902e4d542eb7p-10, + 0x1.c65e17e3ed7fp-12, + 0x1.c8ac8b7f7a1edp-11, + 0x1.db78ccdd1fd38p-10, + 0x1.7b6c0693017c7p-9, + 0x1.d05bc4409a596p-10, + 0x1.29068710fb9d9p-8, + 0x1.9b5cbb5c70c9ap-9, + 0x1.5cfc638aa991fp-10, + 0x1.0e7ff8dc001cfp-9, + 0x1.3634f4c770d72p-9, + 0x1.478240be721fp-11, + 0x1.72d688a9cc372p-12, + 0x1.6ce8c5ec03632p-12, + 0x1.69d998a456671p-11, + 0x1.1d5aebf48a479p-10, + 0x1.a19c862d34f65p-12, + 0x1.09731f97084d2p-9, + 0x1.e3acbe88b5542p-9, + 0x1.1cb530a88a75p-9, + 0x1.a4d61826b00e4p-9, + 0x1.6cae1458f8354p-10, + 0x1.30fb8aecfbab9p-8, + 0x1.a000155165165p-9, + 0x1.3778746bcf6c9p-8, + 0x1.c9077bb15a88bp-9, + 0x1.d57d8ad477251p-10, + 0x1.efe05a8059a7dp-10, + 0x1.faafde62fa5e2p-10, + 0x1.721d35eb328bbp-11, + 0x1.0abbfb404ecc6p-12, + 0x1.7f26e36ecd512p-12, + 0x1.bcf40b35ec199p-11, + 0x1.a45061b6072f5p-9, + 0x1.e147a9665cdfep-10, + 0x1.854532f18e08ap-9, + 0x1.1dc20f956a8dcp-12, + 0x1.a01eb6862a825p-10, + 0x1.1a12a6fc369dcp-9, + 0x1.06d3704631f32p-11, + 0x1.d5f433d8c2138p-11, + 0x1.6ac8e5e4477e3p-10, + 0x1.16073f2d4c0f8p-9, + 0x1.37bff8a56e0e8p-12, + 0x1.3b3137827b6ffp-9, + 0x1.2c537268ec7c3p-9, + 0x1.6e281030810dep-8, + 0x1.7b69b6cfcfbcep-9, + 0x1.ceb4127cf84ffp-10, + 0x1.34790c964cb64p-8, + 0x1.aacb5effed562p-10, + 0x1.8ac8a0e025d4ep-9, + 0x1.40e2005bfcd2bp-9, + 0x1.37855ea5b58d1p-9, + 0x1.04db5310c4a98p-9, + 0x1.01c0e7c243d31p-10, + 0x1.fb9d9236da20dp-12, + 0x1.01c818f0924f6p-8, + 0x1.966d0a159918fp-9, + 0x1.7c01ea070f198p-10, + 0x1.f0ba7ec93924ep-9, + 0x1.3132c0fd92892p-9, + 0x1.a62a690ca01dap-9, + 0x1.5b771112faef9p-12, + 0x1.7b56582475912p-13, + 0x1.972f5449d21c9p-11, + 0x1.c5fc437050c6ep-10, + 0x1.4158891b18c1fp-11, + 0x1.54b5ed7a64a05p-9, + 0x1.5d1f292d14ef1p-10, + 0x1.f62181c929fe7p-9, + 0x1.d735d5deed961p-9, + 0x1.02c7303b85e61p-8, + 0x1.927e7b7d1b9bp-9, + 0x1.ebb97b49b0011p-9, + 0x1.59817edc2f02dp-9, + 0x1.864b268970487p-9, + 0x1.2b0088b5d764ep-9, + 0x1.1d6647444b995p-11, + 0x1.95e82e0d252efp-10, + 0x1.3ef6368e335e6p-11, + 0x1.04c4d6095ce1ap-12, + 0x1.2b12efd6d4119p-8, + 0x1.9a6a2a9240763p-14, + 0x1.6c403fd5b3fc4p-9, + 0x1.33b896e42826p-10, + 0x1.867d40f429b8ep-9, + 0x1.882d6a987abaep-9, + 0x1.94fb12775e5f3p-9, + 0x1.7bc9eb548cdd9p-12, + 0x1.5489417d91482p-11, + 0x1.d5038c6b141dfp-12, + 0x1.b3bc52370d4cep-10, + 0x1.408d7b2ea0595p-11, + 0x1.3ec68aa78492ep-9, + 0x1.0cef391837373p-9, + 0x1.92b9244f17c35p-10, + 0x1.d8e9868b5e58bp-9, + 0x1.9e8b9dbea3eeap-9, + 0x1.c25f2ce1deabap-9, + 0x1.120ce23234074p-9, + 0x1.0f0702cd88a6cp-9, + 0x1.f06599ab3413bp-10, + 0x1.112120e599ec5p-9, + 0x1.717805e79c5efp-10, + 0x1.93af66f54f57fp-12, + 0x1.63f9a03afa452p-11, + 0x1.8f172ce0ba34bp-10, + 0x1.b9f430d8aed26p-10, + 0x1.01a808da4d42p-9, + 0x1.751d502ed3685p-9, + 0x1.b41e0fbbe1522p-9, + 0x1.198126e60ef46p-8, + 0x1.30a5cf81b26d6p-9, + 0x1.3759bcab23d28p-12, + 0x1.4dbc5ac430a36p-10, + 0x1.4d25e95835df2p-11, + 0x1.1ad2e4bec4b1ep-13, + 0x1.bd368e687fe36p-14, + 0x1.5f02a625aa454p-10, + 0x1.3c033a71f15bep-9, + 0x1.9203e27d067c9p-12, + 0x1.1b843b4240979p-9, + 0x1.e081a0d0b1ac7p-9, + 0x1.49e15212cc087p-10, + 0x1.294178637ed85p-9, + 0x1.343befaa25ed7p-10, + 0x1.34ab260bea72fp-9, + 0x1.52113e11045bbp-9, + 0x1.de28feb38f948p-11, + 0x1.31b6a2a45dc23p-10, + 0x1.6c7a51e606348p-11, + 0x1.aa660f16c1ccbp-12, + 0x1.a5681ebd66216p-13, + 0x1.5235a4a95cdecp-10, + 0x1.cc3b060a13e04p-10, + 0x1.6978a4892b367p-9, + 0x1.030405ae9c4b3p-9, + 0x1.7712c310cc9f9p-9, + 0x1.125d0276a0dc3p-9, + 0x1.f8dc6d94702a5p-12, + 0x1.b186c80f15a51p-10, + 0x1.cbf4a6aa51f6bp-13, + 0x1.864fe2e7b9d26p-10, + 0x1.e859350815abap-11, + 0x1.2476a7411b036p-12, + 0x1.bb05a37988426p-10, + 0x1.c90077129b0d5p-9, + 0x1.ac475b496cc6ap-11, + 0x1.04fe007796f05p-10, + 0x1.00562da6418fap-9, + 0x1.1230a7373dd24p-9, + 0x1.690baefdb284ap-9, + 0x1.d970693c23d2ep-13, + 0x1.33c1c87c8101ap-10, + 0x1.a963198337f27p-11, + 0x1.a43de20f95946p-11, + 0x1.ef3c6b6ffff85p-13, + 0x1.46b155931368cp-12, + 0x1.de90fc64e81abp-12, + 0x1.5bef44d4a0477p-10, + 0x1.0037ca6328879p-9, + 0x1.38e45b600136bp-9, + 0x1.89f12a5350f76p-9, + 0x1.b61722623772cp-11, + 0x1.0e5ef648f2893p-10, + 0x1.6d25743bc4aa5p-14, + 0x1.0b4564c15b905p-14, + 0x1.dc831b2c6cd08p-11, + 0x1.98fa4c15a03p-11, + 0x1.0c4c76aa0425fp-11, + 0x1.747677de24accp-10, + 0x1.63f5afa48b8b2p-11, + 0x1.76bbb3ba272cap-10, + 0x1.994f3f80a14adp-10, + 0x1.39a12f1139107p-9, + 0x1.52f0ce198db3ep-11, + 0x1.55f31fcd9a26p-10, + 0x1.b99380b3a557p-11, + 0x1.42e1ca86d20ep-11, + 0x1.99b2abd85aeacp-11, + 0x1.29e9dc5ed27bep-12, + 0x1.2ca4017ba3f34p-11, + 0x1.18ca2d4aa5826p-13, + 0x1.6adc317a6e83p-13, + 0x1.0361355dab74cp-11, + 0x1.36a6edca385d7p-10, + 0x1.ad9dcfdc4f0afp-11, + 0x1.b45830bca013fp-10, + 0x1.5882ed304afafp-10, + 0x1.6b12ee836e611p-13, + 0x1.9159ba6e4f93cp-11, + 0x1.8cf161f01e9c6p-11, + 0x1.c5baefeb9e068p-12, + 0x1.ae57b325b7d35p-13, + 0x1.25ca45511a029p-15, + 0x1.37d5671f93e7bp-11, + 0x1.db87c4fb0fc9fp-12, + 0x1.e0c7cd8603cc1p-14, + 0x1.d9af0d054b7e4p-12, + 0x1.a93a28da60218p-11, + 0x1.847e269b6c2d7p-12, + 0x1.b5cee95db8183p-11, + 0x1.1c43489017dap-10, + 0x1.9bf698f24638ep-12, + 0x1.02cce2e5c4187p-10, + 0x1.cfdfc4a34bb2cp-11, + 0x1.962a7ab702f6cp-13, + 0x1.63131fb438145p-11, + 0x1.82fd05fd6b9d7p-11, + 0x1.4be038282581dp-14, + 0x1.b6d151b47194bp-13, + 0x1.15f914486d3fbp-14, + 0x1.e7215228d0807p-15, + 0x1.743fd53a11d84p-12, + 0x1.cdbb43134e1c7p-12, + 0x1.00815f7387e2dp-11, + 0x1.a37ce5ffc16f3p-11, + 0x1.7d667bdf01a3p-13, + 0x1.68e694fe6fa27p-13, + 0x1.312b2212be965p-11, + 0x1.aed4afd955eap-12, + 0x1.33376b02ffdf5p-16, + 0x1.75ac05537e049p-15, + 0x1.3b6dc56e9e08bp-13, + 0x1.f3edf1ae779fdp-14, + 0x1.6a02dc97cdefep-13, + 0x1.75f1e097da461p-13, + 0x1.9ced55e98d611p-13, + 0x1.e6088dd9bf527p-13, + 0x1.9afddd4b0ef6ap-13, + 0x1.11c128bf7c87bp-12, + 0x1.abc4e2bae893fp-12, + 0x1.6c55a503033a3p-13, + 0x1.495a01c0f8728p-12, + 0x1.2f1f645534dc8p-14, + 0x1.d3b33caef692fp-14, + 0x1.0312b04007346p-16, + 0x1.de16706165ccep-14, + 0x1.59bfa6895acffp-14, + 0x1.816fd8916c531p-15, + 0x1.64c3c2cde4423p-13, + 0x1.fa1627500a21cp-17, + 0x1.107f288e8b6ecp-19 +}}; + +inline constexpr unsigned van_den_bos_unit_square_level_6_degree = 38; +inline constexpr std::size_t van_den_bos_unit_square_level_6_order = 64; + +inline constexpr std::array van_den_bos_unit_square_level_6_weights{{ + 0x1.002003004005p-26, + 0x1.1c6af77ff2646p-19, + 0x1.923958c9dedap-19, + 0x1.1c6af77ff2646p-19, + 0x1.002003004005p-26, + 0x1.1c6af77ff2646p-19, + 0x1.3bd6036189d49p-12, + 0x1.bea7d4e60ed2bp-12, + 0x1.3bd6036189d49p-12, + 0x1.1c6af77ff2646p-19, + 0x1.923958c9dedap-19, + 0x1.bea7d4e60ed2bp-12, + 0x1.3bd49592d534p-11, + 0x1.bea7d4e60ed2bp-12, + 0x1.923958c9dedap-19, + 0x1.1c6af77ff2646p-19, + 0x1.3bd6036189d49p-12, + 0x1.bea7d4e60ed2bp-12, + 0x1.3bd6036189d49p-12, + 0x1.1c6af77ff2646p-19, + 0x1.002003004005p-26, + 0x1.1c6af77ff2646p-19, + 0x1.923958c9dedap-19, + 0x1.1c6af77ff2646p-19, + 0x1.002003004005p-26, + 0x1.7213eb2b28c05p-14, + 0x1.beb028682c336p-13, + 0x1.beb028682c336p-13, + 0x1.55e203242dbddp-13, + 0x1.9ca810194fcbp-12, + 0x1.55e203242dbddp-13, + 0x1.beb028682c336p-13, + 0x1.9ca810194fcbp-12, + 0x1.23ca250e74c0cp-11, + 0x1.9ca810194fcbp-12, + 0x1.e37db917a000ep-13, + 0x1.23ca250e74c0cp-11, + 0x1.23ca250e74c0cp-11, + 0x1.e37db917a000ep-13, + 0x1.beb028682c336p-13, + 0x1.9ca810194fcbp-12, + 0x1.0d942d39bdb96p-11, + 0x1.0d942d39bdb96p-11, + 0x1.beb028682c336p-13, + 0x1.9ca810194fcbp-12, + 0x1.9ca810194fcbp-12, + 0x1.33dfa8b0b58c4p-20, + 0x1.55e203242dbddp-13, + 0x1.beb028682c336p-13, + 0x1.e37db917a000ep-13, + 0x1.beb028682c336p-13, + 0x1.55e203242dbddp-13, + 0x1.7213eb2b28c05p-14, + 0x1.5cc3b6c444ad6p-14, + 0x1.e3bf02a99d3e5p-14, + 0x1.1206c6d1cae8cp-14, + 0x1.7986e83a5d54bp-15, + 0x1.da337b1b2f90cp-13, + 0x1.92027538cd4c5p-13, + 0x1.7986e83a5d54bp-15, + 0x1.23cc0dbc446cfp-12, + 0x1.58326e6cf0d17p-12, + 0x1.0c9e98b6fe011p-13, + 0x1.f04f03ec2197dp-13, + 0x1.b612c78fa3ffap-12, + 0x1.7361c2feba9cfp-12, + 0x1.92027538cd4c5p-13, + 0x1.b4b25441a1a7dp-12, + 0x1.018efbff2ec15p-11, + 0x1.7361c2feba9cfp-12, + 0x1.92027538cd4c5p-13, + 0x1.1e2edcb3cb043p-11, + 0x1.e53aeb69f7ee9p-12, + 0x1.da337b1b2f90cp-13, + 0x1.b612c78fa3ffap-12, + 0x1.1e2edcb3cb043p-11, + 0x1.2fcf5c7658082p-11, + 0x1.da337b1b2f90cp-13, + 0x1.ed391f96138b1p-14, + 0x1.069ab5222f6afp-11, + 0x1.b612c78fa3ffap-12, + 0x1.35c30c2cfabf2p-11, + 0x1.2fcf5c7658082p-11, + 0x1.58326e6cf0d17p-12, + 0x1.e3bf02a99d3e5p-14, + 0x1.e53aeb69f7ee9p-12, + 0x1.92027538cd4c5p-13, + 0x1.018efbff2ec15p-11, + 0x1.e53aeb69f7ee9p-12, + 0x1.7361c2feba9cfp-12, + 0x1.4e70307ab8863p-19, + 0x1.7361c2feba9cfp-12, + 0x1.f04f03ec2197dp-13, + 0x1.0c9e98b6fe011p-13, + 0x1.85f3ed180b29p-13, + 0x1.58326e6cf0d17p-12, + 0x1.58326e6cf0d17p-12, + 0x1.23cc0dbc446cfp-12, + 0x1.f04f03ec2197dp-13, + 0x1.0c9e98b6fe011p-13, + 0x1.7213eb2b28c05p-14, + 0x1.92027538cd4c5p-13, + 0x1.da337b1b2f90cp-13, + 0x1.0c9e98b6fe011p-13, + 0x1.5cc3b6c444ad6p-14, + 0x1.c7adea257efb7p-14, + 0x1.c7adea257efb7p-14, + 0x1.7986e83a5d54bp-15, + 0x1.3a121d012a221p-21, + 0x1.bef01221d192ap-20, + 0x1.1206c6d1cae8cp-14, + 0x1.c7adea257efb7p-14, + 0x1.ed391f96138b1p-14, + 0x1.9a19fd2fcf6e9p-14, + 0x1.812047e23560cp-16, + 0x1.33dfa8b0b58c4p-20, + 0x1.55e203242dbddp-13, + 0x1.92027538cd4c5p-13, + 0x1.da337b1b2f90cp-13, + 0x1.0c9e98b6fe011p-13, + 0x1.7213eb2b28c05p-14, + 0x1.0c9e98b6fe011p-13, + 0x1.85f3ed180b29p-13, + 0x1.58326e6cf0d17p-12, + 0x1.5ef0ab457ac11p-12, + 0x1.443a1025dd684p-12, + 0x1.23cc0dbc446cfp-12, + 0x1.f04f03ec2197dp-13, + 0x1.1206c6d1cae8cp-14, + 0x1.5cc3b6c444ad6p-14, + 0x1.7361c2feba9cfp-12, + 0x1.b612c78fa3ffap-12, + 0x1.f04f03ec2197dp-13, + 0x1.9a19fd2fcf6e9p-14, + 0x1.23cc0dbc446cfp-12, + 0x1.7361c2feba9cfp-12, + 0x1.018efbff2ec15p-11, + 0x1.069ab5222f6afp-11, + 0x1.e53aeb69f7ee9p-12, + 0x1.b4b25441a1a7dp-12, + 0x1.9a19fd2fcf6e9p-14, + 0x1.c7adea257efb7p-14, + 0x1.e53aeb69f7ee9p-12, + 0x1.0d942d39bdb96p-11, + 0x1.1e2edcb3cb043p-11, + 0x1.443a1025dd684p-12, + 0x1.beb028682c336p-13, + 0x1.c7adea257efb7p-14, + 0x1.e3bf02a99d3e5p-14, + 0x1.58326e6cf0d17p-12, + 0x1.2fcf5c7658082p-11, + 0x1.1e2edcb3cb043p-11, + 0x1.018efbff2ec15p-11, + 0x1.58326e6cf0d17p-12, + 0x1.5ef0ab457ac11p-12, + 0x1.069ab5222f6afp-11, + 0x1.35c30c2cfabf2p-11, + 0x1.35c30c2cfabf2p-11, + 0x1.5ef0ab457ac11p-12, + 0x1.ed391f96138b1p-14, + 0x1.e3bf02a99d3e5p-14, + 0x1.da337b1b2f90cp-13, + 0x1.58326e6cf0d17p-12, + 0x1.018efbff2ec15p-11, + 0x1.1e2edcb3cb043p-11, + 0x1.1e2edcb3cb043p-11, + 0x1.b612c78fa3ffap-12, + 0x1.da337b1b2f90cp-13, + 0x1.c7adea257efb7p-14, + 0x1.1e2edcb3cb043p-11, + 0x1.23ca250e74c0cp-11, + 0x1.e53aeb69f7ee9p-12, + 0x1.9ca810194fcbp-12, + 0x1.443a1025dd684p-12, + 0x1.c7adea257efb7p-14, + 0x1.23cc0dbc446cfp-12, + 0x1.7361c2feba9cfp-12, + 0x1.e53aeb69f7ee9p-12, + 0x1.018efbff2ec15p-11, + 0x1.b4b25441a1a7dp-12, + 0x1.23cc0dbc446cfp-12, + 0x1.92027538cd4c5p-13, + 0x1.5cc3b6c444ad6p-14, + 0x1.55e203242dbddp-13, + 0x1.f04f03ec2197dp-13, + 0x1.b612c78fa3ffap-12, + 0x1.b612c78fa3ffap-12, + 0x1.7361c2feba9cfp-12, + 0x1.55e203242dbddp-13, + 0x1.5cc3b6c444ad6p-14, + 0x1.1206c6d1cae8cp-14, + 0x1.f04f03ec2197dp-13, + 0x1.23cc0dbc446cfp-12, + 0x1.443a1025dd684p-12, + 0x1.5ef0ab457ac11p-12, + 0x1.443a1025dd684p-12, + 0x1.85f3ed180b29p-13, + 0x1.1206c6d1cae8cp-14, + 0x1.0c9e98b6fe011p-13, + 0x1.da337b1b2f90cp-13, + 0x1.92027538cd4c5p-13, + 0x1.7986e83a5d54bp-15, + 0x1.7986e83a5d54bp-15, + 0x1.1206c6d1cae8cp-14, + 0x1.9a19fd2fcf6e9p-14, + 0x1.e3bf02a99d3e5p-14, + 0x1.ed391f96138b1p-14, + 0x1.e3bf02a99d3e5p-14, + 0x1.9a19fd2fcf6e9p-14, + 0x1.5cc3b6c444ad6p-14, + 0x1.1206c6d1cae8cp-14, + 0x1.812047e23560cp-16, + 0x1.739b6541e7219p-19, + 0x1.36ecd479dff6dp-19, + 0x1.845d7d52e23aep-17, + 0x1.d4f00f486d2a7p-16, + 0x1.eef9f7e9cc76fp-15, + 0x1.dbf47f1231d1dp-15, + 0x1.845d7d52e23aep-17, + 0x1.38e6dfbe31a61p-14, + 0x1.9a19fd2fcf6e9p-14, + 0x1.d7fc45adbc5c3p-14, + 0x1.ead92195385e9p-14, + 0x1.5cc3b6c444ad6p-14, + 0x1.d106d1827e3dbp-15, + 0x1.a9f9e0ceb015p-15, + 0x1.1b891474590b4p-13, + 0x1.52df315cd35c8p-13, + 0x1.30fa3060f13a9p-13, + 0x1.7cb3c11d9ca15p-16, + 0x1.c7d9d894c63d5p-14, + 0x1.aa66eb9742065p-13, + 0x1.e129ba37d95f4p-13, + 0x1.e129ba37d95f4p-13, + 0x1.32ba52f726e14p-13, + 0x1.18c0b90d59b0cp-14, + 0x1.79d17d6bc4123p-13, + 0x1.cc5e7b3b4c31dp-13, + 0x1.131bd013b0b86p-12, + 0x1.1cf4029103dcap-12, + 0x1.ef2f00cd079b3p-13, + 0x1.18c07cd792fc8p-13, + 0x1.d4f00f486d2a7p-16, + 0x1.979110b389ep-14, + 0x1.4ae0abede47bdp-13, + 0x1.4fd43801418a2p-12, + 0x1.5d4011667dbe5p-12, + 0x1.0f482ae926bccp-12, + 0x1.38e6dfbe31a61p-14, + 0x1.1b5bfae7e4ec8p-12, + 0x1.6169142619ad6p-12, + 0x1.72395647553f7p-12, + 0x1.bd463d29e78e7p-13, + 0x1.32ba52f726e14p-13, + 0x1.38e6dfbe31a61p-14, + 0x1.a51f0a8c81268p-13, + 0x1.bc813e2d079a8p-12, + 0x1.89ea7ae89490bp-12, + 0x1.7d44cf6c90185p-14, + 0x1.35c496783bcfep-12, + 0x1.aea0d5a5ab866p-12, + 0x1.d34217b836e1ep-12, + 0x1.dee6ad1d39242p-12, + 0x1.d34217b836e1ep-12, + 0x1.594579a5ba55p-12, + 0x1.7d44cf6c90185p-14, + 0x1.30fa3060f13a9p-13, + 0x1.ef2f00cd079b3p-13, + 0x1.95fe7b23a6e97p-12, + 0x1.0556ff4fa766ap-11, + 0x1.95fe7b23a6e97p-12, + 0x1.ef2f00cd079b3p-13, + 0x1.b6a4b3ffc4a6ap-15, + 0x1.eb4c6e54479cbp-12, + 0x1.0156073eb7fb6p-11, + 0x1.112fabdb8826cp-11, + 0x1.15326b6e457a1p-11, + 0x1.0156073eb7fb6p-11, + 0x1.eb4c6e54479cbp-12, + 0x1.aa66eb9742065p-13, + 0x1.b2fc24e456ad3p-14, + 0x1.52df315cd35c8p-13, + 0x1.131bd013b0b86p-12, + 0x1.72395647553f7p-12, + 0x1.72395647553f7p-12, + 0x1.dbf47f1231d1dp-15, + 0x1.d34217b836e1ep-12, + 0x1.1739b772c9b18p-11, + 0x1.2e3b26ec46ac9p-11, + 0x1.286c8253654a1p-11, + 0x1.1739b772c9b18p-11, + 0x1.f697fbf28bb2bp-12, + 0x1.1cf4029103dcap-12, + 0x1.d7fc45adbc5c3p-14, + 0x1.240db12122d8cp-12, + 0x1.112fabdb8826cp-11, + 0x1.b612c78fa3ffap-12, + 0x1.e3bf02a99d3e5p-14, + 0x1.ead92195385e9p-14, + 0x1.bc813e2d079a8p-12, + 0x1.0556ff4fa766ap-11, + 0x1.344534e0733b3p-11, + 0x1.38cbd0d3294e9p-11, + 0x1.2cc6982015a2p-11, + 0x1.e5ee9656b2435p-12, + 0x1.285759f1ebdd6p-12, + 0x1.6ecab14b2f63fp-13, + 0x1.2e3b26ec46ac9p-11, + 0x1.3a4f433e0dde2p-11, + 0x1.1689c57b7e1f8p-11, + 0x1.6ecab14b2f63fp-13, + 0x1.f15f12f98a101p-15, + 0x1.eef9f7e9cc76fp-15, + 0x1.5d4011667dbe5p-12, + 0x1.e5ee9656b2435p-12, + 0x1.15326b6e457a1p-11, + 0x1.3a4f433e0dde2p-11, + 0x1.344534e0733b3p-11, + 0x1.22627540e2deep-11, + 0x1.8ecc24e8e12d8p-12, + 0x1.286c8253654a1p-11, + 0x1.344534e0733b3p-11, + 0x1.018efbff2ec15p-11, + 0x1.240db12122d8cp-12, + 0x1.67be7b7476ef3p-13, + 0x1.dbf47f1231d1dp-15, + 0x1.5eff8200647b4p-13, + 0x1.1cf4029103dcap-12, + 0x1.ab6c4ca8ff0dfp-12, + 0x1.f697fbf28bb2bp-12, + 0x1.2cc6982015a2p-11, + 0x1.2137a078810c5p-11, + 0x1.7f78dc4b09f7bp-12, + 0x1.1739b772c9b18p-11, + 0x1.22627540e2deep-11, + 0x1.c31d8b518c68p-12, + 0x1.131bd013b0b86p-12, + 0x1.cb8307cc21019p-15, + 0x1.aa66eb9742065p-13, + 0x1.6169142619ad6p-12, + 0x1.eb4c6e54479cbp-12, + 0x1.112fabdb8826cp-11, + 0x1.0a8b6a5df5a38p-11, + 0x1.eb4c6e54479cbp-12, + 0x1.cf3196b56cb6bp-12, + 0x1.6169142619ad6p-12, + 0x1.aa66eb9742065p-13, + 0x1.9d8cf8d0fa38ap-15, + 0x1.95fe7b23a6e97p-12, + 0x1.069ab5222f6afp-11, + 0x1.4d318b5e139f8p-12, + 0x1.7d44cf6c90185p-14, + 0x1.75beebbe367fdp-13, + 0x1.0f482ae926bccp-12, + 0x1.c31d8b518c68p-12, + 0x1.dee6ad1d39242p-12, + 0x1.e8487d7046de7p-12, + 0x1.dee6ad1d39242p-12, + 0x1.c31d8b518c68p-12, + 0x1.79733adb87f2fp-12, + 0x1.75beebbe367fdp-13, + 0x1.7d44cf6c90185p-14, + 0x1.594579a5ba55p-12, + 0x1.89ea7ae89490bp-12, + 0x1.a51f0a8c81268p-13, + 0x1.3b8893f0f861bp-15, + 0x1.d16313c000fdfp-14, + 0x1.bd463d29e78e7p-13, + 0x1.4d318b5e139f8p-12, + 0x1.72395647553f7p-12, + 0x1.8ecc24e8e12d8p-12, + 0x1.8906fb9f100eap-12, + 0x1.72395647553f7p-12, + 0x1.fc71b8506bc3cp-13, + 0x1.38e6dfbe31a61p-14, + 0x1.4ae0abede47bdp-13, + 0x1.bd463d29e78e7p-13, + 0x1.3580927291291p-12, + 0x1.0f482ae926bccp-12, + 0x1.1454c75189208p-15, + 0x1.59d2b4e7ed4c3p-14, + 0x1.ef2f00cd079b3p-13, + 0x1.1cf4029103dcap-12, + 0x1.29c66a911aa4ep-12, + 0x1.240db12122d8cp-12, + 0x1.131bd013b0b86p-12, + 0x1.4ae0abede47bdp-13, + 0x1.c7d9d894c63d5p-14, + 0x1.c7d9d894c63d5p-14, + 0x1.32ba52f726e14p-13, + 0x1.aa66eb9742065p-13, + 0x1.75beebbe367fdp-13, + 0x1.18c0b90d59b0cp-14, + 0x1.7cb3c11d9ca15p-16, + 0x1.20d013b3c3f7cp-16, + 0x1.18c0b90d59b0cp-14, + 0x1.979110b389ep-14, + 0x1.1b891474590b4p-13, + 0x1.67be7b7476ef3p-13, + 0x1.6ecab14b2f63fp-13, + 0x1.52df315cd35c8p-13, + 0x1.30fa3060f13a9p-13, + 0x1.d16313c000fdfp-14, + 0x1.1e676cd667ca1p-15, + 0x1.b2fc24e456ad3p-14, + 0x1.d7fc45adbc5c3p-14, + 0x1.d7fc45adbc5c3p-14, + 0x1.d106d1827e3dbp-15, + 0x1.1e676cd667ca1p-15, + 0x1.845d7d52e23aep-17, + 0x1.845d7d52e23aep-17, + 0x1.3b8893f0f861bp-15, + 0x1.9d8cf8d0fa38ap-15, + 0x1.cb8307cc21019p-15, + 0x1.eef9f7e9cc76fp-15, + 0x1.eef9f7e9cc76fp-15, + 0x1.cb8307cc21019p-15, + 0x1.9d8cf8d0fa38ap-15, + 0x1.8079b6c1e519dp-15, + 0x1.1454c75189208p-15, + 0x1.d4f00f486d2a7p-16, + 0x1.845d7d52e23aep-17, + 0x1.7b3acfa9c3d3ep-20, + 0x1.7b3acfa9c3d3ep-20, + 0x1.33dfa8b0b58c4p-20, + 0x1.87a1ac1eabcdbp-18, + 0x1.20d013b3c3f7cp-16, + 0x1.1454c75189208p-15, + 0x1.5fb2a21520846p-15, + 0x1.9d8cf8d0fa38ap-15, + 0x1.cb8307cc21019p-15, + 0x1.e7d08e6d347c4p-15, + 0x1.f15f12f98a101p-15, + 0x1.eef9f7e9cc76fp-15, + 0x1.e7d08e6d347c4p-15, + 0x1.cb8307cc21019p-15, + 0x1.9d8cf8d0fa38ap-15, + 0x1.5fb2a21520846p-15, + 0x1.1454c75189208p-15, + 0x1.20d013b3c3f7cp-16, + 0x1.812047e23560cp-16, + 0x1.7986e83a5d54bp-15, + 0x1.7d44cf6c90185p-14, + 0x1.b2fc24e456ad3p-14, + 0x1.ead92195385e9p-14, + 0x1.d7fc45adbc5c3p-14, + 0x1.b2fc24e456ad3p-14, + 0x1.7d44cf6c90185p-14, + 0x1.38e6dfbe31a61p-14, + 0x1.7986e83a5d54bp-15, + 0x1.845d7d52e23aep-17, + 0x1.20d013b3c3f7cp-16, + 0x1.18c0b90d59b0cp-14, + 0x1.979110b389ep-14, + 0x1.035cfd2d1dc57p-13, + 0x1.437b6fee6b24ap-13, + 0x1.5eff8200647b4p-13, + 0x1.6d068d2130368p-13, + 0x1.6d068d2130368p-13, + 0x1.437b6fee6b24ap-13, + 0x1.035cfd2d1dc57p-13, + 0x1.d16313c000fdfp-14, + 0x1.59d2b4e7ed4c3p-14, + 0x1.a9f9e0ceb015p-15, + 0x1.18c0b90d59b0cp-14, + 0x1.32ba52f726e14p-13, + 0x1.75beebbe367fdp-13, + 0x1.ceac262809173p-13, + 0x1.ceac262809173p-13, + 0x1.aa66eb9742065p-13, + 0x1.75beebbe367fdp-13, + 0x1.7cb3c11d9ca15p-16, + 0x1.d106d1827e3dbp-15, + 0x1.59d2b4e7ed4c3p-14, + 0x1.18c07cd792fc8p-13, + 0x1.4ae0abede47bdp-13, + 0x1.ef2f00cd079b3p-13, + 0x1.069d5fc76ebep-12, + 0x1.240db12122d8cp-12, + 0x1.29c66a911aa4ep-12, + 0x1.240db12122d8cp-12, + 0x1.131bd013b0b86p-12, + 0x1.cc5e7b3b4c31dp-13, + 0x1.a51f0a8c81268p-13, + 0x1.4ae0abede47bdp-13, + 0x1.c7d9d894c63d5p-14, + 0x1.d106d1827e3dbp-15, + 0x1.1454c75189208p-15, + 0x1.f04f03ec2197dp-13, + 0x1.0f482ae926bccp-12, + 0x1.443a1025dd684p-12, + 0x1.5d4011667dbe5p-12, + 0x1.3580927291291p-12, + 0x1.bd463d29e78e7p-13, + 0x1.4ae0abede47bdp-13, + 0x1.979110b389ep-14, + 0x1.1454c75189208p-15, + 0x1.d16313c000fdfp-14, + 0x1.32ba52f726e14p-13, + 0x1.bd463d29e78e7p-13, + 0x1.fc71b8506bc3cp-13, + 0x1.4d318b5e139f8p-12, + 0x1.72395647553f7p-12, + 0x1.8906fb9f100eap-12, + 0x1.90ba1dfe04d87p-12, + 0x1.8906fb9f100eap-12, + 0x1.7f78dc4b09f7bp-12, + 0x1.6169142619ad6p-12, + 0x1.35c496783bcfep-12, + 0x1.fc71b8506bc3cp-13, + 0x1.79d17d6bc4123p-13, + 0x1.d16313c000fdfp-14, + 0x1.5fb2a21520846p-15, + 0x1.55e203242dbddp-13, + 0x1.1b5bfae7e4ec8p-12, + 0x1.594579a5ba55p-12, + 0x1.89ea7ae89490bp-12, + 0x1.ab6c4ca8ff0dfp-12, + 0x1.bc813e2d079a8p-12, + 0x1.ab6c4ca8ff0dfp-12, + 0x1.594579a5ba55p-12, + 0x1.a51f0a8c81268p-13, + 0x1.5cc3b6c444ad6p-14, + 0x1.5fb2a21520846p-15, + 0x1.1b891474590b4p-13, + 0x1.75beebbe367fdp-13, + 0x1.cc5e7b3b4c31dp-13, + 0x1.0f482ae926bccp-12, + 0x1.594579a5ba55p-12, + 0x1.95fe7b23a6e97p-12, + 0x1.c31d8b518c68p-12, + 0x1.e5ee9656b2435p-12, + 0x1.e5ee9656b2435p-12, + 0x1.c31d8b518c68p-12, + 0x1.95fe7b23a6e97p-12, + 0x1.79733adb87f2fp-12, + 0x1.35c496783bcfep-12, + 0x1.75beebbe367fdp-13, + 0x1.1b891474590b4p-13, + 0x1.9d8cf8d0fa38ap-15, + 0x1.4d318b5e139f8p-12, + 0x1.cf3196b56cb6bp-12, + 0x1.f697fbf28bb2bp-12, + 0x1.0556ff4fa766ap-11, + 0x1.cf3196b56cb6bp-12, + 0x1.23cc0dbc446cfp-12, + 0x1.30fa3060f13a9p-13, + 0x1.9d8cf8d0fa38ap-15, + 0x1.b2fc24e456ad3p-14, + 0x1.437b6fee6b24ap-13, + 0x1.069d5fc76ebep-12, + 0x1.6169142619ad6p-12, + 0x1.aea0d5a5ab866p-12, + 0x1.0a8b6a5df5a38p-11, + 0x1.15326b6e457a1p-11, + 0x1.1689c57b7e1f8p-11, + 0x1.112fabdb8826cp-11, + 0x1.0a8b6a5df5a38p-11, + 0x1.cf3196b56cb6bp-12, + 0x1.89ea7ae89490bp-12, + 0x1.3580927291291p-12, + 0x1.437b6fee6b24ap-13, + 0x1.cb8307cc21019p-15, + 0x1.443a1025dd684p-12, + 0x1.0156073eb7fb6p-11, + 0x1.22627540e2deep-11, + 0x1.22627540e2deep-11, + 0x1.1739b772c9b18p-11, + 0x1.0156073eb7fb6p-11, + 0x1.c31d8b518c68p-12, + 0x1.131bd013b0b86p-12, + 0x1.739b6541e7219p-19, + 0x1.d7fc45adbc5c3p-14, + 0x1.ceac262809173p-13, + 0x1.4fd43801418a2p-12, + 0x1.ab6c4ca8ff0dfp-12, + 0x1.f697fbf28bb2bp-12, + 0x1.2137a078810c5p-11, + 0x1.286c8253654a1p-11, + 0x1.2cc6982015a2p-11, + 0x1.2137a078810c5p-11, + 0x1.0a8b6a5df5a38p-11, + 0x1.ab6c4ca8ff0dfp-12, + 0x1.4fd43801418a2p-12, + 0x1.ceac262809173p-13, + 0x1.5eff8200647b4p-13, + 0x1.e7d08e6d347c4p-15, + 0x1.67be7b7476ef3p-13, + 0x1.dee6ad1d39242p-12, + 0x1.018efbff2ec15p-11, + 0x1.286c8253654a1p-11, + 0x1.35c30c2cfabf2p-11, + 0x1.344534e0733b3p-11, + 0x1.112fabdb8826cp-11, + 0x1.dee6ad1d39242p-12, + 0x1.8906fb9f100eap-12, + 0x1.240db12122d8cp-12, + 0x1.67be7b7476ef3p-13, + 0x1.e7d08e6d347c4p-15, + 0x1.6d068d2130368p-13, + 0x1.e129ba37d95f4p-13, + 0x1.285759f1ebdd6p-12, + 0x1.5d4011667dbe5p-12, + 0x1.8ecc24e8e12d8p-12, + 0x1.15326b6e457a1p-11, + 0x1.22627540e2deep-11, + 0x1.2cc6982015a2p-11, + 0x1.38cbd0d3294e9p-11, + 0x1.344534e0733b3p-11, + 0x1.22627540e2deep-11, + 0x1.0556ff4fa766ap-11, + 0x1.bc813e2d079a8p-12, + 0x1.5d4011667dbe5p-12, + 0x1.e129ba37d95f4p-13, + 0x1.ead92195385e9p-14, + 0x1.eef9f7e9cc76fp-15, + 0x1.f15f12f98a101p-15, + 0x1.29c66a911aa4ep-12, + 0x1.e8487d7046de7p-12, + 0x1.1689c57b7e1f8p-11, + 0x1.3a4f433e0dde2p-11, + 0x1.2e3b26ec46ac9p-11, + 0x1.e8487d7046de7p-12, + 0x1.90ba1dfe04d87p-12, + 0x1.29c66a911aa4ep-12, + 0x1.ead92195385e9p-14, + 0x1.e129ba37d95f4p-13, + 0x1.285759f1ebdd6p-12, + 0x1.8ecc24e8e12d8p-12, + 0x1.bc813e2d079a8p-12, + 0x1.0556ff4fa766ap-11, + 0x1.2cc6982015a2p-11, + 0x1.38cbd0d3294e9p-11, + 0x1.38cbd0d3294e9p-11, + 0x1.2cc6982015a2p-11, + 0x1.15326b6e457a1p-11, + 0x1.0556ff4fa766ap-11, + 0x1.bc813e2d079a8p-12, + 0x1.5d4011667dbe5p-12, + 0x1.e129ba37d95f4p-13, + 0x1.ead92195385e9p-14, + 0x1.67be7b7476ef3p-13, + 0x1.8906fb9f100eap-12, + 0x1.112fabdb8826cp-11, + 0x1.2fcf5c7658082p-11, + 0x1.344534e0733b3p-11, + 0x1.112fabdb8826cp-11, + 0x1.dee6ad1d39242p-12, + 0x1.e7d08e6d347c4p-15, + 0x1.80e796b538f46p-19, + 0x1.d7fc45adbc5c3p-14, + 0x1.ceac262809173p-13, + 0x1.4fd43801418a2p-12, + 0x1.d34217b836e1ep-12, + 0x1.0a8b6a5df5a38p-11, + 0x1.1739b772c9b18p-11, + 0x1.286c8253654a1p-11, + 0x1.2cc6982015a2p-11, + 0x1.286c8253654a1p-11, + 0x1.1739b772c9b18p-11, + 0x1.f697fbf28bb2bp-12, + 0x1.ab6c4ca8ff0dfp-12, + 0x1.4fd43801418a2p-12, + 0x1.1cf4029103dcap-12, + 0x1.ceac262809173p-13, + 0x1.d7fc45adbc5c3p-14, + 0x1.dbf47f1231d1dp-15, + 0x1.443a1025dd684p-12, + 0x1.72395647553f7p-12, + 0x1.c31d8b518c68p-12, + 0x1.0156073eb7fb6p-11, + 0x1.22627540e2deep-11, + 0x1.1739b772c9b18p-11, + 0x1.0156073eb7fb6p-11, + 0x1.72395647553f7p-12, + 0x1.52df315cd35c8p-13, + 0x1.b6a4b3ffc4a6ap-15, + 0x1.437b6fee6b24ap-13, + 0x1.069d5fc76ebep-12, + 0x1.89ea7ae89490bp-12, + 0x1.cf3196b56cb6bp-12, + 0x1.0156073eb7fb6p-11, + 0x1.0a8b6a5df5a38p-11, + 0x1.1689c57b7e1f8p-11, + 0x1.15326b6e457a1p-11, + 0x1.112fabdb8826cp-11, + 0x1.aea0d5a5ab866p-12, + 0x1.89ea7ae89490bp-12, + 0x1.3580927291291p-12, + 0x1.437b6fee6b24ap-13, + 0x1.b6a4b3ffc4a6ap-15, + 0x1.9a19fd2fcf6e9p-14, + 0x1.ef2f00cd079b3p-13, + 0x1.4d318b5e139f8p-12, + 0x1.b4b25441a1a7dp-12, + 0x1.cf3196b56cb6bp-12, + 0x1.0556ff4fa766ap-11, + 0x1.f697fbf28bb2bp-12, + 0x1.cf3196b56cb6bp-12, + 0x1.95fe7b23a6e97p-12, + 0x1.ef2f00cd079b3p-13, + 0x1.9a19fd2fcf6e9p-14, + 0x1.8079b6c1e519dp-15, + 0x1.1b891474590b4p-13, + 0x1.cc5e7b3b4c31dp-13, + 0x1.594579a5ba55p-12, + 0x1.79733adb87f2fp-12, + 0x1.95fe7b23a6e97p-12, + 0x1.d34217b836e1ep-12, + 0x1.e5ee9656b2435p-12, + 0x1.e5ee9656b2435p-12, + 0x1.aea0d5a5ab866p-12, + 0x1.95fe7b23a6e97p-12, + 0x1.594579a5ba55p-12, + 0x1.0f482ae926bccp-12, + 0x1.cc5e7b3b4c31dp-13, + 0x1.1b891474590b4p-13, + 0x1.8079b6c1e519dp-15, + 0x1.5fb2a21520846p-15, + 0x1.035cfd2d1dc57p-13, + 0x1.1b5bfae7e4ec8p-12, + 0x1.89ea7ae89490bp-12, + 0x1.bc813e2d079a8p-12, + 0x1.bc813e2d079a8p-12, + 0x1.ab6c4ca8ff0dfp-12, + 0x1.594579a5ba55p-12, + 0x1.1b5bfae7e4ec8p-12, + 0x1.035cfd2d1dc57p-13, + 0x1.79d17d6bc4123p-13, + 0x1.fc71b8506bc3cp-13, + 0x1.1b5bfae7e4ec8p-12, + 0x1.35c496783bcfep-12, + 0x1.7f78dc4b09f7bp-12, + 0x1.8906fb9f100eap-12, + 0x1.90ba1dfe04d87p-12, + 0x1.7f78dc4b09f7bp-12, + 0x1.6169142619ad6p-12, + 0x1.35c496783bcfep-12, + 0x1.1b5bfae7e4ec8p-12, + 0x1.bd463d29e78e7p-13, + 0x1.32ba52f726e14p-13, + 0x1.d16313c000fdfp-14, + 0x1.3b8893f0f861bp-15, + 0x1.1454c75189208p-15, + 0x1.979110b389ep-14, + 0x1.0f482ae926bccp-12, + 0x1.3580927291291p-12, + 0x1.5d4011667dbe5p-12, + 0x1.5d4011667dbe5p-12, + 0x1.bd463d29e78e7p-13, + 0x1.4ae0abede47bdp-13, + 0x1.d4f00f486d2a7p-16, + 0x1.d106d1827e3dbp-15, + 0x1.c7d9d894c63d5p-14, + 0x1.4ae0abede47bdp-13, + 0x1.79d17d6bc4123p-13, + 0x1.a51f0a8c81268p-13, + 0x1.069d5fc76ebep-12, + 0x1.131bd013b0b86p-12, + 0x1.240db12122d8cp-12, + 0x1.1cf4029103dcap-12, + 0x1.069d5fc76ebep-12, + 0x1.ef2f00cd079b3p-13, + 0x1.cc5e7b3b4c31dp-13, + 0x1.a51f0a8c81268p-13, + 0x1.79d17d6bc4123p-13, + 0x1.18c07cd792fc8p-13, + 0x1.59d2b4e7ed4c3p-14, + 0x1.d106d1827e3dbp-15, + 0x1.d4f00f486d2a7p-16, + 0x1.7986e83a5d54bp-15, + 0x1.75beebbe367fdp-13, + 0x1.ceac262809173p-13, + 0x1.e129ba37d95f4p-13, + 0x1.e129ba37d95f4p-13, + 0x1.ceac262809173p-13, + 0x1.aa66eb9742065p-13, + 0x1.32ba52f726e14p-13, + 0x1.c7d9d894c63d5p-14, + 0x1.1e676cd667ca1p-15, + 0x1.a9f9e0ceb015p-15, + 0x1.59d2b4e7ed4c3p-14, + 0x1.d16313c000fdfp-14, + 0x1.035cfd2d1dc57p-13, + 0x1.30fa3060f13a9p-13, + 0x1.437b6fee6b24ap-13, + 0x1.52df315cd35c8p-13, + 0x1.5eff8200647b4p-13, + 0x1.6d068d2130368p-13, + 0x1.67be7b7476ef3p-13, + 0x1.5eff8200647b4p-13, + 0x1.437b6fee6b24ap-13, + 0x1.1b891474590b4p-13, + 0x1.035cfd2d1dc57p-13, + 0x1.59d2b4e7ed4c3p-14, + 0x1.18c0b90d59b0cp-14, + 0x1.a9f9e0ceb015p-15, + 0x1.20d013b3c3f7cp-16, + 0x1.845d7d52e23aep-17, + 0x1.1e676cd667ca1p-15, + 0x1.38e6dfbe31a61p-14, + 0x1.7d44cf6c90185p-14, + 0x1.ead92195385e9p-14, + 0x1.ead92195385e9p-14, + 0x1.b2fc24e456ad3p-14, + 0x1.7d44cf6c90185p-14, + 0x1.38e6dfbe31a61p-14, + 0x1.3a121d012a221p-21, + 0x1.87a1ac1eabcdbp-18, + 0x1.d4f00f486d2a7p-16, + 0x1.1454c75189208p-15, + 0x1.5fb2a21520846p-15, + 0x1.8079b6c1e519dp-15, + 0x1.b6a4b3ffc4a6ap-15, + 0x1.dbf47f1231d1dp-15, + 0x1.e7d08e6d347c4p-15, + 0x1.f15f12f98a101p-15, + 0x1.e7d08e6d347c4p-15, + 0x1.dbf47f1231d1dp-15, + 0x1.b6a4b3ffc4a6ap-15, + 0x1.7cb3c11d9ca15p-16, + 0x1.20d013b3c3f7cp-16, + 0x1.87a1ac1eabcdbp-18, + 0x1.33dfa8b0b58c4p-20, + 0x1.739b6541e7219p-19, + 0x1.36ecd479dff6dp-19, + 0x1.fe57f6a6e731ep-20, + 0x1.bef01221d192ap-20, + 0x1.3cb6557d7c9abp-22, + 0x1.40ffdae8854acp-15, + 0x1.f35ff85705158p-15, + 0x1.e0cacd0d5fea7p-14, + 0x1.86e0e7979f837p-13, + 0x1.d4082a41ab091p-13, + 0x1.0ce7ae42c1726p-13, + 0x1.5b80fabe894e4p-14, + 0x1.e14cce9063968p-14, + 0x1.4dbf2cbef2b28p-13, + 0x1.4828f42f2c9dp-14, + 0x1.39a66bccfa3e7p-14, + 0x1.cc553c5ded118p-15, + 0x1.b277d809f6df6p-15, + 0x1.9dbe66aa5995dp-13, + 0x1.6757e936356acp-16, + 0x1.4b4fce42c6c91p-13, + 0x1.00d97b8194d7p-12, + 0x1.20c1052e2556cp-12, + 0x1.347ad6eb21009p-12, + 0x1.d3c0ee74ecd41p-13, + 0x1.03e2cdbcb48cap-13, + 0x1.d34d3f5e7475ap-16, + 0x1.3c2be98defa82p-16, + 0x1.0608b8dd901dfp-13, + 0x1.368c1a39495fbp-12, + 0x1.8de1cce97b376p-12, + 0x1.25916ea53dca7p-13, + 0x1.b3068502894e8p-13, + 0x1.178ae35bae64p-12, + 0x1.09ac02a2a0ee8p-11, + 0x1.276acfbc185cp-12, + 0x1.e6355f39a4d76p-12, + 0x1.ec08957c5500cp-13, + 0x1.07ba5d4c475a6p-12, + 0x1.23b4cbe13e42ep-13, + 0x1.7fa141897382cp-14, + 0x1.ee6a02999aa09p-15, + 0x1.574d4feef8756p-15, + 0x1.7664a1318c9c3p-15, + 0x1.0855765c3132p-12, + 0x1.eb11b73e4447ep-12, + 0x1.e13612d535f2dp-12, + 0x1.9163473369c68p-12, + 0x1.6acf555cd744cp-13, + 0x1.21d7e8a2cf1e6p-11, + 0x1.22ee15624a89cp-12, + 0x1.7321b82432018p-13, + 0x1.2757f823f5d66p-13, + 0x1.2dd900af8296p-14, + 0x1.020309f01ed3ep-12, + 0x1.902cb235018b7p-12, + 0x1.2510f3239330dp-13, + 0x1.50ffff111a7b5p-11, + 0x1.566414e33a184p-11, + 0x1.f14f02c3c202fp-13, + 0x1.ad287a188586ep-11, + 0x1.0f303e27fd2dp-12, + 0x1.9f99912dee285p-11, + 0x1.33742eb64e032p-11, + 0x1.2a601dbc04e2p-12, + 0x1.637fc46af1a3p-12, + 0x1.98143c0f8dd3ep-13, + 0x1.0838b53647827p-11, + 0x1.e1ee8655cd66bp-11, + 0x1.34503d0c51d89p-11, + 0x1.4c703ef7c1b5bp-11, + 0x1.239d6b5344f34p-10, + 0x1.e5b79886959a2p-11, + 0x1.d650e582cabf9p-13, + 0x1.023f8b44a5b6ap-11, + 0x1.ce161bf44e16dp-13, + 0x1.795165f54608bp-12, + 0x1.d042e2ccea46ap-14, + 0x1.3008d7563e2f3p-15, + 0x1.2119d26e4e236p-12, + 0x1.2d69e7f2a0708p-11, + 0x1.4be4faa0b26c5p-12, + 0x1.8425a5ad7c89dp-11, + 0x1.6041e40711abcp-11, + 0x1.01552061f902p-11, + 0x1.2b5993c136239p-11, + 0x1.2d0efd24ef8edp-11, + 0x1.067d366bfe13ap-10, + 0x1.383581f5a0487p-11, + 0x1.8ee0eeef67ee3p-12, + 0x1.0aea2e76820cbp-12, + 0x1.4ff758a1384a9p-13, + 0x1.da5acba496a04p-14, + 0x1.19e124fd51ad3p-13, + 0x1.0c374837c6dc5p-10, + 0x1.21b4a72417d2ap-10, + 0x1.60fac0246d18ap-10, + 0x1.9043ed72efcp-10, + 0x1.2c8744bb8345ap-12, + 0x1.3fd8211ba4b29p-12, + 0x1.be7113706a8a5p-11, + 0x1.2254f9a5a17bfp-13, + 0x1.4f14a1844bd0bp-13, + 0x1.2fd07986f70afp-11, + 0x1.237171196be2bp-11, + 0x1.86cf36c7d8807p-12, + 0x1.31450e2325611p-13, + 0x1.1c3ed3beb370ep-10, + 0x1.3872713ca0fep-10, + 0x1.6cfaeae1e5ff1p-10, + 0x1.f2320c22ef5e5p-11, + 0x1.34bf7cb0a5c08p-10, + 0x1.0ed669f7ccc69p-10, + 0x1.537b023a6bb1bp-11, + 0x1.ff87cf33afde4p-16, + 0x1.6379536f05b32p-13, + 0x1.bfba7afda0dffp-12, + 0x1.6fe0b3eb38f1ap-12, + 0x1.1b8fa65903986p-11, + 0x1.171a137e777ddp-9, + 0x1.8e0947f4ed25ap-10, + 0x1.2e9af2cdd22afp-10, + 0x1.8efdee653b0eep-11, + 0x1.8c66b956c9eadp-12, + 0x1.fa0b1467ce3dap-12, + 0x1.3ce073f425d9ap-12, + 0x1.a3895cf4a772ap-11, + 0x1.e165956f44526p-11, + 0x1.be9f273e9b36p-10, + 0x1.c884d62793766p-11, + 0x1.7cfb70c362dap-10, + 0x1.9ff3a2f6bd1f8p-10, + 0x1.65edc5b178d1cp-10, + 0x1.e672173a39783p-10, + 0x1.48da490898c35p-10, + 0x1.7418416bbe40ep-12, + 0x1.25d9e8b3b1339p-12, + 0x1.1d62d81e0f133p-12, + 0x1.1f17216ed01c9p-12, + 0x1.87b0be93330f3p-13, + 0x1.267e7b44435a9p-14, + 0x1.1780c7eb83103p-11, + 0x1.77ff8bf6e262fp-11, + 0x1.f36b7bad179d9p-10, + 0x1.90eb8aa9cbcb6p-10, + 0x1.97a0363939ae9p-11, + 0x1.ccb747a9d90e5p-11, + 0x1.a92164b87a3a5p-14, + 0x1.52ad51b77221dp-12, + 0x1.c99ee4bf5aee8p-11, + 0x1.8e0fbb8a25614p-10, + 0x1.979f6cc9198a3p-12, + 0x1.5721dfb97a785p-10, + 0x1.92ea3905bb722p-11, + 0x1.a53bcab17972dp-10, + 0x1.025e90121e2e4p-9, + 0x1.f20bc249ff23p-11, + 0x1.1689f3f74acb9p-10, + 0x1.345b5e5311a23p-9, + 0x1.a779ced3faac4p-11, + 0x1.0546d6512618p-11, + 0x1.b9947c1ae78f6p-15, + 0x1.3016cec31dd23p-13, + 0x1.732e290e097e1p-10, + 0x1.f9d84a480acddp-11, + 0x1.e6c3204bf032p-11, + 0x1.d17935d700cf6p-10, + 0x1.9cb105b0e3034p-10, + 0x1.91ea1e83790c7p-12, + 0x1.1732a1926f85fp-9, + 0x1.6362db288d296p-10, + 0x1.d2ed14b580996p-10, + 0x1.de8fd10b00615p-13, + 0x1.5c17fe188acdbp-11, + 0x1.4b190e362d78ap-10, + 0x1.b37fc6c90a43cp-10, + 0x1.a309560a671cp-11, + 0x1.8234b99068737p-11, + 0x1.28052b28bd299p-9, + 0x1.5cd328e10b856p-10, + 0x1.4857808771b4ap-10, + 0x1.6312daf41d5eep-11, + 0x1.123b23aabc8dfp-10, + 0x1.19d9c86c37f02p-13, + 0x1.1c21cca6422bbp-13, + 0x1.3d7b770d4f4c8p-12, + 0x1.0cfe9abab7386p-10, + 0x1.34e124a5884f4p-10, + 0x1.3437cc5b7b70bp-10, + 0x1.14784501d65aep-9, + 0x1.9a5b5a5b6b9f5p-9, + 0x1.0b78858312413p-9, + 0x1.82fdbb4d8d5d1p-10, + 0x1.7354110981ea1p-10, + 0x1.861ae20375007p-15, + 0x1.204d8a21a955ep-12, + 0x1.a32ecec07863ap-12, + 0x1.051e41500d788p-11, + 0x1.c4a8842fad169p-10, + 0x1.8df9f2b992d87p-10, + 0x1.144cb70a21p-11, + 0x1.1fd254f957796p-9, + 0x1.3eeaf14a6e1d9p-9, + 0x1.430a94c8a6dbap-9, + 0x1.65f3b45d8c729p-10, + 0x1.fc5cf9b202919p-11, + 0x1.17d89558a7255p-10, + 0x1.06b3f20f991b4p-11, + 0x1.8f07aaa9f6454p-11, + 0x1.eb330eefb2135p-16, + 0x1.b644a8936f7aep-13, + 0x1.307b611deba29p-10, + 0x1.a31fecda52437p-9, + 0x1.5bb49c7057719p-13, + 0x1.2a327796eaf45p-10, + 0x1.ffc9d5ca35478p-12, + 0x1.2d6114f395cbcp-9, + 0x1.a2cb1edf18179p-12, + 0x1.e15e968bdebbfp-11, + 0x1.80e1f99de3402p-10, + 0x1.2bcbfbd5c7b92p-11, + 0x1.b13fd66f28aa6p-10, + 0x1.e8540c34cb916p-10, + 0x1.5cda3ed888ae4p-9, + 0x1.41b85e4e8713dp-9, + 0x1.03fd687fbe68p-10, + 0x1.2f71343f9ac06p-9, + 0x1.2f40b025d3c13p-10, + 0x1.39b1dee5bb1f2p-9, + 0x1.059419433b40fp-9, + 0x1.18c30db9be7e5p-9, + 0x1.3a57e8425e9f7p-10, + 0x1.e775aa9b7223cp-11, + 0x1.c3b65425ad0cdp-11, + 0x1.45376a71a0d45p-12, + 0x1.84272896fd26bp-13, + 0x1.07243de946089p-14, + 0x1.ba68a0bc6b2b9p-10, + 0x1.de3fffd0d4579p-12, + 0x1.358a7ea8ccc2p-12, + 0x1.616dbec2e4075p-10, + 0x1.17913fae2b209p-12, + 0x1.a94de82c18d3cp-14, + 0x1.7e1f68422dfb4p-11, + 0x1.b6cf5bfbe0857p-11, + 0x1.7a8426fa2b8c4p-10, + 0x1.aedb2c3529c4p-10, + 0x1.ddeb33443e43ep-11, + 0x1.5c0f9ee83143dp-10, + 0x1.a5ea966af4059p-9, + 0x1.9287b06178f3ep-10, + 0x1.db00ad2b5b2efp-10, + 0x1.6e5f61df04e31p-9, + 0x1.1b17bda8cad74p-12, + 0x1.afac138c675ddp-10, + 0x1.58ef85fce1f51p-9, + 0x1.0529cdd5ed74ap-9, + 0x1.45da5b19c5bc6p-10, + 0x1.b84d53b49f87fp-11, + 0x1.21b7f8ba092c9p-11, + 0x1.a462f30316902p-10, + 0x1.3bb7f93e10b07p-10, + 0x1.20a06b387af8fp-9, + 0x1.d850d30ece03fp-9, + 0x1.7a5ab9f56cb22p-9, + 0x1.ca59337d84c91p-10, + 0x1.8dc7ad5072c7fp-14, + 0x1.87df1182db862p-12, + 0x1.20e1b16fc3373p-12, + 0x1.62cd868927491p-10, + 0x1.3413adb1515b9p-9, + 0x1.1e80b35f079ap-10, + 0x1.033a69b23590bp-11, + 0x1.13d2d0fe68f24p-12, + 0x1.28a7b85ecad63p-9, + 0x1.868a012b5bc53p-10, + 0x1.82c2d6c5149ap-9, + 0x1.740e206dc6e81p-12, + 0x1.120a9c861d5f1p-9, + 0x1.49c35f06c7cc2p-11, + 0x1.74bb0d1102c48p-10, + 0x1.dae1e4dbbd8fap-11, + 0x1.0f3e2bccfbad8p-13, + 0x1.94555fffbf1e1p-12, + 0x1.ace1fe0a6722ep-12, + 0x1.a1989b56bd93bp-10, + 0x1.7a9f4623bbea1p-11, + 0x1.790cac959c7cbp-9, + 0x1.93fc16ff7080cp-9, + 0x1.e2651575e6bp-9, + 0x1.3d5b3e448389fp-9, + 0x1.46de94b234d67p-10, + 0x1.e2093d5015879p-11, + 0x1.0bc9e1f2ad2d2p-10, + 0x1.8d1a9b5c7bbddp-11, + 0x1.39b63fd385d9bp-9, + 0x1.c744499cfa4d6p-10, + 0x1.a04afaae379fdp-9, + 0x1.08427eedaad0ap-13, + 0x1.be8b51266786cp-9, + 0x1.be4a1978015eap-11, + 0x1.8e3a93068604ep-10, + 0x1.1da7ae85118cp-9, + 0x1.17d4d3f8f12dp-10, + 0x1.65373d6ad8974p-10, + 0x1.203e04e9ca0b7p-10, + 0x1.03747139da701p-12, + 0x1.963630378a2bep-12, + 0x1.30d1fb5ccd312p-12, + 0x1.957d8bbe0c3fdp-10, + 0x1.85d0f51d640e9p-9, + 0x1.f354d7f0f146fp-11, + 0x1.4a5d6db63a106p-9, + 0x1.e34a19fb25fd1p-10, + 0x1.33ad0e5d87ff4p-9, + 0x1.8b5f6aeeef1fp-13, + 0x1.e54e08ba4924p-11, + 0x1.c7f70705eec19p-11, + 0x1.8820e27a0dcbbp-10, + 0x1.555165df3aabcp-9, + 0x1.7e47764889f1ap-9, + 0x1.f3fbd6303db08p-10, + 0x1.e03046a5c1986p-9, + 0x1.d0c1ae93f5ep-10, + 0x1.7d0ee40246369p-10, + 0x1.e5745d23307ffp-11, + 0x1.b0f7b7225aa43p-9, + 0x1.4f16643fd1ae3p-10, + 0x1.65719e6ee4a17p-10, + 0x1.9eddf923d1a0dp-10, + 0x1.317e24ec751c2p-13, + 0x1.bed709a40bd22p-11, + 0x1.124df5626b368p-10, + 0x1.be5883c889a07p-12, + 0x1.df7cbd7634883p-13, + 0x1.9affea24920cfp-10, + 0x1.54c402216eaaep-10, + 0x1.521d48f5ac877p-9, + 0x1.1deae55c5234ep-9, + 0x1.367461830862p-11, + 0x1.451a39a6e34c8p-11, + 0x1.2c40eca9040bbp-11, + 0x1.4bf2a81285afap-10, + 0x1.5ac38a663825ep-10, + 0x1.45096a989b8d9p-9, + 0x1.cfa50926b55f1p-10, + 0x1.38a8f620c36cp-9, + 0x1.504e1cc56fa91p-9, + 0x1.706aed98c3acfp-10, + 0x1.ea66357433cb4p-12, + 0x1.fe712ef5ccccep-9, + 0x1.fc9fd34d773bap-10, + 0x1.2e66a85ca7eebp-9, + 0x1.42a6ef73a3cdbp-9, + 0x1.51bbccc8f28cep-11, + 0x1.e131f5f76e003p-10, + 0x1.2b812e2cee05dp-11, + 0x1.87927e20235cbp-12, + 0x1.168b7dfd4ca46p-9, + 0x1.04acdedfd240ep-10, + 0x1.33d3dca8d9c38p-9, + 0x1.3c504007bb006p-9, + 0x1.15bf066529e9p-10, + 0x1.0b94c4c766064p-11, + 0x1.d2267b320eda3p-11, + 0x1.1da8075829dfcp-12, + 0x1.e7d25c1479c97p-12, + 0x1.c1c9a5c575953p-11, + 0x1.d4957f1c3b915p-10, + 0x1.1fca1a741c655p-9, + 0x1.50880728ef46bp-10, + 0x1.0842b5e89ac81p-8, + 0x1.2b868695891c9p-9, + 0x1.44dc61705131p-9, + 0x1.a815db2636919p-9, + 0x1.0b6b966412a32p-9, + 0x1.006391bb030fcp-10, + 0x1.31c7675aaf5b4p-9, + 0x1.33345861978ffp-9, + 0x1.535964c951acfp-11, + 0x1.fe023e180ddafp-13, + 0x1.fc782f3f567bbp-13, + 0x1.08b40f55887d9p-9, + 0x1.ae3177013156fp-9, + 0x1.6ec1e1f93ef03p-9, + 0x1.362aaafa1f184p-10, + 0x1.e6daec69897f4p-11, + 0x1.fbc28455015cp-14, + 0x1.c7a4ba81771dbp-12, + 0x1.9a0c4d151789bp-11, + 0x1.18ad7d8b62c2p-9, + 0x1.07192ad296a63p-9, + 0x1.509c6e29a135p-9, + 0x1.2d9536d7506a7p-8, + 0x1.0a723552d97e9p-9, + 0x1.59ca897a07c19p-9, + 0x1.512d44b8abd6ep-11, + 0x1.c619e9a448c85p-12, + 0x1.7b760a1a5accfp-9, + 0x1.1fff2e71a0169p-9, + 0x1.e94ac1f6fbcaap-11, + 0x1.dc64962369a0ap-11, + 0x1.7d4ddedbbf12dp-12, + 0x1.a0ee8bd8560dbp-15, + 0x1.9e5c0ec34f658p-10, + 0x1.38073899ffa25p-9, + 0x1.9d385b34ab8b3p-10, + 0x1.f1e854d817c16p-9, + 0x1.5ae76da3ec62fp-9, + 0x1.17b5e10f22717p-12, + 0x1.5bb0d2196dce9p-10, + 0x1.f989a5e4fa916p-12, + 0x1.78b0d17281b1bp-12, + 0x1.7ada908921ebp-13, + 0x1.83481a4ff242cp-12, + 0x1.0c616de6f9998p-10, + 0x1.2e7534cffdbb5p-10, + 0x1.b5173ae506863p-11, + 0x1.1c276c6e89f74p-9, + 0x1.4bab698607ee2p-10, + 0x1.5ae669f08f203p-9, + 0x1.69d71014349f5p-10, + 0x1.038072ece3be7p-9, + 0x1.320ddb26b9b0bp-9, + 0x1.939248d7a560fp-9, + 0x1.29bd7992b4e66p-11, + 0x1.38faa10f2c716p-9, + 0x1.6dfe509f14d01p-10, + 0x1.8fa9b916606f7p-12, + 0x1.3ff41208ccac1p-11, + 0x1.7f446faca2972p-11, + 0x1.ebc1540b40b8ap-10, + 0x1.86b0026f720c1p-9, + 0x1.f1e85f97716ep-10, + 0x1.5114beeb22dc7p-9, + 0x1.6db1a84312197p-12, + 0x1.6013607567b25p-11, + 0x1.719896851662cp-9, + 0x1.e5f90a1f6b582p-11, + 0x1.286a524bb11fcp-13, + 0x1.79f46a275874fp-12, + 0x1.d6da84cfdcbb2p-10, + 0x1.894ca8980a887p-12, + 0x1.1c349d86ed82ep-11, + 0x1.d806452a1aaa3p-9, + 0x1.bdd2053ab68b7p-9, + 0x1.049cbc1ed27b4p-9, + 0x1.901eb69ecccfbp-10, + 0x1.dc4b8fd988238p-9, + 0x1.275ccd6e9d8d2p-10, + 0x1.bf01ab237d14ap-11, + 0x1.c852f901d6898p-12, + 0x1.2e39b700e405ap-9, + 0x1.812cd25a7ce9ap-12, + 0x1.4858c75f8f361p-11, + 0x1.c8a504e441bcp-11, + 0x1.2125a27e32984p-10, + 0x1.02e98143ace6cp-9, + 0x1.8ca1e3dc10408p-9, + 0x1.07be2073e5e7bp-9, + 0x1.9cd35f04dee95p-9, + 0x1.25cdc9b89d959p-10, + 0x1.b5378c209166cp-15, + 0x1.021c58973b30ep-11, + 0x1.a5344d1161288p-11, + 0x1.a1655c36cc559p-13, + 0x1.3a433ca8f85f5p-9, + 0x1.85f28a1a398ep-9, + 0x1.d6b7d9d5e9df6p-9, + 0x1.97679f2d4376p-9, + 0x1.5427ad0c88b23p-10, + 0x1.dce164e062e0cp-11, + 0x1.519dbff76a6ffp-9, + 0x1.31df738a86dabp-9, + 0x1.80a769d67ca2fp-9, + 0x1.b72c6a4751b6p-11, + 0x1.5a87776d25a87p-10, + 0x1.6d07411c4e509p-13, + 0x1.fee89c2445a43p-12, + 0x1.d9d618c6397b9p-11, + 0x1.13685d82770f8p-10, + 0x1.5c39d33b1ae35p-9, + 0x1.ea22045460e44p-10, + 0x1.ac3f15df90fe8p-11, + 0x1.816c6a89723ap-12, + 0x1.c0d4500b60878p-12, + 0x1.530707a5c84f7p-14, + 0x1.3ef6f8d021712p-12, + 0x1.194294110aa48p-9, + 0x1.53cd0e56fb0bep-10, + 0x1.0334c2df96b53p-10, + 0x1.7f7eed7094f35p-9, + 0x1.9c0d6f387a952p-10, + 0x1.9ac0701a2ec64p-9, + 0x1.183fda8ca14f8p-10, + 0x1.a03a94db9262fp-9, + 0x1.08874688a84bcp-9, + 0x1.d1f7dc2a634e3p-10, + 0x1.160b445c1d40cp-9, + 0x1.ff92bc35078c2p-10, + 0x1.91744800015afp-11, + 0x1.cb816bb8ab903p-12, + 0x1.efeb425962f35p-11, + 0x1.e64c5a63f60bap-11, + 0x1.21cf8d6b34f3ep-9, + 0x1.1aa282e68e6e5p-9, + 0x1.88fc323ec6dafp-11, + 0x1.8943e839b36fcp-10, + 0x1.25afb808d33cp-10, + 0x1.5d7ac1bfd67d3p-11, + 0x1.09c346f61ed98p-14, + 0x1.3f61d6d1be326p-12, + 0x1.1ad42a573d6f7p-10, + 0x1.744ab78b3183dp-12, + 0x1.44249b874515fp-9, + 0x1.12aba24c0bd9fp-11, + 0x1.cdece3d3efa3fp-10, + 0x1.0a84e2c43a86cp-9, + 0x1.88c8df6e6170fp-9, + 0x1.b3f8346459795p-9, + 0x1.7287ef0c9de5fp-10, + 0x1.122ec520bde45p-9, + 0x1.1881fdbdc64c3p-10, + 0x1.2351c1a16f71ep-10, + 0x1.545fe750fbe14p-10, + 0x1.e305ae3d2be76p-11, + 0x1.750dc9978c3e9p-11, + 0x1.e8bed60e31e4fp-10, + 0x1.149f799f67756p-9, + 0x1.88f8d08ef55f5p-9, + 0x1.12fa0dee3be8ap-9, + 0x1.e31d61463a089p-13, + 0x1.9df500af3c537p-14, + 0x1.2bf1662508936p-12, + 0x1.c816fb3ab49afp-14, + 0x1.e01736cfaeebfp-11, + 0x1.2a69ad95b956bp-12, + 0x1.0d5c791183318p-9, + 0x1.c4ab3acefe685p-11, + 0x1.45b67d823ab58p-9, + 0x1.b0ee1ef77e698p-10, + 0x1.4ec88fd5acbbp-9, + 0x1.73533d2b888e8p-10, + 0x1.2f22340a2f363p-10, + 0x1.ef0d8cc44ee0cp-10, + 0x1.5ff1c6f43545fp-10, + 0x1.5bd82bff3bafbp-10, + 0x1.1e96abdf7863cp-10, + 0x1.164f65f6b8d06p-10, + 0x1.3f4abb1ebfccfp-11, + 0x1.25b253961d313p-9, + 0x1.9d0e931f179d4p-11, + 0x1.d405e2113771p-10, + 0x1.4c4bdf46dc30fp-10, + 0x1.617372af8bae4p-9, + 0x1.1a13c8213daedp-11, + 0x1.fd90b388df7e5p-13, + 0x1.829a06baf8814p-13, + 0x1.119f36ccb3b11p-10, + 0x1.479ea085dafc5p-11, + 0x1.ebbd140fec8cap-14, + 0x1.4f00ef973c5fap-10, + 0x1.44daf9b696d96p-10, + 0x1.52e8fc4bac3c5p-10, + 0x1.6ec3b2f75c3f3p-10, + 0x1.505be63a80187p-9, + 0x1.5940eb934771ap-9, + 0x1.8789bf38b5ddep-12, + 0x1.a210729f46d87p-10, + 0x1.6a59f34fd38e2p-10, + 0x1.2ef75fc4bc03ap-9, + 0x1.2fbb69508e128p-11, + 0x1.fa3190845fb7cp-11, + 0x1.aa0a1ba84c37p-11, + 0x1.45c00bc7c58a9p-13, + 0x1.3a5328c31121cp-10, + 0x1.c118a3546ccbap-11, + 0x1.584c344e0e9p-10, + 0x1.4b07ac83bcc21p-13, + 0x1.1a0b8f935a6bp-10, + 0x1.d1e11c7d48cacp-11, + 0x1.09e6ed5f58e1bp-14, + 0x1.ca78b8da58ae3p-14, + 0x1.2d25ae06dd649p-13, + 0x1.b0ed850f24b6cp-11, + 0x1.6accf0119c5bap-13, + 0x1.67936fc143a6bp-10, + 0x1.436d1694b8cc6p-10, + 0x1.b6c8fd9cedda7p-10, + 0x1.0d1362f93fe2fp-10, + 0x1.1ebb02b77c3e6p-9, + 0x1.79a936b188f14p-10, + 0x1.98a5de9534c6bp-10, + 0x1.76a9670903761p-9, + 0x1.d200be5947ddbp-10, + 0x1.ad574291c123ap-10, + 0x1.84b5b5697eaddp-10, + 0x1.02cfbaac6d854p-11, + 0x1.c45926c13045fp-13, + 0x1.c1eebea2fca19p-12, + 0x1.ac25276de0585p-12, + 0x1.cff7256b97281p-13, + 0x1.b36c712fc2326p-11, + 0x1.6922356c8ad5ap-12, + 0x1.7ea71de1979e9p-10, + 0x1.358f935c35c71p-10, + 0x1.a9b88e8e4743ep-11, + 0x1.b975d5b3fb2ddp-12, + 0x1.d467f2436ce44p-15, + 0x1.d4409bb0eccc7p-11, + 0x1.39d2b8c369154p-11, + 0x1.de3a5b7b268bfp-13, + 0x1.11244795dfa3p-10, + 0x1.adea19d9fb0aap-10, + 0x1.1d998b8074efdp-9, + 0x1.4788cb10d5268p-11, + 0x1.2a0177be37ebp-9, + 0x1.385803b8a201p-10, + 0x1.9acad1edc53f4p-10, + 0x1.bdd6c77711156p-12, + 0x1.41a78ce0cf414p-10, + 0x1.bc576d0ae0504p-11, + 0x1.3e311f076c6acp-10, + 0x1.ab79cb43036bbp-11, + 0x1.84acb7122e4dfp-12, + 0x1.62fa7b1c928eap-10, + 0x1.2a296f00109a1p-9, + 0x1.74710a8cd2a52p-10, + 0x1.946718fc222dcp-11, + 0x1.378722d82aaa6p-11, + 0x1.3da0ea562e8ddp-13, + 0x1.cf8da8b9e4ep-14, + 0x1.64752e050722dp-14, + 0x1.50f2a72713532p-11, + 0x1.10aebd041f3cdp-12, + 0x1.c1c99a62d58a3p-11, + 0x1.0f6c5f57756d7p-10, + 0x1.2fc729ba97bd3p-10, + 0x1.3529d49538e0dp-12, + 0x1.0e586b99330b2p-9, + 0x1.5aaef15b0db46p-10, + 0x1.57b240fc6ec5p-10, + 0x1.5bc62fcbcc966p-12, + 0x1.baf8605adb2e2p-13, + 0x1.6783af112b183p-10, + 0x1.0d3ac5e0d72afp-11, + 0x1.a46954e6bac06p-13, + 0x1.e61205b7b6dccp-14, + 0x1.327cb7e248b72p-11, + 0x1.8c64043a8e578p-11, + 0x1.1f881be45b5bcp-10, + 0x1.fce1fd1bf1a26p-10, + 0x1.be696dbba06b3p-10, + 0x1.116329ed3fabfp-10, + 0x1.d04d927d640dp-11, + 0x1.481412949efafp-13, + 0x1.d527d97ce9b55p-15, + 0x1.e77b2f384ed11p-14, + 0x1.45d7aaa83a2cbp-12, + 0x1.95d584715c7cbp-11, + 0x1.7d4f2bbc94af1p-14, + 0x1.bf66f943870bdp-12, + 0x1.d9019d9597p-12, + 0x1.b9573c096a637p-10, + 0x1.0830da40fec3dp-10, + 0x1.b5c3b29438476p-11, + 0x1.d652195ab1131p-10, + 0x1.141672856a8dap-10, + 0x1.f1752301c0a38p-12, + 0x1.06da6ada0bcc6p-12, + 0x1.3c1a18b0da6d5p-12, + 0x1.af896f1eac6b5p-12, + 0x1.ee9547ad2ad9ep-12, + 0x1.16f9bad7878ccp-11, + 0x1.9253599b11476p-11, + 0x1.25dc8fd4550b5p-13, + 0x1.20d3dd42f33bdp-12, + 0x1.126ae9cc1db58p-10, + 0x1.05d533e597189p-11, + 0x1.5675820fd7402p-14, + 0x1.01a2a4da6ac53p-15, + 0x1.746f1e027b7bp-12, + 0x1.24b6c766496bp-12, + 0x1.3a346d8d438f1p-11, + 0x1.c93d1d97d964dp-14, + 0x1.aadc46e21c46p-11, + 0x1.a7819114225c5p-12, + 0x1.f3bd104c57e45p-14, + 0x1.a07f8549c3656p-10, + 0x1.910421e23eb8fp-12, + 0x1.2dc5a82130802p-10, + 0x1.424f7bfe2ba16p-11, + 0x1.9114b19ab2786p-13, + 0x1.372288c28832fp-10, + 0x1.1c675090fb6ecp-14, + 0x1.b2ccf8ec4bb25p-11, + 0x1.7acd90c29402dp-13, + 0x1.429800272bb67p-11, + 0x1.3efe9c72ca319p-12, + 0x1.9c49bcf054d7bp-14, + 0x1.be9196d06832ep-13, + 0x1.6b788cd68551ep-13, + 0x1.8e71593fc521p-12, + 0x1.fa35dedd5e691p-12, + 0x1.4907b187b7b17p-12, + 0x1.cacef12853b1dp-14, + 0x1.ea7416e539691p-15, + 0x1.58526ffebb6dp-12, + 0x1.fa1a9224b3602p-15, + 0x1.067583f1eb11ap-13, + 0x1.4ef907c08e522p-11, + 0x1.56e404a936331p-11, + 0x1.a73e3ffead2cbp-13, + 0x1.83143f88f91f1p-11, + 0x1.0981353283b8cp-13, + 0x1.ed39b7269df85p-11, + 0x1.3d8bf16670e8p-13, + 0x1.96c868ade2bf4p-11, + 0x1.40d8823bc58e6p-11, + 0x1.a1b82dd989585p-11, + 0x1.631dd6a67a8d7p-12, + 0x1.a6748c44034f7p-12, + 0x1.910670329fa3ap-12, + 0x1.7656cb2cf07f4p-12, + 0x1.0ec2c7691e16ep-13, + 0x1.35aeacf21653cp-14, + 0x1.51429197e8298p-16, + 0x1.9fe621a90ce1ap-14, + 0x1.160ed365137f7p-12, + 0x1.1985dc09f5ab1p-15, + 0x1.2945300e17761p-11, + 0x1.2d12d8718d7c2p-12, + 0x1.47d86239270ebp-13, + 0x1.2ec212e755627p-15, + 0x1.18fa57471dddep-14, + 0x1.7bcd5071399f2p-13, + 0x1.2c96bdc92dfdfp-12, + 0x1.4b8d9e4d7a5c9p-12, + 0x1.2a5d0f1ef6a74p-15, + 0x1.e5f0687e22e29p-13, + 0x1.ba18903321225p-12, + 0x1.4b768ebad2923p-12, + 0x1.76c2f002e3fd9p-14, + 0x1.2298a66ebe939p-11, + 0x1.006022c5aacd9p-11, + 0x1.ddf8fe1f83cep-13, + 0x1.4052dc84adf95p-12, + 0x1.7437245557867p-13, + 0x1.dc5766228c06fp-15, + 0x1.18c47719f09p-14, + 0x1.2571a4cffc0fcp-14, + 0x1.421eb940ab86cp-15, + 0x1.391457575a1dcp-16, + 0x1.36690904f97a2p-14, + 0x1.1b55a90915becp-13, + 0x1.58ac8eceac032p-12, + 0x1.6f537fe914adep-14, + 0x1.aa5a9bef71e7cp-14, + 0x1.21cd3aa0aa923p-14, + 0x1.a4862bb412e06p-14, + 0x1.323f03acfa50bp-14, + 0x1.1ce3030300366p-13, + 0x1.643c180ba5a5ap-14, + 0x1.b9d17542096cep-16, + 0x1.86d1ef6d45f3dp-17, + 0x1.41cbd9524a992p-16, + 0x1.5c3c08b5ebe22p-14, + 0x1.9fd7b8123880dp-16, + 0x1.9927ff2c1f399p-16, + 0x1.6bdb770061fd4p-14, + 0x1.a416df0b992edp-15, + 0x1.a28a224f91b88p-14, + 0x1.c5a9d520ed9c8p-14, + 0x1.366327031a104p-14, + 0x1.d3421fa166da6p-14, + 0x1.ea6a12f4162fap-15, + 0x1.1d03414bc3623p-13, + 0x1.5d9156980d77ap-15, + 0x1.0eeadbd797c66p-13, + 0x1.8ea484fc315abp-14, + 0x1.aaca1450b722dp-14, + 0x1.868760dedcf34p-16, + 0x1.7f504ab93c85cp-17, + 0x1.18d6ba4247145p-17, + 0x1.16deb37730098p-16 +}}; + +inline constexpr std::array van_den_bos_unit_square_coordinates{{ + 0x0p+0, + 0x1.2bec333018867p-3, + 0x1p-1, + 0x1.b504f333f9de6p-1, + 0x1p+0, + 0x1.37ca1866b95cfp-5, + 0x1.3c10eaca8ab4fp-2, + 0x1.61f78a9abaa59p-1, + 0x1.ec835e79946a3p-1, + 0x1.3ad06011469fbp-7, + 0x1.31f17078d34c1p-1, + 0x1.d4db3148750d2p-1, + 0x1.9c1d1f0e5967dp-2, + 0x1.8e39d9cd73464p-1, + 0x1.fb14be7fbae58p-1, + 0x1.592675bc57974p-4, + 0x1.c71898ca32e6fp-3, + 0x1.a267992848eebp-1, + 0x1.3b92e176d6d31p-9, + 0x1.e3a6873fa1279p-5, + 0x1.cdd0b287ac97bp-2, + 0x1.4a5018bb567c1p-1, + 0x1.d0dfe53aba2fdp-4, + 0x1.6b5fce895307dp-2, + 0x1.1917a6bc29b43p-1, + 0x1.e1c5978c05ed8p-1, + 0x1.60bea939d225ap-6, + 0x1.76619b5edc454p-3, + 0x1.0ea5163fc84e2p-2, + 0x1.c5e40358a8bap-1, + 0x1.f4fa0ab6316edp-1, + 0x1.fec46d1e89293p-1, + 0x1.78ad74e01bd8fp-1, + 0x1.3bc390d250439p-11, + 0x1.9307ee031e2fdp-4, + 0x1.5052d96e626c1p-3, + 0x1.f18f0cdba0025p-3, + 0x1.53832c52a7012p-2, + 0x1.3e33f2f642be3p-1, + 0x1.db941a28cb71fp-1, + 0x1.62aa03dd6ba58p-8, + 0x1.894285e19c468p-5, + 0x1.235f2eb9a470ap-4, + 0x1.09441bb2aa0a2p-3, + 0x1.e6e09a0ef227fp-2, + 0x1.563e69d6ac7f7p-1, + 0x1.abeb49a46765p-1, + 0x1.e76bd7a1e63b9p-1, + 0x1.fd3aabf84528bp-1, + 0x1.ffb10f1bcb6bfp-1, + 0x1.25177fb0f51ap-2, + 0x1.0c8fb2f886ec1p-1, + 0x1.259020dd1cc27p-1, + 0x1.6d7440278573p-1, + 0x1.987fbfe70b81ap-1, + 0x1.83981a137a839p-2, + 0x1.839c3cc917ff7p-1, + 0x1.bdaef913557d7p-1, + 0x1.f853f7dc9186cp-1, + 0x1.eb0208db9e51bp-7, + 0x1.b4dfbe45c67b1p-2, + 0x1.cd9f023f9c3ap-1, + 0x1.9e010063d1f96p-3, + 0x1.f1090827b4372p-1, + 0x1.dedefb09791b4p-6 +}}; + +inline constexpr std::array, 1609> van_den_bos_unit_square_node_indices{{ + {{0, 0}}, + {{0, 1}}, + {{0, 2}}, + {{0, 3}}, + {{0, 4}}, + {{1, 0}}, + {{1, 1}}, + {{1, 2}}, + {{1, 3}}, + {{1, 4}}, + {{2, 0}}, + {{2, 1}}, + {{2, 2}}, + {{2, 3}}, + {{2, 4}}, + {{3, 0}}, + {{3, 1}}, + {{3, 2}}, + {{3, 3}}, + {{3, 4}}, + {{4, 0}}, + {{4, 1}}, + {{4, 2}}, + {{4, 3}}, + {{4, 4}}, + {{5, 5}}, + {{5, 6}}, + {{5, 7}}, + {{5, 3}}, + {{1, 6}}, + {{1, 8}}, + {{6, 5}}, + {{6, 1}}, + {{6, 2}}, + {{6, 3}}, + {{2, 5}}, + {{2, 6}}, + {{2, 7}}, + {{2, 8}}, + {{7, 5}}, + {{7, 1}}, + {{7, 6}}, + {{7, 7}}, + {{7, 8}}, + {{3, 6}}, + {{3, 7}}, + {{8, 0}}, + {{8, 1}}, + {{8, 6}}, + {{8, 2}}, + {{8, 7}}, + {{8, 3}}, + {{8, 8}}, + {{9, 1}}, + {{9, 10}}, + {{9, 11}}, + {{5, 9}}, + {{5, 12}}, + {{5, 13}}, + {{5, 14}}, + {{15, 16}}, + {{15, 10}}, + {{15, 8}}, + {{1, 15}}, + {{1, 12}}, + {{1, 13}}, + {{16, 5}}, + {{16, 16}}, + {{16, 10}}, + {{16, 3}}, + {{16, 8}}, + {{6, 12}}, + {{6, 13}}, + {{12, 5}}, + {{12, 1}}, + {{12, 6}}, + {{12, 10}}, + {{12, 8}}, + {{2, 9}}, + {{2, 13}}, + {{10, 1}}, + {{10, 2}}, + {{10, 10}}, + {{10, 11}}, + {{10, 14}}, + {{7, 16}}, + {{13, 5}}, + {{13, 12}}, + {{13, 7}}, + {{13, 3}}, + {{13, 4}}, + {{3, 16}}, + {{3, 11}}, + {{11, 5}}, + {{11, 15}}, + {{11, 12}}, + {{11, 10}}, + {{11, 13}}, + {{11, 3}}, + {{11, 8}}, + {{8, 5}}, + {{8, 16}}, + {{8, 10}}, + {{8, 11}}, + {{14, 1}}, + {{14, 6}}, + {{14, 7}}, + {{14, 8}}, + {{0, 9}}, + {{0, 11}}, + {{9, 15}}, + {{9, 6}}, + {{9, 2}}, + {{9, 13}}, + {{9, 14}}, + {{5, 0}}, + {{5, 1}}, + {{5, 16}}, + {{5, 10}}, + {{5, 11}}, + {{5, 8}}, + {{15, 5}}, + {{15, 15}}, + {{15, 12}}, + {{15, 2}}, + {{15, 7}}, + {{15, 13}}, + {{15, 3}}, + {{15, 14}}, + {{1, 9}}, + {{1, 16}}, + {{1, 10}}, + {{1, 11}}, + {{16, 9}}, + {{16, 15}}, + {{16, 1}}, + {{16, 12}}, + {{16, 2}}, + {{16, 7}}, + {{16, 13}}, + {{16, 14}}, + {{6, 9}}, + {{6, 16}}, + {{6, 6}}, + {{6, 10}}, + {{6, 11}}, + {{6, 8}}, + {{6, 14}}, + {{12, 9}}, + {{12, 15}}, + {{12, 12}}, + {{12, 7}}, + {{12, 13}}, + {{12, 11}}, + {{2, 15}}, + {{2, 16}}, + {{2, 12}}, + {{2, 10}}, + {{2, 11}}, + {{2, 14}}, + {{10, 9}}, + {{10, 5}}, + {{10, 15}}, + {{10, 16}}, + {{10, 6}}, + {{10, 7}}, + {{10, 3}}, + {{10, 8}}, + {{7, 9}}, + {{7, 12}}, + {{7, 2}}, + {{7, 13}}, + {{7, 3}}, + {{7, 11}}, + {{7, 14}}, + {{13, 15}}, + {{13, 1}}, + {{13, 6}}, + {{13, 10}}, + {{13, 13}}, + {{13, 11}}, + {{13, 8}}, + {{3, 9}}, + {{3, 5}}, + {{3, 15}}, + {{3, 12}}, + {{3, 10}}, + {{3, 13}}, + {{3, 8}}, + {{3, 14}}, + {{11, 9}}, + {{11, 1}}, + {{11, 16}}, + {{11, 6}}, + {{11, 2}}, + {{11, 7}}, + {{11, 11}}, + {{11, 14}}, + {{8, 15}}, + {{8, 12}}, + {{8, 13}}, + {{8, 14}}, + {{14, 5}}, + {{14, 15}}, + {{14, 16}}, + {{14, 12}}, + {{14, 2}}, + {{14, 10}}, + {{14, 13}}, + {{14, 3}}, + {{14, 11}}, + {{14, 14}}, + {{4, 7}}, + {{0, 17}}, + {{18, 9}}, + {{18, 19}}, + {{18, 20}}, + {{18, 21}}, + {{18, 14}}, + {{9, 22}}, + {{9, 16}}, + {{9, 23}}, + {{9, 24}}, + {{9, 3}}, + {{9, 25}}, + {{26, 26}}, + {{26, 27}}, + {{26, 7}}, + {{26, 13}}, + {{5, 18}}, + {{5, 19}}, + {{5, 28}}, + {{5, 20}}, + {{5, 24}}, + {{5, 29}}, + {{5, 30}}, + {{19, 22}}, + {{19, 27}}, + {{19, 6}}, + {{19, 21}}, + {{19, 13}}, + {{19, 25}}, + {{19, 31}}, + {{15, 26}}, + {{15, 19}}, + {{15, 23}}, + {{15, 24}}, + {{15, 17}}, + {{22, 9}}, + {{22, 1}}, + {{22, 28}}, + {{22, 7}}, + {{22, 11}}, + {{22, 8}}, + {{22, 14}}, + {{1, 19}}, + {{1, 20}}, + {{1, 32}}, + {{27, 9}}, + {{27, 22}}, + {{27, 28}}, + {{27, 23}}, + {{27, 10}}, + {{27, 21}}, + {{27, 3}}, + {{27, 14}}, + {{16, 26}}, + {{16, 19}}, + {{16, 27}}, + {{16, 20}}, + {{16, 17}}, + {{16, 25}}, + {{28, 18}}, + {{28, 28}}, + {{28, 6}}, + {{28, 12}}, + {{28, 24}}, + {{28, 7}}, + {{28, 32}}, + {{28, 8}}, + {{28, 14}}, + {{6, 26}}, + {{6, 19}}, + {{6, 22}}, + {{6, 29}}, + {{23, 18}}, + {{23, 27}}, + {{23, 6}}, + {{23, 2}}, + {{23, 10}}, + {{23, 7}}, + {{23, 13}}, + {{23, 25}}, + {{23, 14}}, + {{12, 19}}, + {{12, 28}}, + {{12, 3}}, + {{12, 14}}, + {{20, 9}}, + {{20, 1}}, + {{20, 16}}, + {{20, 12}}, + {{20, 24}}, + {{20, 21}}, + {{20, 17}}, + {{20, 25}}, + {{2, 26}}, + {{2, 23}}, + {{2, 20}}, + {{2, 32}}, + {{2, 30}}, + {{2, 31}}, + {{24, 18}}, + {{24, 15}}, + {{24, 27}}, + {{24, 28}}, + {{24, 2}}, + {{24, 10}}, + {{24, 7}}, + {{24, 29}}, + {{10, 23}}, + {{10, 24}}, + {{10, 13}}, + {{10, 25}}, + {{10, 30}}, + {{21, 18}}, + {{21, 26}}, + {{21, 19}}, + {{21, 1}}, + {{21, 16}}, + {{21, 20}}, + {{21, 21}}, + {{21, 29}}, + {{7, 23}}, + {{7, 24}}, + {{7, 17}}, + {{7, 25}}, + {{7, 31}}, + {{32, 5}}, + {{32, 22}}, + {{32, 28}}, + {{32, 12}}, + {{32, 21}}, + {{32, 32}}, + {{32, 13}}, + {{32, 29}}, + {{32, 8}}, + {{13, 18}}, + {{13, 27}}, + {{13, 2}}, + {{13, 29}}, + {{17, 9}}, + {{17, 5}}, + {{17, 15}}, + {{17, 6}}, + {{17, 12}}, + {{17, 2}}, + {{17, 10}}, + {{17, 7}}, + {{17, 17}}, + {{17, 8}}, + {{17, 14}}, + {{3, 27}}, + {{3, 32}}, + {{3, 25}}, + {{29, 18}}, + {{29, 26}}, + {{29, 15}}, + {{29, 16}}, + {{29, 6}}, + {{29, 20}}, + {{29, 10}}, + {{29, 7}}, + {{29, 29}}, + {{29, 14}}, + {{11, 19}}, + {{11, 22}}, + {{11, 32}}, + {{11, 17}}, + {{11, 31}}, + {{25, 26}}, + {{25, 16}}, + {{25, 23}}, + {{25, 2}}, + {{25, 10}}, + {{25, 7}}, + {{25, 11}}, + {{25, 8}}, + {{8, 19}}, + {{8, 22}}, + {{8, 28}}, + {{8, 17}}, + {{8, 30}}, + {{8, 31}}, + {{30, 18}}, + {{30, 5}}, + {{30, 15}}, + {{30, 27}}, + {{30, 12}}, + {{30, 2}}, + {{30, 7}}, + {{30, 13}}, + {{30, 29}}, + {{30, 14}}, + {{14, 28}}, + {{14, 23}}, + {{14, 21}}, + {{14, 25}}, + {{14, 30}}, + {{14, 31}}, + {{31, 9}}, + {{31, 22}}, + {{31, 16}}, + {{31, 6}}, + {{31, 20}}, + {{31, 24}}, + {{31, 7}}, + {{31, 13}}, + {{31, 17}}, + {{31, 11}}, + {{31, 25}}, + {{31, 14}}, + {{4, 19}}, + {{0, 19}}, + {{0, 8}}, + {{18, 18}}, + {{18, 26}}, + {{18, 15}}, + {{18, 1}}, + {{18, 16}}, + {{18, 6}}, + {{18, 12}}, + {{18, 2}}, + {{18, 24}}, + {{18, 10}}, + {{18, 7}}, + {{18, 13}}, + {{18, 3}}, + {{18, 11}}, + {{18, 30}}, + {{9, 9}}, + {{9, 5}}, + {{9, 27}}, + {{9, 28}}, + {{9, 20}}, + {{9, 21}}, + {{9, 32}}, + {{9, 17}}, + {{9, 29}}, + {{9, 8}}, + {{9, 31}}, + {{26, 18}}, + {{26, 5}}, + {{26, 15}}, + {{26, 1}}, + {{26, 28}}, + {{26, 23}}, + {{26, 20}}, + {{26, 24}}, + {{26, 32}}, + {{26, 3}}, + {{26, 29}}, + {{26, 25}}, + {{26, 30}}, + {{5, 26}}, + {{5, 22}}, + {{5, 27}}, + {{5, 23}}, + {{5, 21}}, + {{5, 32}}, + {{5, 17}}, + {{5, 31}}, + {{19, 9}}, + {{19, 26}}, + {{19, 19}}, + {{19, 15}}, + {{19, 16}}, + {{19, 28}}, + {{19, 12}}, + {{19, 2}}, + {{19, 10}}, + {{19, 7}}, + {{19, 17}}, + {{19, 3}}, + {{19, 11}}, + {{19, 8}}, + {{19, 14}}, + {{15, 18}}, + {{15, 1}}, + {{15, 27}}, + {{15, 6}}, + {{15, 20}}, + {{15, 32}}, + {{15, 29}}, + {{15, 25}}, + {{15, 30}}, + {{15, 31}}, + {{22, 26}}, + {{22, 5}}, + {{22, 15}}, + {{22, 22}}, + {{22, 16}}, + {{22, 6}}, + {{22, 12}}, + {{22, 2}}, + {{22, 10}}, + {{22, 21}}, + {{22, 32}}, + {{22, 17}}, + {{22, 29}}, + {{22, 25}}, + {{22, 30}}, + {{1, 18}}, + {{1, 5}}, + {{1, 22}}, + {{1, 27}}, + {{1, 28}}, + {{1, 23}}, + {{1, 24}}, + {{1, 21}}, + {{1, 17}}, + {{1, 25}}, + {{1, 14}}, + {{1, 31}}, + {{27, 26}}, + {{27, 5}}, + {{27, 19}}, + {{27, 15}}, + {{27, 1}}, + {{27, 16}}, + {{27, 6}}, + {{27, 20}}, + {{27, 24}}, + {{27, 7}}, + {{27, 13}}, + {{27, 17}}, + {{27, 29}}, + {{27, 8}}, + {{27, 30}}, + {{16, 18}}, + {{16, 22}}, + {{16, 28}}, + {{16, 23}}, + {{16, 24}}, + {{16, 32}}, + {{16, 11}}, + {{16, 30}}, + {{16, 31}}, + {{28, 9}}, + {{28, 26}}, + {{28, 19}}, + {{28, 22}}, + {{28, 27}}, + {{28, 23}}, + {{28, 20}}, + {{28, 2}}, + {{28, 10}}, + {{28, 21}}, + {{28, 13}}, + {{28, 3}}, + {{28, 11}}, + {{28, 30}}, + {{6, 18}}, + {{6, 15}}, + {{6, 28}}, + {{6, 20}}, + {{6, 24}}, + {{6, 21}}, + {{6, 32}}, + {{6, 17}}, + {{6, 25}}, + {{6, 4}}, + {{23, 9}}, + {{23, 5}}, + {{23, 15}}, + {{23, 1}}, + {{23, 16}}, + {{23, 23}}, + {{23, 12}}, + {{23, 20}}, + {{23, 21}}, + {{23, 32}}, + {{23, 3}}, + {{23, 11}}, + {{23, 8}}, + {{23, 30}}, + {{12, 18}}, + {{12, 26}}, + {{12, 27}}, + {{12, 16}}, + {{12, 23}}, + {{12, 2}}, + {{12, 24}}, + {{12, 32}}, + {{12, 17}}, + {{12, 29}}, + {{12, 25}}, + {{12, 30}}, + {{12, 31}}, + {{20, 26}}, + {{20, 5}}, + {{20, 19}}, + {{20, 15}}, + {{20, 22}}, + {{20, 28}}, + {{20, 6}}, + {{20, 23}}, + {{20, 20}}, + {{20, 10}}, + {{20, 7}}, + {{20, 13}}, + {{20, 3}}, + {{20, 11}}, + {{20, 8}}, + {{20, 14}}, + {{20, 31}}, + {{2, 18}}, + {{2, 19}}, + {{2, 27}}, + {{2, 28}}, + {{2, 24}}, + {{2, 21}}, + {{2, 17}}, + {{2, 29}}, + {{2, 25}}, + {{24, 9}}, + {{24, 5}}, + {{24, 19}}, + {{24, 22}}, + {{24, 1}}, + {{24, 16}}, + {{24, 23}}, + {{24, 20}}, + {{24, 24}}, + {{24, 21}}, + {{24, 32}}, + {{24, 13}}, + {{24, 3}}, + {{24, 11}}, + {{24, 8}}, + {{24, 14}}, + {{10, 26}}, + {{10, 22}}, + {{10, 28}}, + {{10, 12}}, + {{10, 20}}, + {{10, 32}}, + {{10, 17}}, + {{10, 31}}, + {{21, 0}}, + {{21, 9}}, + {{21, 5}}, + {{21, 15}}, + {{21, 27}}, + {{21, 28}}, + {{21, 6}}, + {{21, 12}}, + {{21, 24}}, + {{21, 10}}, + {{21, 7}}, + {{21, 13}}, + {{21, 3}}, + {{21, 11}}, + {{21, 25}}, + {{21, 8}}, + {{21, 14}}, + {{21, 31}}, + {{7, 15}}, + {{7, 22}}, + {{7, 27}}, + {{7, 28}}, + {{7, 20}}, + {{7, 21}}, + {{7, 32}}, + {{7, 29}}, + {{7, 30}}, + {{32, 18}}, + {{32, 26}}, + {{32, 19}}, + {{32, 1}}, + {{32, 16}}, + {{32, 6}}, + {{32, 23}}, + {{32, 2}}, + {{32, 24}}, + {{32, 10}}, + {{32, 17}}, + {{32, 3}}, + {{32, 11}}, + {{32, 30}}, + {{32, 31}}, + {{13, 9}}, + {{13, 19}}, + {{13, 22}}, + {{13, 16}}, + {{13, 28}}, + {{13, 20}}, + {{13, 21}}, + {{13, 32}}, + {{13, 17}}, + {{13, 25}}, + {{13, 14}}, + {{17, 18}}, + {{17, 26}}, + {{17, 19}}, + {{17, 1}}, + {{17, 27}}, + {{17, 16}}, + {{17, 23}}, + {{17, 20}}, + {{17, 24}}, + {{17, 32}}, + {{17, 13}}, + {{17, 3}}, + {{17, 11}}, + {{17, 25}}, + {{17, 30}}, + {{17, 31}}, + {{3, 18}}, + {{3, 26}}, + {{3, 22}}, + {{3, 28}}, + {{3, 20}}, + {{3, 24}}, + {{3, 21}}, + {{3, 17}}, + {{3, 29}}, + {{3, 30}}, + {{29, 19}}, + {{29, 22}}, + {{29, 1}}, + {{29, 27}}, + {{29, 23}}, + {{29, 12}}, + {{29, 2}}, + {{29, 21}}, + {{29, 32}}, + {{29, 17}}, + {{29, 3}}, + {{29, 11}}, + {{29, 8}}, + {{29, 30}}, + {{29, 31}}, + {{11, 18}}, + {{11, 26}}, + {{11, 27}}, + {{11, 28}}, + {{11, 20}}, + {{11, 24}}, + {{11, 29}}, + {{11, 25}}, + {{25, 18}}, + {{25, 9}}, + {{25, 5}}, + {{25, 15}}, + {{25, 22}}, + {{25, 1}}, + {{25, 28}}, + {{25, 6}}, + {{25, 12}}, + {{25, 21}}, + {{25, 32}}, + {{25, 13}}, + {{25, 17}}, + {{25, 3}}, + {{25, 29}}, + {{25, 25}}, + {{25, 30}}, + {{25, 14}}, + {{25, 31}}, + {{8, 9}}, + {{8, 27}}, + {{8, 23}}, + {{8, 20}}, + {{8, 24}}, + {{8, 21}}, + {{8, 32}}, + {{8, 29}}, + {{8, 25}}, + {{30, 9}}, + {{30, 26}}, + {{30, 19}}, + {{30, 22}}, + {{30, 1}}, + {{30, 16}}, + {{30, 28}}, + {{30, 6}}, + {{30, 23}}, + {{30, 24}}, + {{30, 10}}, + {{30, 21}}, + {{30, 32}}, + {{30, 17}}, + {{30, 3}}, + {{30, 25}}, + {{30, 8}}, + {{30, 30}}, + {{30, 31}}, + {{14, 18}}, + {{14, 26}}, + {{14, 22}}, + {{14, 27}}, + {{14, 20}}, + {{14, 24}}, + {{14, 32}}, + {{14, 17}}, + {{14, 29}}, + {{14, 4}}, + {{31, 18}}, + {{31, 19}}, + {{31, 15}}, + {{31, 1}}, + {{31, 27}}, + {{31, 28}}, + {{31, 23}}, + {{31, 12}}, + {{31, 2}}, + {{31, 10}}, + {{31, 21}}, + {{31, 32}}, + {{31, 8}}, + {{31, 30}}, + {{31, 31}}, + {{4, 5}}, + {{4, 6}}, + {{4, 17}}, + {{4, 29}}, + {{4, 11}}, + {{4, 31}}, + {{33, 26}}, + {{33, 34}}, + {{33, 35}}, + {{33, 36}}, + {{33, 37}}, + {{33, 20}}, + {{33, 24}}, + {{33, 38}}, + {{33, 32}}, + {{33, 13}}, + {{33, 39}}, + {{33, 30}}, + {{18, 40}}, + {{18, 41}}, + {{18, 42}}, + {{18, 43}}, + {{18, 44}}, + {{18, 45}}, + {{18, 46}}, + {{18, 29}}, + {{18, 47}}, + {{18, 48}}, + {{18, 49}}, + {{40, 26}}, + {{40, 34}}, + {{40, 27}}, + {{40, 16}}, + {{40, 50}}, + {{40, 37}}, + {{40, 12}}, + {{40, 51}}, + {{40, 52}}, + {{40, 53}}, + {{40, 54}}, + {{40, 11}}, + {{40, 8}}, + {{40, 30}}, + {{9, 33}}, + {{9, 40}}, + {{9, 42}}, + {{9, 36}}, + {{9, 55}}, + {{9, 38}}, + {{9, 45}}, + {{9, 56}}, + {{9, 57}}, + {{9, 39}}, + {{9, 58}}, + {{9, 48}}, + {{59, 26}}, + {{59, 41}}, + {{59, 22}}, + {{59, 1}}, + {{59, 50}}, + {{59, 60}}, + {{59, 44}}, + {{59, 52}}, + {{59, 7}}, + {{59, 17}}, + {{59, 61}}, + {{59, 47}}, + {{26, 9}}, + {{26, 34}}, + {{26, 62}}, + {{26, 37}}, + {{26, 12}}, + {{26, 51}}, + {{26, 38}}, + {{26, 54}}, + {{26, 57}}, + {{26, 39}}, + {{26, 63}}, + {{26, 31}}, + {{64, 33}}, + {{64, 5}}, + {{64, 42}}, + {{64, 35}}, + {{64, 50}}, + {{64, 23}}, + {{64, 60}}, + {{64, 21}}, + {{64, 53}}, + {{64, 56}}, + {{64, 46}}, + {{64, 61}}, + {{64, 58}}, + {{5, 40}}, + {{5, 59}}, + {{5, 41}}, + {{5, 43}}, + {{5, 36}}, + {{5, 44}}, + {{5, 52}}, + {{5, 54}}, + {{5, 57}}, + {{5, 39}}, + {{5, 47}}, + {{5, 48}}, + {{41, 64}}, + {{41, 42}}, + {{41, 34}}, + {{41, 35}}, + {{41, 62}}, + {{41, 37}}, + {{41, 12}}, + {{41, 21}}, + {{41, 7}}, + {{41, 17}}, + {{41, 8}}, + {{41, 49}}, + {{19, 18}}, + {{19, 43}}, + {{19, 50}}, + {{19, 20}}, + {{19, 51}}, + {{19, 56}}, + {{19, 57}}, + {{19, 61}}, + {{19, 58}}, + {{42, 59}}, + {{42, 5}}, + {{42, 19}}, + {{42, 34}}, + {{42, 35}}, + {{42, 36}}, + {{42, 50}}, + {{42, 23}}, + {{42, 20}}, + {{42, 10}}, + {{42, 53}}, + {{42, 54}}, + {{42, 25}}, + {{42, 8}}, + {{42, 30}}, + {{42, 31}}, + {{15, 40}}, + {{15, 62}}, + {{15, 60}}, + {{15, 21}}, + {{15, 46}}, + {{15, 61}}, + {{15, 39}}, + {{34, 33}}, + {{34, 9}}, + {{34, 5}}, + {{34, 22}}, + {{34, 1}}, + {{34, 36}}, + {{34, 50}}, + {{34, 55}}, + {{34, 2}}, + {{34, 24}}, + {{34, 7}}, + {{34, 13}}, + {{34, 47}}, + {{34, 58}}, + {{34, 31}}, + {{22, 40}}, + {{22, 42}}, + {{22, 27}}, + {{22, 62}}, + {{22, 37}}, + {{22, 60}}, + {{22, 44}}, + {{22, 52}}, + {{22, 53}}, + {{22, 57}}, + {{22, 48}}, + {{43, 26}}, + {{43, 1}}, + {{43, 28}}, + {{43, 12}}, + {{43, 24}}, + {{43, 21}}, + {{43, 17}}, + {{43, 61}}, + {{43, 39}}, + {{43, 63}}, + {{43, 49}}, + {{1, 33}}, + {{1, 59}}, + {{1, 41}}, + {{1, 34}}, + {{1, 62}}, + {{1, 37}}, + {{1, 44}}, + {{1, 53}}, + {{1, 56}}, + {{1, 46}}, + {{1, 30}}, + {{35, 40}}, + {{35, 64}}, + {{35, 42}}, + {{35, 1}}, + {{35, 16}}, + {{35, 23}}, + {{35, 12}}, + {{35, 24}}, + {{35, 38}}, + {{35, 13}}, + {{35, 11}}, + {{35, 25}}, + {{35, 8}}, + {{35, 14}}, + {{35, 31}}, + {{27, 59}}, + {{27, 34}}, + {{27, 50}}, + {{27, 60}}, + {{27, 45}}, + {{27, 46}}, + {{27, 57}}, + {{62, 40}}, + {{62, 64}}, + {{62, 19}}, + {{62, 22}}, + {{62, 35}}, + {{62, 62}}, + {{62, 55}}, + {{62, 20}}, + {{62, 2}}, + {{62, 51}}, + {{62, 10}}, + {{62, 7}}, + {{62, 32}}, + {{62, 54}}, + {{62, 61}}, + {{62, 25}}, + {{62, 63}}, + {{62, 58}}, + {{62, 49}}, + {{16, 33}}, + {{16, 36}}, + {{16, 37}}, + {{16, 60}}, + {{16, 21}}, + {{16, 57}}, + {{36, 18}}, + {{36, 59}}, + {{36, 42}}, + {{36, 34}}, + {{36, 43}}, + {{36, 27}}, + {{36, 50}}, + {{36, 37}}, + {{36, 12}}, + {{36, 24}}, + {{36, 10}}, + {{36, 53}}, + {{36, 56}}, + {{36, 46}}, + {{36, 61}}, + {{36, 25}}, + {{36, 63}}, + {{36, 48}}, + {{28, 5}}, + {{28, 1}}, + {{28, 36}}, + {{28, 44}}, + {{28, 45}}, + {{28, 54}}, + {{28, 39}}, + {{50, 18}}, + {{50, 59}}, + {{50, 42}}, + {{50, 27}}, + {{50, 16}}, + {{50, 37}}, + {{50, 55}}, + {{50, 60}}, + {{50, 10}}, + {{50, 32}}, + {{50, 3}}, + {{50, 57}}, + {{50, 61}}, + {{50, 25}}, + {{50, 58}}, + {{50, 49}}, + {{6, 64}}, + {{6, 41}}, + {{6, 34}}, + {{6, 35}}, + {{6, 50}}, + {{6, 23}}, + {{6, 51}}, + {{6, 45}}, + {{6, 54}}, + {{6, 63}}, + {{37, 59}}, + {{37, 42}}, + {{37, 43}}, + {{37, 62}}, + {{37, 12}}, + {{37, 20}}, + {{37, 10}}, + {{37, 53}}, + {{37, 56}}, + {{37, 46}}, + {{37, 29}}, + {{37, 11}}, + {{37, 47}}, + {{37, 14}}, + {{37, 31}}, + {{23, 40}}, + {{23, 41}}, + {{23, 36}}, + {{23, 50}}, + {{23, 51}}, + {{23, 45}}, + {{23, 54}}, + {{55, 33}}, + {{55, 64}}, + {{55, 15}}, + {{55, 22}}, + {{55, 35}}, + {{55, 6}}, + {{55, 23}}, + {{55, 20}}, + {{55, 44}}, + {{55, 52}}, + {{55, 21}}, + {{55, 53}}, + {{55, 3}}, + {{55, 29}}, + {{55, 11}}, + {{55, 25}}, + {{55, 8}}, + {{55, 30}}, + {{55, 48}}, + {{12, 59}}, + {{12, 42}}, + {{12, 62}}, + {{12, 38}}, + {{12, 54}}, + {{60, 40}}, + {{60, 26}}, + {{60, 5}}, + {{60, 34}}, + {{60, 43}}, + {{60, 16}}, + {{60, 28}}, + {{60, 23}}, + {{60, 12}}, + {{60, 44}}, + {{60, 51}}, + {{60, 24}}, + {{60, 45}}, + {{60, 56}}, + {{60, 3}}, + {{60, 61}}, + {{60, 25}}, + {{60, 14}}, + {{20, 41}}, + {{20, 35}}, + {{20, 37}}, + {{20, 38}}, + {{20, 32}}, + {{20, 57}}, + {{20, 47}}, + {{20, 63}}, + {{20, 49}}, + {{44, 9}}, + {{44, 64}}, + {{44, 19}}, + {{44, 22}}, + {{44, 62}}, + {{44, 50}}, + {{44, 12}}, + {{44, 20}}, + {{44, 2}}, + {{44, 45}}, + {{44, 13}}, + {{44, 17}}, + {{44, 61}}, + {{44, 58}}, + {{2, 33}}, + {{2, 34}}, + {{2, 35}}, + {{2, 52}}, + {{2, 53}}, + {{2, 39}}, + {{2, 63}}, + {{2, 48}}, + {{51, 9}}, + {{51, 26}}, + {{51, 15}}, + {{51, 62}}, + {{51, 36}}, + {{51, 23}}, + {{51, 2}}, + {{51, 21}}, + {{51, 7}}, + {{51, 56}}, + {{51, 54}}, + {{51, 3}}, + {{51, 29}}, + {{51, 47}}, + {{51, 14}}, + {{24, 0}}, + {{24, 41}}, + {{24, 43}}, + {{24, 6}}, + {{24, 60}}, + {{24, 52}}, + {{24, 46}}, + {{24, 39}}, + {{24, 30}}, + {{24, 48}}, + {{24, 49}}, + {{52, 40}}, + {{52, 64}}, + {{52, 1}}, + {{52, 16}}, + {{52, 50}}, + {{52, 60}}, + {{52, 2}}, + {{52, 10}}, + {{52, 21}}, + {{52, 53}}, + {{52, 56}}, + {{52, 54}}, + {{52, 29}}, + {{52, 47}}, + {{52, 58}}, + {{10, 59}}, + {{10, 42}}, + {{10, 34}}, + {{10, 27}}, + {{10, 36}}, + {{10, 37}}, + {{10, 55}}, + {{10, 51}}, + {{10, 46}}, + {{10, 63}}, + {{38, 33}}, + {{38, 40}}, + {{38, 19}}, + {{38, 43}}, + {{38, 16}}, + {{38, 12}}, + {{38, 2}}, + {{38, 52}}, + {{38, 38}}, + {{38, 45}}, + {{38, 32}}, + {{38, 46}}, + {{38, 29}}, + {{38, 11}}, + {{38, 25}}, + {{38, 48}}, + {{21, 64}}, + {{21, 34}}, + {{21, 35}}, + {{21, 50}}, + {{21, 23}}, + {{21, 54}}, + {{21, 30}}, + {{45, 33}}, + {{45, 59}}, + {{45, 41}}, + {{45, 42}}, + {{45, 43}}, + {{45, 16}}, + {{45, 20}}, + {{45, 24}}, + {{45, 10}}, + {{45, 38}}, + {{45, 53}}, + {{45, 56}}, + {{45, 57}}, + {{45, 39}}, + {{45, 47}}, + {{45, 49}}, + {{7, 40}}, + {{7, 64}}, + {{7, 34}}, + {{7, 37}}, + {{7, 55}}, + {{7, 45}}, + {{7, 63}}, + {{7, 58}}, + {{53, 33}}, + {{53, 41}}, + {{53, 42}}, + {{53, 35}}, + {{53, 62}}, + {{53, 28}}, + {{53, 20}}, + {{53, 2}}, + {{53, 52}}, + {{53, 38}}, + {{53, 7}}, + {{53, 54}}, + {{53, 46}}, + {{53, 61}}, + {{53, 47}}, + {{53, 48}}, + {{32, 59}}, + {{32, 34}}, + {{32, 27}}, + {{32, 55}}, + {{32, 45}}, + {{32, 56}}, + {{32, 25}}, + {{32, 58}}, + {{32, 49}}, + {{56, 18}}, + {{56, 5}}, + {{56, 19}}, + {{56, 43}}, + {{56, 36}}, + {{56, 50}}, + {{56, 37}}, + {{56, 60}}, + {{56, 24}}, + {{56, 7}}, + {{56, 32}}, + {{56, 46}}, + {{56, 57}}, + {{56, 11}}, + {{56, 63}}, + {{13, 41}}, + {{13, 62}}, + {{13, 44}}, + {{13, 38}}, + {{13, 54}}, + {{13, 47}}, + {{13, 58}}, + {{13, 31}}, + {{54, 18}}, + {{54, 59}}, + {{54, 64}}, + {{54, 15}}, + {{54, 22}}, + {{54, 36}}, + {{54, 6}}, + {{54, 55}}, + {{54, 51}}, + {{54, 52}}, + {{54, 7}}, + {{54, 3}}, + {{54, 29}}, + {{54, 39}}, + {{54, 8}}, + {{54, 14}}, + {{17, 35}}, + {{17, 37}}, + {{17, 44}}, + {{17, 21}}, + {{17, 56}}, + {{17, 29}}, + {{46, 18}}, + {{46, 9}}, + {{46, 5}}, + {{46, 19}}, + {{46, 34}}, + {{46, 43}}, + {{46, 16}}, + {{46, 50}}, + {{46, 23}}, + {{46, 60}}, + {{46, 24}}, + {{46, 10}}, + {{46, 21}}, + {{46, 7}}, + {{46, 17}}, + {{46, 57}}, + {{46, 39}}, + {{46, 30}}, + {{46, 49}}, + {{3, 42}}, + {{3, 35}}, + {{3, 50}}, + {{3, 54}}, + {{3, 61}}, + {{3, 47}}, + {{3, 48}}, + {{57, 18}}, + {{57, 9}}, + {{57, 26}}, + {{57, 41}}, + {{57, 22}}, + {{57, 62}}, + {{57, 36}}, + {{57, 37}}, + {{57, 55}}, + {{57, 44}}, + {{57, 2}}, + {{57, 10}}, + {{57, 53}}, + {{57, 56}}, + {{57, 3}}, + {{57, 29}}, + {{57, 39}}, + {{57, 30}}, + {{57, 48}}, + {{29, 64}}, + {{29, 34}}, + {{29, 28}}, + {{29, 45}}, + {{29, 54}}, + {{29, 25}}, + {{61, 40}}, + {{61, 59}}, + {{61, 41}}, + {{61, 19}}, + {{61, 15}}, + {{61, 1}}, + {{61, 27}}, + {{61, 6}}, + {{61, 23}}, + {{61, 60}}, + {{61, 2}}, + {{61, 24}}, + {{61, 10}}, + {{61, 13}}, + {{61, 46}}, + {{61, 61}}, + {{61, 8}}, + {{61, 58}}, + {{11, 36}}, + {{11, 21}}, + {{11, 53}}, + {{11, 57}}, + {{11, 39}}, + {{11, 48}}, + {{11, 49}}, + {{39, 9}}, + {{39, 26}}, + {{39, 5}}, + {{39, 15}}, + {{39, 43}}, + {{39, 28}}, + {{39, 37}}, + {{39, 55}}, + {{39, 51}}, + {{39, 52}}, + {{39, 7}}, + {{39, 32}}, + {{39, 17}}, + {{39, 63}}, + {{39, 58}}, + {{25, 33}}, + {{25, 34}}, + {{25, 35}}, + {{25, 62}}, + {{25, 20}}, + {{25, 56}}, + {{25, 57}}, + {{25, 39}}, + {{25, 47}}, + {{25, 48}}, + {{47, 40}}, + {{47, 5}}, + {{47, 19}}, + {{47, 42}}, + {{47, 36}}, + {{47, 50}}, + {{47, 37}}, + {{47, 44}}, + {{47, 24}}, + {{47, 38}}, + {{47, 7}}, + {{47, 61}}, + {{47, 63}}, + {{47, 14}}, + {{8, 59}}, + {{8, 43}}, + {{8, 35}}, + {{8, 62}}, + {{8, 56}}, + {{8, 54}}, + {{8, 46}}, + {{8, 47}}, + {{8, 49}}, + {{63, 33}}, + {{63, 5}}, + {{63, 15}}, + {{63, 22}}, + {{63, 35}}, + {{63, 28}}, + {{63, 6}}, + {{63, 23}}, + {{63, 12}}, + {{63, 20}}, + {{63, 51}}, + {{63, 52}}, + {{63, 38}}, + {{63, 7}}, + {{63, 32}}, + {{63, 13}}, + {{63, 17}}, + {{63, 29}}, + {{63, 11}}, + {{63, 8}}, + {{63, 30}}, + {{30, 40}}, + {{30, 42}}, + {{30, 36}}, + {{30, 39}}, + {{30, 58}}, + {{30, 48}}, + {{58, 64}}, + {{58, 41}}, + {{58, 34}}, + {{58, 1}}, + {{58, 62}}, + {{58, 6}}, + {{58, 23}}, + {{58, 60}}, + {{58, 44}}, + {{58, 51}}, + {{58, 10}}, + {{58, 21}}, + {{58, 32}}, + {{58, 54}}, + {{58, 3}}, + {{58, 61}}, + {{58, 47}}, + {{58, 30}}, + {{58, 48}}, + {{58, 49}}, + {{14, 9}}, + {{14, 42}}, + {{14, 43}}, + {{14, 50}}, + {{14, 46}}, + {{14, 57}}, + {{48, 33}}, + {{48, 26}}, + {{48, 41}}, + {{48, 34}}, + {{48, 27}}, + {{48, 16}}, + {{48, 37}}, + {{48, 12}}, + {{48, 20}}, + {{48, 2}}, + {{48, 24}}, + {{48, 45}}, + {{48, 32}}, + {{48, 54}}, + {{48, 11}}, + {{48, 25}}, + {{48, 8}}, + {{48, 30}}, + {{48, 14}}, + {{48, 31}}, + {{31, 59}}, + {{31, 43}}, + {{31, 36}}, + {{31, 38}}, + {{31, 56}}, + {{31, 46}}, + {{31, 57}}, + {{31, 29}}, + {{31, 39}}, + {{31, 63}}, + {{31, 48}}, + {{49, 40}}, + {{49, 26}}, + {{49, 41}}, + {{49, 42}}, + {{49, 34}}, + {{49, 1}}, + {{49, 62}}, + {{49, 6}}, + {{49, 23}}, + {{49, 12}}, + {{49, 44}}, + {{49, 51}}, + {{49, 10}}, + {{49, 21}}, + {{49, 53}}, + {{49, 54}}, + {{49, 57}}, + {{49, 47}}, + {{49, 58}}, + {{49, 31}}, + {{4, 51}} +}}; + +inline constexpr std::size_t van_den_bos_unit_square_level_count = 7; + +inline constexpr std::array van_den_bos_unit_square_weights{{ + van_den_bos_unit_square_level_0_weights.data(), + van_den_bos_unit_square_level_1_weights.data(), + van_den_bos_unit_square_level_2_weights.data(), + van_den_bos_unit_square_level_3_weights.data(), + van_den_bos_unit_square_level_4_weights.data(), + van_den_bos_unit_square_level_5_weights.data(), + van_den_bos_unit_square_level_6_weights.data() +}}; + +inline constexpr std::array van_den_bos_unit_square_sizes{{ + van_den_bos_unit_square_level_0_weights.size(), + van_den_bos_unit_square_level_1_weights.size(), + van_den_bos_unit_square_level_2_weights.size(), + van_den_bos_unit_square_level_3_weights.size(), + van_den_bos_unit_square_level_4_weights.size(), + van_den_bos_unit_square_level_5_weights.size(), + van_den_bos_unit_square_level_6_weights.size() +}}; + +inline constexpr std::array van_den_bos_unit_square_degrees{{ + van_den_bos_unit_square_level_0_degree, + van_den_bos_unit_square_level_1_degree, + van_den_bos_unit_square_level_2_degree, + van_den_bos_unit_square_level_3_degree, + van_den_bos_unit_square_level_4_degree, + van_den_bos_unit_square_level_5_degree, + van_den_bos_unit_square_level_6_degree +}}; + +inline constexpr std::array van_den_bos_unit_square_orders{{ + van_den_bos_unit_square_level_0_order, + van_den_bos_unit_square_level_1_order, + van_den_bos_unit_square_level_2_order, + van_den_bos_unit_square_level_3_order, + van_den_bos_unit_square_level_4_order, + van_den_bos_unit_square_level_5_order, + van_den_bos_unit_square_level_6_order +}}; + +}}}} // namespaces + +#endif diff --git a/include/boost/math/quadrature/van_den_bos_unit_square.hpp b/include/boost/math/quadrature/van_den_bos_unit_square.hpp new file mode 100644 index 0000000000..11c541a4d8 --- /dev/null +++ b/include/boost/math/quadrature/van_den_bos_unit_square.hpp @@ -0,0 +1,232 @@ +// Copyright 2026 Nicholas Thompson and Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_MATH_QUADRATURE_VAN_DEN_BOS_UNIT_SQUARE_HPP +#define BOOST_MATH_QUADRATURE_VAN_DEN_BOS_UNIT_SQUARE_HPP + +#include + +#ifdef BOOST_MATH_NO_CXX17_IF_CONSTEXPR +#error "The header requires C++17 or later." +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_MATH_INSTRUMENT +#include +#endif + +namespace boost { namespace math { namespace quadrature { + +namespace detail { + +struct van_den_bos_unit_square_level_view +{ + std::array const* node_indices; + double const* weights; + std::size_t size; + unsigned degree; + std::size_t order; + + std::array point(std::size_t index) const + { + const std::array& node = node_indices[index]; + return {{ + van_den_bos_unit_square_coordinates[node[0]], + van_den_bos_unit_square_coordinates[node[1]]}}; + } +}; + +inline van_den_bos_unit_square_level_view +van_den_bos_unit_square_level(std::size_t level) +{ + if (level >= van_den_bos_unit_square_level_count) + { + throw std::out_of_range( + "van_den_bos_unit_square: requested level exceeds " + "the precomputed hierarchy."); + } + + return { + van_den_bos_unit_square_node_indices.data(), + van_den_bos_unit_square_weights[level], + van_den_bos_unit_square_sizes[level], + van_den_bos_unit_square_degrees[level], + van_den_bos_unit_square_orders[level]}; +} + +} // namespace detail + +/* + * Adaptive positive cubature on the reference square [0,1]^2. + * + * The quadrature nodes are a strictly nested immutable hierarchy generated + * offline in higher precision. The generator starts from tensor-product + * Clenshaw-Curtis rules for continuous uniform (Lebesgue) measure and applies + * protected-node van-den-Bos reduction. This differs from the equal-weight + * empirical sample measure used in the paper, while retaining its positive + * nullspace reduction and nested-node construction. + * + * If physical coordinates are required, the caller is responsible for the + * coordinate map and its Jacobian. + * + * Runtime performs no rule construction and mutates no shared state. + * Independent invocations are therefore thread-safe. + * Convergence requires two consecutive adjacent-level differences to satisfy + * the requested tolerance, guarding against an isolated cancellation. + */ +template +auto van_den_bos_unit_square( + F const& f, + double tolerance, + double* error_estimate = 0, + double* L1 = 0, + std::size_t* evaluations = 0) + -> decltype(f(std::declval(), std::declval())) +{ + using std::abs; + typedef decltype( + f(std::declval(), std::declval())) result_type; + + static_assert(!std::is_integral::value, + "The return type cannot be integral, it must be either a real or " + "complex floating point type."); + + typedef typename std::decay< + decltype(abs(std::declval()))>::type magnitude_type; + + if (!(tolerance > 0)) + { + throw std::domain_error( + "van_den_bos_unit_square: tolerance must be positive."); + } + + std::vector values; + + result_type previous = result_type(0); + result_type current = result_type(0); + + double current_l1 = 0; + double current_error = + (std::numeric_limits::infinity)(); + + std::size_t evaluation_count = 0; + bool have_previous = false; + bool previous_estimate_satisfied = false; + + for (std::size_t level_index = 0; + level_index < detail::van_den_bos_unit_square_level_count; + ++level_index) + { + const detail::van_den_bos_unit_square_level_view level = + detail::van_den_bos_unit_square_level(level_index); + + // Generator invariant: the previous level is an exact prefix. + // Therefore only the new suffix requires function evaluations. + values.reserve(level.size); + while (values.size() < level.size) + { + const std::array point = + level.point(values.size()); + values.push_back(f(point[0], point[1])); + ++evaluation_count; + } + + current = result_type(0); + current_l1 = 0; + + for (std::size_t j = 0; j < level.size; ++j) + { + current += level.weights[j] * values[j]; + current_l1 += level.weights[j] * abs(values[j]); + } + +#ifdef BOOST_MATH_INSTRUMENT + std::cout + << std::setprecision( + std::numeric_limits::max_digits10) + << "VDB_LEVEL" + << ",level=" << level_index + << ",degree=" << level.degree + << ",order=" << level.order + << ",nodes=" << level.size + << ",evaluations=" << evaluation_count + << ",value=" << current; +#endif + + if (have_previous) + { + const double delta = abs(current - previous); + const double scale = + (std::max)(1.0, static_cast(abs(current))); + + // Paper Sec. 2.3: adjacent nested-rule difference. The floor + // prevents reporting a meaningless zero below the accumulator's + // precision. + const double roundoff_floor = + 8 * static_cast( + (std::numeric_limits::epsilon)()) * scale; + current_error = (std::max)(delta, roundoff_floor); + +#ifdef BOOST_MATH_INSTRUMENT + std::cout + << ",delta=" << delta + << ",error_estimate=" << current_error + << '\n'; +#endif + + const bool estimate_satisfied = + current_error <= tolerance * scale; + + // One accidentally small adjacent difference is not reliable for + // non-monotone convergence. Require confirmation by the next + // nested rule before stopping. + if (estimate_satisfied && previous_estimate_satisfied) + { + break; + } + previous_estimate_satisfied = estimate_satisfied; + } + else + { +#ifdef BOOST_MATH_INSTRUMENT + std::cout << ",delta=nan,error_estimate=nan\n"; +#endif + have_previous = true; + } + + previous = current; + } + + if (error_estimate) + { + *error_estimate = current_error; + } + if (L1) + { + *L1 = current_l1; + } + if (evaluations) + { + *evaluations = evaluation_count; + } + + return current; +} + +}}} // namespaces + +#endif diff --git a/reporting/accuracy/plot_van_den_bos_unit_square_convergence.py b/reporting/accuracy/plot_van_den_bos_unit_square_convergence.py new file mode 100644 index 0000000000..1a65fd481a --- /dev/null +++ b/reporting/accuracy/plot_van_den_bos_unit_square_convergence.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +# Copyright Nicholas Thompson 2026. +# Use, modification and distribution are subject to the +# Boost Software License, Version 1.0. (See accompanying file +# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "matplotlib>=3.8", +# ] +# /// + +import argparse +import math +import re +from pathlib import Path + +import matplotlib + +matplotlib.use("Agg") +import matplotlib.pyplot as plt + + +REPOSITORY_ROOT = Path(__file__).resolve().parents[2] +DEFAULT_TRACE = ( + REPOSITORY_ROOT + / "build" + / "vdb" + / "van_den_bos_unit_square_convergence.csv" +) +DEFAULT_OUTPUT = DEFAULT_TRACE.with_suffix(".png") + + +def parse_value(s): + s = s.strip() + if s.startswith("(") and s.endswith(")") and "," in s: + a, b = s[1:-1].split(",", 1) + return complex(float(a), float(b)) + return float(s) + +def parse_trace(path): + cases = {} + current = None + + for raw in Path(path).read_text().splitlines(): + if raw.startswith("VDB_CASE,"): + match = re.fullmatch(r"VDB_CASE,name=([^,]+),exact=(.+)", raw) + if not match: + raise ValueError(f"cannot parse case record: {raw}") + current = match.group(1) + cases[current] = { + "exact": parse_value(match.group(2)), + "levels": [], + } + elif raw.startswith("VDB_LEVEL,") and current is not None: + match = re.fullmatch( + r"VDB_LEVEL,level=(\d+),degree=(\d+),order=(\d+)," + r"nodes=(\d+),evaluations=(\d+),value=(\([^)]*\)|[^,]+)," + r"delta=([^,]+),error_estimate=(.+)", + raw, + ) + if not match: + raise ValueError(f"cannot parse level record: {raw}") + + value = parse_value(match.group(6)) + exact = cases[current]["exact"] + actual_error = abs(value - exact) + error_text = match.group(8) + cases[current]["levels"].append({ + "level": int(match.group(1)), + "degree": int(match.group(2)), + "order": int(match.group(3)), + "nodes": int(match.group(4)), + "evaluations": int(match.group(5)), + "value": value, + "actual_error": actual_error, + "estimated_error": float(error_text) + if error_text != "nan" + else math.nan, + }) + elif raw.startswith("VDB_END,"): + current = None + + return cases + +def main(): + ap = argparse.ArgumentParser( + description="Plot van den Bos unit-square convergence traces.", + ) + ap.add_argument( + "trace", + nargs="?", + type=Path, + default=DEFAULT_TRACE, + help=f"trace CSV (default: {DEFAULT_TRACE})", + ) + ap.add_argument( + "--out", + type=Path, + default=DEFAULT_OUTPUT, + help=f"output image (default: {DEFAULT_OUTPUT})", + ) + ap.add_argument( + "--separate", + action="store_true", + help="also write one convergence plot per integrand", + ) + args = ap.parse_args() + + cases = parse_trace(args.trace) + if not cases: + raise ValueError(f"no van den Bos trace records found in {args.trace}") + + args.out.parent.mkdir(parents=True, exist_ok=True) + + fig, ax = plt.subplots() + + for name, case in cases.items(): + xs = [row["evaluations"] for row in case["levels"]] + ys = [max(row["actual_error"], 1e-18) for row in case["levels"]] + ax.plot(xs, ys, marker="o", label=name) + + ax.set_yscale("log") + ax.set_xlabel("Function evaluations") + ax.set_ylabel("Absolute error") + ax.set_title("van den Bos unit-square convergence") + ax.grid(True, which="both", alpha=0.25) + ax.legend() + fig.tight_layout() + fig.savefig(args.out, dpi=180) + plt.close(fig) + print(f"wrote {args.out}") + + if args.separate: + out = args.out + for name, case in cases.items(): + fig, ax = plt.subplots() + xs = [row["evaluations"] for row in case["levels"]] + ys = [max(row["actual_error"], 1e-18) for row in case["levels"]] + estimates = [ + max(row["estimated_error"], 1e-18) + if math.isfinite(row["estimated_error"]) + else math.nan + for row in case["levels"] + ] + ax.plot(xs, ys, marker="o", label="actual error") + ax.plot(xs, estimates, marker="x", label="estimated error") + ax.set_yscale("log") + ax.set_xlabel("Function evaluations") + ax.set_ylabel("Absolute error") + ax.set_title(name) + ax.grid(True, which="both", alpha=0.25) + ax.legend() + fig.tight_layout() + fig.savefig( + out.with_name(f"{out.stem}_{name}{out.suffix}"), + dpi=180, + ) + plt.close(fig) + +if __name__ == "__main__": + main() diff --git a/reporting/accuracy/van_den_bos_unit_square_convergence.cpp b/reporting/accuracy/van_den_bos_unit_square_convergence.cpp new file mode 100644 index 0000000000..1bdc04cfe0 --- /dev/null +++ b/reporting/accuracy/van_den_bos_unit_square_convergence.cpp @@ -0,0 +1,144 @@ +// Copyright Nicholas Thompson 2026. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + * Convergence trace driver for van_den_bos_unit_square. + * + * Build: + * c++ -O3 -DNDEBUG -DBOOST_MATH_INSTRUMENT -std=c++17 -Iinclude \ + * reporting/accuracy/van_den_bos_unit_square_convergence.cpp \ + * -o vdb_unit_square_convergence + * + * Run: + * ./vdb_unit_square_convergence > van_den_bos_unit_square_convergence.csv + */ + +#include + +#include +#include +#include +#include +#include +#include + +namespace { + +using boost::math::quadrature::van_den_bos_unit_square; + +template +void run_case(char const* name, F const& f, Exact const& exact, double tol = 1e-12) +{ + double error = 0; + double l1 = 0; + std::size_t evaluations = 0; + + std::cout << std::setprecision(std::numeric_limits::max_digits10) + << "VDB_CASE,name=" << name << ",exact=" << exact << '\n'; + (void)van_den_bos_unit_square( + f, tol, &error, &l1, &evaluations); + std::cout << "VDB_END,name=" << name + << ",error_estimate=" << error + << ",evaluations=" << evaluations << '\n'; +} + +std::complex exact_exp_5ixy() +{ + std::complex exact(0, 0); + std::complex power(1, 0); + double factorial = 1; + + for (unsigned k = 0; k < 100; ++k) + { + if (k > 0) + { + power *= std::complex(0, 5); + factorial *= double(k); + } + const double kp1 = double(k + 1); + const auto term = power / (factorial * kp1 * kp1); + exact += term; + if (std::abs(term) < 1e-18) + break; + } + return exact; +} + +} // namespace + +int main() +{ + run_case( + "quadratic", + [](double x, double y) + { + return x * x + y * y + x * y; + }, + 11.0 / 12.0); + + run_case( + "exp_x_plus_y", + [](double x, double y) + { + return std::exp(x + y); + }, + std::pow(std::expm1(1.0), 2)); + + run_case( + "exp_xy", + [](double x, double y) + { + return std::exp(x * y); + }, + [] { + double s = 0; + double factorial = 1; + for (unsigned k = 0; k < 100; ++k) + { + if (k > 0) + factorial *= double(k); + const double kp1 = double(k + 1); + const double term = 1.0 / (factorial * kp1 * kp1); + s += term; + if (term < 1e-18) + break; + } + return s; + }()); + + run_case( + "one_over_1_plus_x_plus_y", + [](double x, double y) + { + return 1.0 / (1.0 + x + y); + }, + 3.0 * std::log(3.0) - 4.0 * std::log(2.0)); + + run_case( + "complex_exp_5ixy", + [](double x, double y) + { + return std::exp(std::complex(0, 5 * x * y)); + }, + exact_exp_5ixy()); + + run_case( + "cos_5xy", + [](double x, double y) + { + return std::cos(5.0 * x * y); + }, + exact_exp_5ixy().real()); + + run_case( + "sqrt_x_plus_y", + [](double x, double y) + { + return std::sqrt(x + y); + }, + (4.0 / 15.0) * (std::pow(2.0, 2.5) - 2.0)); + + return 0; +} diff --git a/reporting/performance/van_den_bos_unit_square_performance.cpp b/reporting/performance/van_den_bos_unit_square_performance.cpp new file mode 100644 index 0000000000..be57eaef1d --- /dev/null +++ b/reporting/performance/van_den_bos_unit_square_performance.cpp @@ -0,0 +1,110 @@ +// Copyright Nicholas Thompson 2026. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + * Google Benchmark suite for van_den_bos_unit_square integrands. + * + * Example: + * c++ -O3 -DNDEBUG -std=c++17 -Iinclude \ + * reporting/performance/van_den_bos_unit_square_performance.cpp \ + * -lbenchmark -lpthread -o vdb_bench + */ + +#include +#include + +#include +#include +#include + +namespace { + +using boost::math::quadrature::van_den_bos_unit_square; + +template +void benchmark_integrand(benchmark::State& state, F const& f, double tol) +{ + for (auto _ : state) + { + const auto value = van_den_bos_unit_square(f, tol); + benchmark::DoNotOptimize(value); + } +} + +static void BM_quadratic(benchmark::State& state) +{ + benchmark_integrand( + state, + [](double x, double y) + { + return x * x + y * y + x * y; + }, + 1e-12); +} +BENCHMARK(BM_quadratic); + +static void BM_exp_x_plus_y(benchmark::State& state) +{ + benchmark_integrand( + state, + [](double x, double y) + { + return std::exp(x + y); + }, + 1e-10); +} +BENCHMARK(BM_exp_x_plus_y); + +static void BM_exp_xy(benchmark::State& state) +{ + benchmark_integrand( + state, + [](double x, double y) + { + return std::exp(x * y); + }, + 1e-10); +} +BENCHMARK(BM_exp_xy); + +static void BM_one_over_1_plus_x_plus_y(benchmark::State& state) +{ + benchmark_integrand( + state, + [](double x, double y) + { + return 1.0 / (1.0 + x + y); + }, + 1e-10); +} +BENCHMARK(BM_one_over_1_plus_x_plus_y); + +static void BM_cos_5xy(benchmark::State& state) +{ + benchmark_integrand( + state, + [](double x, double y) + { + return std::cos(5.0 * x * y); + }, + 1e-8); +} +BENCHMARK(BM_cos_5xy); + +static void BM_complex_exp_5ixy(benchmark::State& state) +{ + benchmark_integrand( + state, + [](double x, double y) + { + return std::exp(std::complex(0, 5 * x * y)); + }, + 1e-8); +} +BENCHMARK(BM_complex_exp_5ixy); + +} // namespace + +BENCHMARK_MAIN(); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 9ae3016a6c..e795dcf17a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1339,6 +1339,13 @@ test-suite quadrature : [ compile compile_test/gauss_concept_test.cpp : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_smart_ptr cxx11_unified_initialization_syntax ] [ check-target-builds ../config//is_ci_sanitizer_run "Sanitizer CI run" : no ] ] [ compile compile_test/gauss_kronrod_concept_test.cpp : [ requires cxx11_auto_declarations cxx11_lambdas cxx11_smart_ptr cxx11_unified_initialization_syntax ] [ check-target-builds ../config//is_ci_sanitizer_run "Sanitizer CI run" : no ] ] + [ run test_van_den_bos_unit_square.cpp : : : + 17 + [ requires cxx17_if_constexpr cxx11_auto_declarations cxx11_lambdas cxx11_hdr_array cxx11_hdr_thread ] + linux:"-pthread" ] + [ compile-fail test_van_den_bos_unit_square_integral_return_fail.cpp : + 17 + [ requires cxx17_if_constexpr cxx11_auto_declarations cxx11_lambdas cxx11_hdr_array ] ] [ run git_issue_898.cpp ] [ run git_issue_1075.cpp : : : $(float128_type) ] diff --git a/test/test_van_den_bos_unit_square.cpp b/test/test_van_den_bos_unit_square.cpp new file mode 100644 index 0000000000..601cc43eb4 --- /dev/null +++ b/test/test_van_den_bos_unit_square.cpp @@ -0,0 +1,376 @@ +// Copyright 2026 Nicholas Thompson and Matt Borland +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include "math_unit_test.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using boost::math::quadrature::van_den_bos_unit_square; + +std::complex exact_complex_exp_5ixy() +{ + std::complex exact(0, 0); + std::complex power(1, 0); + double factorial = 1; + + for (unsigned k = 0; k < 100; ++k) + { + if (k > 0) + { + power *= std::complex(0, 5); + factorial *= double(k); + } + + const double kp1 = double(k + 1); + const auto term = power / (factorial * kp1 * kp1); + exact += term; + + if (std::abs(term) < 1e-18) + { + break; + } + } + + return exact; +} + +double shifted_legendre(unsigned n, double x) +{ + const double t = 2 * x - 1; + if (n == 0) + { + return 1; + } + if (n == 1) + { + return t; + } + + double pnm2 = 1; + double pnm1 = t; + for (unsigned k = 2; k <= n; ++k) + { + const double pn = + ((2 * k - 1) * t * pnm1 - (k - 1) * pnm2) / k; + pnm2 = pnm1; + pnm1 = pn; + } + return pnm1; +} + +void test_table_properties() +{ + namespace detail = boost::math::quadrature::detail; + + std::size_t previous_size = 0; + for (std::size_t level_index = 0; + level_index < detail::van_den_bos_unit_square_level_count; + ++level_index) + { + const detail::van_den_bos_unit_square_level_view level = + detail::van_den_bos_unit_square_level(level_index); + const std::size_t moment_count = + (level.degree + 1) * (level.degree + 2) / 2; + + const std::size_t expected_size = level_index == 0 + ? (level.order + 1) * (level.order + 1) + : previous_size + moment_count; + CHECK_EQUAL(level.size, expected_size); + + double weight_sum = 0; + for (std::size_t j = 0; j < level.size; ++j) + { + CHECK_EQUAL(level.weights[j] > 0, true); + const auto point = level.point(j); + CHECK_GE(point[0], 0.0); + CHECK_LE(point[0], 1.0); + CHECK_GE(point[1], 0.0); + CHECK_LE(point[1], 1.0); + weight_sum += level.weights[j]; + + for (std::size_t i = 0; i < j; ++i) + { + CHECK_EQUAL(level.point(i) == point, false); + } + } + CHECK_ABSOLUTE_ERROR(weight_sum, 1.0, 4e-15); + + if (level_index > 0) + { + const detail::van_den_bos_unit_square_level_view previous = + detail::van_den_bos_unit_square_level(level_index - 1); + CHECK_EQUAL(previous.size, previous_size); + for (std::size_t j = 0; j < previous.size; ++j) + { + CHECK_EQUAL(level.point(j) == previous.point(j), true); + } + } + + for (unsigned total = 0; total <= level.degree; ++total) + { + for (unsigned px = 0; px <= total; ++px) + { + const unsigned py = total - px; + double moment = 0; + for (std::size_t j = 0; j < level.size; ++j) + { + moment += level.weights[j] * + shifted_legendre(px, level.point(j)[0]) * + shifted_legendre(py, level.point(j)[1]); + } + const double exact = total == 0 ? 1.0 : 0.0; + CHECK_ABSOLUTE_ERROR(moment, exact, 5e-13); + } + } + + previous_size = level.size; + } +} + +void test_polynomial() +{ + double error = 0; + std::size_t evaluations = 0; + + const double value = van_den_bos_unit_square( + [](double x, double y) + { + return x * x + y * y + x * y; + }, + 1e-12, + &error, + nullptr, + &evaluations); + + CHECK_ABSOLUTE_ERROR(value, 11.0 / 12.0, 2e-14); + CHECK_GE(evaluations, std::size_t(1)); +} + +void test_exp_x_plus_y() +{ + const double exact = std::pow(std::expm1(1.0), 2); + + double error = 0; + const double value = van_den_bos_unit_square( + [](double x, double y) + { + return std::exp(x + y); + }, + 1e-10, + &error); + + CHECK_ABSOLUTE_ERROR(value, exact, 2e-10); + CHECK_LE(error, 2e-10); +} + +void test_dilogarithm_integral() +{ + const double pi = boost::math::constants::pi(); + const double log_two = std::log(2.0); + const double exact = pi * pi / 6 - log_two * log_two; + + double error = 0; + const double value = van_den_bos_unit_square( + [](double x, double y) + { + return 1 / (1 - x * y / 2); + }, + 1e-10, + &error); + + CHECK_ABSOLUTE_ERROR(value, exact, 2e-10); + CHECK_LE(error, 2e-10); +} + +void test_square_lattice_green_function() +{ + constexpr double z = 3; + const double pi = boost::math::constants::pi(); + const double exact = 2 * boost::math::ellint_1(2 / z) / (pi * z); + + double error = 0; + const double value = van_den_bos_unit_square( + [](double x, double y) + { + const double two_pi = + 2 * boost::math::constants::pi(); + return 1 / (z - std::cos(two_pi * x) + - std::cos(two_pi * y)); + }, + 1e-6, + &error); + + CHECK_ABSOLUTE_ERROR(value, exact, 5e-9); + CHECK_LE(error, 1e-6); +} + +void test_complex_integrand() +{ + const auto exact = exact_complex_exp_5ixy(); + + double error = 0; + double L1 = 0; + std::size_t evaluations = 0; + + const auto computed = van_den_bos_unit_square( + [](double x, double y) + { + return std::exp( + std::complex(0, 5 * x * y)); + }, + 1e-8, + &error, + &L1, + &evaluations); + + CHECK_ABSOLUTE_ERROR(exact.real(), computed.real(), 2e-8); + CHECK_ABSOLUTE_ERROR(exact.imag(), computed.imag(), 5e-8); + CHECK_LE(error, 1e-8); + CHECK_GE(L1, 0.0); + CHECK_GE(evaluations, std::size_t(1)); +} + +void test_final_precomputed_level() +{ + double error = 0; + + const double value = van_den_bos_unit_square( + [](double x, double y) + { + return std::sqrt(x + y); + }, + 1e-30, + &error); + + const double exact = + (4.0 / 15.0) * (std::pow(2.0, 2.5) - 2.0); + + CHECK_ABSOLUTE_ERROR(value, exact, 1e-4); + CHECK_GE(error, 0.0); +} + +void test_oscillatory_convergence_guard() +{ + constexpr double frequency = 9.41; + const double exact = std::sin(frequency) / frequency; + + double error = 0; + std::size_t evaluations = 0; + const double value = van_den_bos_unit_square( + [](double x, double) + { + return std::cos(frequency * x); + }, + 1e-6, + &error, + nullptr, + &evaluations); + + CHECK_ABSOLUTE_ERROR(value, exact, 1e-12); + CHECK_LE(error, 1e-6); + CHECK_GE(evaluations, std::size_t(109)); +} + +void test_float_roundoff_floor() +{ + namespace detail = boost::math::quadrature::detail; + + double error = 0; + std::size_t evaluations = 0; + const auto value = van_den_bos_unit_square( + [](double, double) + { + return float(1); + }, + 1e-10, + &error, + nullptr, + &evaluations); + + static_assert(std::is_same::value, + "The quadrature must preserve the integrand's floating-point type."); + const float epsilon = (std::numeric_limits::epsilon)(); + CHECK_ABSOLUTE_ERROR(value, 1.0f, 64 * epsilon); + CHECK_GE(error, double(8 * epsilon)); + CHECK_EQUAL(evaluations, + detail::van_den_bos_unit_square_level( + detail::van_den_bos_unit_square_level_count - 1).size); +} + +void test_concurrent_integrations() +{ + constexpr std::size_t thread_count = 4; + + std::array results{}; + std::array errors{}; + std::array evaluations{}; + std::vector threads; + threads.reserve(thread_count); + + for (std::size_t k = 0; k < thread_count; ++k) + { + threads.emplace_back([&, k] + { + const double scale = double(k + 1); + + results[k] = van_den_bos_unit_square( + [=](double x, double y) + { + return std::exp( + scale * (x + y) / 8.0); + }, + 1e-9, + &errors[k], + nullptr, + &evaluations[k]); + }); + } + + for (auto& thread : threads) + { + thread.join(); + } + + for (std::size_t k = 0; k < thread_count; ++k) + { + const double a = double(k + 1) / 8.0; + const double exact = + std::pow(std::expm1(a) / a, 2); + + CHECK_ABSOLUTE_ERROR(exact, results[k], 2e-8); + CHECK_LE( + errors[k], + 2e-9 * (std::max)(1.0, std::abs(results[k]))); + CHECK_GE(evaluations[k], std::size_t(1)); + } +} + +} // namespace + +int main() +{ + test_table_properties(); + test_polynomial(); + test_exp_x_plus_y(); + test_dilogarithm_integral(); + test_square_lattice_green_function(); + test_complex_integrand(); + test_final_precomputed_level(); + test_oscillatory_convergence_guard(); + test_float_roundoff_floor(); + test_concurrent_integrations(); + + return boost::math::test::report_errors(); +} diff --git a/test/test_van_den_bos_unit_square_integral_return_fail.cpp b/test/test_van_den_bos_unit_square_integral_return_fail.cpp new file mode 100644 index 0000000000..36a1da327c --- /dev/null +++ b/test/test_van_den_bos_unit_square_integral_return_fail.cpp @@ -0,0 +1,14 @@ +// Copyright 2026 Nicholas Thompson and Matt Borland +// Distributed under the Boost Software License, Version 1.0. + +#include + +int main() +{ + return boost::math::quadrature::van_den_bos_unit_square( + [](double, double) + { + return 1; + }, + 1e-12); +} diff --git a/tools/dump_van_den_bos_unit_square.cpp b/tools/dump_van_den_bos_unit_square.cpp new file mode 100644 index 0000000000..b895f7d0e8 --- /dev/null +++ b/tools/dump_van_den_bos_unit_square.cpp @@ -0,0 +1,477 @@ +// Copyright 2026 Nicholas Thompson +// Distributed under the Boost Software License, Version 1.0. + +/* + * One-shot generator for nested van den Bos rules on [0,1]^2. + * + * Construction precision: + * boost::multiprecision::cpp_bin_float_quad + * + * Storage/runtime precision: + * IEEE-754 binary64, rounded once at emission and written as exact + * hexadecimal floating-point literals. + * + * Build from the Boost tree: + * + * c++ -O2 -DNDEBUG -std=c++17 -Iinclude -I/path/to/eigen \ + * tools/dump_van_den_bos_unit_square.cpp -o dump_vdb_unit_square + * + * ./dump_vdb_unit_square \ + * > include/boost/math/quadrature/detail/van_den_bos_unit_square_tables.hpp + */ + +#include +#include + +#include "van_den_bos_generator.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using quad = boost::multiprecision::cpp_bin_float_quad; +using point_quad = std::array; +using point_double = std::array; + +template +void validate_quad_rule(Rule const& rule, unsigned degree, std::size_t level) +{ + using boost::math::quadrature::van_den_bos_legendre_basis; + using boost::math::quadrature::van_den_bos_moment_residual; + using std::abs; + + van_den_bos_legendre_basis basis(degree); + auto moments = basis.moments(); + + quad sum_weights = 0; + quad min_weight = (std::numeric_limits::infinity)(); + for (std::size_t j = 0; j < rule.size(); ++j) + { + const quad w = rule.weight(j); + if (!(w > 0)) + { + throw std::runtime_error( + "nonpositive quad weight at level " + + std::to_string(level)); + } + sum_weights += w; + min_weight = (std::min)(min_weight, w); + + for (std::size_t d = 0; d < 2; ++d) + { + const quad x = rule.point(j)[d]; + if (x < 0 || x > 1) + { + throw std::runtime_error( + "quad node outside the unit square at level " + + std::to_string(level)); + } + } + } + + const quad sum_error = abs(sum_weights - 1); + const quad residual = + van_den_bos_moment_residual(rule, basis, moments); + const quad tolerance = + quad(1000000000) * std::numeric_limits::epsilon(); + + std::cerr + << "level " << level + << ": quad sumw error=" << std::scientific + << std::setprecision(std::numeric_limits::max_digits10) + << sum_error + << ", quad minw=" << min_weight + << ", quad moment residual=" << residual + << '\n'; + + if (sum_error > tolerance || residual > tolerance) + { + throw std::runtime_error( + "quad rule moment residual is too large at level " + + std::to_string(level)); + } +} + +template +double rounded_moment_residual(Rule const& rule, unsigned degree) +{ + using boost::math::quadrature::van_den_bos_legendre_basis; + + van_den_bos_legendre_basis basis(degree); + auto moments = basis.moments(); + + double max_residual = 0; + + for (std::size_t k = 0; k < basis.size(); ++k) + { + double moment = 0; + for (std::size_t j = 0; j < rule.size(); ++j) + { + point_double p{ + static_cast(rule.point(j)[0]), + static_cast(rule.point(j)[1]) + }; + const double w = static_cast(rule.weight(j)); + moment += w * basis(p, k); + } + + max_residual = + (std::max)(max_residual, std::abs(moment - moments[k])); + } + + return max_residual; +} + +template +void validate_rounded_rule(Rule const& rule, unsigned degree, std::size_t level) +{ + double sum_weights = 0; + double min_weight = (std::numeric_limits::infinity)(); + + for (std::size_t j = 0; j < rule.size(); ++j) + { + const double w = static_cast(rule.weight(j)); + + if (!std::isfinite(w)) + { + throw std::runtime_error( + "non-finite rounded weight at level " + std::to_string(level)); + } + + sum_weights += w; + min_weight = (std::min)(min_weight, w); + + for (std::size_t d = 0; d < 2; ++d) + { + const double x = static_cast(rule.point(j)[d]); + if (!std::isfinite(x) || x < 0.0 || x > 1.0) + { + throw std::runtime_error( + "invalid rounded node at level " + std::to_string(level)); + } + } + + for (std::size_t i = 0; i < j; ++i) + { + if (static_cast(rule.point(i)[0]) == + static_cast(rule.point(j)[0]) && + static_cast(rule.point(i)[1]) == + static_cast(rule.point(j)[1])) + { + throw std::runtime_error( + "duplicate rounded node at level " + + std::to_string(level)); + } + } + } + + const double residual = rounded_moment_residual(rule, degree); + + std::cerr + << "level " << level + << ": rounded sumw error=" << std::setprecision(17) + << std::abs(sum_weights - 1.0) + << ", rounded minw=" << min_weight + << ", rounded moment residual=" << residual + << '\n'; + + if (min_weight < 0.0) + { + throw std::runtime_error( + "negative rounded weight at level " + std::to_string(level)); + } + + if (std::abs(sum_weights - 1.0) > 1e-13) + { + throw std::runtime_error( + "rounded weights do not sum to one at level " + + std::to_string(level)); + } + + if (residual > 5e-13) + { + throw std::runtime_error( + "rounded rule moment residual is too large at level " + + std::to_string(level)); + } +} + +template +void emit_level( + std::ostream& os, + Rule const& rule, + std::size_t level, + unsigned degree, + std::size_t order) +{ + os << std::hexfloat; + os + << "inline constexpr unsigned van_den_bos_unit_square_level_" << level + << "_degree = " << degree << ";\n" + << "inline constexpr std::size_t van_den_bos_unit_square_level_" << level + << "_order = " << order << ";\n\n"; + + os + << "inline constexpr std::array van_den_bos_unit_square_level_" << level << "_weights{{\n"; + + for (std::size_t j = 0; j < rule.size(); ++j) + { + const double w = static_cast(rule.weight(j)); + + os << " " << w; + if (j + 1 != rule.size()) + { + os << ","; + } + os << "\n"; + } + os << "}};\n\n"; +} + +template +void emit_points(std::ostream& os, Rule const& rule) +{ + os << std::hexfloat; + std::vector coordinates; + std::vector> indices; + indices.reserve(rule.size()); + + for (std::size_t j = 0; j < rule.size(); ++j) + { + std::array point_indices{}; + for (std::size_t d = 0; d < 2; ++d) + { + const double coordinate = + static_cast(rule.point(j)[d]); + auto const found = + std::find(coordinates.begin(), coordinates.end(), coordinate); + if (found == coordinates.end()) + { + point_indices[d] = coordinates.size(); + coordinates.push_back(coordinate); + } + else + { + point_indices[d] = static_cast( + found - coordinates.begin()); + } + } + indices.push_back(point_indices); + } + + if (coordinates.size() > + static_cast((std::numeric_limits::max)()) + 1) + { + throw std::runtime_error( + "too many distinct coordinates for uint8_t node indices"); + } + + os + << "inline constexpr std::array van_den_bos_unit_square_coordinates{{\n"; + + for (std::size_t j = 0; j < coordinates.size(); ++j) + { + os << " " << coordinates[j] + << (j + 1 == coordinates.size() ? "\n" : ",\n"); + } + os << "}};\n\n"; + + os + << "inline constexpr std::array, " + << rule.size() + << "> van_den_bos_unit_square_node_indices{{\n"; + + for (std::size_t j = 0; j < rule.size(); ++j) + { + os << " {{" << indices[j][0] << ", " << indices[j][1] << "}}"; + if (j + 1 != rule.size()) + { + os << ","; + } + os << "\n"; + } + os << "}};\n\n"; +} + +void emit_hierarchy(std::ostream& os, std::size_t max_level) +{ + const std::size_t level_count = max_level + 1; + os + << "inline constexpr std::size_t " + << "van_den_bos_unit_square_level_count = " << level_count + << ";\n\n"; + + os << "inline constexpr std::array van_den_bos_unit_square_weights{{\n"; + for (std::size_t k = 0; k < level_count; ++k) + { + os << " van_den_bos_unit_square_level_" << k << "_weights.data()" + << (k + 1 == level_count ? "\n" : ",\n"); + } + os << "}};\n\n"; + + os << "inline constexpr std::array van_den_bos_unit_square_sizes{{\n"; + for (std::size_t k = 0; k < level_count; ++k) + { + os << " van_den_bos_unit_square_level_" << k << "_weights.size()" + << (k + 1 == level_count ? "\n" : ",\n"); + } + os << "}};\n\n"; + + os << "inline constexpr std::array van_den_bos_unit_square_degrees{{\n"; + for (std::size_t k = 0; k < level_count; ++k) + { + os << " van_den_bos_unit_square_level_" << k << "_degree" + << (k + 1 == level_count ? "\n" : ",\n"); + } + os << "}};\n\n"; + + os << "inline constexpr std::array van_den_bos_unit_square_orders{{\n"; + for (std::size_t k = 0; k < level_count; ++k) + { + os << " van_den_bos_unit_square_level_" << k << "_order" + << (k + 1 == level_count ? "\n" : ",\n"); + } + os << "}};\n\n"; +} + +} // namespace + +int main(int argc, char** argv) +{ + using boost::math::quadrature::positive_cubature_rule; + using boost::math::quadrature::van_den_bos_cache; + + // The full construction is performed in cpp_bin_float_quad. A full + // tensor Clenshaw-Curtis rule is the reproducible, strictly positive seed. + // It is already exact for the initial total-degree-four space, so no + // numerically fragile minimal-support seed is needed. + auto seed = + boost::math::quadrature::detail:: + clenshaw_curtis_tensor_rule(4); + + van_den_bos_cache cache( + positive_cubature_rule( + std::move(seed.first), std::move(seed.second)), + 4); + + std::cout << +R"(/* + * Copyright 2026 Nicholas Thompson and Matt Borland + * Distributed under the Boost Software License, Version 1.0. + * + * Generated by tools/dump_van_den_bos_unit_square.cpp. + * + * The Clenshaw-Curtis candidates, moment matrices, support reductions, nodes, + * and weights were all computed in cpp_bin_float_quad. Nodes and weights + * were rounded once, at emission, to IEEE-754 binary64. + * + * Every hexadecimal floating-point literal exactly represents its intended + * IEEE-754 binary64 value. C++17 or later is therefore required. + */ +#ifndef BOOST_MATH_QUADRATURE_DETAIL_VAN_DEN_BOS_UNIT_SQUARE_TABLES_HPP +#define BOOST_MATH_QUADRATURE_DETAIL_VAN_DEN_BOS_UNIT_SQUARE_TABLES_HPP + +#include +#include +#include + +namespace boost { namespace math { namespace quadrature { namespace detail { + +)"; + + std::size_t max_level = 6; + if (argc == 2) + { + max_level = static_cast(std::stoul(argv[1])); + if (max_level > 6) + { + throw std::invalid_argument("maximum generated level is 6"); + } + } + else if (argc != 1) + { + throw std::invalid_argument("usage: dump_vdb_unit_square [max-level]"); + } + + for (std::size_t k = 0; k <= max_level; ++k) + { + auto level = cache.ensure_level(k); + auto const& rule = *level->rule; + + if (k > 0) + { + auto previous = cache.ensure_level(k - 1); + if (rule.size() <= previous->rule->size()) + { + throw std::runtime_error( + "nested hierarchy did not grow at level " + + std::to_string(k)); + } + + for (std::size_t j = 0; j < previous->rule->size(); ++j) + { + for (std::size_t d = 0; d < 2; ++d) + { + if (rule.point(j)[d] != previous->rule->point(j)[d]) + { + throw std::runtime_error( + "quad prefix nesting failed at level " + + std::to_string(k)); + } + if (static_cast(rule.point(j)[d]) != + static_cast(previous->rule->point(j)[d])) + { + throw std::runtime_error( + "rounded prefix nesting failed at level " + + std::to_string(k)); + } + } + } + } + + std::cerr + << "constructed level " << k + << ": degree=" << level->degree + << ", order=" << level->clenshaw_curtis_order + << ", nodes=" << rule.size() + << '\n'; + + validate_quad_rule(rule, level->degree, k); + + // Crucially, validate the binary64 rule we are about to freeze, + // not merely the higher-precision construction. + validate_rounded_rule(rule, level->degree, k); + + emit_level( + std::cout, + rule, + k, + level->degree, + level->clenshaw_curtis_order); + } + + emit_points(std::cout, *cache.ensure_level(max_level)->rule); + emit_hierarchy(std::cout, max_level); + + std::cout << +R"(}}}} // namespaces + +#endif +)"; + + return 0; +} diff --git a/tools/van_den_bos_generator.hpp b/tools/van_den_bos_generator.hpp new file mode 100644 index 0000000000..efb206ac51 --- /dev/null +++ b/tools/van_den_bos_generator.hpp @@ -0,0 +1,2199 @@ +/* + * Copyright 2026 Nicholas Thompson + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. + * + * Positive cubature reduction in the style of: + * + * L. M. M. van den Bos, B. Sanderse, W. A. A. M. Bierbooms, + * G. J. W. van Bussel, + * "Generating nested quadrature rules with positive weights based on + * arbitrary sample sets", SIAM/ASA Journal on Uncertainty Quantification. + */ + +#ifndef BOOST_MATH_TOOLS_VAN_DEN_BOS_GENERATOR_HPP +#define BOOST_MATH_TOOLS_VAN_DEN_BOS_GENERATOR_HPP + +#ifndef BOOST_MATH_BUILD_MODULE +#include +#include +#include +#include +#include +#ifdef BOOST_MATH_INSTRUMENT +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include + +#include + +namespace boost { namespace math { namespace quadrature { + +template +class positive_cubature_rule +{ +public: + using point_type = Point; + using real_type = Real; + + positive_cubature_rule() = default; + + positive_cubature_rule(std::vector points, std::vector weights) + : points_(std::move(points)), weights_(std::move(weights)) + { + if (points_.size() != weights_.size()) + { + throw std::invalid_argument( + "positive_cubature_rule: points and weights must have the same size."); + } + } + + std::size_t size() const noexcept + { + return points_.size(); + } + + std::vector const& points() const noexcept + { + return points_; + } + + std::vector const& weights() const noexcept + { + return weights_; + } + + Point const& point(std::size_t i) const noexcept + { + return points_[i]; + } + + Real weight(std::size_t i) const noexcept + { + return weights_[i]; + } + + template + auto integrate(F const& f, Real* L1 = nullptr) const + -> decltype(std::declval()(std::declval())) + { + using std::abs; + using result_type = decltype(f(std::declval())); + + static_assert(!std::is_integral::value, + "The integrand return type must be a real or complex floating-point type."); + + result_type result = result_type(0); + Real l1 = Real(0); + + for (std::size_t i = 0; i < points_.size(); ++i) + { + result_type y = f(points_[i]); + result += weights_[i] * y; + l1 += weights_[i] * abs(y); + } + + if (L1) + { + *L1 = l1; + } + return result; + } + +private: + std::vector points_; + std::vector weights_; +}; + +namespace detail { + +template +using matrix_type = Eigen::Matrix; + +template +using vector_type = Eigen::Matrix; + +template +auto fill_moment_values( + Point const& point, + Basis const& basis, + Real* values, + std::size_t moment_count, + int) + -> decltype(basis.evaluate(point, values, moment_count), void()) +{ + basis.evaluate(point, values, moment_count); +} + +template +void fill_moment_values( + Point const& point, + Basis const& basis, + Real* values, + std::size_t moment_count, + long) +{ + for (std::size_t k = 0; k < moment_count; ++k) + { + values[k] = basis(point, k); + } +} + +template +matrix_type moment_matrix( + std::vector const& points, + std::vector const& indices, + Basis const& basis, + std::size_t moment_count) +{ + matrix_type A( + static_cast(moment_count), + static_cast(indices.size())); + + for (std::size_t j = 0; j < indices.size(); ++j) + { + fill_moment_values( + points[indices[j]], + basis, + A.col(static_cast(j)).data(), + moment_count, + 0); + } + return A; +} + +template +matrix_type moment_matrix( + std::vector const& points, + Basis const& basis, + std::size_t moment_count) +{ + std::vector indices(points.size()); + for (std::size_t i = 0; i < indices.size(); ++i) + { + indices[i] = i; + } + return moment_matrix(points, indices, basis, moment_count); +} + +template +vector_type to_eigen(std::vector const& x) +{ + vector_type result(static_cast(x.size())); + for (std::size_t i = 0; i < x.size(); ++i) + { + result(static_cast(i)) = x[i]; + } + return result; +} + +template +std::vector from_eigen(vector_type const& x) +{ + std::vector result(static_cast(x.size())); + for (Eigen::Index i = 0; i < x.size(); ++i) + { + result[static_cast(i)] = x(i); + } + return result; +} + +template +matrix_type kernel(matrix_type const& A, Real rank_tolerance) +{ + Eigen::ColPivHouseholderQR> qr(A); + qr.setThreshold(rank_tolerance); + + const Eigen::Index rank = qr.rank(); + const Eigen::Index n = A.cols(); + const Eigen::Index nullity = n - rank; + + matrix_type Z = matrix_type::Zero(n, nullity); + if (nullity == 0) + { + return Z; + } + + // A P = Q R, with R = [R11 R12]. In permuted coordinates, + // + // R11 y1 + R12 y2 = 0, + // + // so a nullspace basis is + // + // y = [-R11^{-1} R12; I]. + matrix_type R = qr.matrixR().topLeftCorner(rank, n); + matrix_type Y = matrix_type::Zero(n, nullity); + + if (rank > 0) + { + Y.topRows(rank) = + -R.leftCols(rank) + .template triangularView() + .solve(R.rightCols(nullity)); + } + + Y.bottomRows(nullity).setIdentity(); + Z = qr.colsPermutation() * Y; + return Z; +} + +template +vector_type kernel_vector( + matrix_type const& A, + Real rank_tolerance) +{ + Eigen::ColPivHouseholderQR> qr(A); + qr.setThreshold(rank_tolerance); + + const Eigen::Index rank = qr.rank(); + const Eigen::Index n = A.cols(); + if (rank == n) + { + return vector_type(); + } + + // Set the first free variable in permuted coordinates to one and solve + // R11 y1 + r12 = 0. Reduction needs a single null direction, so avoid + // materializing the potentially very large complete nullspace. + vector_type y = vector_type::Zero(n); + y(rank) = Real(1); + if (rank > 0) + { + matrix_type R = qr.matrixR().topLeftCorner(rank, rank + 1); + y.head(rank) = + -R.leftCols(rank) + .template triangularView() + .solve(R.col(rank)); + } + return qr.colsPermutation() * y; +} + +template +bool solve_square( + matrix_type const& A, + std::vector const& b, + std::vector& x, + Real rank_tolerance) +{ + if (A.rows() != A.cols() || A.rows() != static_cast(b.size())) + { + return false; + } + + Eigen::ColPivHouseholderQR> qr(A); + qr.setThreshold(rank_tolerance); + if (qr.rank() != A.cols()) + { + return false; + } + + vector_type solution = qr.solve(to_eigen(b)); + x = from_eigen(solution); + return true; +} + +template +struct reduction_candidate +{ + bool valid = false; + Real alpha = Real(0); + Real protected_margin = Real(0); + std::size_t boundary_index = 0; +}; + +template +reduction_candidate choose_boundary( + std::vector const& w, + vector_type const& c, + std::vector const& protected_local, + Real positivity_tolerance) +{ + const Real inf = (std::numeric_limits::infinity)(); + + Real upper = inf; + Real lower = -inf; + std::size_t upper_idx = 0; + std::size_t lower_idx = 0; + bool have_upper = false; + bool have_lower = false; + + for (std::size_t i = 0; i < w.size(); ++i) + { + Real ci = c(static_cast(i)); + if (ci > positivity_tolerance) + { + Real a = w[i] / ci; + if (!have_upper || a < upper) + { + upper = a; + upper_idx = i; + have_upper = true; + } + } + else if (ci < -positivity_tolerance) + { + Real a = w[i] / ci; + if (!have_lower || a > lower) + { + lower = a; + lower_idx = i; + have_lower = true; + } + } + } + + reduction_candidate best; + + auto inspect = [&](Real alpha, std::size_t boundary_index) + { + if (protected_local[boundary_index]) + { + return; + } + + Real margin = inf; + for (std::size_t i = 0; i < w.size(); ++i) + { + Real wi = w[i] - alpha * c(static_cast(i)); + if (wi < -positivity_tolerance) + { + return; + } + if (protected_local[i]) + { + margin = (std::min)(margin, wi); + } + } + + if (!best.valid || margin > best.protected_margin) + { + best.valid = true; + best.alpha = alpha; + best.protected_margin = margin; + best.boundary_index = boundary_index; + } + }; + + if (have_upper) + { + inspect(upper, upper_idx); + } + if (have_lower) + { + inspect(lower, lower_idx); + } + + return best; +} + +inline std::vector complement_indices( + std::size_t n, + std::vector const& removed) +{ + std::vector is_removed(n, 0); + for (std::size_t i : removed) + { + is_removed[i] = 1; + } + + std::vector result; + result.reserve(n - removed.size()); + for (std::size_t i = 0; i < n; ++i) + { + if (!is_removed[i]) + { + result.push_back(i); + } + } + return result; +} + +template +bool weights_for_support( + std::vector const& points, + std::vector const& support, + Basis const& basis, + std::vector const& moments, + std::vector& weights, + Real rank_tolerance) +{ + if (support.size() != moments.size()) + { + return false; + } + + matrix_type A = moment_matrix( + points, support, basis, moments.size()); + return solve_square(A, moments, weights, rank_tolerance); +} + +template +bool initial_basic_removal( + std::vector const& points, + std::vector weights, + Basis const& basis, + std::vector const& moments, + std::vector& removed, + Real rank_tolerance, + Real positivity_tolerance) +{ + using std::abs; + + std::vector active(points.size()); + for (std::size_t i = 0; i < active.size(); ++i) + { + active[i] = i; + } + removed.clear(); + + while (active.size() > moments.size()) + { + matrix_type A = moment_matrix( + points, active, basis, moments.size()); + matrix_type Z = kernel(A, rank_tolerance); + if (Z.cols() == 0) + { + return false; + } + + vector_type c = Z.col(0); + Real scale = c.cwiseAbs().maxCoeff(); + if (scale == Real(0)) + { + return false; + } + c /= scale; + + Real upper = (std::numeric_limits::infinity)(); + Real lower = -(std::numeric_limits::infinity)(); + bool have_upper = false; + bool have_lower = false; + + for (std::size_t j = 0; j < active.size(); ++j) + { + Real cj = c(static_cast(j)); + Real wj = weights[active[j]]; + if (cj > positivity_tolerance) + { + Real a = wj / cj; + if (!have_upper || a < upper) + { + upper = a; + have_upper = true; + } + } + else if (cj < -positivity_tolerance) + { + Real a = wj / cj; + if (!have_lower || a > lower) + { + lower = a; + have_lower = true; + } + } + } + + if (!have_upper && !have_lower) + { + return false; + } + + Real alpha; + if (!have_lower) + { + alpha = upper; + } + else if (!have_upper) + { + alpha = lower; + } + else + { + alpha = abs(lower) <= abs(upper) ? lower : upper; + } + + for (std::size_t j = 0; j < active.size(); ++j) + { + weights[active[j]] -= alpha * c(static_cast(j)); + } + + bool deleted = false; + std::vector next; + next.reserve(active.size() - 1); + for (std::size_t index : active) + { + if (!deleted && abs(weights[index]) <= positivity_tolerance) + { + weights[index] = Real(0); + removed.push_back(index); + deleted = true; + } + else + { + next.push_back(index); + } + } + + if (!deleted) + { + return false; + } + active.swap(next); + } + + std::sort(removed.begin(), removed.end()); + return true; +} + + +template +std::vector> +total_degree_multi_indices(unsigned degree) +{ + std::vector> result; + std::array alpha{}; + + auto append = [&](auto&& self, + std::size_t coordinate, + unsigned remaining) -> void + { + if (coordinate + 1 == Dimension) + { + alpha[coordinate] = remaining; + result.push_back(alpha); + return; + } + + for (unsigned k = 0; k <= remaining; ++k) + { + alpha[coordinate] = k; + self(self, coordinate + 1, remaining - k); + } + }; + + for (unsigned total = 0; total <= degree; ++total) + { + append(append, 0, total); + } + return result; +} + +template +Real shifted_legendre(unsigned n, Real x) +{ + const Real t = Real(2) * x - Real(1); + + if (n == 0) + { + return Real(1); + } + if (n == 1) + { + return t; + } + + Real pnm2 = Real(1); + Real pnm1 = t; + for (unsigned k = 2; k <= n; ++k) + { + const Real pn = + (Real(2 * k - 1) * t * pnm1 - Real(k - 1) * pnm2) / Real(k); + pnm2 = pnm1; + pnm1 = pn; + } + return pnm1; +} + +/* + * Reduce only the unprotected suffix to a basic positive solution while the + * protected prefix and its current candidate weights remain fixed. This is + * the straightforward nested extension described at the start of paper + * Section 3.2, before the minimal M-removal construction. + * + * A basis inverse is reused across simplex-style pivots. Rebuilding it + * periodically avoids the cost of a fresh rectangular QR decomposition for + * every removed node while keeping the offline multiprecision construction + * numerically controlled. + */ +template +positive_cubature_rule reduce_protected_basic( + std::vector points, + std::vector weights, + Basis const& basis, + std::vector const& moments, + std::size_t protected_count, + Real rank_tolerance, + Real positivity_tolerance) +{ + using std::abs; + + const std::size_t moment_count = moments.size(); + const std::size_t suffix_count = points.size() - protected_count; + if (suffix_count < moment_count) + { + throw std::runtime_error( + "reduce_protected_basic: too few removable candidate nodes."); + } + + std::vector suffix_indices(suffix_count); + for (std::size_t j = 0; j < suffix_count; ++j) + { + suffix_indices[j] = protected_count + j; + } + + matrix_type A = moment_matrix( + points, suffix_indices, basis, moment_count); + + std::vector residual = moments; + std::vector protected_moments(moment_count); + for (std::size_t j = 0; j < protected_count; ++j) + { + fill_moment_values( + points[j], + basis, + protected_moments.data(), + moment_count, + 0); + for (std::size_t k = 0; k < moment_count; ++k) + { + residual[k] -= weights[j] * protected_moments[k]; + } + } + + Eigen::ColPivHouseholderQR> qr(A); + qr.setThreshold(rank_tolerance); + if (qr.rank() != static_cast(moment_count)) + { + throw std::runtime_error( + "reduce_protected_basic: candidate moment matrix is rank deficient."); + } + + std::vector basic(moment_count); + std::vector is_basic(suffix_count, 0); + for (std::size_t j = 0; j < moment_count; ++j) + { + const std::size_t index = static_cast( + qr.colsPermutation().indices()(static_cast(j))); + basic[j] = index; + is_basic[index] = 1; + } + + matrix_type B( + static_cast(moment_count), + static_cast(moment_count)); + matrix_type inverse; + const Real solve_tolerance = Real(1000) * rank_tolerance; + + auto inverse_residual = [&] + { + return (B * inverse - matrix_type::Identity( + static_cast(moment_count), + static_cast(moment_count))) + .cwiseAbs() + .maxCoeff(); + }; + + auto rebuild_inverse = [&] + { + for (std::size_t j = 0; j < moment_count; ++j) + { + B.col(static_cast(j)) = + A.col(static_cast(basic[j])); + } + + Eigen::PartialPivLU> basis_lu(B); + inverse = basis_lu.inverse(); + + if (inverse_residual() > solve_tolerance) + { + Eigen::ColPivHouseholderQR> basis_qr(B); + basis_qr.setThreshold(rank_tolerance); + if (basis_qr.rank() != static_cast(moment_count)) + { + throw std::runtime_error( + "reduce_protected_basic: pivot basis is rank deficient."); + } + inverse = basis_qr.solve(matrix_type::Identity( + static_cast(moment_count), + static_cast(moment_count))); + if (inverse_residual() > solve_tolerance) + { + throw std::runtime_error( + "reduce_protected_basic: inverse residual is too large."); + } + } + }; + rebuild_inverse(); + + std::vector basic_weights(moment_count); + std::vector nonbasic_weights(suffix_count); + for (std::size_t j = 0; j < suffix_count; ++j) + { + nonbasic_weights[j] = weights[protected_count + j]; + } + for (std::size_t j = 0; j < moment_count; ++j) + { + basic_weights[j] = weights[protected_count + basic[j]]; + nonbasic_weights[basic[j]] = Real(0); + } + + for (std::size_t candidate = 0; candidate < suffix_count; ++candidate) + { + if (is_basic[candidate]) + { + continue; + } + + if (abs(nonbasic_weights[candidate]) <= positivity_tolerance) + { + nonbasic_weights[candidate] = Real(0); + continue; + } + + const auto candidate_column = + A.col(static_cast(candidate)); + vector_type z = inverse * candidate_column; + if ((B * z - candidate_column).cwiseAbs().maxCoeff() + > solve_tolerance) + { + rebuild_inverse(); + z = inverse * candidate_column; + if ((B * z - candidate_column).cwiseAbs().maxCoeff() + > solve_tolerance) + { + throw std::runtime_error( + "reduce_protected_basic: candidate solve residual is too large."); + } + } + const Real candidate_weight = nonbasic_weights[candidate]; + + struct boundary + { + bool valid = false; + Real alpha = Real(0); + std::size_t killed = 0; + std::size_t zero_count = 0; + }; + + auto inspect = [&](Real alpha, std::size_t killed) + { + boundary result; + result.valid = true; + result.alpha = alpha; + result.killed = killed; + + const Real updated_candidate = candidate_weight - alpha; + if (abs(updated_candidate) <= positivity_tolerance) + { + ++result.zero_count; + } + else if (updated_candidate < -positivity_tolerance) + { + result.valid = false; + } + + for (std::size_t j = 0; j < moment_count; ++j) + { + const Real updated = + basic_weights[j] + + alpha * z(static_cast(j)); + if (abs(updated) <= positivity_tolerance) + { + ++result.zero_count; + } + else if (updated < -positivity_tolerance) + { + result.valid = false; + } + } + return result; + }; + + Real upper = candidate_weight; + std::size_t upper_killed = moment_count; + Real lower = -(std::numeric_limits::infinity)(); + std::size_t lower_killed = moment_count; + bool have_lower = false; + + for (std::size_t j = 0; j < moment_count; ++j) + { + const Real zj = z(static_cast(j)); + if (zj < -positivity_tolerance) + { + const Real ratio = basic_weights[j] / (-zj); + if (ratio < upper) + { + upper = ratio; + upper_killed = j; + } + } + else if (zj > positivity_tolerance) + { + const Real ratio = -basic_weights[j] / zj; + if (!have_lower || ratio > lower) + { + lower = ratio; + lower_killed = j; + have_lower = true; + } + } + } + + boundary chosen = inspect(upper, upper_killed); + if (have_lower) + { + boundary alternative = inspect(lower, lower_killed); + if (!chosen.valid || + alternative.zero_count < chosen.zero_count || + (alternative.zero_count == chosen.zero_count && + abs(alternative.alpha) < abs(chosen.alpha))) + { + chosen = alternative; + } + } + + if (!chosen.valid || chosen.zero_count != 1) + { + throw std::runtime_error( + "reduce_protected_basic: degenerate positivity boundary."); + } + + std::vector updated_weights(moment_count); + for (std::size_t j = 0; j < moment_count; ++j) + { + updated_weights[j] = + basic_weights[j] + + chosen.alpha * z(static_cast(j)); + if (abs(updated_weights[j]) <= positivity_tolerance) + { + updated_weights[j] = Real(0); + } + } + Real updated_candidate = candidate_weight - chosen.alpha; + if (abs(updated_candidate) <= positivity_tolerance) + { + updated_candidate = Real(0); + } + + if (chosen.killed == moment_count) + { + // The candidate left the active support; the basis is unchanged. + basic_weights = std::move(updated_weights); + nonbasic_weights[candidate] = Real(0); + continue; + } + + const std::size_t replaced = chosen.killed; + if (!(updated_candidate > Real(0)) || + z(static_cast(replaced)) == Real(0)) + { + throw std::runtime_error( + "reduce_protected_basic: invalid basis pivot."); + } + + const std::size_t removed = basic[replaced]; + is_basic[removed] = 0; + nonbasic_weights[removed] = Real(0); + is_basic[candidate] = 1; + nonbasic_weights[candidate] = Real(0); + basic[replaced] = candidate; + B.col(static_cast(replaced)) = candidate_column; + basic_weights = std::move(updated_weights); + basic_weights[replaced] = updated_candidate; + + vector_type update = z; + update(static_cast(replaced)) -= Real(1); + inverse -= + (update * inverse.row(static_cast(replaced))) / + z(static_cast(replaced)); + + } + + std::sort(basic.begin(), basic.end()); + std::vector support(moment_count); + for (std::size_t j = 0; j < moment_count; ++j) + { + support[j] = protected_count + basic[j]; + } + + std::vector final_weights; + if (!weights_for_support( + points, + support, + basis, + residual, + final_weights, + rank_tolerance)) + { + throw std::runtime_error( + "reduce_protected_basic: final support is singular."); + } + + std::vector reduced_points; + std::vector reduced_weights; + reduced_points.reserve(protected_count + moment_count); + reduced_weights.reserve(protected_count + moment_count); + + for (std::size_t j = 0; j < protected_count; ++j) + { + reduced_points.push_back(points[j]); + reduced_weights.push_back(weights[j]); + } + for (std::size_t j = 0; j < moment_count; ++j) + { + if (!(final_weights[j] > Real(0))) + { + throw std::runtime_error( + "reduce_protected_basic: final weight is not positive."); + } + reduced_points.push_back(points[support[j]]); + reduced_weights.push_back(final_weights[j]); + } + + return positive_cubature_rule( + std::move(reduced_points), std::move(reduced_weights)); +} + +} // namespace detail + +template +positive_cubature_rule van_den_bos_reduce( + std::vector points, + std::vector weights, + Basis const& basis, + std::vector const& moments, + std::size_t target_size = 0, + std::size_t protected_count = 0, + Real rank_tolerance = Real(100) * boost::math::tools::epsilon(), + Real positivity_tolerance = Real(1000) * boost::math::tools::epsilon()) +{ + using std::abs; + + if (points.size() != weights.size()) + { + throw std::invalid_argument( + "van_den_bos_reduce: points and weights must have the same size."); + } + if (protected_count > points.size()) + { + throw std::invalid_argument( + "van_den_bos_reduce: protected_count exceeds number of points."); + } + if (moments.empty()) + { + throw std::invalid_argument( + "van_den_bos_reduce: moments must not be empty."); + } + + for (Real w : weights) + { + if (w < -positivity_tolerance) + { + throw std::domain_error( + "van_den_bos_reduce: input rule must have nonnegative weights."); + } + } + + if (target_size == 0) + { + target_size = moments.size(); + } + target_size = (std::max)(target_size, protected_count); + + std::vector protected_flag(points.size(), 0); + for (std::size_t i = 0; i < protected_count; ++i) + { + protected_flag[i] = 1; + } + + for (std::size_t i = points.size(); i-- > protected_count;) + { + if (abs(weights[i]) <= positivity_tolerance) + { + points.erase(points.begin() + static_cast(i)); + weights.erase(weights.begin() + static_cast(i)); + protected_flag.erase( + protected_flag.begin() + static_cast(i)); + } + } + + if (protected_count > 0 && + target_size == protected_count + moments.size()) + { + return detail::reduce_protected_basic( + std::move(points), + std::move(weights), + basis, + moments, + protected_count, + rank_tolerance, + positivity_tolerance); + } + + while (points.size() > target_size) + { + // Compute directions supported only on removable nodes. Consequently + // the protected prefix retains its coordinates and positive weights + // while each boundary step deletes one unprotected node and preserves + // every requested moment. + std::vector removable(points.size() - protected_count); + for (std::size_t i = 0; i < removable.size(); ++i) + { + removable[i] = protected_count + i; + } + + detail::matrix_type A = + detail::moment_matrix( + points, removable, basis, moments.size()); + detail::vector_type local_c = + detail::kernel_vector(A, rank_tolerance); + if (local_c.size() == 0) + { + break; + } + + bool reduced = false; + Real scale = local_c.cwiseAbs().maxCoeff(); + if (scale != Real(0)) + { + local_c /= scale; + + detail::vector_type c = + detail::vector_type::Zero( + static_cast(points.size())); + for (std::size_t i = 0; i < removable.size(); ++i) + { + c(static_cast(removable[i])) = + local_c(static_cast(i)); + } + + auto candidate = detail::choose_boundary( + weights, c, protected_flag, positivity_tolerance); + if (candidate.valid) + { + for (std::size_t i = 0; i < weights.size(); ++i) + { + weights[i] -= + candidate.alpha * c(static_cast(i)); + if (abs(weights[i]) <= positivity_tolerance) + { + weights[i] = Real(0); + } + } + + if (protected_count == 0) + { + // An unprotected basic reduction may hit a higher + // dimensional face. Remove every boundary node, as in + // Algorithm 1; the exact-size postcondition below rejects + // an unsuitable reduction path. + for (std::size_t i = points.size(); i-- > 0;) + { + if (abs(weights[i]) <= positivity_tolerance) + { + points.erase( + points.begin() + + static_cast(i)); + weights.erase( + weights.begin() + + static_cast(i)); + protected_flag.erase( + protected_flag.begin() + + static_cast(i)); + } + } + } + else + { + const std::size_t removed = candidate.boundary_index; + if (protected_flag[removed]) + { + throw std::runtime_error( + "van_den_bos_reduce: attempted to remove a protected node."); + } + points.erase( + points.begin() + static_cast(removed)); + weights.erase( + weights.begin() + static_cast(removed)); + protected_flag.erase( + protected_flag.begin() + + static_cast(removed)); + } + reduced = true; + } + } + + if (!reduced) + { + break; + } + } + + if (points.size() != target_size) + { + throw std::runtime_error( + "van_den_bos_reduce: could not reach the requested nested support size."); + } + + return positive_cubature_rule( + std::move(points), std::move(weights)); +} + +/* + * Enumerate the M-removals of van den Bos et al. If n nodes and r moment + * constraints are supplied, M=n-r. Each returned sorted set contains M + * nodes whose simultaneous removal leaves a positive r-node cubature rule. + */ +template +std::vector> van_den_bos_m_removals( + std::vector const& points, + std::vector const& weights, + Basis const& basis, + std::vector const& moments, + std::size_t max_removals = 0, + Real rank_tolerance = Real(100) * boost::math::tools::epsilon(), + Real positivity_tolerance = Real(1000) * boost::math::tools::epsilon()) +{ + using std::abs; + + if (points.size() != weights.size() || moments.empty() || + points.size() < moments.size()) + { + throw std::invalid_argument("van_den_bos_m_removals: invalid sizes."); + } + + const std::size_t n = points.size(); + const std::size_t r = moments.size(); + const std::size_t M = n - r; + + if (M == 0) + { + return {{}}; + } + + std::vector initial; + if (!detail::initial_basic_removal( + points, weights, basis, moments, initial, + rank_tolerance, positivity_tolerance)) + { + return {}; + } + + std::queue> queue; + std::set> seen; + std::vector> result; + + queue.push(initial); + seen.insert(initial); + + while (!queue.empty()) + { + std::vector q = queue.front(); + queue.pop(); + result.push_back(q); + + if (max_removals && result.size() >= max_removals) + { + break; + } + + for (std::size_t ri = 0; ri < M; ++ri) + { + std::vector fixed_removed; + fixed_removed.reserve(M - 1); + for (std::size_t j = 0; j < M; ++j) + { + if (j != ri) + { + fixed_removed.push_back(q[j]); + } + } + + std::vector extended_support = + detail::complement_indices(n, fixed_removed); + detail::matrix_type A = + detail::moment_matrix( + points, extended_support, basis, r); + detail::matrix_type Z = detail::kernel(A, rank_tolerance); + if (Z.cols() != 1) + { + continue; + } + detail::vector_type c = Z.col(0); + + std::vector support = + detail::complement_indices(n, q); + std::vector basic_weights; + if (!detail::weights_for_support( + points, support, basis, moments, + basic_weights, rank_tolerance)) + { + continue; + } + + std::vector extended_weights(extended_support.size(), Real(0)); + std::size_t b = 0; + std::size_t restored_local = extended_support.size(); + for (std::size_t j = 0; j < extended_support.size(); ++j) + { + if (extended_support[j] == q[ri]) + { + restored_local = j; + } + else + { + extended_weights[j] = basic_weights[b++]; + } + } + if (restored_local == extended_support.size()) + { + continue; + } + + Real upper = (std::numeric_limits::infinity)(); + Real lower = -(std::numeric_limits::infinity)(); + bool have_upper = false; + bool have_lower = false; + std::size_t upper_index = 0; + std::size_t lower_index = 0; + + for (std::size_t j = 0; j < extended_support.size(); ++j) + { + Real cj = c(static_cast(j)); + if (cj > positivity_tolerance) + { + Real a = extended_weights[j] / cj; + if (!have_upper || a < upper) + { + upper = a; + upper_index = j; + have_upper = true; + } + } + else if (cj < -positivity_tolerance) + { + Real a = extended_weights[j] / cj; + if (!have_lower || a > lower) + { + lower = a; + lower_index = j; + have_lower = true; + } + } + } + + std::size_t killed = extended_support.size(); + if (have_upper && abs(upper) > positivity_tolerance) + { + killed = upper_index; + } + if (have_lower && abs(lower) > positivity_tolerance) + { + if (killed == extended_support.size() || abs(lower) > abs(upper)) + { + killed = lower_index; + } + } + if (killed == extended_support.size()) + { + continue; + } + + std::size_t replacement = extended_support[killed]; + if (replacement == q[ri]) + { + continue; + } + + std::vector qhat = q; + qhat[ri] = replacement; + std::sort(qhat.begin(), qhat.end()); + if (std::adjacent_find(qhat.begin(), qhat.end()) != qhat.end()) + { + continue; + } + + std::vector candidate_support = + detail::complement_indices(n, qhat); + std::vector candidate_weights; + if (!detail::weights_for_support( + points, candidate_support, basis, moments, + candidate_weights, rank_tolerance)) + { + continue; + } + + bool positive = true; + for (Real w : candidate_weights) + { + if (w < -positivity_tolerance) + { + positive = false; + break; + } + } + if (!positive) + { + continue; + } + + if (seen.insert(qhat).second) + { + queue.push(std::move(qhat)); + } + } + } + + return result; +} + +template +positive_cubature_rule van_den_bos_reduce_multiple( + std::vector const& points, + std::vector const& weights, + Basis const& basis, + std::vector const& moments, + std::size_t protected_count = 0, + bool require_protected = true, + std::size_t max_removals = 0, + Real rank_tolerance = Real(100) * boost::math::tools::epsilon(), + Real positivity_tolerance = Real(1000) * boost::math::tools::epsilon()) +{ + if (protected_count > points.size()) + { + throw std::invalid_argument( + "van_den_bos_reduce_multiple: invalid protected_count."); + } + + auto removals = van_den_bos_m_removals( + points, weights, basis, moments, max_removals, + rank_tolerance, positivity_tolerance); + if (removals.empty()) + { + throw std::runtime_error( + "van_den_bos_reduce_multiple: no M-removal found."); + } + + std::vector const* best = nullptr; + std::size_t best_hits = (std::numeric_limits::max)(); + + for (auto const& q : removals) + { + std::size_t hits = 0; + for (std::size_t i : q) + { + if (i < protected_count) + { + ++hits; + } + } + + if (require_protected && hits != 0) + { + continue; + } + if (!best || hits < best_hits || (hits == best_hits && q < *best)) + { + best = &q; + best_hits = hits; + } + } + + if (!best) + { + throw std::runtime_error( + "van_den_bos_reduce_multiple: no removal preserves protected nodes."); + } + + std::vector support = + detail::complement_indices(points.size(), *best); + std::vector final_weights; + if (!detail::weights_for_support( + points, support, basis, moments, + final_weights, rank_tolerance)) + { + throw std::runtime_error( + "van_den_bos_reduce_multiple: selected support is singular."); + } + + std::vector final_points; + final_points.reserve(support.size()); + for (std::size_t i : support) + { + final_points.push_back(points[i]); + } + + return positive_cubature_rule( + std::move(final_points), std::move(final_weights)); +} + +template +Real van_den_bos_moment_residual( + positive_cubature_rule const& rule, + Basis const& basis, + std::vector const& moments) +{ + using std::abs; + + Real result = 0; + for (std::size_t k = 0; k < moments.size(); ++k) + { + Real q = 0; + for (std::size_t j = 0; j < rule.size(); ++j) + { + q += rule.weight(j) * basis(rule.point(j), k); + } + result = (std::max)(result, abs(q - moments[k])); + } + return result; +} + + +/* + * Total-degree tensor-product shifted Legendre basis on [0,1]^Dimension. + * + * van den Bos et al. use products of Legendre polynomials rather than + * monomials to improve conditioning of the Vandermonde matrix. For + * Lebesgue measure on the unit cube, every nonconstant basis function has + * zero moment, so the exact moment vector is (1, 0, ..., 0). + */ +template +class van_den_bos_legendre_basis +{ +public: + using point_type = std::array; + using multi_index_type = std::array; + + explicit van_den_bos_legendre_basis(unsigned degree) + : degree_(degree), + indices_(detail::total_degree_multi_indices(degree)) + {} + + std::size_t size() const noexcept + { + return indices_.size(); + } + + Real operator()(point_type const& x, std::size_t k) const + { + Real value = Real(1); + auto const& alpha = indices_[k]; + for (std::size_t j = 0; j < Dimension; ++j) + { + value *= detail::shifted_legendre(alpha[j], x[j]); + } + return value; + } + + void evaluate( + point_type const& x, + Real* values, + std::size_t count) const + { + std::array, Dimension> polynomials; + for (std::size_t j = 0; j < Dimension; ++j) + { + polynomials[j].resize(degree_ + 1); + polynomials[j][0] = Real(1); + if (degree_ == 0) + { + continue; + } + + const Real t = Real(2) * x[j] - Real(1); + polynomials[j][1] = t; + for (unsigned k = 2; k <= degree_; ++k) + { + polynomials[j][k] = + (Real(2 * k - 1) * t * polynomials[j][k - 1] + - Real(k - 1) * polynomials[j][k - 2]) / Real(k); + } + } + + for (std::size_t k = 0; k < count; ++k) + { + Real value = Real(1); + for (std::size_t j = 0; j < Dimension; ++j) + { + value *= polynomials[j][indices_[k][j]]; + } + values[k] = value; + } + } + + std::vector moments() const + { + std::vector result(size(), Real(0)); + if (!result.empty()) + { + result[0] = Real(1); + } + return result; + } + + std::vector const& indices() const noexcept + { + return indices_; + } + +private: + unsigned degree_; + std::vector indices_; +}; + + +namespace detail { + +template +std::pair, std::vector> +clenshaw_curtis_rule(std::size_t n) +{ + using std::acos; + using std::cos; + + if (n == 0) + { + return {{Real(0.5)}, {Real(1)}}; + } + + const Real pi = acos(Real(-1)); + std::vector x(n + 1); + std::vector w(n + 1); + + for (std::size_t j = 0; j <= n; ++j) + { + const Real theta = pi * Real(j) / Real(n); + // Map the usual [-1,1] Clenshaw-Curtis nodes to [0,1]. + x[j] = (Real(1) - cos(theta)) / Real(2); + } + + if (n == 1) + { + w[0] = Real(0.5); + w[1] = Real(0.5); + return {x, w}; + } + + if ((n & 1U) == 0U) + { + const Real endpoint = Real(1) / (Real(2) * Real(n * n - 1)); + w[0] = endpoint; + w[n] = endpoint; + + for (std::size_t j = 1; j < n; ++j) + { + const Real theta = pi * Real(j) / Real(n); + Real v = Real(1); + + for (std::size_t k = 1; k < n / 2; ++k) + { + v -= Real(2) * cos(Real(2 * k) * theta) + / Real(4 * k * k - 1); + } + + v -= cos(Real(n) * theta) / Real(n * n - 1); + w[j] = v / Real(n); + } + } + else + { + const Real endpoint = Real(1) / (Real(2) * Real(n * n)); + w[0] = endpoint; + w[n] = endpoint; + + for (std::size_t j = 1; j < n; ++j) + { + const Real theta = pi * Real(j) / Real(n); + Real v = Real(1); + + for (std::size_t k = 1; k <= (n - 1) / 2; ++k) + { + v -= Real(2) * cos(Real(2 * k) * theta) + / Real(4 * k * k - 1); + } + + w[j] = v / Real(n); + } + } + + return {x, w}; +} + +template +std::pair< + std::vector>, + std::vector> +clenshaw_curtis_tensor_rule(std::size_t n) +{ + using point_type = std::array; + + auto one_dimensional = clenshaw_curtis_rule(n); + auto const& x = one_dimensional.first; + auto const& w = one_dimensional.second; + + std::size_t count = 1; + for (std::size_t d = 0; d < Dimension; ++d) + { + count *= n + 1; + } + + std::vector points; + std::vector weights; + points.reserve(count); + weights.reserve(count); + + std::array index{}; + bool done = false; + + while (!done) + { + point_type point{}; + Real weight = Real(1); + + for (std::size_t d = 0; d < Dimension; ++d) + { + point[d] = x[index[d]]; + weight *= w[index[d]]; + } + + points.push_back(point); + weights.push_back(weight); + + for (std::size_t d = Dimension; d-- > 0;) + { + ++index[d]; + if (index[d] <= n) + { + break; + } + + index[d] = 0; + if (d == 0) + { + done = true; + } + } + } + + return {std::move(points), std::move(weights)}; +} + +template +bool same_point( + std::array const& x, + std::array const& y) +{ + using std::abs; + + const Real tolerance = + Real(64) * (std::numeric_limits::epsilon)(); + + for (std::size_t d = 0; d < Dimension; ++d) + { + if (abs(x[d] - y[d]) > + tolerance * (std::max)(Real(1), (std::max)(abs(x[d]), abs(y[d])))) + { + return false; + } + } + return true; +} + +inline std::size_t next_power_of_two(std::size_t n) +{ + std::size_t result = 1; + while (result < n) + { + if (result > (std::numeric_limits::max)() / 2) + { + throw std::overflow_error( + "van_den_bos_cache: candidate-grid order overflow."); + } + result *= 2; + } + return result; +} + +template +void place_protected_prefix( + positive_cubature_rule, Real> const& old_rule, + std::vector>& points, + std::vector& weights) +{ + using point_type = std::array; + + std::vector reordered_points; + std::vector reordered_weights; + reordered_points.reserve(points.size()); + reordered_weights.reserve(weights.size()); + + std::vector used(points.size(), 0); + + for (point_type const& old_point : old_rule.points()) + { + std::size_t match = points.size(); + + for (std::size_t j = 0; j < points.size(); ++j) + { + if (!used[j] && same_point(old_point, points[j])) + { + match = j; + break; + } + } + + if (match == points.size()) + { + throw std::runtime_error( + "van_den_bos_cache: refined candidate grid does not contain an old node."); + } + + used[match] = 1; + // Preserve the old point bit-for-bit so cached evaluations can be + // carried forward without coordinate comparisons. + reordered_points.push_back(old_point); + reordered_weights.push_back(weights[match]); + } + + for (std::size_t j = 0; j < points.size(); ++j) + { + if (!used[j]) + { + reordered_points.push_back(points[j]); + reordered_weights.push_back(weights[j]); + } + } + + points = std::move(reordered_points); + weights = std::move(reordered_weights); +} + +} // namespace detail + +/* + * Thread-safe shared hierarchy of immutable van-den-Bos cubature rules. + * + * Individual integrations remain serial. Many integrations may share one + * cache concurrently. Reading an existing level takes a shared lock; only + * construction of a new level takes the exclusive lock. The second check + * under the exclusive lock prevents duplicate refinement when several threads + * request the same new level simultaneously. + * + * Refinement uses dyadically nested Clenshaw-Curtis tensor candidates on + * [0,1]^Dimension and the shifted-Legendre moment basis recommended by + * van den Bos et al. Polynomial-space dimension is increased by at most + * max_moment_growth at each level. Each reduced rule contains the preceding + * rule as an exact prefix, followed by at most one new node per moment. + */ +template +class van_den_bos_cache +{ +public: + using real_type = Real; + using point_type = std::array; + using rule_type = positive_cubature_rule; + + struct level_type + { + std::shared_ptr rule; + unsigned degree = 0; + std::size_t clenshaw_curtis_order = 0; + }; + + explicit van_den_bos_cache( + unsigned initial_degree = 4, + std::size_t max_moment_growth = 2, + Real rank_tolerance = + Real(100) * boost::math::tools::epsilon(), + Real positivity_tolerance = + Real(1000) * boost::math::tools::epsilon()) + : initial_degree_(initial_degree), + max_moment_growth_(max_moment_growth), + rank_tolerance_(rank_tolerance), + positivity_tolerance_(positivity_tolerance) + { + if (initial_degree_ == 0) + { + throw std::invalid_argument( + "van_den_bos_cache: initial_degree must be positive."); + } + if (max_moment_growth_ < 2) + { + throw std::invalid_argument( + "van_den_bos_cache: max_moment_growth must be at least 2."); + } + levels_.push_back(make_level(nullptr, initial_degree_)); + } + + van_den_bos_cache( + rule_type initial_rule, + unsigned initial_degree, + std::size_t max_moment_growth = 2, + Real rank_tolerance = + Real(100) * boost::math::tools::epsilon(), + Real positivity_tolerance = + Real(1000) * boost::math::tools::epsilon()) + : initial_degree_(initial_degree), + max_moment_growth_(max_moment_growth), + rank_tolerance_(rank_tolerance), + positivity_tolerance_(positivity_tolerance) + { + if (initial_rule.size() == 0 || initial_degree_ == 0) + { + throw std::invalid_argument( + "van_den_bos_cache: initial rule and degree must be nonzero."); + } + if (max_moment_growth_ < 2) + { + throw std::invalid_argument( + "van_den_bos_cache: max_moment_growth must be at least 2."); + } + + auto initial = std::make_shared(); + initial->rule = std::make_shared( + std::move(initial_rule)); + initial->degree = initial_degree_; + initial->clenshaw_curtis_order = + detail::next_power_of_two( + static_cast(initial_degree_)); + levels_.push_back(initial); + } + + std::shared_ptr level(std::size_t index) const + { + std::shared_lock lock(mutex_); + if (index >= levels_.size()) + { + return {}; + } + return levels_[index]; + } + + std::shared_ptr ensure_level(std::size_t index) + { + { + std::shared_lock lock(mutex_); + if (index < levels_.size()) + { + return levels_[index]; + } + } + + std::unique_lock lock(mutex_); + while (index >= levels_.size()) + { + auto const& previous = levels_.back(); + const unsigned next_degree = choose_next_degree(*previous); + levels_.push_back(make_level(previous.get(), next_degree)); + } + return levels_[index]; + } + + std::size_t size() const + { + std::shared_lock lock(mutex_); + return levels_.size(); + } + +private: + unsigned choose_next_degree(level_type const& previous) const + { + van_den_bos_legendre_basis previous_basis( + previous.degree); + const std::size_t budget = + max_moment_growth_ * previous_basis.size(); + + unsigned degree = previous.degree + 1; + while (true) + { + van_den_bos_legendre_basis candidate(degree + 1); + if (candidate.size() > budget) + { + break; + } + ++degree; + } + return degree; + } + + std::shared_ptr make_level( + level_type const* previous, + unsigned degree) const + { + van_den_bos_legendre_basis basis(degree); + const std::size_t order = detail::next_power_of_two( + static_cast(degree)); + auto moments = basis.moments(); + + auto candidate = + detail::clenshaw_curtis_tensor_rule(order); + auto points = std::move(candidate.first); + auto weights = std::move(candidate.second); + + const std::size_t protected_count = + previous ? previous->rule->size() : 0; + if (previous) + { + detail::place_protected_prefix( + *previous->rule, points, weights); + } + + const std::size_t target_size = protected_count + basis.size(); + rule_type reduced = van_den_bos_reduce( + std::move(points), + std::move(weights), + basis, + moments, + target_size, + protected_count, + rank_tolerance_, + positivity_tolerance_); + + if (previous) + { + for (std::size_t i = 0; i < protected_count; ++i) + { + if (reduced.point(i) != previous->rule->point(i)) + { + throw std::runtime_error( + "van_den_bos_cache: nested prefix invariant failed."); + } + } + } + + auto result = std::make_shared(); + result->rule = + std::make_shared(std::move(reduced)); + result->degree = degree; + result->clenshaw_curtis_order = order; + return result; + } + + unsigned initial_degree_; + std::size_t max_moment_growth_; + Real rank_tolerance_; + Real positivity_tolerance_; + + mutable std::shared_mutex mutex_; + std::vector> levels_; +}; + +/* + * Adaptive integration over the unit cube [0,1]^Dimension. + * + * One call is deliberately serial. The shared cache only synchronizes rule + * refinement; function values are private to this invocation. If another + * thread has already published the next level, this call immediately reuses + * that immutable rule. + * + * Function values are cached by point inside this invocation. A later rule + * may have a different support, but any point already sampled is reused. + * This avoids a global integrand-value cache, which would be incorrect when + * many stiffness-matrix entries use different integrands. + */ +template +auto van_den_bos( + F const& f, + van_den_bos_cache& cache, + Real tolerance, + std::size_t max_refinements = 10, + Real* error_estimate = nullptr, + Real* L1 = nullptr, + std::size_t* evaluations = nullptr) + -> decltype(f(std::declval const&>())) +{ + using std::abs; + using result_type = + decltype(f(std::declval const&>())); + + if (!(tolerance > Real(0))) + { + throw std::domain_error( + "van_den_bos: tolerance must be positive."); + } + + std::vector> sampled_points; + std::vector sampled_values; + result_type previous = result_type(0); + result_type current = result_type(0); + Real current_l1 = Real(0); + Real current_error = (std::numeric_limits::infinity)(); + Real previous_delta = (std::numeric_limits::infinity)(); + std::size_t evaluation_count = 0; + std::shared_ptr::rule_type const> + previous_rule; + + auto same_rule = [](auto const& lhs, auto const& rhs) + { + using std::abs; + + if (lhs.size() != rhs.size()) + { + return false; + } + + const Real tolerance = + Real(256) * (std::numeric_limits::epsilon)(); + + for (std::size_t j = 0; j < lhs.size(); ++j) + { + if (!detail::same_point(lhs.point(j), rhs.point(j))) + { + return false; + } + + const Real scale = + (std::max)(Real(1), + (std::max)(abs(lhs.weight(j)), abs(rhs.weight(j)))); + if (abs(lhs.weight(j) - rhs.weight(j)) > tolerance * scale) + { + return false; + } + } + return true; + }; + + for (std::size_t level_index = 0; + level_index <= max_refinements; + ++level_index) + { + auto level = cache.ensure_level(level_index); + auto const& rule = *level->rule; + + current = result_type(0); + current_l1 = Real(0); + + for (std::size_t j = 0; j < rule.size(); ++j) + { + auto const& point = rule.point(j); + + std::size_t cached = sampled_points.size(); + for (std::size_t k = 0; k < sampled_points.size(); ++k) + { + if (detail::same_point(point, sampled_points[k])) + { + cached = k; + break; + } + } + + if (cached == sampled_points.size()) + { + sampled_points.push_back(point); + sampled_values.push_back(f(point)); + ++evaluation_count; + } + + auto const& value = sampled_values[cached]; + current += rule.weight(j) * value; + current_l1 += rule.weight(j) * abs(value); + } + +#ifdef BOOST_MATH_INSTRUMENT + std::cout + << "VDB_LEVEL" + << ",level=" << level_index + << ",degree=" << level->degree + << ",order=" << level->clenshaw_curtis_order + << ",nodes=" << rule.size() + << ",evaluations=" << evaluation_count + << ",value=" << current; +#endif + + if (previous_rule && !same_rule(*previous_rule, rule)) + { + const Real delta = abs(current - previous); + const Real scale = + (std::max)(Real(1), static_cast(abs(current))); + + // With three genuinely different rules, estimate the remaining + // geometric tail from the observed contraction: + // + // r_k = delta_k / delta_{k-1} + // error_k ~= r_k * delta_k / (1 - r_k) + // + // If contraction is absent, fall back to the adjacent-rule + // difference. + current_error = delta; + if (std::isfinite(previous_delta) && + previous_delta > Real(0)) + { + const Real ratio = delta / previous_delta; + if (ratio >= Real(0) && ratio < Real(1)) + { + current_error = + ratio * delta / (Real(1) - ratio); + } + } + +#ifdef BOOST_MATH_INSTRUMENT + std::cout + << ",delta=" << delta + << ",error_estimate=" << current_error + << '\n'; +#endif + + if (current_error <= tolerance * scale) + { + break; + } + + previous_delta = delta; + previous = current; + previous_rule = level->rule; + } + else if (!previous_rule) + { +#ifdef BOOST_MATH_INSTRUMENT + std::cout + << ",delta=nan" + << ",error_estimate=nan" + << '\n'; +#endif + previous = current; + previous_rule = level->rule; + } + else + { +#ifdef BOOST_MATH_INSTRUMENT + std::cout + << ",delta=0" + << ",error_estimate=" << current_error + << '\n'; +#endif + } + } + + if (error_estimate) + { + *error_estimate = current_error; + } + if (L1) + { + *L1 = current_l1; + } + if (evaluations) + { + *evaluations = evaluation_count; + } + + return current; +} + +}}} // namespaces + +#endif