ruby-fftw3 0.4.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 12c13d848d56ccf4b757876d37f1fa98c9104014
4
- data.tar.gz: be570dca5edbb4a73f186f70f1db3b68194bedde
3
+ metadata.gz: d047492085717f1d43edf5ed933ede4c3bfbc6d4
4
+ data.tar.gz: ad2fc2f85587f9cf41174a9926df784bfd2ab8ba
5
5
  SHA512:
6
- metadata.gz: 2abb3ea036c9b2aecbdd3d12e888b7f3d75887860a3b6f0f57d25daa4e9649460d8fe0d301e7a381e6915a9b0261d6725cfce99221bbb4712069f874d5b11a27
7
- data.tar.gz: 12df2c95fc26b9bb524d66386cf7cf87980168b10d81605475f2b77abf7f1653e9a10b64094637b259c19797bcf1d45a9359c602c4175031171ec9a1e78d3109
6
+ metadata.gz: 3afac8add19a71908a500e2eabe95ee3ec2ccebc9d442d384d50a7d195d5735f23225999a5361c229979fde51eb074695b183faa69f8956bd36bfdd593e0ce02
7
+ data.tar.gz: b53efbcb4a4577f6de1994bf50f695b6f7633d446218181f776781aff64b20eaaf15e5fe2c104f06548fc3c60c640b1de3c19e3c8acbed19e0092736fd45e6c5
File without changes
data/.gitignore CHANGED
@@ -1,8 +1,7 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
1
+ *.[oa]
2
+ *~
3
+ *.so
4
+ Makefile
5
+ ChangeLog
6
6
  /pkg/
7
- /spec/reports/
8
7
  /tmp/
@@ -1,7 +1,7 @@
1
1
  Ruby-FFTW3 is copyrighted free software by Takeshi Horinouchi and GFD
