ndwt 0.1.0

High-performance discrete and lifting wavelet transforms for 1-D and N-D signals, with SIMD acceleration, adjoint operations, and 8 boundary conditions.
Documentation
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
pub use crate::daubechies::*;
use ndwt_macros::implement_dwt_orthogonal;

implement_dwt_orthogonal! {
    Daubechies1,
    [
        7.071067811865475244008443621048490392848359376884740365883399e-1,
        7.071067811865475244008443621048490392848359376884740365883399e-1
    ]
}

implement_dwt_orthogonal! {
    Daubechies2,
    [
        -1.294095225512603811744494188120241641745344506599652569070016e-1,
        2.241438680420133810259727622404003554678835181842717613871683e-1,
        8.365163037378079055752937809168732034593703883484392934953415e-1,
        4.829629131445341433748715998644486838169524195042022752011715e-1
    ]
}

implement_dwt_orthogonal! {
    Daubechies3,
    [
        3.522629188570953660274066471551002932775838791743161039893406e-2,
        -8.544127388202666169281916918177331153619763898808662976351749e-2,
        -1.350110200102545886963899066993744805622198452237811919756863e-1,
        4.598775021184915700951519421476167208081101774314923066433868e-1,
        8.068915093110925764944936040887134905192973949948236181650921e-1,
        3.326705529500826159985115891390056300129233992450683597084706e-1
    ]
}

implement_dwt_orthogonal! {
    Daubechies4,
    [
        -1.059740178506903210488320852402722918109996490637641983484974e-2,
        3.288301166688519973540751354924438866454194113754971259727278e-2,
        3.084138183556076362721936253495905017031482172003403341821219e-2,
        -1.870348117190930840795706727890814195845441743745800912057771e-1,
        -2.798376941685985421141374718007538541198732022449175284003358e-2,
        6.308807679298589078817163383006152202032229226771951174057473e-1,
        7.148465705529156470899219552739926037076084010993081758450110e-1,
        2.303778133088965008632911830440708500016152482483092977910968e-1
    ]
}

implement_dwt_orthogonal! {
    Daubechies5,
    [
        3.335725285473771277998183415817355747636524742305315099706429e-3,
        -1.258075199908199946850973993177579294920459162609785020169233e-2,
        -6.241490212798274274190519112920192970763557165687607323417435e-3,
        7.757149384004571352313048938860181980623099452012527983210146e-2,
        -3.224486958463837464847975506213492831356498416379847225434268e-2,
        -2.422948870663820318625713794746163619914908080626185983913727e-1,
        1.384281459013207315053971463390246973141057911739561022694652e-1,
        7.243085284377729277280712441022186407687562182320073725767335e-1,
        6.038292697971896705401193065250621075074221631016986987969283e-1,
        1.601023979741929144807237480204207336505441246250578327725699e-1
    ]
}

implement_dwt_orthogonal! {
    Daubechies6,
    [
        -1.077301085308479564852621609587200035235233609334419689818581e-3,
        4.777257510945510639635975246820707050230501216581434297593255e-3,
        5.538422011614961392519183980465012206110262773864964295476525e-4,
        -3.158203931748602956507908069984866905747953237314842337511465e-2,
        2.752286553030572862554083950419321365738758783043454321494203e-2,
        9.750160558732304910234355253812534233983074749525514279893193e-2,
        -1.297668675672619355622896058765854608452337492235814701599311e-1,
        -2.262646939654398200763145006609034656705401539728969940143488e-1,
        3.152503517091976290859896548109263966495199235172945244404164e-1,
        7.511339080210953506789344984397316855802547833382612009730421e-1,
        4.946238903984530856772041768778555886377863828962743623531835e-1,
        1.115407433501094636213239172409234390425395919844216759082360e-1
    ]
}

