2
* Copyright (c) 2003, 2006 Matteo Frigo
3
* Copyright (c) 2003, 2006 Massachusetts Institute of Technology
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
/* $Id: dft-r2hc.c,v 1.37 2006-01-27 02:10:50 athena Exp $ */
23
/* Compute the complex DFT by combining R2HC RDFTs on the real
24
and imaginary parts. This could be useful for people just wanting
25
to link to the real codelets and not the complex ones. It could
26
also even be faster than the complex algorithms for split (as opposed
27
to interleaved) real/imag complex data. */
44
static void apply(const plan *ego_, R *ri, R *ii, R *ro, R *io)
46
const P *ego = (const P *) ego_;
51
{ /* transform vector of real & imag parts: */
52
plan_rdft *cld = (plan_rdft *) ego->cld;
53
cld->apply((plan *) cld, ri + ego->ishift, ro + ego->oshift);
59
for (i = 1; i < (n + 1)/2; ++i) {
63
rom = ro[os * (n - i)];
64
iom = io[os * (n - i)];
65
ro[os * i] = rop - iom;
66
io[os * i] = iop + rom;
67
ro[os * (n - i)] = rop + iom;
68
io[os * (n - i)] = iop - rom;
73
static void awake(plan *ego_, enum wakefulness wakefulness)
76
X(plan_awake)(ego->cld, wakefulness);
79
static void destroy(plan *ego_)
82
X(plan_destroy_internal)(ego->cld);
85
static void print(const plan *ego_, printer *p)
87
const P *ego = (const P *) ego_;
88
p->print(p, "(dft-r2hc-%D%(%p%))", ego->n, ego->cld);
92
static int applicable0(const problem *p_)
94
const problem_dft *p = (const problem_dft *) p_;
95
return ((p->sz->rnk == 1 && p->vecsz->rnk == 0)
96
|| (p->sz->rnk == 0 && FINITE_RNK(p->vecsz->rnk))
100
static int splitp(R *r, R *i, INT n, INT s)
102
return ((r > i ? (r - i) : (i - r)) >= n * (s > 0 ? s : 0-s));
105
static int applicable(const problem *p_, const planner *plnr)
107
if (!applicable0(p_)) return 0;
110
const problem_dft *p = (const problem_dft *) p_;
112
/* rank-0 problems are always OK */
113
if (p->sz->rnk == 0) return 1;
115
/* this solver is ok for split arrays */
116
if (p->sz->rnk == 1 &&
117
splitp(p->ri, p->ii, p->sz->dims[0].n, p->sz->dims[0].is) &&
118
splitp(p->ro, p->io, p->sz->dims[0].n, p->sz->dims[0].os))
121
return !(NO_DFT_R2HCP(plnr));
125
static plan *mkplan(const solver *ego_, const problem *p_, planner *plnr)
128
const problem_dft *p;
130
INT ishift = 0, oshift = 0;
132
static const plan_adt padt = {
133
X(dft_solve), awake, print, destroy
137
if (!applicable(p_, plnr))
140
p = (const problem_dft *) p_;
143
tensor *ri_vec = X(mktensor_1d)(2, p->ii - p->ri, p->io - p->ro);
144
tensor *cld_vec = X(tensor_append)(ri_vec, p->vecsz);
146
for (i = 0; i < cld_vec->rnk; ++i) { /* make all istrides > 0 */
147
if (cld_vec->dims[i].is < 0) {
148
INT nm1 = cld_vec->dims[i].n - 1;
149
ishift -= nm1 * (cld_vec->dims[i].is *= -1);
150
oshift -= nm1 * (cld_vec->dims[i].os *= -1);
153
cld = X(mkplan_d)(plnr,
154
X(mkproblem_rdft_1)(p->sz, cld_vec,
156
p->ro + oshift, R2HC));
157
X(tensor_destroy2)(ri_vec, cld_vec);
159
if (!cld) return (plan *)0;
161
pln = MKPLAN_DFT(P, &padt, apply);
163
if (p->sz->rnk == 0) {
168
pln->n = p->sz->dims[0].n;
169
pln->os = p->sz->dims[0].os;
171
pln->ishift = ishift;
172
pln->oshift = oshift;
176
pln->super.super.ops = cld->ops;
177
pln->super.super.ops.other += 8 * ((pln->n - 1)/2);
178
pln->super.super.ops.add += 4 * ((pln->n - 1)/2);
179
pln->super.super.ops.other += 1; /* estimator hack for nop plans */
181
return &(pln->super.super);
185
static solver *mksolver(void)
187
static const solver_adt sadt = { PROBLEM_DFT, mkplan };
188
S *slv = MKSOLVER(S, &sadt);
189
return &(slv->super);
192
void X(dft_r2hc_register)(planner *p)
194
REGISTER_SOLVER(p, mksolver());