Coverage Report

Created: 2026-08-13 06:10

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
76
{
45
76
     const P *ego = (const P *) ego_;
46
76
     INT n;
47
48
76
     UNUSED(ii);
49
50
76
     { /* transform vector of real & imag parts: */
51
76
    plan_rdft *cld = (plan_rdft *) ego->cld;
52
76
    cld->apply((plan *) cld, ri + ego->ishift, ro + ego->oshift);
53
76
     }
54
55
76
     n = ego->n;
56
76
     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
76
}
71
72
static void awake(plan *ego_, enum wakefulness wakefulness)
73
76
{
74
76
     P *ego = (P *) ego_;
75
76
     X(plan_awake)(ego->cld, wakefulness);
76
76
}
77
78
static void destroy(plan *ego_)
79
272
{
80
272
     P *ego = (P *) ego_;
81
272
     X(plan_destroy_internal)(ego->cld);
82
272
}
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.85k
{
93
1.85k
     const problem_dft *p = (const problem_dft *) p_;
94
1.85k
     return ((p->sz->rnk == 1 && p->vecsz->rnk == 0)
95
1.40k
       || (p->sz->rnk == 0 && FINITE_RNK(p->vecsz->rnk))
96
1.85k
    );
97
1.85k
}
98
99
static int splitp(R *r, R *i, INT n, INT s)
100
443
{
101
443
     return ((r > i ? (r - i) : (i - r)) >= n * (s > 0 ? s : 0-s));
102
443
}
103
104
static int applicable(const problem *p_, const planner *plnr)
105
1.85k
{
106
1.85k
     if (!applicable0(p_)) return 0;
107
108
848
     {
109
848
    const problem_dft *p = (const problem_dft *) p_;
110
111
    /* rank-0 problems are always OK */
112
848
    if (p->sz->rnk == 0) return 1;
113
114
    /* this solver is ok for split arrays */
115
443
    if (p->sz->rnk == 1 &&
116
443
        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
443
    return !(NO_DFT_R2HCP(plnr));
121
443
     }
122
443
}
123
124
static plan *mkplan(const solver *ego_, const problem *p_, planner *plnr)
125
1.85k
{
126
1.85k
     P *pln;
127
1.85k
     const problem_dft *p;
128
1.85k
     plan *cld;
129
1.85k
     INT ishift = 0, oshift = 0;
130
131
1.85k
     static const plan_adt padt = {
132
1.85k
    X(dft_solve), awake, print, destroy
133
1.85k
     };
134
135
1.85k
     UNUSED(ego_);
136
1.85k
     if (!applicable(p_, plnr))
137
1.44k
          return (plan *)0;
138
139
405
     p = (const problem_dft *) p_;
140
141
405
     {
142
405
    tensor *ri_vec = X(mktensor_1d)(2, p->ii - p->ri, p->io - p->ro);
143
405
    tensor *cld_vec = X(tensor_append)(ri_vec, p->vecsz);
144
405
    int i;
145
1.57k
    for (i = 0; i < cld_vec->rnk; ++i) { /* make all istrides > 0 */
146
1.16k
         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.16k
    }
152
405
    cld = X(mkplan_d)(plnr, 
153
405
          X(mkproblem_rdft_1)(p->sz, cld_vec, 
154
405
            p->ri + ishift, 
155
405
            p->ro + oshift, R2HC));
156
405
    X(tensor_destroy2)(ri_vec, cld_vec);
157
405
     }
158
405
     if (!cld) return (plan *)0;
159
160
272
     pln = MKPLAN_DFT(P, &padt, apply);
161
162
272
     if (p->sz->rnk == 0) {
163
272
    pln->n = 1;
164
272
    pln->os = 0;
165
272
     }
166
0
     else {
167
0
    pln->n = p->sz->dims[0].n;
168
0
    pln->os = p->sz->dims[0].os;
169
0
     }
170
272
     pln->ishift = ishift;
171
272
     pln->oshift = oshift;
172
173
272
     pln->cld = cld;
174
     
175
272
     pln->super.super.ops = cld->ops;
176
272
     pln->super.super.ops.other += 8 * ((pln->n - 1)/2);
177
272
     pln->super.super.ops.add += 4 * ((pln->n - 1)/2);
178
272
     pln->super.super.ops.other += 1; /* estimator hack for nop plans */
179
180
272
     return &(pln->super.super);
181
405
}
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
}