implement_dwt_orthogonal! {
    Daubechies7,
    [
        3.537137999745202484462958363064254310959060059520040012524276e-4,
        -1.801640704047490915268262912739550962585651469641090625323865e-3,
        4.295779729213665211321291228197322228235350396942409742946367e-4,
        1.255099855609984061298988603418777957289474046048710038411818e-2,
        -1.657454163066688065410767489170265479204504394820713705239273e-2,
        -3.802993693501441357959206160185803585446196938467869898283123e-2,
        8.061260915108307191292248035938190585823820965629489058139218e-2,
        7.130921926683026475087657050112904822711327451412314659575113e-2,
        -2.240361849938749826381404202332509644757830896773246552665095e-1,
        -1.439060039285649754050683622130460017952735705499084834401753e-1,
        4.697822874051931224715911609744517386817913056787359532392529e-1,
        7.291320908462351199169430703392820517179660611901363782697716e-1,
        3.965393194819173065390003909368428563587151149333287401110500e-1,
        7.785205408500917901996352195789374837918305292795568438702937e-2
    ]
}

implement_dwt_orthogonal! {
    Daubechies8,
    [
        -1.174767841247695337306282316988909444086693950311503927620014e-4,
        6.754494064505693663695475738792991218489630013558432103617077e-4,
        -3.917403733769470462980803573237762675229350073890493724492695e-4,
        -4.870352993451574310422181557109824016634978512157003764736209e-3,
        8.746094047405776716382743246475640180402147081140676742686747e-3,
        1.398102791739828164872293057263345144239559532934347169146368e-2,
        -4.408825393079475150676372323896350189751839190110996472750392e-2,
        -1.736930100180754616961614886809598311413086529488394316977315e-2,
        1.287474266204784588570292875097083843022601575556488795577000e-1,
        4.724845739132827703605900098258949861948011288770074644084096e-4,
        -2.840155429615469265162031323741647324684350124871451793599205e-1,
        -1.582910525634930566738054787646630415774471154502826559735336e-2,
        5.853546836542067127712655200450981944303266678053369055707175e-1,
        6.756307362972898068078007670471831499869115906336364227766760e-1,
        3.128715909142999706591623755057177219497319740370229185698712e-1,
        5.441584224310400995500940520299935503599554294733050397729281e-2
    ]
}

implement_dwt_orthogonal! {
    Daubechies9,
    [
        3.934732031627159948068988306589150707782477055517013507359938e-5,
        -2.519631889427101369749886842878606607282181543478028214134265e-4,
        2.303857635231959672052163928245421692940662052463711972260007e-4,
        1.847646883056226476619129491125677051121081359600318160732515e-3,
        -4.281503682463429834496795002314531876481181811463288374860455e-3,
        -4.723204757751397277925707848242465405729514912627938018758527e-3,
        2.236166212367909720537378270269095241855646688308853754721816e-2,
        2.509471148314519575871897499885543315176271993709633321834165e-4,
        -6.763282906132997367564227482971901592578790871353739900748331e-2,
        3.072568147933337921231740072037882714105805024670744781503061e-2,
        1.485407493381063801350727175060423024791258577280603060771649e-1,
        -9.684078322297646051350813353769660224825458104599099679471268e-2,
        -2.932737832791749088064031952421987310438961628589906825725113e-1,
        1.331973858250075761909549458997955536921780768433661136154347e-1,
        6.572880780513005380782126390451732140305858669245918854436034e-1,
        6.048231236901111119030768674342361708959562711896117565333714e-1,
        2.438346746125903537320415816492844155263611085609231361429088e-1,
        3.807794736387834658869765887955118448771714496278417476647192e-2
    ]
}

implement_dwt_orthogonal! {
    Daubechies10,
    [
        -1.326420289452124481243667531226683305749240960605829756400675e-5,
        9.358867032006959133405013034222854399688456215297276443521874e-5,
        -1.164668551292854509514809710258991891527461854347597362819235e-4,
        -6.858566949597116265613709819265714196625043336786920516211904e-4,
        1.992405295185056117158742242640643211762555365514105280067936e-3,
        1.395351747052901165789318447957707567660542855688552426721118e-3,
        -1.073317548333057504431811410651364448111548781143923213370334e-2,
        3.606553566956169655423291417133403299517350518618994762730612e-3,
        3.321267405934100173976365318215912897978337413267096043323351e-2,
        -2.945753682187581285828323760141839199388200516064948779769654e-2,
        -7.139414716639708714533609307605064767292611983702150917523756e-2,
        9.305736460357235116035228983545273226942917998946925868063974e-2,
        1.273693403357932600826772332014009770786177480422245995563098e-1,
        -1.959462743773770435042992543190981318766776476382778474396782e-1,
        -2.498464243273153794161018979207791000564669737132073715013122e-1,
        2.811723436605774607487269984455892876243888859026150413831544e-1,
        6.884590394536035657418717825492358539771364042407339537279681e-1,
        5.272011889317255864817448279595081924981402680840223445318549e-1,
        1.881768000776914890208929736790939942702546758640393484348595e-1,
        2.667005790055555358661744877130858277192498290851289932779976e-2
    ]
}

