File: wavelet_transform_test.cpp

package info (click to toggle)
scipy 1.16.0-1exp7
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 234,820 kB
  • sloc: cpp: 503,145; python: 344,611; ansic: 195,638; javascript: 89,566; fortran: 56,210; cs: 3,081; f90: 1,150; sh: 848; makefile: 785; pascal: 284; csh: 135; lisp: 134; xml: 56; perl: 51
file content (163 lines) | stat: -rw-r--r-- 5,430 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 * 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 <numeric>
#include <utility>
#include <iomanip>
#include <iostream>
#include <cmath>
#include <cfloat>
#include <boost/core/demangle.hpp>
#include <boost/hana/for_each.hpp>
#include <boost/hana/ext/std/integer_sequence.hpp>
#include <boost/math/quadrature/wavelet_transforms.hpp>
#include <boost/math/tools/minima.hpp>
#include <boost/math/quadrature/trapezoidal.hpp>

#if __has_include(<stdfloat>)
#  include <stdfloat>
#endif

#ifdef BOOST_HAS_FLOAT128
#include <boost/multiprecision/float128.hpp>
using boost::multiprecision::float128;
#endif


using boost::math::constants::pi;
using boost::math::constants::root_two;
using boost::math::quadrature::daubechies_wavelet_transform;
using boost::math::quadrature::trapezoidal;

template<typename Real, int p>
void test_wavelet_transform()
{
    using std::abs;
    std::cout << "Testing wavelet transform of " << p << " vanishing moment Daubechies wavelet on type " << boost::core::demangle(typeid(Real).name()) << "\n";
    auto psi = boost::math::daubechies_wavelet<Real, p>();

    auto abs_psi = [&psi](Real x) {
        return abs(psi(x));
    };
    auto [a, b] = psi.support();
    auto psil1 = trapezoidal(abs_psi, a, b, 100*std::numeric_limits<Real>::epsilon());
    Real psi_sup_norm = 0;
    for (double x = a; x < b; x += 0.00001)
    {
        Real y = psi(x);
        if (std::abs(y) > psi_sup_norm)
        {
            psi_sup_norm = std::abs(y);
        }
    }
    // An even function:
    auto f = [](Real x) {
        return std::exp(-abs(x));
    };
    Real fmax = 1;
    Real fl2 = 1;
    Real fl1 = 2;

    auto Wf = daubechies_wavelet_transform(f, psi);
    for (double s = 0; s < 10; s += 0.01)
    {
        Real w1 = Wf(s, 0.0);
        Real w2 = Wf(-s, 0.0);
        // Since f is an even function, we get w1 = w2:
        CHECK_ULP_CLOSE(w1, w2, 12);
    }

    // The wavelet transform with respect to Daubechies wavelets 
    for (double s = -10; s < 10; s += 0.1)
    {
        for (double t = -10; t < 10; t+= 0.1)
        {
            Real w = Wf(s, t);
            // Integral inequality:
            Real r1 = sqrt(abs(s))*fmax*psil1;
            if (!CHECK_LE(abs(w), r1))
            {
                std::cerr << "  Integral inequality |W[f](s,t)| <= ||f||_infty ||psi||_1 is violated.\n";
            }
            if (!CHECK_LE(abs(w), fl2))
            {
                std::cerr << "  Integral inequality | int f psi_s,t| <= ||f||_2 ||psi||_2 violated.\n";
            }
            Real r4 = sqrt(abs(s))*fl1*psi_sup_norm;
            if (!CHECK_LE(abs(w), r4))
            {
                std::cerr << "  Integral inequality |W[f](s,t)| <= sqrt(|s|)||f||_1 ||psi||_infty is violated.\n";
            }
            Real r5 = sqrt(abs(s))*fmax*psil1;
            if (!CHECK_LE(abs(w), r5))
            {
                std::cerr << "  Integral inequality |W[f](s,t)| <= sqrt(|s|)||f||_infty ||psi||_1 is violated.\n";
            }
            if (s != 0)
            {
                Real r2 = fl1*psi_sup_norm/sqrt(abs(s));
                if(!CHECK_LE(abs(w), r2))
                {
                    std::cerr << "  Integral inequality |W[f](s,t)| <= ||f||_1 ||psi||_infty/sqrt(|s|) is violated.\n";
                }
            }

        }
    }

    if (p > 5)
    {
        // Wavelet transform of a constant is zero.
        // The quadrature sum is horribly ill-conditioned (technically infinite),
        // so we'll only test on the more rapidly converging sums.
        auto g = [](Real ) { return Real(7); };
        auto Wg = daubechies_wavelet_transform(g, psi);
        for (double s = -10; s < 10; s += 0.1)
        {
            for (double t = -10; t < 10; t+= 0.1)
            {
                Real w = Wg(s, t);
                if (!CHECK_LE(abs(w), Real(10*sqrt(std::numeric_limits<Real>::epsilon()))))
                {
                    std::cerr << "  Wavelet transform of constant with respect to " << p << " vanishing moment Daubechies wavelet is insufficiently small\n";
                }

            }
        }
        // Wavelet transform of psi evaluated at s = 1, t = 0 is L2 norm of psi:
        auto Wpsi = daubechies_wavelet_transform(psi, psi);
        CHECK_MOLLIFIED_CLOSE(Real(1), Wpsi(1,0), Real(2*sqrt(std::numeric_limits<Real>::epsilon())));
    }

}

int main()
{
    try{
       #ifdef __STDCPP_FLOAT64_T__
       test_wavelet_transform<std::float64_t, 2>();
       test_wavelet_transform<std::float64_t, 8>();
       test_wavelet_transform<std::float64_t, 16>();
       #else
       test_wavelet_transform<double, 2>();
       test_wavelet_transform<double, 8>();
       test_wavelet_transform<double, 16>();
       #endif
       // All these tests pass, but the compilation takes too long on CI:
       //boost::hana::for_each(std::make_index_sequence<17>(), [&](auto i) {
       //    test_wavelet_transform<double, i+3>();
       //});
    }
    catch (std::bad_alloc const & e)
    {
        std::cerr << "Ran out of memory in wavelet transform test: " << e.what() << "\n";
       // not much we can do about this, this test uses lots of memory!
    }

    return boost::math::test::report_errors();
}