Coverage Report

Created: 2025-07-23 07:03

/src/fftw3/rdft/hc2hc.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
#include "rdft/hc2hc.h"
22
23
hc2hc_solver *(*X(mksolver_hc2hc_hook))(size_t, INT, hc2hc_mkinferior) = 0;
24
25
typedef struct {
26
     plan_rdft super;
27
     plan *cld;
28
     plan *cldw;
29
     INT r;
30
} P;
31
32
static void apply_dit(const plan *ego_, R *I, R *O)
33
0
{
34
0
     const P *ego = (const P *) ego_;
35
0
     plan_rdft *cld;
36
0
     plan_hc2hc *cldw;
37
38
0
     cld = (plan_rdft *) ego->cld;
39
0
     cld->apply(ego->cld, I, O);
40
41
0
     cldw = (plan_hc2hc *) ego->cldw;
42
0
     cldw->apply(ego->cldw, O);
43
0
}
44
45
static void apply_dif(const plan *ego_, R *I, R *O)
46
0
{
47
0
     const P *ego = (const P *) ego_;
48
0
     plan_rdft *cld;
49
0
     plan_hc2hc *cldw;
50
51
0
     cldw = (plan_hc2hc *) ego->cldw;
52
0
     cldw->apply(ego->cldw, I);
53
54
0
     cld = (plan_rdft *) ego->cld;
55
0
     cld->apply(ego->cld, I, O);
56
0
}
57
58
static void awake(plan *ego_, enum wakefulness wakefulness)
59
0
{
60
0
     P *ego = (P *) ego_;
61
0
     X(plan_awake)(ego->cld, wakefulness);
62
0
     X(plan_awake)(ego->cldw, wakefulness);
63
0
}
64
65
static void destroy(plan *ego_)
66
0
{
67
0
     P *ego = (P *) ego_;
68
0
     X(plan_destroy_internal)(ego->cldw);
69
0
     X(plan_destroy_internal)(ego->cld);
70
0
}
71
72
static void print(const plan *ego_, printer *p)
73
0
{
74
0
     const P *ego = (const P *) ego_;
75
0
     p->print(p, "(rdft-ct-%s/%D%(%p%)%(%p%))",
76
0
        ego->super.apply == apply_dit ? "dit" : "dif",
77
0
        ego->r, ego->cldw, ego->cld);
78
0
}
79
80
static int applicable0(const hc2hc_solver *ego, const problem *p_, planner *plnr)
81
30.1k
{
82
30.1k
     const problem_rdft *p = (const problem_rdft *) p_;
83
30.1k
     INT r;
84
85
30.1k
     return (1
86
30.1k
       && p->sz->rnk == 1
87
30.1k
       && p->vecsz->rnk <= 1 
88
89
30.1k
       && (/* either the problem is R2HC, which is solved by DIT */
90
0
      (p->kind[0] == R2HC)
91
0
      ||
92
      /* or the problem is HC2R, in which case it is solved
93
         by DIF, which destroys the input */
94
0
      (p->kind[0] == HC2R && 
95
0
       (p->I == p->O || !NO_DESTROY_INPUTP(plnr))))
96
      
97
30.1k
       && ((r = X(choose_radix)(ego->r, p->sz->dims[0].n)) > 0)
98
30.1k
       && p->sz->dims[0].n > r);
99
30.1k
}
100
101
int X(hc2hc_applicable)(const hc2hc_solver *ego, const problem *p_, planner *plnr)
102
30.1k
{
103
30.1k
     const problem_rdft *p;
104
105
30.1k
     if (!applicable0(ego, p_, plnr))
106
30.1k
          return 0;
107
108
0
     p = (const problem_rdft *) p_;
109
110
0
     return (0
111
0
       || p->vecsz->rnk == 0
112
0
       || !NO_VRECURSEP(plnr)
113
0
    );
114
30.1k
}
115
116
static plan *mkplan(const solver *ego_, const problem *p_, planner *plnr)
117
30.1k
{
118
30.1k
     const hc2hc_solver *ego = (const hc2hc_solver *) ego_;
119
30.1k
     const problem_rdft *p;
120
30.1k
     P *pln = 0;
121
30.1k
     plan *cld = 0, *cldw = 0;
122
30.1k
     INT n, r, m, v, ivs, ovs;
123
30.1k
     iodim *d;
124
125
30.1k
     static const plan_adt padt = {
126
30.1k
    X(rdft_solve), awake, print, destroy
127
30.1k
     };
128
129
30.1k
     if (NO_NONTHREADEDP(plnr) || !X(hc2hc_applicable)(ego, p_, plnr))
130
30.1k
          return (plan *) 0;
131
132
0
     p = (const problem_rdft *) p_;
133
0
     d = p->sz->dims;
134
0
     n = d[0].n;
135
0
     r = X(choose_radix)(ego->r, n);
136
0
     m = n / r;
137
138
0
     X(tensor_tornk1)(p->vecsz, &v, &ivs, &ovs);
139
140
0
     switch (p->kind[0]) {
141
0
   case R2HC:
142
0
        cldw = ego->mkcldw(ego, 
143
0
         R2HC, r, m, d[0].os, v, ovs, 0, (m+2)/2, 
144
0
         p->O, plnr);
145
0
        if (!cldw) goto nada;
146
147
0
        cld = X(mkplan_d)(plnr, 
148
0
        X(mkproblem_rdft_d)(
149
0
             X(mktensor_1d)(m, r * d[0].is, d[0].os),
150
0
             X(mktensor_2d)(r, d[0].is, m * d[0].os,
151
0
                v, ivs, ovs),
152
0
             p->I, p->O, p->kind)
153
0
       );
154
0
        if (!cld) goto nada;
155
156
0
        pln = MKPLAN_RDFT(P, &padt, apply_dit);
157
0
        break;
158
159
0
   case HC2R:
160
0
        cldw = ego->mkcldw(ego,
161
0
         HC2R, r, m, d[0].is, v, ivs, 0, (m+2)/2, 
162
0
         p->I, plnr);
163
0
        if (!cldw) goto nada;
164
165
0
        cld = X(mkplan_d)(plnr, 
166
0
        X(mkproblem_rdft_d)(
167
0
             X(mktensor_1d)(m, d[0].is, r * d[0].os),
168
0
             X(mktensor_2d)(r, m * d[0].is, d[0].os,
169
0
                v, ivs, ovs),
170
0
             p->I, p->O, p->kind)
171
0
       );
172
0
        if (!cld) goto nada;
173
        
174
0
        pln = MKPLAN_RDFT(P, &padt, apply_dif);
175
0
        break;
176
177
0
   default: 
178
0
        A(0);
179
0
     }
180
181
0
     pln->cld = cld;
182
0
     pln->cldw = cldw;
183
0
     pln->r = r;
184
0
     X(ops_add)(&cld->ops, &cldw->ops, &pln->super.super.ops);
185
186
     /* inherit could_prune_now_p attribute from cldw */
187
0
     pln->super.super.could_prune_now_p = cldw->could_prune_now_p;
188
189
0
     return &(pln->super.super);
190
191
0
 nada:
192
0
     X(plan_destroy_internal)(cldw);
193
0
     X(plan_destroy_internal)(cld);
194
0
     return (plan *) 0;
195
0
}
196
197
hc2hc_solver *X(mksolver_hc2hc)(size_t size, INT r, hc2hc_mkinferior mkcldw)
198
93
{
199
93
     static const solver_adt sadt = { PROBLEM_RDFT, mkplan, 0 };
200
93
     hc2hc_solver *slv = (hc2hc_solver *)X(mksolver)(size, &sadt);
201
93
     slv->r = r;
202
93
     slv->mkcldw = mkcldw;
203
93
     return slv;
204
93
}
205
206
plan *X(mkplan_hc2hc)(size_t size, const plan_adt *adt, hc2hcapply apply)
207
0
{
208
0
     plan_hc2hc *ego;
209
210
0
     ego = (plan_hc2hc *) X(mkplan)(size, adt);
211
0
     ego->apply = apply;
212
213
0
     return &(ego->super);
214
0
}