/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 | } |