2
2
  Dennou Club (http://www.gfd-dennou.org/).
3
3
 
4
- Copyright 2001 (C) Takeshi Horinouchi and GFD Dennou Club
4
+ Copyright 2001-2016 (C) Takeshi Horinouchi and GFD Dennou Club
5
5
  (http://www.gfd-dennou.org/) All rights reserved.
6
6
 
7
7
  Redistribution and use in source and binary forms, with or without
data/Rakefile CHANGED
@@ -1,2 +1,36 @@
1
- require "bundler/gem_tasks"
1
+ # -* coding: utf-8 -*-
2
+ require 'rake/testtask'
3
+ require 'rake/extensiontask'
4
+ require 'rake/packagetask'
5
+ begin
6
+ require 'bundler/gem_helper' # instead of 'bundler/gem_tasks' -> need manual
7
+ # calls of install_tasks (see below)
8
+ rescue LoadError
9
+ puts 'If you want to create gem, You must install Bundler'
10
+ end
2
11
 
12
+ Bundler::GemHelper.install_tasks(name: "ruby-fftw3")
13
+ ##Bundler::GemHelper.install_tasks(name: "ruby-fftw3-bigmem")
14
+
15
+ require './lib/numru/fftw3/version.rb'
16
+ def version
17
+ NumRu::FFTW3::VERSION
18
+ end
19
+
20
+ task :default => :test
21
+ task :test => :compile
22
+ Rake::TestTask.new do |t|
23
+ t.libs << 'lib' << 'test'
24
+ t.test_files = FileList['test/*.rb']
25
+ end
26
+
27
+ Rake::ExtensionTask.new do |ext|
28
+ ext.name = 'fftw3'
29
+ ext.ext_dir = 'ext/numru/fftw3'
30
+ ext.lib_dir = 'lib/numru/fftw3'
31
+ end
32
+
33
+ Rake::PackageTask.new('ruby-fftw3', "#{version}") do |t|
34
+ t.need_tar_gz = true
35
+ t.package_files.include `git ls-files`.split("\n")
36
+ end
@@ -1,12 +1,38 @@
1
1
  require "mkmf"
2
+ require "rubygems" unless defined?(Gem)
2
3
 
3
- gem_narray_path=File::dirname(`gem which narray`)
4
- narray_include=gem_narray_path
5
- narray_lib=gem_narray_path
6
- dir_config('narray',narray_include,narray_lib)
7
-
8
4
  dir_config('fftw3','/usr/local')
9
5
 
6
+ require "rbconfig"
7
+ so = RbConfig::CONFIG["DLEXT"]
8
+
9
+ raise("Your gem is too old") unless Gem.respond_to?(:find_files)
10
+
11
+ env = ENV['NARRAY_TYPE']
12
+ if env == "NArray" || env == "narray"
13
+ na_type = "narray"
14
+ elsif env == "NumRu::NArray" || env == "numru-narray"
15
+ na_type = "numru-narray"
16
+ elsif !env.nil?
17
+ raise "Unsupported value for the environment variable NARRAY_TYPE: #{env}"
18
+ else
19
+ if Gem.find_files("narray.h").length > 0
20
+ na_type = "narray"
21
+ elsif Gem.find_files("numru/narray/narray.h").length > 0
22
+ na_type = "numru-narray"
23
+ end
24
+ end
25
+
26
+ case na_type
27
+ when "narray"
28
+ narray_include = File.expand_path(File.dirname(Gem.find_files("narray.h")[0]))
29
+ narray_lib = File.expand_path(File.dirname(Gem.find_files("narray." + so)[0]))
30
+ when "numru-narray"
31
+ narray_include = File.expand_path(File.dirname(Gem.find_files("numru/narray/narray.h")[0]))
32
+ narray_lib = File.expand_path(File.dirname(Gem.find_files("numru/narray/narray." + so)[0]))
33
+ end
34
+
35
+ dir_config('narray', narray_include, narray_lib)
10
36
  if ( ! ( have_header("narray.h") && have_header("narray_config.h") ) ) then
11
37
  print <<-EOS
12
38
  ** configure error **
@@ -43,4 +69,4 @@ if /cygwin|mingw/ =~ RUBY_PLATFORM
43
69
  have_library("narray") || raise("ERROR: narray library is not found")
44
70
  end
45
71
 
46
- create_makefile("numru/fftw3")
72
+ create_makefile("numru/fftw3/fftw3")
@@ -0,0 +1,690 @@
1
+ /*
2
+ na_fftw3.c
3
+
4
+ FFT using FFTW Ver.3 (www.fftw.org)
5
+
6
+ (C) Takeshi Horinouchi
7
+ NO WARRANTY.
8
+
9
+ */
10
+
11
+ #include <ruby.h>
12
+ #include "narray.h"
13
+ #include <fftw3.h>
14
+
15
+ VALUE rb_mFFTW3;
16
+ VALUE mNumRu;
17
+
18
+ static VALUE
19
+ #ifdef FFTW3_HAS_SINGLE_SUPPORT
20
+ na_fftw3_double(int argc, VALUE *argv, VALUE self)
21
+ /* to be called by na_fftw3 */
22
+ #else
23
+ na_fftw3(int argc, VALUE *argv, VALUE self)
24
+ /* to be called directly */
25
+ #endif
26
+ {
27
+ VALUE val, vdir;
28
+ struct NARRAY *a1, *a2;
29
+ int i, dir, *shape, *bucket;
30
+ fftw_plan p;
31
+ fftw_complex *in, *out;
32
+ volatile VALUE v1, v2;
33
+
34
+ if (argc<2){
35
+ rb_raise(rb_eArgError, "Usage: fft(narray, direction [,dim0,dim1,...])");
36
+ }
37
+ val = argv[0];
38
+ vdir = argv[1];
39
+
40
+ dir = NUM2INT(vdir);
41
+ if ( dir != 1 && dir != -1 ){
42
+ rb_raise(rb_eArgError, "direction should be 1 or -1");
43
+ }
44
+ v1 = na_cast_object(val, NA_DCOMPLEX);
45
+ GetNArray(v1,a1);
46
+ v2 = na_make_object( NA_DCOMPLEX, a1->rank, a1->shape, CLASS_OF(v1) );
47
+ GetNArray(v2,a2);
48
+
49
+ shape = ALLOCA_N(int, a2->rank);
50
+ for (i=0; i<a2->rank; i++){
51
+ shape[i] = a2->shape[a2->rank-1-i];
52
+ }
53
+ in = (fftw_complex*)a1->ptr;
54
+ out = (fftw_complex*)a2->ptr;
55
+
56
+ if (argc==2) {
57
+ /* apply FFT to all dimensions */
58
+ p = fftw_plan_dft( a2->rank, shape,
59
+ in, out, dir, FFTW_ESTIMATE );
60
+ } else {
61
+ /* apply FFT to selected dimensions (by using the Guru interface) */
62
+ { /* introduce a new scope for additonal local variables */
63
+ int fft_rank, howmany_rank, j, jf, je, dim;
64
+ fftw_iodim *fft_dims, *howmany_dims;
65
+ int *dimids;
66
+ fft_rank = argc - 2;
67
+ fft_dims = ALLOCA_N(fftw_iodim, fft_rank);
68
+ dimids = ALLOCA_N(int, fft_rank);
69
+ howmany_rank = fft_rank + 1;
70
+ howmany_dims = ALLOCA_N(fftw_iodim, howmany_rank);
71
+
72
+ for (i=2;i<argc;i++){
73
+ dim = NUM2INT(argv[i]);
74
+ if (dim<0) dim += a2->rank; /* negative: count from the end */
75
+ if (dim<0 || dim>=a2->rank){
76
+ rb_raise(rb_eArgError, "dimension < 0 or >= rank");
77
+ }
78
+ dimids[i-2] = a2->rank - 1 - dim;
79
+ if ( i>2 && dimids[i-2] == dimids[i-3] ){
80
+ rb_raise(rb_eArgError, "redundant -- a same dimension is reppeated");
81
+ }
82
+ }
83
+
84
+ /* bukcet sort in increasing order */
85
+ bucket = ALLOCA_N(int,a2->rank);
86
+ for(j=0; j<a2->rank; j++) bucket[j] = 0; /* initialize */
87
+ for(i=0; i<fft_rank; i++) bucket[ dimids[i] ] = 1;
88
+ for(j=0,i=0; j<a2->rank; j++) {
89
+ if (bucket[j]==1){
90
+ dimids[i] = j;
91
+ i++;
92
+ }
93
+ }
94
+
95
+ for(j=0; j<fft_rank; j++){
96
+ fft_dims[j].n = shape[ dimids[j] ];
97
+ fft_dims[j].is = 1;
98
+ for (i=dimids[j]+1 ; i<a2->rank ; i++){
99
+ fft_dims[j].is *= shape[i];
100
+ }
101
+ fft_dims[j].os = fft_dims[j].is;
102
+ /* printf("fft_ %d n:%d is:%d\n",j,
103
+ fft_dims[j].n,fft_dims[j].is);*/
104
+ }
105
+ for(j=0; j<=fft_rank; j++){
106
+ howmany_dims[j].n = 1;
107
+ jf = (j==0) ? 0 : (dimids[j-1]+1) ;
108
+ je = (j==fft_rank) ? a2->rank : (dimids[j]) ;
109
+ for (i=jf; i<je; i++){
110
+ howmany_dims[j].n *= shape[i];
111
+ }
112
+ howmany_dims[j].is = 1;
113
+ if (j<fft_rank){
114
+ for (i=dimids[j]; i<a2->rank; i++){
115
+ howmany_dims[j].is *= shape[i];
116
+ }
117
+ }
118
+ howmany_dims[j].os = howmany_dims[j].is;
119
+ /* printf("how_ %d n:%d is:%d\n",j,
120
+ howmany_dims[j].n,howmany_dims[j].is); */
121
+ }
122
+
123
+ p = fftw_plan_guru_dft( fft_rank, fft_dims,
124
+ howmany_rank, howmany_dims,
125
+ in, out, dir, FFTW_ESTIMATE );
126
+
127
+ }
128
+ }
129
+
130
+ fftw_execute(p);
131
+ fftw_destroy_plan(p);
132
+
133
+ return v2;
134
+ }
135
+
136
+ #ifdef FFTW3_HAS_SINGLE_SUPPORT
137
+
138
+ /* sourse code generation of na_fftw3_float:
139
+ Copy na_fftw3_double, and replace
140
+ fftw --> fftwf
141
+ DCOMPLEX --> SCOMPLEX
142
+ */
143
+ static VALUE
144
+ na_fftw3_float(int argc, VALUE *argv, VALUE self)
145
+ {
146
+ VALUE val, vdir;
147
+ struct NARRAY *a1, *a2;
148
+ int i, dir, *shape, *bucket;
149
+ fftwf_plan p;
150
+ fftwf_complex *in, *out;
151
+ volatile VALUE v1, v2;
152
+
153
+ if (argc<2){
154
+ rb_raise(rb_eArgError, "Usage: fft(narray, direction [,dim0,dim1,...])");
155
+ }
156
+ val = argv[0];
157
+ vdir = argv[1];
158
+
159
+ dir = NUM2INT(vdir);
160
+ if ( dir != 1 && dir != -1 ){
161
+ rb_raise(rb_eArgError, "direction should be 1 or -1");
162
+ }
163
+ v1 = na_cast_object(val, NA_SCOMPLEX);
164
+ GetNArray(v1,a1);
165
+ v2 = na_make_object( NA_SCOMPLEX, a1->rank, a1->shape, CLASS_OF(v1) );
166
+ GetNArray(v2,a2);
167
+
168
+ shape = ALLOCA_N(int, a2->rank);
169
+ for (i=0; i<a2->rank; i++){
170
+ shape[i] = a2->shape[a2->rank-1-i];
171
+ }
172
+ in = (fftwf_complex*)a1->ptr;
173
+ out = (fftwf_complex*)a2->ptr;
174
+
175
+ if (argc==2) {
176
+ /* apply FFT to all dimensions */
177
+ p = fftwf_plan_dft( a2->rank, shape,
178
+ in, out, dir, FFTW_ESTIMATE );
179
+ } else {
180
+ /* apply FFT to selected dimensions (by using the Guru interface) */
181
+ { /* introduce a new scope for additonal local variables */
182
+ int fft_rank, howmany_rank, j, jf, je, dim;
183
+ fftw_iodim *fft_dims, *howmany_dims;
184
+ int *dimids;
185
+ fft_rank = argc - 2;
186
+ fft_dims = ALLOCA_N(fftw_iodim, fft_rank);
187
+ dimids = ALLOCA_N(int, fft_rank);
188
+ howmany_rank = fft_rank + 1;
189
+ howmany_dims = ALLOCA_N(fftw_iodim, howmany_rank);
190
+
191
+ for (i=2;i<argc;i++){
192
+ dim = NUM2INT(argv[i]);
193
+ if (dim<0) dim += a2->rank; /* negative: count from the end */
194
+ if (dim<0 || dim>=a2->rank){
195
+ rb_raise(rb_eArgError, "dimension < 0 or >= rank");
196
+ }
197
+ dimids[i-2] = a2->rank - 1 - dim;
198
+ if ( i>2 && dimids[i-2] == dimids[i-3] ){
199
+ rb_raise(rb_eArgError, "redundant -- a same dimension is reppeated");
200
+ }
201
+ }
202
+
203
+ /* bukcet sort in increasing order */
204
+ bucket = ALLOCA_N(int,a2->rank);
205
+ for(j=0; j<a2->rank; j++) bucket[j] = 0; /* initialize */
206
+ for(i=0; i<fft_rank; i++) bucket[ dimids[i] ] = 1;
207
+ for(j=0,i=0; j<a2->rank; j++) {
208
+ if (bucket[j]==1){
209
+ dimids[i] = j;
210
+ i++;
211
+ }
212
+ }
213
+
214
+ for(j=0; j<fft_rank; j++){
215
+ fft_dims[j].n = shape[ dimids[j] ];
216
+ fft_dims[j].is = 1;
217
+ for (i=dimids[j]+1 ; i<a2->rank ; i++){
218
+ fft_dims[j].is *= shape[i];
219
+ }
220
+ fft_dims[j].os = fft_dims[j].is;
221
+ /* printf("fft_ %d n:%d is:%d\n",j,
222
+ fft_dims[j].n,fft_dims[j].is);*/
223
+ }
224
+ for(j=0; j<=fft_rank; j++){
225
+ howmany_dims[j].n = 1;
226
+ jf = (j==0) ? 0 : (dimids[j-1]+1) ;
227
+ je = (j==fft_rank) ? a2->rank : (dimids[j]) ;
228
+ for (i=jf; i<je; i++){
229
+ howmany_dims[j].n *= shape[i];
230
+ }
231
+ howmany_dims[j].is = 1;
232
+ if (j<fft_rank){
233
+ for (i=dimids[j]; i<a2->rank; i++){
234
+ howmany_dims[j].is *= shape[i];
235
+ }
236
+ }
237
+ howmany_dims[j].os = howmany_dims[j].is;
238
+ /* printf("how_ %d n:%d is:%d\n",j,
239
+ howmany_dims[j].n,howmany_dims[j].is); */
240
+ }
241
+
242
+ p = fftwf_plan_guru_dft( fft_rank, fft_dims,
243
+ howmany_rank, howmany_dims,
244
+ in, out, dir, FFTW_ESTIMATE );
245
+
246
+ }
247
+ }
248
+
249
+ fftwf_execute(p);
250
+ fftwf_destroy_plan(p);
251
+
252
+ return v2;
253
+ }
254
+
255
+ /*
256
+ * call-seq:
257
+ * FFTW3.fft(narray, dir [, dim, dim, ...])
258
+ *
259
+ * Conducts complex FFT (unnormalized). You can use more user-friendly wrappers
260
+ * fft_fw and fft_bk.
261
+ *
262
+ * ARGUMENTS
263
+ * * narray (NArray or NArray-compatible Array) : array to be
264
+ * transformed. If real, coerced to complex before transformation.
265
+ * If narray is single-precision and the single-precision
266
+ * version of FFTW3 is installed (before installing this module),
267
+ * this method does a single-precision transform.
268
+ * Otherwise, a double-precision transform is used.
269
+ * * dir (FORWARD (which is simply equal to -1;
270
+ * referable as NumRu::FFTW3::FORWARD) or BACKWARD
271
+ * (which is simply 1) ) : the direction of FFT,
272
+ * forward if FORWARD and backward if BACKWARD.
273
+ * * optional 3rd, 4th,... arguments (Integer) : Specifies dimensions
274
+ * to apply FFT. For example, if 0, the first dimension is
275
+ * transformed (1D FFT); If -1, the last dimension is used (1D FFT);
276
+ * If 0,2,4, the first, third, and fifth dimensions
277
+ * are transformed (3D FFT); If entirely omitted, ALL DIMENSIONS
278
+ * ARE SUBJECT TO FFT, so 3D FFT is done with a 3D array.
279
+ *
280
+ * RETURN VALUE
281
+ * * a complex NArray
282
+ *
283
+ * NOTE
284
+ * * As in FFTW, return value is NOT normalized. Thus, a consecutive
285
+ * forward and backward transform would multiply the size of
286
+ * data used for transform. You can normalize, for example,
287
+ * the forward transform FFTW.fft(narray, -1, 0, 1)
288
+ * (FFT regarding the first (dim 0) & second (dim 1) dimensions) by
289
+ * dividing with (narray.shape[0]*narray.shape[1]). Likewise,
290
+ * the result of FFTW.fft(narray, -1) (FFT for all dimensions)
291
+ * can be normalized by narray.length.
292
+ */
293
+ static VALUE
294
+ na_fftw3(int argc, VALUE *argv, VALUE self)
295
+ {
296
+ VALUE val;
297
+ volatile VALUE v1;
298
+ struct NARRAY *a1;
299
+
300
+ if (argc<2){
301
+ rb_raise(rb_eArgError, "Usage: fft(narray, direction [,dim0,dim1,...])");
302
+ }
303
+ val = argv[0];
304
+ v1 = na_to_narray(val);
305
+ GetNArray(v1,a1);
306
+ if(a1->type <= NA_SFLOAT || a1->type == NA_SCOMPLEX ){
307
+ return( na_fftw3_float(argc, argv, self) );
308
+ } else {
309
+ return( na_fftw3_double(argc, argv, self) );
310
+ }
311
+
312
+ }
313
+
314
+ #endif
315
+
316
+ static VALUE
317
+ #ifdef FFTW3_HAS_SINGLE_SUPPORT
318
+ na_fftw3_r2r_double(int argc, VALUE *argv, VALUE self)
319
+ /* to be called by na_fftw3_r2r */
320
+ #else
321
+ na_fftw3_r2r(int argc, VALUE *argv, VALUE self)
322
+ /* to be called directly */
323
+ #endif
324
+ {
325
+ VALUE val, vkinds;
326
+ struct NARRAY *a1, *a2;
327
+ int i, *shape, *bucket, len;
328
+ fftw_r2r_kind *kinds;
329
+ fftw_plan p;
330
+ double *in, *out;
331
+ volatile VALUE v1, v2;
332
+
333
+ if (argc<2){
334
+ rb_raise(rb_eArgError, "Usage: fft_r2r(narray, kinds [,dim0,dim1,...])");
335
+ }
336
+ val = argv[0];
337
+ vkinds = argv[1];
338
+
339
+ v1 = na_cast_object(val, NA_DFLOAT);
340
+ GetNArray(v1,a1);
341
+ v2 = na_make_object( NA_DFLOAT, a1->rank, a1->shape, CLASS_OF(v1) );
342
+ GetNArray(v2,a2);
343
+
344
+ shape = ALLOCA_N(int, a2->rank);
345
+ for (i=0; i<a2->rank; i++){
346
+ shape[i] = a2->shape[a2->rank-1-i];
347
+ }
348
+ in = (double*)a1->ptr;
349
+ out = (double*)a2->ptr;
350
+
351
+ switch (TYPE(vkinds)) {
352
+ case T_ARRAY:
353
+ len = RARRAY_LEN(vkinds);
354
+ kinds = ALLOCA_N(fftw_r2r_kind, len);
355
+ for (i = 0; i < len; i++) {
356
+ kinds[i] = NUM2INT(RARRAY_PTR(vkinds)[len-1-i]);//column- to row-major
357
+ }
358
+ break;
359
+ case T_FIXNUM:
360
+ if (argc == 2) {
361
+ len = a1->rank;
362
+ } else {
363
+ len = argc-2;
364
+ }
365
+ kinds = ALLOCA_N(fftw_r2r_kind, len);
366
+ for (i = 0; i < len; i++) {
367
+ kinds[i] = NUM2INT(vkinds);
368
+ }
369
+ break;
370
+ default:
371
+ rb_raise(rb_eTypeError, "unsupported kinds type");
372
+ break;
373
+ }
374
+
375
+ for (i = 0; i < len; i++) {
376
+ if ( kinds[i] < FFTW_R2HC || kinds[i] > FFTW_RODFT11 ){
377
+ rb_raise(rb_eArgError, "unsupported kind (%d).", kinds[i]);
378
+ }
379
+ }
380
+
381
+ if (argc==2) {
382
+ /* apply FFT to all dimensions */
383
+ p = fftw_plan_r2r( a2->rank, shape,
384
+ in, out, kinds, FFTW_ESTIMATE );
385
+ } else {
386
+ /* apply FFT to selected dimensions (by using the Guru interface) */
387
+ { /* introduce a new scope for additonal local variables */
388
+ int fft_rank, howmany_rank, j, jf, je, dim;
389
+ fftw_iodim *fft_dims, *howmany_dims;
390
+ int *dimids;
391
+ fft_rank = argc - 2;
392
+ fft_dims = ALLOCA_N(fftw_iodim, fft_rank);
393
+ dimids = ALLOCA_N(int, fft_rank);
394
+ howmany_rank = fft_rank + 1;
395
+ howmany_dims = ALLOCA_N(fftw_iodim, howmany_rank);
396
+
397
+ for (i=2;i<argc;i++){
398
+ dim = NUM2INT(argv[i]);
399
+ if (dim<0) dim += a2->rank; /* negative: count from the end */
400
+ if (dim<0 || dim>=a2->rank){
401
+ rb_raise(rb_eArgError, "dimension < 0 or >= rank");
402
+ }
403
+ dimids[i-2] = a2->rank - 1 - dim;
404
+ if ( i>2 && dimids[i-2] == dimids[i-3] ){
405
+ rb_raise(rb_eArgError, "redundant -- a same dimension is reppeated");
406
+ }
407
+ }
408
+
409
+ /* bukcet sort in increasing order */
410
+ bucket = ALLOCA_N(int,a2->rank);
411
+ for(j=0; j<a2->rank; j++) bucket[j] = 0; /* initialize */
412
+ for(i=0; i<fft_rank; i++) bucket[ dimids[i] ] = 1;
413
+ for(j=0,i=0; j<a2->rank; j++) {
414
+ if (bucket[j]==1){
415
+ dimids[i] = j;
416
+ i++;
417
+ }
418
+ }
419
+
420
+ for(j=0; j<fft_rank; j++){
421
+ fft_dims[j].n = shape[ dimids[j] ];
422
+ fft_dims[j].is = 1;
423
+ for (i=dimids[j]+1 ; i<a2->rank ; i++){
424
+ fft_dims[j].is *= shape[i];
425
+ }
426
+ fft_dims[j].os = fft_dims[j].is;
427
+ /* printf("fft_ %d n:%d is:%d\n",j,
428
+ fft_dims[j].n,fft_dims[j].is);*/
429
+ }
430
+ for(j=0; j<=fft_rank; j++){
431
+ howmany_dims[j].n = 1;
432
+ jf = (j==0) ? 0 : (dimids[j-1]+1) ;
433
+ je = (j==fft_rank) ? a2->rank : (dimids[j]) ;
434
+ for (i=jf; i<je; i++){
435
+ howmany_dims[j].n *= shape[i];
436
+ }
437
+ howmany_dims[j].is = 1;
438
+ if (j<fft_rank){
439
+ for (i=dimids[j]; i<a2->rank; i++){
440
+ howmany_dims[j].is *= shape[i];
441
+ }
442
+ }
443
+ howmany_dims[j].os = howmany_dims[j].is;
444
+ /* printf("how_ %d n:%d is:%d\n",j,
445
+ howmany_dims[j].n,howmany_dims[j].is); */
446
+ }
447
+
448
+ p = fftw_plan_guru_r2r( fft_rank, fft_dims,
449
+ howmany_rank, howmany_dims,
450
+ in, out, kinds, FFTW_ESTIMATE );
451
+
452
+ }
453
+ }
454
+
455
+ fftw_execute(p);
456
+ fftw_destroy_plan(p);
457
+
458
+ return v2;
459
+ }
460
+
461
+ static VALUE
462
+ #ifdef FFTW3_HAS_SINGLE_SUPPORT
463
+ na_fftw3_r2r_float(int argc, VALUE *argv, VALUE self)
464
+ /* to be called by na_fftw3_r2r */
465
+ {
466
+ VALUE val, vkinds;
467
+ struct NARRAY *a1, *a2;
468
+ int i, *shape, *bucket, len;
469
+ fftwf_r2r_kind *kinds;
470
+ fftwf_plan p;
471
+ float *in, *out;
472
+ volatile VALUE v1, v2;
473
+
474
+ if (argc<2){
475
+ rb_raise(rb_eArgError, "Usage: fft_r2r(narray, kinds [,dim0,dim1,...])");
476
+ }
477
+ val = argv[0];
478
+ vkinds = argv[1];
479
+
480
+ v1 = na_cast_object(val, NA_SFLOAT);
481
+ GetNArray(v1,a1);
482
+ v2 = na_make_object( NA_SFLOAT, a1->rank, a1->shape, CLASS_OF(v1) );
483
+ GetNArray(v2,a2);
484
+
485
+ shape = ALLOCA_N(int, a2->rank);
486
+ for (i=0; i<a2->rank; i++){
487
+ shape[i] = a2->shape[a2->rank-1-i];
488
+ }
489
+ in = (float*)a1->ptr;
490
+ out = (float*)a2->ptr;
491
+
492
+ switch (TYPE(vkinds)) {
493
+ case T_ARRAY:
494
+ len = RARRAY_LEN(vkinds);
495
+ kinds = ALLOCA_N(fftwf_r2r_kind, len);
496
+ for (i = 0; i < len; i++) {
497
+ kinds[i] = NUM2INT(RARRAY_PTR(vkinds)[len-1-i]);//column- to row-major
498
+ }
499
+ break;
500
+ case T_FIXNUM:
501
+ if (argc == 2) {
502
+ len = a1->rank;
503
+ } else {
504
+ len = argc-2;
505
+ }
506
+ kinds = ALLOCA_N(fftwf_r2r_kind, len);
507
+ for (i = 0; i < len; i++) {
508
+ kinds[i] = NUM2INT(vkinds);
509
+ }
510
+ break;
511
+ default:
512
+ rb_raise(rb_eTypeError, "unsupported kinds type");
513
+ break;
514
+ }
515
+
516
+ for (i = 0; i < len; i++) {
517
+ if ( kinds[i] < FFTW_R2HC || kinds[i] > FFTW_RODFT11 ){
518
+ rb_raise(rb_eArgError, "unsupported kind (%d).", kinds[i]);
519
+ }
520
+ }
521
+
522
+ if (argc==2) {
523
+ /* apply FFT to all dimensions */
524
+ p = fftwf_plan_r2r( a2->rank, shape,
525
+ in, out, kinds, FFTW_ESTIMATE );
526
+ } else {
527
+ /* apply FFT to selected dimensions (by using the Guru interface) */
528
+ { /* introduce a new scope for additonal local variables */
529
+ int fft_rank, howmany_rank, j, jf, je, dim;
530
+ fftwf_iodim *fft_dims, *howmany_dims;
531
+ int *dimids;
532
+ fft_rank = argc - 2;
533
+ fft_dims = ALLOCA_N(fftwf_iodim, fft_rank);
534
+ dimids = ALLOCA_N(int, fft_rank);
535
+ howmany_rank = fft_rank + 1;
536
+ howmany_dims = ALLOCA_N(fftwf_iodim, howmany_rank);
537
+
538
+ for (i=2;i<argc;i++){
539
+ dim = NUM2INT(argv[i]);
540
+ if (dim<0) dim += a2->rank; /* negative: count from the end */
541
+ if (dim<0 || dim>=a2->rank){
542
+ rb_raise(rb_eArgError, "dimension < 0 or >= rank");
543
+ }
544
+ dimids[i-2] = a2->rank - 1 - dim;
545
+ if ( i>2 && dimids[i-2] == dimids[i-3] ){
546
+ rb_raise(rb_eArgError, "redundant -- a same dimension is reppeated");
547
+ }
548
+ }
549
+
550
+ /* bukcet sort in increasing order */
551
+ bucket = ALLOCA_N(int,a2->rank);
552
+ for(j=0; j<a2->rank; j++) bucket[j] = 0; /* initialize */
553
+ for(i=0; i<fft_rank; i++) bucket[ dimids[i] ] = 1;
554
+ for(j=0,i=0; j<a2->rank; j++) {
555
+ if (bucket[j]==1){
556
+ dimids[i] = j;
557
+ i++;
558
+ }
559
+ }
560
+
561
+ for(j=0; j<fft_rank; j++){
562
+ fft_dims[j].n = shape[ dimids[j] ];
563
+ fft_dims[j].is = 1;
564
+ for (i=dimids[j]+1 ; i<a2->rank ; i++){
565
+ fft_dims[j].is *= shape[i];
566
+ }
567
+ fft_dims[j].os = fft_dims[j].is;
568
+ /* printf("fft_ %d n:%d is:%d\n",j,
569
+ fft_dims[j].n,fft_dims[j].is);*/
570
+ }
571
+ for(j=0; j<=fft_rank; j++){
572
+ howmany_dims[j].n = 1;
573
+ jf = (j==0) ? 0 : (dimids[j-1]+1) ;
574
+ je = (j==fft_rank) ? a2->rank : (dimids[j]) ;
575
+ for (i=jf; i<je; i++){
576
+ howmany_dims[j].n *= shape[i];
577
+ }
578
+ howmany_dims[j].is = 1;
579
+ if (j<fft_rank){
580
+ for (i=dimids[j]; i<a2->rank; i++){
581
+ howmany_dims[j].is *= shape[i];
582
+ }
583
+ }
584
+ howmany_dims[j].os = howmany_dims[j].is;
585
+ /* printf("how_ %d n:%d is:%d\n",j,
586
+ howmany_dims[j].n,howmany_dims[j].is); */
587
+ }
588
+
589
+ p = fftwf_plan_guru_r2r( fft_rank, fft_dims,
590
+ howmany_rank, howmany_dims,
591
+ in, out, kinds, FFTW_ESTIMATE );
592
+
593
+ }
594
+ }
595
+
596
+ fftwf_execute(p);
597
+ fftwf_destroy_plan(p);
598
+
599
+ return v2;
600
+ }
601
+
602
+ /*
603
+ * call-seq:
604
+ * FFTW3.fft_r2r(narray, kind [, dim, dim, ...])
605
+ *
606
+ * Conducts real FFT (unnormalized).
607
+ *
608
+ * ARGUMENTS
609
+ * * narray (NArray or NArray-compatible Array) : array to be
610
+ * transformed. Cannot be complex.
611
+ * * kind : specifies the kind of FFT. One of the following:
612
+ * R2HC, HC2R, DHT, REDFT00, REDFT01, REDFT10, REDFT11, RODFT00, RODFT01,
613
+ * RODFT10, or RODFT11 (referable as NumRu::FFTW3::REDFT10). See Ch.2 of
614
+ * http://www.fftw.org/fftw3_doc/ (http://www.fftw.org/fftw3.pdf).
615
+ * * optional 3rd, 4th,... arguments (Integer) : See FFTW3.fft.
616
+ *
617
+ *
618
+ * RETURN VALUE
619
+ * * a real NArray
620
+ *
621
+ * NOTE
622
+ * * As in FFTW, return value is NOT normalized, and the length needed
623
+ * normalize is different for each kind.
624
+ */
625
+ static VALUE
626
+ na_fftw3_r2r(int argc, VALUE *argv, VALUE self)
627
+ {
628
+ VALUE val;
629
+ volatile VALUE v1;
630
+ struct NARRAY *a1;
631
+
632
+ if (argc<2){
633
+ rb_raise(rb_eArgError, "Usage: fft_r2r(narray, kinds [,dim0,dim1,...])");
634
+ }
635
+ val = argv[0];
636
+ v1 = na_to_narray(val);
637
+ GetNArray(v1,a1);
638
+ if(a1->type <= NA_SFLOAT || a1->type == NA_SCOMPLEX ){
639
+ return( na_fftw3_r2r_float(argc, argv, self) );
640
+ } else {
641
+ return( na_fftw3_r2r_double(argc, argv, self) );
642
+ }
643
+
644
+ }
645
+
646
+ #endif
647
+
648
+ void
649
+ Init_fftw3()
650
+ {
651
+ rb_require("narray");
652
+ mNumRu = rb_define_module("NumRu");
653
+ rb_mFFTW3 = rb_define_module_under(mNumRu, "FFTW3");
654
+ rb_define_module_function(rb_mFFTW3, "fft", na_fftw3, -1);
655
+ rb_define_module_function(rb_mFFTW3, "fft_r2r", na_fftw3_r2r, -1);
656
+ /* Specifier of forward complex FFT. Integer equal to -1. */
657
+ rb_define_const(rb_mFFTW3, "FORWARD", INT2NUM(FFTW_FORWARD));
658
+ /* Specifier of backward complex FFT. Integer equal to 1. */
659
+ rb_define_const(rb_mFFTW3, "BACKWARD", INT2NUM(FFTW_BACKWARD));
660
+ /* Specifier of real FFT kind. real to "halfcomplex" */
661
+ rb_define_const(rb_mFFTW3, "R2HC", INT2NUM(FFTW_R2HC));
662
+ /* Specifier of real FFT kind. "halfcomplex" to real */
663
+ rb_define_const(rb_mFFTW3, "HC2R", INT2NUM(FFTW_HC2R));
664
+ /* Specifier of real FFT kind. Discrete Hartley Transform */
665
+ rb_define_const(rb_mFFTW3, "DHT", INT2NUM(FFTW_DHT));
666
+ /* Specifier of real FFT kind. cosine (even) transform;
667
+ logical data length 2*(n-1); inverse is itself */
668
+ rb_define_const(rb_mFFTW3, "REDFT00", INT2NUM(FFTW_REDFT00));
669
+ /* Specifier of real FFT kind. cosine (even) transform;
670
+ * logical data length 2*n; inverse is REDFT10 */
671
+ rb_define_const(rb_mFFTW3, "REDFT01", INT2NUM(FFTW_REDFT01));
672
+ /* Specifier of real FFT kind. cosine (even) transform;
673
+ * logical data length 2*n; inverse is REDFT01 */
674
+ rb_define_const(rb_mFFTW3, "REDFT10", INT2NUM(FFTW_REDFT10));
675
+ /* Specifier of real FFT kind. cosine (even) transform;
676
+ * logical data length 2*n; inverse is itself */
677
+ rb_define_const(rb_mFFTW3, "REDFT11", INT2NUM(FFTW_REDFT11));
678
+ /* Specifier of real FFT kind. sine (odd) transform;
679
+ * logical data length 2*(n+1); inverse is itself */
680
+ rb_define_const(rb_mFFTW3, "RODFT00", INT2NUM(FFTW_RODFT00));
681
+ /* Specifier of real FFT kind. sine (odd) transform;
682
+ * logical data length 2*n; inverse is RODFT10 */
683
+ rb_define_const(rb_mFFTW3, "RODFT01", INT2NUM(FFTW_RODFT01));
684
+ /* Specifier of real FFT kind. sine (odd) transform;
685
+ * logical data length 2*n; inverse is RODFT01 */
686
+ rb_define_const(rb_mFFTW3, "RODFT10", INT2NUM(FFTW_RODFT10));
687
+ /* Specifier of real FFT kind. sine (odd) transform;
688
+ * logical data length 2*n; inverse is itself */
689
+ rb_define_const(rb_mFFTW3, "RODFT11", INT2NUM(FFTW_RODFT11));
690
+ }