#[cfg(test)]
mod test {

    use super::*;
    use crate::boundarys::BoundaryCondition;
    use crate::dwt::{DiscreteTransform, get_outlen};
    use crate::tests::{test_approx_adjoint, test_approx_equal};

    use rstest::rstest;

    const RTOL: f64 = 1E-13;
    const ATOL: f64 = 0.0;

    macro_rules! test_wavelet {
        ($test_name:ident, $per_test_name:ident, $adj_test_name:ident, $wvlt:ident) => {
            #[rstest]
            fn $test_name(
                #[values(
                    BoundaryCondition::Zero,
                    BoundaryCondition::Periodic,
                    BoundaryCondition::Constant,
                    BoundaryCondition::Reflect,
                    BoundaryCondition::Symmetric,
                    BoundaryCondition::Antisymmetric,
                    BoundaryCondition::Smooth,
                    BoundaryCondition::Antireflect
                )]
                bc: BoundaryCondition,
                #[values(1, 2, 4, 5, 20, 64, 65)] n: usize,
            ) {
                let x: Vec<f64> = (0..n).map(|i| (i + 1) as f64).collect();
                let mut x2 = vec![0.0; n];

                let nsd = get_outlen($wvlt::WIDTH, n);

                let mut s = vec![0.0; nsd];
                let mut d = vec![0.0; nsd];

                $wvlt::forward(&x, &mut s, &mut d, &bc);
                $wvlt::inverse(&s, &d, &mut x2);

                test_approx_equal(&x2, &x, RTOL, ATOL);
            }

            #[rstest]
            fn $per_test_name(#[values(1, 2, 4, 5, 20, 64, 65)] n: usize) {
                let x: Vec<f64> = (0..n).map(|i| (i + 1) as f64).collect();
                let mut x2 = vec![0.0; n];
                let nd = n / 2;
                let ns = (n + 1) / 2;

                let mut s = vec![0.0; ns];
                let mut d = vec![0.0; nd];

                $wvlt::forward_per(&x, &mut s, &mut d);
                $wvlt::inverse_per(&s, &d, &mut x2);

                test_approx_equal(&x2, &x, RTOL, ATOL);
            }

