Coverage Report

Created: 2025-06-22 06:45

/src/fftw3/rdft/rdft-dht.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2003, 2007-14 Matteo Frigo
3
 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
 *
19
 */
20
21
22
/* Solve an R2HC/HC2R problem via post/pre processing of a DHT.  This
23
   is mainly useful because we can use Rader to compute DHTs of prime
24
   sizes.  It also allows us to express hc2r problems in terms of r2hc
25
   (via dht-r2hc), and to do hc2r problems without destroying the input. */
26
27
#include "rdft/rdft.h"
28
29
typedef struct {
30
     solver super;
31
} S;
32
33
typedef struct {
34
     plan_rdft super;
35
     plan *cld;
36
     INT is, os;
37
     INT n;
38
} P;
39
40
static void apply_r2hc(const plan *ego_, R *I, R *O)
41
0
{
42
0
     const P *ego = (const P *) ego_;
43
0
     INT os;
44
0
     INT i, n;
45
46
0
     {
47
0
    plan_rdft *cld = (plan_rdft *) ego->cld;
48
0
    cld->apply((plan *) cld, I, O);
49
0
     }
50
51
0
     n = ego->n;
52
0
     os = ego->os;
53
0
     for (i = 1; i < n - i; ++i) {
54
0
    E a, b;
55
0
    a = K(0.5) * O[os * i];
56
0
    b = K(0.5) * O[os * (n - i)];
57
0
    O[os * i] = a + b;
58
0
#if FFT_SIGN == -1
59
0
    O[os * (n - i)] = b - a;
60
#else
61
    O[os * (n - i)] = a - b;
62
#endif
63
0
     }
64
0
}
65
66
/* hc2r, destroying input as usual */
67
static void apply_hc2r(const plan *ego_, R *I, R *O)
68
0
{
69
0
     const P *ego = (const P *) ego_;
70
0
     INT is = ego->is;
71
0
     INT i, n = ego->n;
72
73
0
     for (i = 1; i < n - i; ++i) {
74
0
    E a, b;
75
0
    a = I[is * i];
76
0
    b = I[is * (n - i)];
77
0
#if FFT_SIGN == -1
78
0
    I[is * i] = a - b;
79
0
    I[is * (n - i)] = a + b;
80
#else
81
    I[is * i] = a + b;
82
    I[is * (n - i)] = a - b;
83
#endif
84
0
     }
85
86
0
     {
87
0
    plan_rdft *cld = (plan_rdft *) ego->cld;
88
0
    cld->apply((plan *) cld, I, O);
89
0
     }
90
0
}
91
92
/* hc2r, without destroying input */
93
static void apply_hc2r_save(const plan *ego_, R *I, R *O)
94
0
{
95
0
     const P *ego = (const P *) ego_;
96
0
     INT is = ego->is, os = ego->os;
97
0
     INT i, n = ego->n;
98
99
0
     O[0] = I[0];
100
0
     for (i = 1; i < n - i; ++i) {
101
0
    E a, b;
102
0
    a = I[is * i];
103
0
    b = I[is * (n - i)];
104
0
#if FFT_SIGN == -1
105
0
    O[os * i] = a - b;
106
0
    O[os * (n - i)] = a + b;
107
#else
108
    O[os * i] = a + b;
109
    O[os * (n - i)] = a - b;
110
#endif
111
0
     }
112
0
     if (i == n - i)
113
0
    O[os * i] = I[is * i];
114
115
0
     {
116
0
    plan_rdft *cld = (plan_rdft *) ego->cld;
117
0
    cld->apply((plan *) cld, O, O);
118
0
     }
119
0
}
120
121
static void awake(plan *ego_, enum wakefulness wakefulness)
122
0
{
123
0
     P *ego = (P *) ego_;
124
0
     X(plan_awake)(ego->cld, wakefulness);
125
0
}
126
127
static void destroy(plan *ego_)
128
0
{
129
0
     P *ego = (P *) ego_;
130
0
     X(plan_destroy_internal)(ego->cld);
131
0
}
132
133
static void print(const plan *ego_, printer *p)
134
0
{
135
0
     const P *ego = (const P *) ego_;
136
0
     p->print(p, "(%s-dht-%D%(%p%))", 
137
0
        ego->super.apply == apply_r2hc ? "r2hc" : "hc2r",
138
0
        ego->n, ego->cld);
139
0
}
140
141
static int applicable0(const solver *ego_, const problem *p_)
142
0
{
143
0
     const problem_rdft *p = (const problem_rdft *) p_;
144
0
     UNUSED(ego_);
145
146
0
     return (1
147
0
       && p->sz->rnk == 1
148
0
       && p->vecsz->rnk == 0
149
0
       && (p->kind[0] == R2HC || p->kind[0] == HC2R)
150
151
       /* hack: size-2 DHT etc. are defined as being equivalent
152
    to size-2 R2HC in problem.c, so we need this to prevent
153
    infinite loops for size 2 in EXHAUSTIVE mode: */
154
0
       && p->sz->dims[0].n > 2
155
0
    );
156
0
}
157
158
static int applicable(const solver *ego, const problem *p_, 
159
          const planner *plnr)
