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 +4 -4
- data/{ChangeLog → .ChangeLog.until20110419} +0 -0
- data/.gitignore +5 -6
- data/LICENSE.txt +1 -1
- data/Rakefile +35 -1
- data/{extconf.rb → ext/numru/fftw3/extconf.rb} +32 -6
- data/ext/numru/fftw3/na_fftw3.c +690 -0
- data/lib/numru/fftw3.rb +102 -0
- data/lib/numru/fftw3/version.rb +2 -2
- data/ruby-fftw3-bigmem.gemspec +25 -0
- data/ruby-fftw3.gemspec +5 -12
- data/test/complexFFT.rb +57 -34
- data/test/r2rFFT.rb +77 -0
- metadata +19 -22
- data/.rspec +0 -2
- data/.travis.yml +0 -3
- data/README.rd +0 -0
- data/doc/ruby-fftw3.html +0 -116
- data/doc/ruby-fftw3.rd +0 -115
- data/na_fftw3.c +0 -285
- data/spec/ruby/fftw3_spec.rb +0 -11
- data/spec/spec_helper.rb +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d047492085717f1d43edf5ed933ede4c3bfbc6d4
|
4
|
+
data.tar.gz: ad2fc2f85587f9cf41174a9926df784bfd2ab8ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3afac8add19a71908a500e2eabe95ee3ec2ccebc9d442d384d50a7d195d5735f23225999a5361c229979fde51eb074695b183faa69f8956bd36bfdd593e0ce02
|
7
|
+
data.tar.gz: b53efbcb4a4577f6de1994bf50f695b6f7633d446218181f776781aff64b20eaaf15e5fe2c104f06548fc3c60c640b1de3c19e3c8acbed19e0092736fd45e6c5
|
File without changes
|
data/.gitignore
CHANGED
data/LICENSE.txt
CHANGED
@@ -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
|
-
|
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
|
+
}
|