            #[rstest]
            fn $adj_test_name(#[values(1, 2, 4, 5, 20, 64, 65)] n: usize) {
                let x: Vec<f64> = (0..n).map(|i| (i + 1) as f64).collect();
                let mut x2 = vec![0.0; n];
                let nd = n / 2;
                let ns = (n + 1) / 2;

                let mut s = vec![0.0; ns];
                let mut d = vec![0.0; nd];

                $wvlt::adjoint_inverse_per(&x, &mut s, &mut d);
                $wvlt::adjoint_forward_per(&s, &d, &mut x2);

                test_approx_equal(&x2, &x, RTOL, ATOL);

                let u = (0..n as isize).map(|i| (i + 1) as f64).collect::<Vec<_>>();
                let v = (0..n as isize).map(|i| (5 - i) as f64).collect::<Vec<_>>();

                test_approx_adjoint(
                    |u, out| {
                        let (s, d) = out.split_at_mut(ns);
                        $wvlt::adjoint_inverse_per(u, s, d);
                    },
                    |v, out| {
                        let (s, d) = v.split_at(ns);
                        $wvlt::inverse_per(s, d, out);
                    },
                    &u,
                    &v,
                    RTOL,
                    ATOL,
                );

                test_approx_adjoint(
                    |u, out| {
                        let (s, d) = out.split_at_mut(ns);
                        $wvlt::forward_per(u, s, d);
                    },
                    |v, out| {
                        let (s, d) = v.split_at(ns);
                        $wvlt::adjoint_forward_per(s, d, out);
                    },
                    &u,
                    &v,
                    RTOL,
                    ATOL,
                );
            }
        };
    }
    test_wavelet!(test_db1, test_db1_per, test_db1_adj, Daubechies1);
    test_wavelet!(test_db2, test_db2_per, test_db2_adj, Daubechies2);
    test_wavelet!(test_db3, test_db3_per, test_db3_adj, Daubechies3);
    test_wavelet!(test_db4, test_db4_per, test_db4_adj, Daubechies4);
    test_wavelet!(test_db5, test_db5_per, test_db5_adj, Daubechies5);
    test_wavelet!(test_db6, test_db6_per, test_db6_adj, Daubechies6);
    test_wavelet!(test_db7, test_db7_per, test_db7_adj, Daubechies7);
    test_wavelet!(test_db8, test_db8_per, test_db8_adj, Daubechies8);
    test_wavelet!(test_db9, test_db9_per, test_db9_adj, Daubechies9);
    test_wavelet!(test_db10, test_db10_per, test_db10_adj, Daubechies10);

    #[rstest]
    fn test_adjoint_db3(
        #[values(
            BoundaryCondition::Zero,
            BoundaryCondition::Periodic,
            BoundaryCondition::Constant,
            BoundaryCondition::Reflect,
            BoundaryCondition::Symmetric,
            BoundaryCondition::Antisymmetric,
            BoundaryCondition::Smooth,
            BoundaryCondition::Antireflect
        )]
        bc: BoundaryCondition,
        #[values(64, 65)] n: usize,
    ) {
        type Wvlt = Daubechies3;

        let nsd = get_outlen(Wvlt::WIDTH, n);

        let u = (0..n as isize).map(|i| (i + 1) as f64).collect::<Vec<_>>();
        let v = (0..(2 * nsd) as isize)
            .map(|i| (5 - i) as f64)
            .collect::<Vec<_>>();

        test_approx_adjoint(
            |u, out| {
                let (s, d) = out.split_at_mut(nsd);
                Wvlt::adjoint_inverse(u, s, d);
            },
            |v, out| {
                let (s, d) = v.split_at(nsd);
                Wvlt::inverse(s, d, out);
            },
            &u,
            &v,
            RTOL,
            ATOL,
        );

        test_approx_adjoint(
            |u, out| {
                let (s, d) = out.split_at_mut(nsd);
                Wvlt::forward(u, s, d, &bc);
            },
            |v, out| {
                let (s, d) = v.split_at(nsd);
                Wvlt::adjoint_forward(s, d, out, &bc);
            },
            &u,
            &v,
            RTOL,
            ATOL,
        );
    }

    #[rstest]
    fn test_adjoint_db2(
        #[values(
            BoundaryCondition::Zero,
            BoundaryCondition::Periodic,
            BoundaryCondition::Constant,
            BoundaryCondition::Reflect,
            BoundaryCondition::Symmetric,
            BoundaryCondition::Antisymmetric,
            BoundaryCondition::Smooth,
            BoundaryCondition::Antireflect
        )]
        bc: BoundaryCondition,
        #[values(64, 65)] n: usize,
    ) {
        type Wvlt = Daubechies2;

        let nsd = get_outlen(Wvlt::WIDTH, n);

        let u = (0..n as isize).map(|i| (i + 1) as f64).collect::<Vec<_>>();
        let v = (0..(2 * nsd) as isize)
            .map(|i| (5 - i) as f64)
            .collect::<Vec<_>>();

        test_approx_adjoint(
            |u, out| {
                let (s, d) = out.split_at_mut(nsd);
                Wvlt::adjoint_inverse(u, s, d);
            },
            |v, out| {
                let (s, d) = v.split_at(nsd);
                Wvlt::inverse(s, d, out);
            },
            &u,
            &v,
            RTOL,
            ATOL,
        );

        test_approx_adjoint(
            |u, out| {
                let (s, d) = out.split_at_mut(nsd);
                Wvlt::forward(u, s, d, &bc);
            },
            |v, out| {
                let (s, d) = v.split_at(nsd);
                Wvlt::adjoint_forward(s, d, out, &bc);
            },
            &u,
            &v,
            RTOL,
            ATOL,
        );
    }
}