Coverage Report

Created: 2026-10-28 06:50

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