Coverage Report

Created: 2024-09-08 06:43

/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
70
{
74
70
     P *ego = (P *) ego_;
75
70
     X(plan_awake)(ego->cld, wakefulness);
76
70
}
77
78
static void destroy(plan *ego_)
79
269
{
80
269
     P *ego = (P *) ego_;
81
269
     X(plan_destroy_internal)(ego->cld);
82
269
}
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.84k
       || (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
441
{
101
441
     return ((r > i ? (r - i) : (i - r)) >= n * (s > 0 ? s : 0-s));
102
441
}
103
104
static int applicable(const problem *p_, const planner *plnr)
105
1.84k
{
106
1.84k
     if (!applicable0(p_)) return 0;
107
108
841
     {
109
841
    const problem_dft *p = (const problem_dft *) p_;
110
111
    /* rank-0 problems are always OK */
112
841
    if (p->sz->rnk == 0) return 1;
113
114
    /* this solver is ok for split arrays */
115
441
    if (p->sz->rnk == 1 &&
116
441
        splitp(p->ri, p->ii, p->sz->dims[0].n, p->sz->dims[0].is) &&
117
441
        splitp(p->ro, p->io, p->sz->dims[0].n, p->sz->dims[0].os))
118
0
         return 1;
119
120
441
    return !(NO_DFT_R2HCP(plnr));
121
441
     }
122
441
}
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.44k
          return (plan *)0;
138
139
400
     p = (const problem_dft *) p_;
140
141
400
     {
142
400
    tensor *ri_vec = X(mktensor_1d)(2, p->ii - p->ri, p->io - p->ro);
143
400
    tensor *cld_vec = X(tensor_append)(ri_vec, p->vecsz);
144
400
    int i;
145
1.56k
    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
400
    cld = X(mkplan_d)(plnr, 
153
400
          X(mkproblem_rdft_1)(p->sz, cld_vec, 
154
400
            p->ri + ishift, 
155
400
            p->ro + oshift, R2HC));
156
400
    X(tensor_destroy2)(ri_vec, cld_vec);
157
400
     }
158
400
     if (!cld) return (plan *)0;
159
160
269
     pln = MKPLAN_DFT(P, &padt, apply);
161
162
269
     if (p->sz->rnk == 0) {
163
269
    pln->n = 1;
164
269
    pln->os = 0;
165
269
     }
166
0
     else {
167
0
    pln->n = p->sz->dims[0].n;
168
0
    pln->os = p->sz->dims[0].os;
169
0
     }
170
269
     pln->ishift = ishift;
171
269
     pln->oshift = oshift;
172
173
269
     pln->cld = cld;
174
     
175
269
     pln->super.super.ops = cld->ops;
176
269
     pln->super.super.ops.other += 8 * ((pln->n - 1)/2);
177
269
     pln->super.super.ops.add += 4 * ((pln->n - 1)/2);
178
269
     pln->super.super.ops.other += 1; /* estimator hack for nop plans */
179
180
269
     return &(pln->super.super);
181
400
}
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
}