ruby-fftw3 0.4.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }