Coverage Report

Created: 2025-08-03 06:50

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