/* * Copyright Nick Thompson, 2020 * 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) */ #include "math_unit_test.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BOOST_HAS_FLOAT128 #include using boost::multiprecision::float128; #endif using boost::math::constants::pi; using boost::math::constants::root_two; template void test_exact_value() { // The global phase of the wavelet is not constrained by anything other than convention. // Make sure that our conventions match the rest of the world: auto psi = boost::math::daubechies_wavelet(2); Real computed = psi(1); Real expected = -1.366025403784439; CHECK_MOLLIFIED_CLOSE(expected, computed, 0.0001); } template void test_quadratures() { std::cout << "Testing quadratures of " << p << " vanishing moment Daubechies wavelet on type " << boost::core::demangle(typeid(Real).name()) << "\n"; using boost::math::quadrature::trapezoidal; auto psi = boost::math::daubechies_wavelet(); std::cout << "Wavelet functor size is " << psi.bytes() << " bytes" << std::endl; Real tol = std::numeric_limits::epsilon(); Real error_estimate = std::numeric_limits::quiet_NaN(); Real L1 = std::numeric_limits::quiet_NaN(); auto [a, b] = psi.support(); CHECK_ULP_CLOSE(Real(-p+1), a, 0); CHECK_ULP_CLOSE(Real(p), b, 0); // A wavelet is a function of zero average; ensure the quadrature over its support is zero. Real Q = trapezoidal(psi, a, b, tol, 15, &error_estimate, &L1); if (!CHECK_MOLLIFIED_CLOSE(Real(0), Q, Real(0.0001))) { std::cerr << " Quadrature of " << p << " vanishing moment wavelet does not vanish.\n"; std::cerr << " Error estimate: " << error_estimate << ", L1 norm: " << L1 << "\n"; } auto psi_sq = [psi](Real x) { Real t = psi(x); return t*t; }; Q = trapezoidal(psi_sq, a, b, tol, 15, &error_estimate, &L1); Real quad_tol = 2000*std::sqrt(std::numeric_limits::epsilon())/(p*p*p); if (!CHECK_MOLLIFIED_CLOSE(Real(1), Q, quad_tol)) { std::cerr << " L2 norm of " << p << " vanishing moment wavelet does not vanish.\n"; std::cerr << " Error estimate: " << error_estimate << ", L1 norm: " << L1 << "\n"; } // psi is orthogonal to its integer translates: \int \psi(x-k) \psi(x) \, \mathrm{d}x = 0 // g_n = 1/sqrt(2) (Mallat, 7.55) // Now hit the boundary. Much can go wrong here; this just tests for segfaults: int samples = 500; Real xlo = a; Real xhi = b; for (int i = 0; i < samples; ++i) { CHECK_ULP_CLOSE(Real(0), psi(xlo), 0); CHECK_ULP_CLOSE(Real(0), psi(xhi), 0); if constexpr (p > 2) { CHECK_ULP_CLOSE(Real(0), psi.prime(xlo), 0); CHECK_ULP_CLOSE(Real(0), psi.prime(xhi), 0); if constexpr (p >= 6) { CHECK_ULP_CLOSE(Real(0), psi.double_prime(xlo), 0); CHECK_ULP_CLOSE(Real(0), psi.double_prime(xhi), 0); } } xlo = std::nextafter(xlo, std::numeric_limits::lowest()); xhi = std::nextafter(xhi, std::numeric_limits::max()); } xlo = a; xhi = b; for (int i = 0; i < samples; ++i) { std::cout << std::setprecision(std::numeric_limits::max_digits10); assert(abs(psi(xlo)) <= 5); assert(abs(psi(xhi)) <= 5); if constexpr (p > 2) { assert(abs(psi.prime(xlo)) <= 5); assert(abs(psi.prime(xhi)) <= 5); if constexpr (p >= 6) { assert(abs(psi.double_prime(xlo)) <= 5); assert(abs(psi.double_prime(xhi)) <= 5); } } xlo = std::nextafter(xlo, std::numeric_limits::max()); xhi = std::nextafter(xhi, std::numeric_limits::lowest()); } } int main() { test_exact_value(); boost::hana::for_each(std::make_index_sequence<17>(), [&](auto i){ test_quadratures(); test_quadratures(); }); return boost::math::test::report_errors(); }