Mercurial > hg > sv-dependency-builds
comparison src/fftw-3.3.3/rdft/problem2.c @ 10:37bf6b4a2645
Add FFTW3
author | Chris Cannam |
---|---|
date | Wed, 20 Mar 2013 15:35:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
9:c0fb53affa76 | 10:37bf6b4a2645 |
---|---|
1 /* | |
2 * Copyright (c) 2003, 2007-11 Matteo Frigo | |
3 * Copyright (c) 2003, 2007-11 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 #include "dft.h" | |
23 #include "rdft.h" | |
24 #include <stddef.h> | |
25 | |
26 static void destroy(problem *ego_) | |
27 { | |
28 problem_rdft2 *ego = (problem_rdft2 *) ego_; | |
29 X(tensor_destroy2)(ego->vecsz, ego->sz); | |
30 X(ifree)(ego_); | |
31 } | |
32 | |
33 static void hash(const problem *p_, md5 *m) | |
34 { | |
35 const problem_rdft2 *p = (const problem_rdft2 *) p_; | |
36 X(md5puts)(m, "rdft2"); | |
37 X(md5int)(m, p->r0 == p->cr); | |
38 X(md5INT)(m, p->r1 - p->r0); | |
39 X(md5INT)(m, p->ci - p->cr); | |
40 X(md5int)(m, X(alignment_of)(p->r0)); | |
41 X(md5int)(m, X(alignment_of)(p->r1)); | |
42 X(md5int)(m, X(alignment_of)(p->cr)); | |
43 X(md5int)(m, X(alignment_of)(p->ci)); | |
44 X(md5int)(m, p->kind); | |
45 X(tensor_md5)(m, p->sz); | |
46 X(tensor_md5)(m, p->vecsz); | |
47 } | |
48 | |
49 static void print(const problem *ego_, printer *p) | |
50 { | |
51 const problem_rdft2 *ego = (const problem_rdft2 *) ego_; | |
52 p->print(p, "(rdft2 %d %d %T %T)", | |
53 (int)(ego->cr == ego->r0), | |
54 (int)(ego->kind), | |
55 ego->sz, | |
56 ego->vecsz); | |
57 } | |
58 | |
59 static void recur(const iodim *dims, int rnk, R *I0, R *I1) | |
60 { | |
61 if (rnk == RNK_MINFTY) | |
62 return; | |
63 else if (rnk == 0) | |
64 I0[0] = K(0.0); | |
65 else if (rnk > 0) { | |
66 INT i, n = dims[0].n, is = dims[0].is; | |
67 | |
68 if (rnk == 1) { | |
69 for (i = 0; i < n - 1; i += 2) { | |
70 *I0 = *I1 = K(0.0); | |
71 I0 += is; I1 += is; | |
72 } | |
73 if (i < n) | |
74 *I0 = K(0.0); | |
75 } else { | |
76 for (i = 0; i < n; ++i) | |
77 recur(dims + 1, rnk - 1, I0 + i * is, I1 + i * is); | |
78 } | |
79 } | |
80 } | |
81 | |
82 static void vrecur(const iodim *vdims, int vrnk, | |
83 const iodim *dims, int rnk, R *I0, R *I1) | |
84 { | |
85 if (vrnk == RNK_MINFTY) | |
86 return; | |
87 else if (vrnk == 0) | |
88 recur(dims, rnk, I0, I1); | |
89 else if (vrnk > 0) { | |
90 INT i, n = vdims[0].n, is = vdims[0].is; | |
91 | |
92 for (i = 0; i < n; ++i) | |
93 vrecur(vdims + 1, vrnk - 1, | |
94 dims, rnk, I0 + i * is, I1 + i * is); | |
95 } | |
96 } | |
97 | |
98 INT X(rdft2_complex_n)(INT real_n, rdft_kind kind) | |
99 { | |
100 switch (kind) { | |
101 case R2HC: | |
102 case HC2R: | |
103 return (real_n / 2) + 1; | |
104 case R2HCII: | |
105 case HC2RIII: | |
106 return (real_n + 1) / 2; | |
107 default: | |
108 /* can't happen */ | |
109 A(0); | |
110 return 0; | |
111 } | |
112 } | |
113 | |
114 static void zero(const problem *ego_) | |
115 { | |
116 const problem_rdft2 *ego = (const problem_rdft2 *) ego_; | |
117 if (R2HC_KINDP(ego->kind)) { | |
118 /* FIXME: can we avoid the double recursion somehow? */ | |
119 vrecur(ego->vecsz->dims, ego->vecsz->rnk, | |
120 ego->sz->dims, ego->sz->rnk, | |
121 UNTAINT(ego->r0), UNTAINT(ego->r1)); | |
122 } else { | |
123 tensor *sz; | |
124 tensor *sz2 = X(tensor_copy)(ego->sz); | |
125 int rnk = sz2->rnk; | |
126 if (rnk > 0) /* ~half as many complex outputs */ | |
127 sz2->dims[rnk-1].n = | |
128 X(rdft2_complex_n)(sz2->dims[rnk-1].n, ego->kind); | |
129 sz = X(tensor_append)(ego->vecsz, sz2); | |
130 X(tensor_destroy)(sz2); | |
131 X(dft_zerotens)(sz, UNTAINT(ego->cr), UNTAINT(ego->ci)); | |
132 X(tensor_destroy)(sz); | |
133 } | |
134 } | |
135 | |
136 static const problem_adt padt = | |
137 { | |
138 PROBLEM_RDFT2, | |
139 hash, | |
140 zero, | |
141 print, | |
142 destroy | |
143 }; | |
144 | |
145 problem *X(mkproblem_rdft2)(const tensor *sz, const tensor *vecsz, | |
146 R *r0, R *r1, R *cr, R *ci, | |
147 rdft_kind kind) | |
148 { | |
149 problem_rdft2 *ego; | |
150 | |
151 A(kind == R2HC || kind == R2HCII || kind == HC2R || kind == HC2RIII); | |
152 A(X(tensor_kosherp)(sz)); | |
153 A(X(tensor_kosherp)(vecsz)); | |
154 A(FINITE_RNK(sz->rnk)); | |
155 | |
156 /* require in-place problems to use r0 == cr */ | |
157 if (UNTAINT(r0) == UNTAINT(ci)) | |
158 return X(mkproblem_unsolvable)(); | |
159 | |
160 /* FIXME: should check UNTAINT(r1) == UNTAINT(cr) but | |
161 only if odd elements exist, which requires compressing the | |
162 tensors first */ | |
163 | |
164 if (UNTAINT(r0) == UNTAINT(cr)) | |
165 r0 = cr = JOIN_TAINT(r0, cr); | |
166 | |
167 ego = (problem_rdft2 *)X(mkproblem)(sizeof(problem_rdft2), &padt); | |
168 | |
169 if (sz->rnk > 1) { /* have to compress rnk-1 dims separately, ugh */ | |
170 tensor *szc = X(tensor_copy_except)(sz, sz->rnk - 1); | |
171 tensor *szr = X(tensor_copy_sub)(sz, sz->rnk - 1, 1); | |
172 tensor *szcc = X(tensor_compress)(szc); | |
173 if (szcc->rnk > 0) | |
174 ego->sz = X(tensor_append)(szcc, szr); | |
175 else | |
176 ego->sz = X(tensor_compress)(szr); | |
177 X(tensor_destroy2)(szc, szr); X(tensor_destroy)(szcc); | |
178 } else { | |
179 ego->sz = X(tensor_compress)(sz); | |
180 } | |
181 ego->vecsz = X(tensor_compress_contiguous)(vecsz); | |
182 ego->r0 = r0; | |
183 ego->r1 = r1; | |
184 ego->cr = cr; | |
185 ego->ci = ci; | |
186 ego->kind = kind; | |
187 | |
188 A(FINITE_RNK(ego->sz->rnk)); | |
189 return &(ego->super); | |
190 | |
191 } | |
192 | |
193 /* Same as X(mkproblem_rdft2), but also destroy input tensors. */ | |
194 problem *X(mkproblem_rdft2_d)(tensor *sz, tensor *vecsz, | |
195 R *r0, R *r1, R *cr, R *ci, rdft_kind kind) | |
196 { | |
197 problem *p = X(mkproblem_rdft2)(sz, vecsz, r0, r1, cr, ci, kind); | |
198 X(tensor_destroy2)(vecsz, sz); | |
199 return p; | |
200 } | |
201 | |
202 /* Same as X(mkproblem_rdft2_d), but with only one R pointer. | |
203 Used by the API. */ | |
204 problem *X(mkproblem_rdft2_d_3pointers)(tensor *sz, tensor *vecsz, | |
205 R *r0, R *cr, R *ci, rdft_kind kind) | |
206 { | |
207 problem *p; | |
208 int rnk = sz->rnk; | |
209 R *r1; | |
210 | |
211 if (rnk == 0) | |
212 r1 = r0; | |
213 else if (R2HC_KINDP(kind)) { | |
214 r1 = r0 + sz->dims[rnk-1].is; | |
215 sz->dims[rnk-1].is *= 2; | |
216 } else { | |
217 r1 = r0 + sz->dims[rnk-1].os; | |
218 sz->dims[rnk-1].os *= 2; | |
219 } | |
220 | |
221 p = X(mkproblem_rdft2)(sz, vecsz, r0, r1, cr, ci, kind); | |
222 X(tensor_destroy2)(vecsz, sz); | |
223 return p; | |
224 } |