| Bsoft 1.9 Bernard's software package

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

rader.c
Go to the documentation of this file.
1 /*
2 * Copyright (c) 1997-1999, 2003 Massachusetts Institute of Technology
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 */
19
20 /*
21 * Compute transforms of prime sizes using Rader's trick: turn them
22 * into convolutions of size n - 1, which you then perform via a pair
23 * of FFTs.
24 */
25
26 #include <stdlib.h>
27 #include <math.h>
28
29 #include "fftw-int.h"
30
31 #ifdef FFTW_DEBUG
32 #define WHEN_DEBUG(a) a
33 #else
34 #define WHEN_DEBUG(a)
35 #endif
36
37 /* compute n^m mod p, where m >= 0 and p > 0. */
38 static int power_mod(int n, int m, int p)
39 {
40 if (m == 0)
41 return 1;
42 else if (m % 2 == 0) {
43 int x = power_mod(n, m / 2, p);
44 return MULMOD(x, x, p);
45 }
46 else
47 return MULMOD(n, power_mod(n, m - 1, p), p);
48 }
49
50 /*
51 * Find the period of n in the multiplicative group mod p (p prime).
52 * That is, return the smallest m such that n^m == 1 mod p.
53 */
54 static int period(int n, int p)
55 {
56 int prod = n, period = 1;
57
58 while (prod != 1) {
59 prod = MULMOD(prod, n, p);
60 ++period;
61 if (prod == 0)
62 fftw_die("non-prime order in Rader\n");
63 }
64 return period;
65 }
66
67 /* find a generator for the multiplicative group mod p, where p is prime */
68 static int find_generator(int p)
69 {
70 int g;
71
72 for (g = 1; g < p; ++g)
73 if (period(g, p) == p - 1)
74 break;
75 if (g == p)
76 fftw_die("couldn't find generator for Rader\n");
77 return g;
78 }
79
80 /***************************************************************************/
81
82 static fftw_rader_data *create_rader_aux(int p, int flags)
83 {
84 fftw_complex *omega, *work;
85 int g, ginv, gpower;
86 int i;
87 FFTW_TRIG_REAL twoPiOverN;
88 fftw_real scale = 1.0 / (p - 1); /* for convolution */
89 fftw_plan plan;
90 fftw_rader_data *d;
91
92 if (p < 2)
93 fftw_die("non-prime order in Rader\n");
94
95 flags &= ~FFTW_IN_PLACE;
96
97 d = (fftw_rader_data *) fftw_malloc(sizeof(fftw_rader_data));
98
99 g = find_generator(p);
100 ginv = power_mod(g, p - 2, p);
101
102 omega = (fftw_complex *) fftw_malloc((p - 1) * sizeof(fftw_complex));
103
104 plan = fftw_create_plan(p - 1, FFTW_FORWARD,
105 flags & ~FFTW_NO_VECTOR_RECURSE);
106
107 work = (fftw_complex *) fftw_malloc((p - 1) * sizeof(fftw_complex));
108
109 twoPiOverN = FFTW_K2PI / (FFTW_TRIG_REAL) p;
110 gpower = 1;
111 for (i = 0; i < p - 1; ++i) {
112 c_re(work[i]) = scale * FFTW_TRIG_COS(twoPiOverN * gpower);
113 c_im(work[i]) = FFTW_FORWARD * scale * FFTW_TRIG_SIN(twoPiOverN
114 * gpower);
115 gpower = MULMOD(gpower, ginv, p);
116 }
117
118 /* fft permuted roots of unity */
119 fftw_executor_simple(p - 1, work, omega, plan->root, 1, 1,
120 plan->recurse_kind);
121
122 fftw_free(work);
123
124 d->plan = plan;
125 d->omega = omega;
126 d->g = g;
127 d->ginv = ginv;
128 d->p = p;
129 d->flags = flags;
130 d->refcount = 1;
131 d->next = NULL;
132
133 d->cdesc = (fftw_codelet_desc *) fftw_malloc(sizeof(fftw_codelet_desc));
134 d->cdesc->name = NULL;
135 d->cdesc->codelet = NULL;
136 d->cdesc->size = p;
137 d->cdesc->dir = FFTW_FORWARD;
138 d->cdesc->type = FFTW_RADER;
139 d->cdesc->signature = g;
140 d->cdesc->ntwiddle = 0;
141 d->cdesc->twiddle_order = NULL;
142 return d;
143 }
144
145 /***************************************************************************/
146
147 static fftw_rader_data *fftw_create_rader(int p, int flags)
148 {
149 fftw_rader_data *d = fftw_rader_top;
150
151 flags &= ~FFTW_IN_PLACE;
152 while (d && (d->p != p || d->flags != flags))
153 d = d->next;
154 if (d) {
155 d->refcount++;
156 return d;
157 }
158 d = create_rader_aux(p, flags);
159 d->next = fftw_rader_top;
160 fftw_rader_top = d;
161 return d;
162 }
163
164 /***************************************************************************/
165
166 /* Compute the prime FFTs, premultiplied by twiddle factors. Below, we
167 * extensively use the identity that fft(x*)* = ifft(x) in order to
168 * share data between forward and backward transforms and to obviate
169 * the necessity of having separate forward and backward plans. */
170
171 void fftw_twiddle_rader(fftw_complex *A, const fftw_complex *W,
172 int m, int r, int stride,
173 fftw_rader_data * d)
174 {
175 fftw_complex *tmp = (fftw_complex *)
176 fftw_malloc((r - 1) * sizeof(fftw_complex));
177 int i, k, gpower = 1, g = d->g, ginv = d->ginv;
178 fftw_real a0r, a0i;
179 fftw_complex *omega = d->omega;
180
181 for (i = 0; i < m; ++i, A += stride, W += r - 1) {
182 /*
183 * Here, we fft W[k-1] * A[k*(m*stride)], using Rader.
184 * (Actually, W is pre-permuted to match the permutation that we
185 * will do on A.)
186 */
187
188 /* First, permute the input and multiply by W, storing in tmp: */
189 /* gpower == g^k mod r in the following loop */
190 for (k = 0; k < r - 1; ++k, gpower = MULMOD(gpower, g, r)) {
191 fftw_real rA, iA, rW, iW;
192 rW = c_re(W[k]);
193 iW = c_im(W[k]);
194 rA = c_re(A[gpower * (m * stride)]);
195 iA = c_im(A[gpower * (m * stride)]);
196 c_re(tmp[k]) = rW * rA - iW * iA;
197 c_im(tmp[k]) = rW * iA + iW * rA;
198 }
199
200 WHEN_DEBUG( {
201 if (gpower != 1)
202 fftw_die("incorrect generator in Rader\n");
203 }
204 );
205
206 /* FFT tmp to A: */
207 fftw_executor_simple(r - 1, tmp, A + (m * stride),
208 d->plan->root, 1, m * stride,
209 d->plan->recurse_kind);
210
211 /* set output DC component: */
212 a0r = c_re(A[0]);
213 a0i = c_im(A[0]);
214 c_re(A[0]) += c_re(A[(m * stride)]);
215 c_im(A[0]) += c_im(A[(m * stride)]);
216
217 /* now, multiply by omega: */
218 for (k = 0; k < r - 1; ++k) {
219 fftw_real rA, iA, rW, iW;
220 rW = c_re(omega[k]);
221 iW = c_im(omega[k]);
222 rA = c_re(A[(k + 1) * (m * stride)]);
223 iA = c_im(A[(k + 1) * (m * stride)]);
224 c_re(A[(k + 1) * (m * stride)]) = rW * rA - iW * iA;
225 c_im(A[(k + 1) * (m * stride)]) = -(rW * iA + iW * rA);
226 }
227
228 /* this will add A[0] to all of the outputs after the ifft */
229 c_re(A[(m * stride)]) += a0r;
230 c_im(A[(m * stride)]) -= a0i;
231
232 /* inverse FFT: */
233 fftw_executor_simple(r - 1, A + (m * stride), tmp,
234 d->plan->root, m * stride, 1,
235 d->plan->recurse_kind);
236
237 /* finally, do inverse permutation to unshuffle the output: */
238 for (k = 0; k < r - 1; ++k, gpower = MULMOD(gpower, ginv, r)) {
239 c_re(A[gpower * (m * stride)]) = c_re(tmp[k]);
240 c_im(A[gpower * (m * stride)]) = -c_im(tmp[k]);
241 }
242
243 WHEN_DEBUG( {
244 if (gpower != 1)
245 fftw_die("incorrect generator in Rader\n");
246 }
247 );
248
249 }
250
251 fftw_free(tmp);
252 }
253
254 void fftwi_twiddle_rader(fftw_complex *A, const fftw_complex *W,
255 int m, int r, int stride,
256 fftw_rader_data * d)
257 {
258 fftw_complex *tmp = (fftw_complex *)
259 fftw_malloc((r - 1) * sizeof(fftw_complex));
260 int i, k, gpower = 1, g = d->g, ginv = d->ginv;
261 fftw_real a0r, a0i;
262 fftw_complex *omega = d->omega;
263
264 for (i = 0; i < m; ++i, A += stride, W += r - 1) {
265 /*
266 * Here, we fft W[k-1]* * A[k*(m*stride)], using Rader.
267 * (Actually, W is pre-permuted to match the permutation that
268 * we will do on A.)
269 */
270
271 /* First, permute the input and multiply by W*, storing in tmp: */
272 /* gpower == g^k mod r in the following loop */
273 for (k = 0; k < r - 1; ++k, gpower = MULMOD(gpower, g, r)) {
274 fftw_real rA, iA, rW, iW;
275 rW = c_re(W[k]);
276 iW = c_im(W[k]);
277 rA = c_re(A[gpower * (m * stride)]);
278 iA = c_im(A[gpower * (m * stride)]);
279 c_re(tmp[k]) = rW * rA + iW * iA;
280 c_im(tmp[k]) = iW * rA - rW * iA;
281 }
282
283 WHEN_DEBUG( {
284 if (gpower != 1)
285 fftw_die("incorrect generator in Rader\n");
286 }
287 );
288
289 /* FFT tmp to A: */
290 fftw_executor_simple(r - 1, tmp, A + (m * stride),
291 d->plan->root, 1, m * stride,
292 d->plan->recurse_kind);
293
294 /* set output DC component: */
295 a0r = c_re(A[0]);
296 a0i = c_im(A[0]);
297 c_re(A[0]) += c_re(A[(m * stride)]);
298 c_im(A[0]) -= c_im(A[(m * stride)]);
299
300 /* now, multiply by omega: */
301 for (k = 0; k < r - 1; ++k) {
302 fftw_real rA, iA, rW, iW;
303 rW = c_re(omega[k]);
304 iW = c_im(omega[k]);
305 rA = c_re(A[(k + 1) * (m * stride)]);
306 iA = c_im(A[(k + 1) * (m * stride)]);
307 c_re(A[(k + 1) * (m * stride)]) = rW * rA - iW * iA;
308 c_im(A[(k + 1) * (m * stride)]) = -(rW * iA + iW * rA);
309 }
310
311 /* this will add A[0] to all of the outputs after the ifft */
312 c_re(A[(m * stride)]) += a0r;
313 c_im(A[(m * stride)]) += a0i;
314
315 /* inverse FFT: */
316 fftw_executor_simple(r - 1, A + (m * stride), tmp,
317 d->plan->root, m * stride, 1,
318 d->plan->recurse_kind);
319
320 /* finally, do inverse permutation to unshuffle the output: */
321 for (k = 0; k < r - 1; ++k, gpower = MULMOD(gpower, ginv, r)) {
322 A[gpower * (m * stride)] = tmp[k];
323 }
324
325 WHEN_DEBUG( {
326 if (gpower != 1)
327 fftw_die("incorrect generator in Rader\n");
328 }
329 );
330 }
331
332 fftw_free(tmp);
333 }
334
335 /***************************************************************************/
336
337 /*
338 * Make an FFTW_RADER plan node. Note that this function must go
339 * here, rather than in putils.c, because it indirectly calls the
340 * fftw_planner. If we included it in putils.c, which is also used
341 * by rfftw, then any program using rfftw would be linked with all
342 * of the FFTW codelets, even if they were not needed. I wish that the
343 * darn linkers operated on a function rather than a file granularity.
344 */
345 fftw_plan_node *fftw_make_node_rader(int n, int size, fftw_direction dir,
346 fftw_plan_node *recurse,
347 int flags)
348 {
349 fftw_plan_node *p = fftw_make_node();
350
351 p->type = FFTW_RADER;
352 p->nodeu.rader.size = size;
353 p->nodeu.rader.codelet = dir == FFTW_FORWARD ?
354 fftw_twiddle_rader : fftwi_twiddle_rader;
355 p->nodeu.rader.rader_data = fftw_create_rader(size, flags);
356 p->nodeu.rader.recurse = recurse;
357 fftw_use_node(recurse);
358
359 if (flags & FFTW_MEASURE)
360 p->nodeu.rader.tw =
361 fftw_create_twiddle(n, p->nodeu.rader.rader_data->cdesc);
362 else
363 p->nodeu.rader.tw = 0;
364 return p;
365 }
fftw_rader_data_struct::next
struct fftw_rader_data_struct * next
Definition: fftw.h:183
fftw_codelet_desc
Definition: fftw.h:126
fftw_create_twiddle
fftw_twiddle * fftw_create_twiddle(int n, const fftw_codelet_desc *d)
Definition: twiddle.c:175
fftw_rader_data_struct::g
int g
Definition: fftw.h:181
fftw_make_node_rader
fftw_plan_node * fftw_make_node_rader(int n, int size, fftw_direction dir, fftw_plan_node *recurse, int flags)
Definition: rader.c:345
fftw_plan_struct
Definition: fftw.h:271
fftw_rader_data_struct::omega
fftw_complex * omega
Definition: fftw.h:180
fftw-int.h
fftw_plan_node_struct::nodeu
union fftw_plan_node_struct::@0 nodeu
fftw_complex
Definition: fftw.h:57
fftw_use_node
void fftw_use_node(fftw_plan_node *p)
Definition: putils.c:52
FFTW_IN_PLACE
#define FFTW_IN_PLACE
Definition: fftw.h:292
fftw_codelet_desc::twiddle_order
const int * twiddle_order
Definition: fftw.h:134
fftw_codelet_desc::name
const char * name
Definition: fftw.h:127
fftw_plan_node_struct::rader
struct fftw_plan_node_struct::@0::@4 rader
fftw_make_node
fftw_plan_node * fftw_make_node(void)
Definition: putils.c:43
fftw_free
void fftw_free(void *p)
Definition: malloc.c:178
fftw_die
void fftw_die(const char *s)
Definition: malloc.c:192
fftw_plan_struct::recurse_kind
fftw_recurse_kind recurse_kind
Definition: fftw.h:281
fftw_rader_data_struct::plan
struct fftw_plan_struct * plan
Definition: fftw.h:179
fftw_plan_node_struct::size
int size
Definition: fftw.h:198
FFTW_TRIG_COS
#define FFTW_TRIG_COS
Definition: fftw-int.h:186
fftw_rader_data_struct
Definition: fftw.h:178
FFTW_MEASURE
#define FFTW_MEASURE
Definition: fftw.h:289
fftw_plan_struct::root
fftw_plan_node * root
Definition: fftw.h:279
fftw_twiddle_rader
void fftw_twiddle_rader(fftw_complex *A, const fftw_complex *W, int m, int r, int stride, fftw_rader_data *d)
Definition: rader.c:171
FFTW_NO_VECTOR_RECURSE
#define FFTW_NO_VECTOR_RECURSE
Definition: fftw.h:302
fftw_malloc
void * fftw_malloc(size_t n)
Definition: malloc.c:160
fftw_rader_data_struct::cdesc
fftw_codelet_desc * cdesc
Definition: fftw.h:184
fftw_plan_node_struct::dir
fftw_direction dir
Definition: fftw.h:246
fftw_rader_data_struct::p
int p
Definition: fftw.h:182
fftw_codelet_desc::type
enum fftw_node_type type
Definition: fftw.h:131
fftw_plan_node_struct::type
enum fftw_node_type type
Definition: fftw.h:193
fftwi_twiddle_rader
void fftwi_twiddle_rader(fftw_complex *A, const fftw_complex *W, int m, int r, int stride, fftw_rader_data *d)
Definition: rader.c:254
FFTW_TRIG_SIN
#define FFTW_TRIG_SIN
Definition: fftw-int.h:185
fftw_codelet_desc::codelet
void(* codelet)()
Definition: fftw.h:128
fftw_codelet_desc::ntwiddle
int ntwiddle
Definition: fftw.h:133
fftw_rader_top
fftw_rader_data * fftw_rader_top
Definition: putils.c:186
FFTW_RADER
Definition: fftw.h:121
c_re
#define c_re(c)
Definition: fftw.h:60
FFTW_TRIG_REAL
double FFTW_TRIG_REAL
Definition: fftw-int.h:187
MULMOD
#define MULMOD(x, y, p)
Definition: fftw-int.h:154
fftw_codelet_desc::dir
fftw_direction dir
Definition: fftw.h:130
fftw_codelet_desc::size
int size
Definition: fftw.h:129
c_im
#define c_im(c)
Definition: fftw.h:61
fftw_executor_simple
void fftw_executor_simple(int n, const fftw_complex *in, fftw_complex *out, fftw_plan_node *p, int istride, int ostride, fftw_recurse_kind recurse_kind)
Definition: executor.c:212
fftw_create_plan
fftw_plan fftw_create_plan(int n, fftw_direction dir, int flags)
Definition: planner.c:450
FFTW_K2PI
#define FFTW_K2PI
Definition: fftw-int.h:189
fftw_rader_data_struct::flags
int flags
Definition: fftw.h:182
fftw_plan_node_struct
Definition: fftw.h:192
fftw_codelet_desc::signature
int signature
Definition: fftw.h:132
fftw_real
float fftw_real
Definition: fftw.h:49
fftw_plan_node_struct::recurse
struct fftw_plan_node_struct * recurse
Definition: fftw.h:208
WHEN_DEBUG
#define WHEN_DEBUG(a)
Definition: rader.c:34
FFTW_FORWARD
Definition: fftw.h:64
fftw_direction
fftw_direction
Definition: fftw.h:63
fftw_rader_data_struct::refcount
int refcount
Definition: fftw.h:182
fftw_rader_data_struct::ginv
int ginv
Definition: fftw.h:181