Coverage Report

Created: 2025-11-24 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fftw3/rdft/dft-r2hc.c
Line
Count
Source
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
/* Compute the complex DFT by combining R2HC RDFTs on the real
23
   and imaginary parts.   This could be useful for people just wanting
24
   to link to the real codelets and not the complex ones.  It could
25
   also even be faster than the complex algorithms for split (as opposed
26
   to interleaved) real/imag complex data. */
27
28
#include "rdft/rdft.h"
29
#include "dft/dft.h"
30
31
typedef struct {
32
     solver super;
33
} S;
34
35
typedef struct {
36
     plan_dft super;
37
     plan *cld;
38
     INT ishift, oshift;
39
     INT os;
40
     INT n;
41
} P;
42
43
static void apply(const plan *ego_, R *ri, R *ii, R *ro, R *io)
44
84
{
45
84
     const P *ego = (const P *) ego_;
46
84
     INT n;
47
48
84
     UNUSED(ii);
49
50
84
     { /* transform vector of real & imag parts: */
51
84
    plan_rdft *cld = (plan_rdft *) ego->cld;
52
84
    cld->apply((plan *) cld, ri + ego->ishift, ro + ego->oshift);
53
84
     }
54
55
84
     n = ego->n;
56
84
     if (n > 1) {
57
0
    INT i, os = ego->os;
58
0
    for (i = 1; i < (n + 1)/2; ++i) {
59
0
         E rop, iop, iom, rom;
60
0
         rop = ro[os * i];
61
0
         iop = io[os * i];
62
0
         rom = ro[os * (n - i)];
63
0
         iom = io[os * (n - i)];
64
0
         ro[os * i] = rop - iom;
65
0
         io[os * i] = iop + rom;
66
0
         ro[os * (n - i)] = rop + iom;
67
0
         io[os * (n - i)] = iop - rom;
68
0
    }
69
0
     }
70
84
}
71
72
static void awake(plan *ego_, enum wakefulness wakefulness)
73
84
{
74
84
     P *ego = (P *) ego_;
75
84
     X(plan_awake)(ego->cld, wakefulness);
76
84
}
77
78
static void destroy(plan *ego_)
79
282
{
80
282
     P *ego = (P *) ego_;
81
282
     X(plan_destroy_internal)(ego->cld);
82
282
}
83
84
static void print(const plan *ego_, printer *p)
85
0
{
86
0
     const P *ego = (const P *) ego_;
87
0
     p->print(p, "(dft-r2hc-%D%(%p%))", ego->n, ego->cld);
88
0
}
89
90
91
static int applicable0(const problem *p_)
92
1.84k
{
93
1.84k
     const problem_dft *p = (const problem_dft *) p_;
94
1.84k
     return ((p->sz->rnk == 1 && p->vecsz->rnk == 0)
95
1.40k
       || (p->sz->rnk == 0 && FINITE_RNK(p->vecsz->rnk))
96
1.84k
    );
97
1.84k
}
98
99
static int splitp(R *r, R *i, INT n, INT s)
100
434
{
101
434
     return ((r > i ? (r - i) : (i - r)) >= n * (s > 0 ? s : 0-s));
102
434
}
103
104
static int applicable(const problem *p_, const planner *plnr)
105
1.84k
{
106
1.84k
     if (!applicable0(p_)) return 0;
107
108
846
     {
109
846
    const problem_dft *p = (const problem_dft *) p_;
110
111
    /* rank-0 problems are always OK */
112
846
    if (p->sz->rnk == 0) return 1;
113
114
    /* this solver is ok for split arrays */
115
434
    if (p->sz->rnk == 1 &&
116
434
        splitp(p->ri, p->ii, p->sz->dims[0].n, p->sz->dims[0].is) &&
117
0
        splitp(p->ro, p->io, p->sz->dims[0].n, p->sz->dims[0].os))
118
0
         return 1;
119
120
434
    return !(NO_DFT_R2HCP(plnr));
121
434
     }
122
434
}
123
124
static plan *mkplan(const solver *ego_, const problem *p_, planner *plnr)
125
1.84k
{
126
1.84k
     P *pln;
127
1.84k
     const problem_dft *p;
128
1.84k
     plan *cld;
129
1.84k
     INT ishift = 0, oshift = 0;
130
131
1.84k
     static const plan_adt padt = {
132
1.84k
    X(dft_solve), awake, print, destroy
133
1.84k
     };
134
135
1.84k
     UNUSED(ego_);
136
1.84k
     if (!applicable(p_, plnr))
137
1.43k
          return (plan *)0;
138
139
412
     p = (const problem_dft *) p_;
140
141
412
     {
142
412
    tensor *ri_vec = X(mktensor_1d)(2, p->ii - p->ri, p->io - p->ro);
143
412
    tensor *cld_vec = X(tensor_append)(ri_vec, p->vecsz);
144
412
    int i;
145
1.60k
    for (i = 0; i < cld_vec->rnk; ++i) { /* make all istrides > 0 */
146
1.18k
         if (cld_vec->dims[i].is < 0) {
147
0
        INT nm1 = cld_vec->dims[i].n - 1;
148
0
        ishift -= nm1 * (cld_vec->dims[i].is *= -1);
149
0
        oshift -= nm1 * (cld_vec->dims[i].os *= -1);
150
0
         }
151
1.18k
    }
152
412
    cld = X(mkplan_d)(plnr, 
153
412
          X(mkproblem_rdft_1)(p->sz, cld_vec, 
154
412
            p->ri + ishift, 
155
412
            p->ro + oshift, R2HC));
156
412
    X(tensor_destroy2)(ri_vec, cld_vec);
157
412
     }
158
412
     if (!cld) return (plan *)0;
159
160
282
     pln = MKPLAN_DFT(P, &padt, apply);
161
162
282
     if (p->sz->rnk == 0) {
163
282
    pln->n = 1;
164
282
    pln->os = 0;
165
282
     }
166
0
     else {
167
0
    pln->n = p->sz->dims[0].n;
168
0
    pln->os = p->sz->dims[0].os;
169
0
     }
170
282
     pln->ishift = ishift;
171
282
     pln->oshift = oshift;
172
173
282
     pln->cld = cld;
174
     
175
282
     pln->super.super.ops = cld->ops;
176
282
     pln->super.super.ops.other += 8 * ((pln->n - 1)/2);
177
282
     pln->super.super.ops.add += 4 * ((pln->n - 1)/2);
178
282
     pln->super.super.ops.other += 1; /* estimator hack for nop plans */
179
180
282
     return &(pln->super.super);
181
412
}
182
183
/* constructor */
184
static solver *mksolver(void)
185
1
{
186
1
     static const solver_adt sadt = { PROBLEM_DFT, mkplan, 0 };
187
1
     S *slv = MKSOLVER(S, &sadt);
188
1
     return &(slv->super);
189
1
}
190
191
void X(dft_r2hc_register)(planner *p)
192
1
{
193
1
     REGISTER_SOLVER(p, mksolver());
194
1
}