160
327
{
161
327
     return (!NO_SLOWP(plnr) && applicable0(ego, p_));
162
327
}
163
164
static plan *mkplan(const solver *ego_, const problem *p_, planner *plnr)
165
327
{
166
327
     P *pln;
167
327
     const problem_rdft *p;
168
327
     problem *cldp;
169
327
     plan *cld;
170
171
327
     static const plan_adt padt = {
172
327
    X(rdft_solve), awake, print, destroy
173
327
     };
174
175
327
     if (!applicable(ego_, p_, plnr))
176
327
          return (plan *)0;
177
178
0
     p = (const problem_rdft *) p_;
179
180
0
     if (p->kind[0] == R2HC || !NO_DESTROY_INPUTP(plnr))
181
0
    cldp = X(mkproblem_rdft_1)(p->sz, p->vecsz, p->I, p->O, DHT);
182
0
     else {
183
0
    tensor *sz = X(tensor_copy_inplace)(p->sz, INPLACE_OS);
184
0
    cldp = X(mkproblem_rdft_1)(sz, p->vecsz, p->O, p->O, DHT);
185
0
    X(tensor_destroy)(sz);
186
0
     }
187
0
     cld = X(mkplan_d)(plnr, cldp);
188
0
     if (!cld) return (plan *)0;
189
190
0
     pln = MKPLAN_RDFT(P, &padt, p->kind[0] == R2HC ? 
191
0
           apply_r2hc : (NO_DESTROY_INPUTP(plnr) ?
192
0
             apply_hc2r_save : apply_hc2r));
193
0
     pln->n = p->sz->dims[0].n;
194
0
     pln->is = p->sz->dims[0].is;
195
0
     pln->os = p->sz->dims[0].os;
196
0
     pln->cld = cld;
197
     
198
0
     pln->super.super.ops = cld->ops;
199
0
     pln->super.super.ops.other += 4 * ((pln->n - 1)/2);
200
0
     pln->super.super.ops.add += 2 * ((pln->n - 1)/2);
201
0
     if (p->kind[0] == R2HC)
202
0
    pln->super.super.ops.mul += 2 * ((pln->n - 1)/2);
203
0
     if (pln->super.apply == apply_hc2r_save)
204
0
    pln->super.super.ops.other += 2 + (pln->n % 2 ? 0 : 2);
205
206
0
     return &(pln->super.super);
207
0
}
208
209
/* constructor */
210
static solver *mksolver(void)
211
1
{
212
1
     static const solver_adt sadt = { PROBLEM_RDFT, mkplan, 0 };
213
1
     S *slv = MKSOLVER(S, &sadt);
214
1
     return &(slv->super);
215
1
}
216
217
void X(rdft_dht_register)(planner *p)
218
1
{
219
1
     REGISTER_SOLVER(p, mksolver());
220
1
}