ruby-fftw3-1.0.2/0000755000175000017500000000000012752272276013372 5ustar uwabamiuwabamiruby-fftw3-1.0.2/test/0000755000175000017500000000000012752272276014351 5ustar uwabamiuwabamiruby-fftw3-1.0.2/test/complexFFT.rb0000644000175000017500000000302412752272276016704 0ustar uwabamiuwabamibegin require "rubygems" rescue LoadError end require "narray" # This line is needed for rake test when making a gem package. require "numru/fftw3" require "test/unit" include NumRu class FFTW3Test < Test::Unit::TestCase def setup @eps = 1e-10 @seps = 1e-6 end def test_fft_fw_bk na = NArray.float(8,4).fill(1) # will be corced to complex na[1,1]=5 fc = FFTW3.fft_fw(na) nb = FFTW3.fft_bk(fc).real assert( (na-nb).abs.max < @eps ) fc = FFTW3.fft_fw(na,1) nb = FFTW3.fft_bk(fc,1).real assert( (na-nb).abs.max < @eps ) end def test_real_all_dims na = NArray.float(8,4).fill(1) # will be corced to complex na[1,1]=5 fc = FFTW3.fft(na, FFTW3::FORWARD)/na.length nb = FFTW3.fft(fc, FFTW3::BACKWARD).real assert( (na-nb).abs.max < @eps ) end def test_complex_all_dims na = NArray.complex(8,4).fill(1) * Complex::I na[1,1]=5 fc = FFTW3.fft(na, -1)/na.length nb = FFTW3.fft(fc, 1) assert( (na-nb).abs.max < @eps ) end def test_dim_selection na = NArray.float(8,4).indgen! fc = FFTW3.fft(na, FFTW3::FORWARD, 0) fc = FFTW3.fft(fc, FFTW3::FORWARD, 1) fc2 = FFTW3.fft(na, FFTW3::FORWARD) assert( (fc-fc2).abs.max < @eps ) end # TEST: single float (treated as single if lib fftw3f exits). # see http://www.fftw.org/fftw3_doc/Precision.html for more info def test_single_float na = NArray.sfloat(8,4).indgen! fc = FFTW3.fft(na, -1)/na.length nb = FFTW3.fft(fc, 1).real assert( (na-nb).abs.max < @seps ) end end ruby-fftw3-1.0.2/test/r2rFFT.rb0000644000175000017500000000421712752272276015747 0ustar uwabamiuwabamirequire "narray" # This line is needed for rake test when making a gem package. require "numru/fftw3" require "test/unit" include NumRu class FFTW3_R2R_Test < Test::Unit::TestCase def setup @eps = 1e-10 @seps = 1e-5 end def test_r2r_all_dims nx = 8 ny = 4 na = NArray.float(nx,ny).indgen! fc = FFTW3.fft_r2r(na, FFTW3::REDFT00) # cosine trans at 0, 1, 2,... c = 1.0 / (2*(nx-1)) / (2*(ny-1)) nb = FFTW3.fft_r2r(fc*c, FFTW3::REDFT00) assert( (na-nb).abs.max < @eps ) fc = FFTW3.fft_r2r(na, FFTW3::REDFT11) # cosine trans at 1/2, 1+1/2,... c = 1.0 / (2*nx) / (2*ny) nb = FFTW3.fft_r2r(fc*c, FFTW3::REDFT11) assert( (na-nb).abs.max < @eps ) fc = FFTW3.fft_r2r(na, FFTW3::REDFT01) c = 1.0 / (2*nx) / (2*ny) nb = FFTW3.fft_r2r(fc*c, FFTW3::REDFT10) assert( (na-nb).abs.max < @eps ) fc = FFTW3.fft_r2r(na, FFTW3::RODFT00) # sine trans at 1, 2,... c = 1.0 / (2*(nx+1)) / (2*(ny+1)) nb = FFTW3.fft_r2r(fc*c, FFTW3::RODFT00) assert( (na-nb).abs.max < @eps ) fc = FFTW3.fft_r2r(na, FFTW3::RODFT11) # sine trans at 1/2, 1+1/2,... c = 1.0 / (2*nx) / (2*ny) nb = FFTW3.fft_r2r(fc*c, FFTW3::RODFT11) assert( (na-nb).abs.max < @eps ) fc = FFTW3.fft_r2r(na, FFTW3::RODFT01) # sine trans c = 1.0 / (2*nx) / (2*ny) nb = FFTW3.fft_r2r(fc*c, FFTW3::RODFT10) assert( (na-nb).abs.max < @eps ) end def test_r2r_sigle nx = 8 ny = 4 na = NArray.sfloat(nx,ny).indgen! fc = FFTW3.fft_r2r(na, FFTW3::REDFT00) # cosine trans at 0, 1, 2,... c = 1.0 / (2*(nx-1)) / (2*(ny-1)) nb = FFTW3.fft_r2r(fc*c, FFTW3::REDFT00) assert( (na-nb).abs.max < @seps ) end def test_r2r_some_dims nx = 8 ny = 4 na = NArray.float(nx,ny).indgen! fc = FFTW3.fft_r2r(na, FFTW3::REDFT00, 0) nb = FFTW3.fft_r2r(fc, FFTW3::REDFT00, 0) / (2*(nx-1)) assert( (na-nb).abs.max < @eps ) fc = FFTW3.fft_r2r(fc, FFTW3::RODFT11, 1) fc2 = FFTW3.fft_r2r(na, [FFTW3::REDFT00, FFTW3::RODFT11]) fc3 = FFTW3.fft_r2r(na, [FFTW3::REDFT00, FFTW3::RODFT11], 0, 1) assert( (fc-fc2).abs.max < @eps ) assert( (fc-fc3).abs.max < @eps ) end end ruby-fftw3-1.0.2/.ChangeLog.until201104190000644000175000017500000000150312752272276017175 0ustar uwabamiuwabamiTue Apr 19 2011 T Horinouchi * version 0.4 released (cvs tag ruby-fftw3-0_4) * doc/ruby-fftw3.rd and doc/ruby-fftw3.html : updated * na_fftw3.c: added rb_require("narray"); -- then you do not need to require "narray" separately. * test/complexFFT.rb: removed the first line: require "narray" * LICENSE.txt: changed --> BSD 2-clause license Thu Mar 24 2011 T Horinouchi * version 0.3 released (cvs tag ruby-fftw3-0_3) * LICENSE.txt: added Mon Jun 7 2004 T Horinouchi < T Koshiro * version 0.2 released (cvs tag ruby-fftw3-0_2) * extconf.rb: improved Mon Jun 7 2004 T Horinouchi * renamed to ruby-fftw. Started a new cvs module ruby-fftw3. Fri Nov 20 2003 T Horinouchi * version 0.1 released Thu Nov 20 2003 T Horinouchi * na_fftw3.c: debug of na_fftw3_float Tue Nov 18 2003 T Horinouchi * created. version 0.0 ruby-fftw3-1.0.2/LICENSE.txt0000644000175000017500000000327212752272276015221 0ustar uwabamiuwabamiRuby-FFTW3 is copyrighted free software by Takeshi Horinouchi and GFD Dennou Club (http://www.gfd-dennou.org/). Copyright 2001-2016 (C) Takeshi Horinouchi and GFD Dennou Club (http://www.gfd-dennou.org/) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY GFD DENNOU CLUB AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Takeshi Horinouchi and GFD Dennou Club. ruby-fftw3-1.0.2/ruby-fftw3.gemspec0000644000175000017500000000233212752272276016747 0ustar uwabamiuwabami# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'numru/fftw3/version' filelist = %w!ChangeLog .ChangeLog.until20110419 Gemfile LICENSE.txt Rakefile ruby-fftw3.gemspec! filelist.concat(Dir::glob("ext/**/*.c\0ext/**/*.rb\0lib/**/*.rb\0test/**/*.rb")) Gem::Specification.new do |spec| spec.name = "ruby-fftw3" spec.version = NumRu::FFTW3::VERSION spec.authors = ["Takeshi Horinouchi"] spec.email = ['eriko@gfd-dennou.org'] spec.summary = %q{The Ruby interface of the FFTW (ver 3) library} spec.description = %q{The Ruby interface of the FFTW3, Fast Fourier Transform library FFTW Ver.3. Since ver.1, ruby-fftw3 supports all kinds of FFTs in FFTW3. Works with NArray (or NumRu::NArray).} spec.homepage = 'http://www.gfd-dennou.org/arch/ruby/products/ruby-fftw3/' spec.licenses = ["BSD-2-Clause"] spec.files = filelist spec.test_files = spec.files.grep(%r{^test/}) spec.require_paths = ["ext","lib"] spec.required_ruby_version = Gem::Requirement.new(">= 1.8") spec.add_runtime_dependency(%q, [">= 0"]) spec.extensions << "ext/numru/fftw3/extconf.rb" end ruby-fftw3-1.0.2/lib/0000755000175000017500000000000012752272276014140 5ustar uwabamiuwabamiruby-fftw3-1.0.2/lib/numru/0000755000175000017500000000000012752272276015306 5ustar uwabamiuwabamiruby-fftw3-1.0.2/lib/numru/fftw3.rb0000644000175000017500000001014112752272276016661 0ustar uwabamiuwabamibegin require "rubygems" rescue LoadError end require "numru/fftw3/version" require "numru/fftw3/fftw3" if NumRu::FFTW3::SUPPORT_BIGMEM if Object.const_defined?(:NArray) raise "Incompatibility found. The loaded NumRu::FFTW3 was compiled to " + "use NumRu::NArray, but here NArray has already been loaded." end require("numru/narray"); else if ( RUBY_VERSION>="1.9" ? NumRu.const_defined?(:NArray,false) : NumRu.const_defined?(:NArray) ) raise "Incompatibility found. The loaded NumRu::FFTW3 was compiled to " + "use NArray, but here NumRu::NArray has already been loaded." end require("narray"); end module NumRu # Ruby wrapper of FFTW3, a fast discrete Fourier transform library. http://www.fftw.org # # ==Features # # * Uses NArray (https://github.com/masa16/narray). (Also it supports # NumRu::NArray as well, if this library is compiled to use it). # * Multi-dimensional complex and real FFT. # * Supports both double and single float transforms. # # ==How to use # # Copy and paste the following code line-by-line using irb. # Or you can run it by saving it in a file fftw3test.rb (say) # and executing "ruby fftw3test.rb". # # require "numru/fftw3" # include NumRu # # na = NArray.float(8,6) # float -> will be coerced to complex # na[1,1]=1 # # # # # fc = FFTW3.fft(na, FFTW3::FORWARD)/na.length # forward 2D FFT and normalization # nc = FFTW3.fft(fc, FFTW3::BACKWARD) # backward 2D FFT (complex) --> # nb = nc.real # should be equal to na except round errors # p (nb - na).abs.max # => 8.970743058303247e-17 (sufficiently small) # # # # # Same as example 1 but using more user-friendly wrapper of FFTW3.fft # # fc = FFTW3.fft_fw(na) # forward 2D FFT and normalization # nc = FFTW3.fft_bk(fc) # backward 2D FFT (complex) --> # nb = nc.real # should be equal to na except round errors # p (nb - na).abs.max # => 8.970743058303247e-17 (sufficiently small) # # # # fc = FFTW3.fft_fw(na, 0) # forward 1D FFT along the first dim # nc = FFTW3.fft_bk(fc, 0) # backward 1D FFT along the first dim # p (nc.real - na).abs.max # => 1.1102230246251565e-16 (sufficiently small) # # # # fc = FFTW3.fft_fw(na, 1) # forward 1D FFT along the second dim # # # # # fc = FFTW3.fft_r2r(na, FFTW3::RODFT00, 0) # not normalized sine transform along the 1st dim # len = 2*(na.shape[0]+1) # this is the supposed length of this transformation # nc = FFTW3.fft_r2r(fc/len, FFTW3::RODFT00, 0) # forward==backward transformation # p (nc-na).abs.max # => 2.220446049250313e-16 (sufficiently small) # # # # # fc = FFTW3.fft_r2r(na, FFTW3::REDFT11) # unnormalized cosine transform # len = 4*na.length # from (2*na.shape[0]) * (2*na.shape[1]) # nc = FFTW3.fft_r2r(fc/len, FFTW3::REDFT11) # forward==backward transformation # p (nc-na).abs.max # => 6.228190483314256e-17 (sufficiently small) # # See the FFTW3 manual for the kinds of supported real FFTs. See Ch.2 of # http://www.fftw.org/fftw3_doc/ (http://www.fftw.org/fftw3.pdf). # Virtually all kinds are supported! # module FFTW3 module_function # Forward complex FFT with normalization # # This calls FFW3.fft(na, FFW3::FORWARD, *dims) and normalizes the result # by dividing by the length # def fft_fw(na, *dims) fc = fft(na, FORWARD, *dims) if dims.length == 0 len = na.total else len = 1 shape = na.shape dims.each{|d| len *= shape[d]} end fc / len end # Backward complex FFT # # This method simply calls FFW3.fft(na, FFW3::BACKWARD, *dims) # def fft_bk(na, *dims) fft(na, BACKWARD, *dims) end end end ruby-fftw3-1.0.2/lib/numru/fftw3/0000755000175000017500000000000012752272276016337 5ustar uwabamiuwabamiruby-fftw3-1.0.2/lib/numru/fftw3/version.rb0000644000175000017500000000007412752272276020352 0ustar uwabamiuwabamimodule NumRu module FFTW3 VERSION = "1.0.2" end end ruby-fftw3-1.0.2/Rakefile0000644000175000017500000000166112752272276015043 0ustar uwabamiuwabami# -* coding: utf-8 -*- require 'rake/testtask' require 'rake/extensiontask' require 'rake/packagetask' begin require 'bundler/gem_helper' # instead of 'bundler/gem_tasks' -> need manual # calls of install_tasks (see below) rescue LoadError puts 'If you want to create gem, You must install Bundler' end Bundler::GemHelper.install_tasks(name: "ruby-fftw3") ##Bundler::GemHelper.install_tasks(name: "ruby-fftw3-bigmem") require './lib/numru/fftw3/version.rb' def version NumRu::FFTW3::VERSION end task :default => :test task :test => :compile Rake::TestTask.new do |t| t.libs << 'lib' << 'test' t.test_files = FileList['test/*.rb'] end Rake::ExtensionTask.new do |ext| ext.name = 'fftw3' ext.ext_dir = 'ext/numru/fftw3' ext.lib_dir = 'lib/numru/fftw3' end Rake::PackageTask.new('ruby-fftw3', "#{version}") do |t| t.need_tar_gz = true t.package_files.include `git ls-files`.split("\n") end ruby-fftw3-1.0.2/ext/0000755000175000017500000000000012752272276014172 5ustar uwabamiuwabamiruby-fftw3-1.0.2/ext/numru/0000755000175000017500000000000012752272276015340 5ustar uwabamiuwabamiruby-fftw3-1.0.2/ext/numru/fftw3/0000755000175000017500000000000012752272276016371 5ustar uwabamiuwabamiruby-fftw3-1.0.2/ext/numru/fftw3/na_fftw3.c0000644000175000017500000004743212752272276020256 0ustar uwabamiuwabami/* na_fftw3.c FFT using FFTW Ver.3 (www.fftw.org) (C) Takeshi Horinouchi NO WARRANTY. */ #include #include "narray.h" #include VALUE rb_mFFTW3; VALUE mNumRu; static VALUE #ifdef FFTW3_HAS_SINGLE_SUPPORT na_fftw3_double(int argc, VALUE *argv, VALUE self) /* to be called by na_fftw3 */ #else na_fftw3(int argc, VALUE *argv, VALUE self) /* to be called directly */ #endif { VALUE val, vdir; struct NARRAY *a1, *a2; int i, dir, *shape, *bucket; fftw_plan p; fftw_complex *in, *out; volatile VALUE v1, v2; if (argc<2){ rb_raise(rb_eArgError, "Usage: fft(narray, direction [,dim0,dim1,...])"); } val = argv[0]; vdir = argv[1]; dir = NUM2INT(vdir); if ( dir != 1 && dir != -1 ){ rb_raise(rb_eArgError, "direction should be 1 or -1"); } v1 = na_cast_object(val, NA_DCOMPLEX); GetNArray(v1,a1); v2 = na_make_object( NA_DCOMPLEX, a1->rank, a1->shape, CLASS_OF(v1) ); GetNArray(v2,a2); shape = ALLOCA_N(int, a2->rank); for (i=0; irank; i++){ shape[i] = a2->shape[a2->rank-1-i]; } in = (fftw_complex*)a1->ptr; out = (fftw_complex*)a2->ptr; if (argc==2) { /* apply FFT to all dimensions */ p = fftw_plan_dft( a2->rank, shape, in, out, dir, FFTW_ESTIMATE ); } else { /* apply FFT to selected dimensions (by using the Guru interface) */ { /* introduce a new scope for additonal local variables */ int fft_rank, howmany_rank, j, jf, je, dim; fftw_iodim *fft_dims, *howmany_dims; int *dimids; fft_rank = argc - 2; fft_dims = ALLOCA_N(fftw_iodim, fft_rank); dimids = ALLOCA_N(int, fft_rank); howmany_rank = fft_rank + 1; howmany_dims = ALLOCA_N(fftw_iodim, howmany_rank); for (i=2;irank; /* negative: count from the end */ if (dim<0 || dim>=a2->rank){ rb_raise(rb_eArgError, "dimension < 0 or >= rank"); } dimids[i-2] = a2->rank - 1 - dim; if ( i>2 && dimids[i-2] == dimids[i-3] ){ rb_raise(rb_eArgError, "redundant -- a same dimension is reppeated"); } } /* bukcet sort in increasing order */ bucket = ALLOCA_N(int,a2->rank); for(j=0; jrank; j++) bucket[j] = 0; /* initialize */ for(i=0; irank; j++) { if (bucket[j]==1){ dimids[i] = j; i++; } } for(j=0; jrank ; i++){ fft_dims[j].is *= shape[i]; } fft_dims[j].os = fft_dims[j].is; /* printf("fft_ %d n:%d is:%d\n",j, fft_dims[j].n,fft_dims[j].is);*/ } for(j=0; j<=fft_rank; j++){ howmany_dims[j].n = 1; jf = (j==0) ? 0 : (dimids[j-1]+1) ; je = (j==fft_rank) ? a2->rank : (dimids[j]) ; for (i=jf; irank; i++){ howmany_dims[j].is *= shape[i]; } } howmany_dims[j].os = howmany_dims[j].is; /* printf("how_ %d n:%d is:%d\n",j, howmany_dims[j].n,howmany_dims[j].is); */ } p = fftw_plan_guru_dft( fft_rank, fft_dims, howmany_rank, howmany_dims, in, out, dir, FFTW_ESTIMATE ); } } fftw_execute(p); fftw_destroy_plan(p); return v2; } #ifdef FFTW3_HAS_SINGLE_SUPPORT /* sourse code generation of na_fftw3_float: Copy na_fftw3_double, and replace fftw --> fftwf DCOMPLEX --> SCOMPLEX */ static VALUE na_fftw3_float(int argc, VALUE *argv, VALUE self) { VALUE val, vdir; struct NARRAY *a1, *a2; int i, dir, *shape, *bucket; fftwf_plan p; fftwf_complex *in, *out; volatile VALUE v1, v2; if (argc<2){ rb_raise(rb_eArgError, "Usage: fft(narray, direction [,dim0,dim1,...])"); } val = argv[0]; vdir = argv[1]; dir = NUM2INT(vdir); if ( dir != 1 && dir != -1 ){ rb_raise(rb_eArgError, "direction should be 1 or -1"); } v1 = na_cast_object(val, NA_SCOMPLEX); GetNArray(v1,a1); v2 = na_make_object( NA_SCOMPLEX, a1->rank, a1->shape, CLASS_OF(v1) ); GetNArray(v2,a2); shape = ALLOCA_N(int, a2->rank); for (i=0; irank; i++){ shape[i] = a2->shape[a2->rank-1-i]; } in = (fftwf_complex*)a1->ptr; out = (fftwf_complex*)a2->ptr; if (argc==2) { /* apply FFT to all dimensions */ p = fftwf_plan_dft( a2->rank, shape, in, out, dir, FFTW_ESTIMATE ); } else { /* apply FFT to selected dimensions (by using the Guru interface) */ { /* introduce a new scope for additonal local variables */ int fft_rank, howmany_rank, j, jf, je, dim; fftw_iodim *fft_dims, *howmany_dims; int *dimids; fft_rank = argc - 2; fft_dims = ALLOCA_N(fftw_iodim, fft_rank); dimids = ALLOCA_N(int, fft_rank); howmany_rank = fft_rank + 1; howmany_dims = ALLOCA_N(fftw_iodim, howmany_rank); for (i=2;irank; /* negative: count from the end */ if (dim<0 || dim>=a2->rank){ rb_raise(rb_eArgError, "dimension < 0 or >= rank"); } dimids[i-2] = a2->rank - 1 - dim; if ( i>2 && dimids[i-2] == dimids[i-3] ){ rb_raise(rb_eArgError, "redundant -- a same dimension is reppeated"); } } /* bukcet sort in increasing order */ bucket = ALLOCA_N(int,a2->rank); for(j=0; jrank; j++) bucket[j] = 0; /* initialize */ for(i=0; irank; j++) { if (bucket[j]==1){ dimids[i] = j; i++; } } for(j=0; jrank ; i++){ fft_dims[j].is *= shape[i]; } fft_dims[j].os = fft_dims[j].is; /* printf("fft_ %d n:%d is:%d\n",j, fft_dims[j].n,fft_dims[j].is);*/ } for(j=0; j<=fft_rank; j++){ howmany_dims[j].n = 1; jf = (j==0) ? 0 : (dimids[j-1]+1) ; je = (j==fft_rank) ? a2->rank : (dimids[j]) ; for (i=jf; irank; i++){ howmany_dims[j].is *= shape[i]; } } howmany_dims[j].os = howmany_dims[j].is; /* printf("how_ %d n:%d is:%d\n",j, howmany_dims[j].n,howmany_dims[j].is); */ } p = fftwf_plan_guru_dft( fft_rank, fft_dims, howmany_rank, howmany_dims, in, out, dir, FFTW_ESTIMATE ); } } fftwf_execute(p); fftwf_destroy_plan(p); return v2; } /* * call-seq: * FFTW3.fft(narray, dir [, dim, dim, ...]) * * Conducts complex FFT (unnormalized). You can use more user-friendly wrappers * fft_fw and fft_bk. * * ARGUMENTS * * narray (NArray or NArray-compatible Array) : array to be * transformed. If real, coerced to complex before transformation. * If narray is single-precision and the single-precision * version of FFTW3 is installed (before installing this module), * this method does a single-precision transform. * Otherwise, a double-precision transform is used. * * dir (FORWARD (which is simply equal to -1; * referable as NumRu::FFTW3::FORWARD) or BACKWARD * (which is simply 1) ) : the direction of FFT, * forward if FORWARD and backward if BACKWARD. * * optional 3rd, 4th,... arguments (Integer) : Specifies dimensions * to apply FFT. For example, if 0, the first dimension is * transformed (1D FFT); If -1, the last dimension is used (1D FFT); * If 0,2,4, the first, third, and fifth dimensions * are transformed (3D FFT); If entirely omitted, ALL DIMENSIONS * ARE SUBJECT TO FFT, so 3D FFT is done with a 3D array. * * RETURN VALUE * * a complex NArray * * NOTE * * As in FFTW, return value is NOT normalized. Thus, a consecutive * forward and backward transform would multiply the size of * data used for transform. You can normalize, for example, * the forward transform FFTW.fft(narray, -1, 0, 1) * (FFT regarding the first (dim 0) & second (dim 1) dimensions) by * dividing with (narray.shape[0]*narray.shape[1]). Likewise, * the result of FFTW.fft(narray, -1) (FFT for all dimensions) * can be normalized by narray.length. */ static VALUE na_fftw3(int argc, VALUE *argv, VALUE self) { VALUE val; volatile VALUE v1; struct NARRAY *a1; if (argc<2){ rb_raise(rb_eArgError, "Usage: fft(narray, direction [,dim0,dim1,...])"); } val = argv[0]; v1 = na_to_narray(val); GetNArray(v1,a1); if(a1->type <= NA_SFLOAT || a1->type == NA_SCOMPLEX ){ return( na_fftw3_float(argc, argv, self) ); } else { return( na_fftw3_double(argc, argv, self) ); } } #endif static VALUE #ifdef FFTW3_HAS_SINGLE_SUPPORT na_fftw3_r2r_double(int argc, VALUE *argv, VALUE self) /* to be called by na_fftw3_r2r */ #else na_fftw3_r2r(int argc, VALUE *argv, VALUE self) /* to be called directly */ #endif { VALUE val, vkinds; struct NARRAY *a1, *a2; int i, *shape, *bucket, len; fftw_r2r_kind *kinds; fftw_plan p; double *in, *out; volatile VALUE v1, v2; if (argc<2){ rb_raise(rb_eArgError, "Usage: fft_r2r(narray, kinds [,dim0,dim1,...])"); } val = argv[0]; vkinds = argv[1]; v1 = na_cast_object(val, NA_DFLOAT); GetNArray(v1,a1); v2 = na_make_object( NA_DFLOAT, a1->rank, a1->shape, CLASS_OF(v1) ); GetNArray(v2,a2); shape = ALLOCA_N(int, a2->rank); for (i=0; irank; i++){ shape[i] = a2->shape[a2->rank-1-i]; } in = (double*)a1->ptr; out = (double*)a2->ptr; switch (TYPE(vkinds)) { case T_ARRAY: len = RARRAY_LEN(vkinds); kinds = ALLOCA_N(fftw_r2r_kind, len); for (i = 0; i < len; i++) { kinds[i] = NUM2INT(RARRAY_PTR(vkinds)[len-1-i]);//column- to row-major } break; case T_FIXNUM: if (argc == 2) { len = a1->rank; } else { len = argc-2; } kinds = ALLOCA_N(fftw_r2r_kind, len); for (i = 0; i < len; i++) { kinds[i] = NUM2INT(vkinds); } break; default: rb_raise(rb_eTypeError, "unsupported kinds type"); break; } for (i = 0; i < len; i++) { if ( kinds[i] < FFTW_R2HC || kinds[i] > FFTW_RODFT11 ){ rb_raise(rb_eArgError, "unsupported kind (%d).", kinds[i]); } } if (argc==2) { /* apply FFT to all dimensions */ p = fftw_plan_r2r( a2->rank, shape, in, out, kinds, FFTW_ESTIMATE ); } else { /* apply FFT to selected dimensions (by using the Guru interface) */ { /* introduce a new scope for additonal local variables */ int fft_rank, howmany_rank, j, jf, je, dim; fftw_iodim *fft_dims, *howmany_dims; int *dimids; fft_rank = argc - 2; fft_dims = ALLOCA_N(fftw_iodim, fft_rank); dimids = ALLOCA_N(int, fft_rank); howmany_rank = fft_rank + 1; howmany_dims = ALLOCA_N(fftw_iodim, howmany_rank); for (i=2;irank; /* negative: count from the end */ if (dim<0 || dim>=a2->rank){ rb_raise(rb_eArgError, "dimension < 0 or >= rank"); } dimids[i-2] = a2->rank - 1 - dim; if ( i>2 && dimids[i-2] == dimids[i-3] ){ rb_raise(rb_eArgError, "redundant -- a same dimension is reppeated"); } } /* bukcet sort in increasing order */ bucket = ALLOCA_N(int,a2->rank); for(j=0; jrank; j++) bucket[j] = 0; /* initialize */ for(i=0; irank; j++) { if (bucket[j]==1){ dimids[i] = j; i++; } } for(j=0; jrank ; i++){ fft_dims[j].is *= shape[i]; } fft_dims[j].os = fft_dims[j].is; /* printf("fft_ %d n:%d is:%d\n",j, fft_dims[j].n,fft_dims[j].is);*/ } for(j=0; j<=fft_rank; j++){ howmany_dims[j].n = 1; jf = (j==0) ? 0 : (dimids[j-1]+1) ; je = (j==fft_rank) ? a2->rank : (dimids[j]) ; for (i=jf; irank; i++){ howmany_dims[j].is *= shape[i]; } } howmany_dims[j].os = howmany_dims[j].is; /* printf("how_ %d n:%d is:%d\n",j, howmany_dims[j].n,howmany_dims[j].is); */ } p = fftw_plan_guru_r2r( fft_rank, fft_dims, howmany_rank, howmany_dims, in, out, kinds, FFTW_ESTIMATE ); } } fftw_execute(p); fftw_destroy_plan(p); return v2; } #ifdef FFTW3_HAS_SINGLE_SUPPORT static VALUE na_fftw3_r2r_float(int argc, VALUE *argv, VALUE self) /* to be called by na_fftw3_r2r */ { VALUE val, vkinds; struct NARRAY *a1, *a2; int i, *shape, *bucket, len; fftwf_r2r_kind *kinds; fftwf_plan p; float *in, *out; volatile VALUE v1, v2; if (argc<2){ rb_raise(rb_eArgError, "Usage: fft_r2r(narray, kinds [,dim0,dim1,...])"); } val = argv[0]; vkinds = argv[1]; v1 = na_cast_object(val, NA_SFLOAT); GetNArray(v1,a1); v2 = na_make_object( NA_SFLOAT, a1->rank, a1->shape, CLASS_OF(v1) ); GetNArray(v2,a2); shape = ALLOCA_N(int, a2->rank); for (i=0; irank; i++){ shape[i] = a2->shape[a2->rank-1-i]; } in = (float*)a1->ptr; out = (float*)a2->ptr; switch (TYPE(vkinds)) { case T_ARRAY: len = RARRAY_LEN(vkinds); kinds = ALLOCA_N(fftwf_r2r_kind, len); for (i = 0; i < len; i++) { kinds[i] = NUM2INT(RARRAY_PTR(vkinds)[len-1-i]);//column- to row-major } break; case T_FIXNUM: if (argc == 2) { len = a1->rank; } else { len = argc-2; } kinds = ALLOCA_N(fftwf_r2r_kind, len); for (i = 0; i < len; i++) { kinds[i] = NUM2INT(vkinds); } break; default: rb_raise(rb_eTypeError, "unsupported kinds type"); break; } for (i = 0; i < len; i++) { if ( kinds[i] < FFTW_R2HC || kinds[i] > FFTW_RODFT11 ){ rb_raise(rb_eArgError, "unsupported kind (%d).", kinds[i]); } } if (argc==2) { /* apply FFT to all dimensions */ p = fftwf_plan_r2r( a2->rank, shape, in, out, kinds, FFTW_ESTIMATE ); } else { /* apply FFT to selected dimensions (by using the Guru interface) */ { /* introduce a new scope for additonal local variables */ int fft_rank, howmany_rank, j, jf, je, dim; fftwf_iodim *fft_dims, *howmany_dims; int *dimids; fft_rank = argc - 2; fft_dims = ALLOCA_N(fftwf_iodim, fft_rank); dimids = ALLOCA_N(int, fft_rank); howmany_rank = fft_rank + 1; howmany_dims = ALLOCA_N(fftwf_iodim, howmany_rank); for (i=2;irank; /* negative: count from the end */ if (dim<0 || dim>=a2->rank){ rb_raise(rb_eArgError, "dimension < 0 or >= rank"); } dimids[i-2] = a2->rank - 1 - dim; if ( i>2 && dimids[i-2] == dimids[i-3] ){ rb_raise(rb_eArgError, "redundant -- a same dimension is reppeated"); } } /* bukcet sort in increasing order */ bucket = ALLOCA_N(int,a2->rank); for(j=0; jrank; j++) bucket[j] = 0; /* initialize */ for(i=0; irank; j++) { if (bucket[j]==1){ dimids[i] = j; i++; } } for(j=0; jrank ; i++){ fft_dims[j].is *= shape[i]; } fft_dims[j].os = fft_dims[j].is; /* printf("fft_ %d n:%d is:%d\n",j, fft_dims[j].n,fft_dims[j].is);*/ } for(j=0; j<=fft_rank; j++){ howmany_dims[j].n = 1; jf = (j==0) ? 0 : (dimids[j-1]+1) ; je = (j==fft_rank) ? a2->rank : (dimids[j]) ; for (i=jf; irank; i++){ howmany_dims[j].is *= shape[i]; } } howmany_dims[j].os = howmany_dims[j].is; /* printf("how_ %d n:%d is:%d\n",j, howmany_dims[j].n,howmany_dims[j].is); */ } p = fftwf_plan_guru_r2r( fft_rank, fft_dims, howmany_rank, howmany_dims, in, out, kinds, FFTW_ESTIMATE ); } } fftwf_execute(p); fftwf_destroy_plan(p); return v2; } /* * call-seq: * FFTW3.fft_r2r(narray, kind [, dim, dim, ...]) * * Conducts real FFT (unnormalized). * * ARGUMENTS * * narray (NArray or NArray-compatible Array) : array to be * transformed. Cannot be complex. * * kind : specifies the kind of FFT. One of the following: * R2HC, HC2R, DHT, REDFT00, REDFT01, REDFT10, REDFT11, RODFT00, RODFT01, * RODFT10, or RODFT11 (referable as NumRu::FFTW3::REDFT10). See Ch.2 of * http://www.fftw.org/fftw3_doc/ (http://www.fftw.org/fftw3.pdf). * * optional 3rd, 4th,... arguments (Integer) : See FFTW3.fft. * * * RETURN VALUE * * a real NArray * * NOTE * * As in FFTW, return value is NOT normalized, and the length needed * normalize is different for each kind. */ static VALUE na_fftw3_r2r(int argc, VALUE *argv, VALUE self) { VALUE val; volatile VALUE v1; struct NARRAY *a1; if (argc<2){ rb_raise(rb_eArgError, "Usage: fft_r2r(narray, kinds [,dim0,dim1,...])"); } val = argv[0]; v1 = na_to_narray(val); GetNArray(v1,a1); if(a1->type <= NA_SFLOAT || a1->type == NA_SCOMPLEX ){ return( na_fftw3_r2r_float(argc, argv, self) ); } else { return( na_fftw3_r2r_double(argc, argv, self) ); } } #endif void Init_fftw3() { mNumRu = rb_define_module("NumRu"); rb_mFFTW3 = rb_define_module_under(mNumRu, "FFTW3"); rb_define_module_function(rb_mFFTW3, "fft", na_fftw3, -1); rb_define_module_function(rb_mFFTW3, "fft_r2r", na_fftw3_r2r, -1); /* Specifier of forward complex FFT. Integer equal to -1. */ #ifdef NARRAY_BIGMEM rb_define_const(rb_mFFTW3, "SUPPORT_BIGMEM", Qtrue); #else rb_define_const(rb_mFFTW3, "SUPPORT_BIGMEM", Qfalse); #endif rb_define_const(rb_mFFTW3, "FORWARD", INT2NUM(FFTW_FORWARD)); /* Specifier of backward complex FFT. Integer equal to 1. */ rb_define_const(rb_mFFTW3, "BACKWARD", INT2NUM(FFTW_BACKWARD)); /* Specifier of real FFT kind. real to "halfcomplex" */ rb_define_const(rb_mFFTW3, "R2HC", INT2NUM(FFTW_R2HC)); /* Specifier of real FFT kind. "halfcomplex" to real */ rb_define_const(rb_mFFTW3, "HC2R", INT2NUM(FFTW_HC2R)); /* Specifier of real FFT kind. Discrete Hartley Transform */ rb_define_const(rb_mFFTW3, "DHT", INT2NUM(FFTW_DHT)); /* Specifier of real FFT kind. cosine (even) transform; logical data length 2*(n-1); inverse is itself */ rb_define_const(rb_mFFTW3, "REDFT00", INT2NUM(FFTW_REDFT00)); /* Specifier of real FFT kind. cosine (even) transform; * logical data length 2*n; inverse is REDFT10 */ rb_define_const(rb_mFFTW3, "REDFT01", INT2NUM(FFTW_REDFT01)); /* Specifier of real FFT kind. cosine (even) transform; * logical data length 2*n; inverse is REDFT01 */ rb_define_const(rb_mFFTW3, "REDFT10", INT2NUM(FFTW_REDFT10)); /* Specifier of real FFT kind. cosine (even) transform; * logical data length 2*n; inverse is itself */ rb_define_const(rb_mFFTW3, "REDFT11", INT2NUM(FFTW_REDFT11)); /* Specifier of real FFT kind. sine (odd) transform; * logical data length 2*(n+1); inverse is itself */ rb_define_const(rb_mFFTW3, "RODFT00", INT2NUM(FFTW_RODFT00)); /* Specifier of real FFT kind. sine (odd) transform; * logical data length 2*n; inverse is RODFT10 */ rb_define_const(rb_mFFTW3, "RODFT01", INT2NUM(FFTW_RODFT01)); /* Specifier of real FFT kind. sine (odd) transform; * logical data length 2*n; inverse is RODFT01 */ rb_define_const(rb_mFFTW3, "RODFT10", INT2NUM(FFTW_RODFT10)); /* Specifier of real FFT kind. sine (odd) transform; * logical data length 2*n; inverse is itself */ rb_define_const(rb_mFFTW3, "RODFT11", INT2NUM(FFTW_RODFT11)); } ruby-fftw3-1.0.2/ext/numru/fftw3/extconf.rb0000644000175000017500000000376112752272276020373 0ustar uwabamiuwabamirequire "mkmf" require "rubygems" unless defined?(Gem) dir_config('fftw3','/usr/local') require "rbconfig" so = RbConfig::CONFIG["DLEXT"] raise("Your gem is too old") unless Gem.respond_to?(:find_files) env = ENV['NARRAY_TYPE'] if env == "NArray" || env == "narray" na_type = "narray" elsif env == "NumRu::NArray" || env == "numru-narray" na_type = "numru-narray" elsif !env.nil? raise "Unsupported value for the environment variable NARRAY_TYPE: #{env}" else if Gem.find_files("narray.h").length > 0 na_type = "narray" elsif Gem.find_files("numru/narray/narray.h").length > 0 na_type = "numru-narray" end end case na_type when "narray" narray_include = File.expand_path(File.dirname(Gem.find_files("narray.h")[0])) narray_lib = File.expand_path(File.dirname(Gem.find_files("narray." + so)[0])) when "numru-narray" narray_include = File.expand_path(File.dirname(Gem.find_files("numru/narray/narray.h")[0])) narray_lib = File.expand_path(File.dirname(Gem.find_files("numru/narray/narray." + so)[0])) end dir_config('narray', narray_include, narray_lib) if ( ! ( have_header("narray.h") && have_header("narray_config.h") ) ) then print <<-EOS ** configure error ** Header narray.h or narray_config.h is not found. If you have these files in /narraydir/include, try the following: % ruby extconf.rb --with-narray-include=/narraydir/include EOS exit(-1) end if ( ! ( have_header("fftw3.h") && have_library("fftw3") ) ) then print < BSD 2-clause license M ChangeLog M LICENSE.txt 2011-04-12 Takeshi Horinouchi Tue Apr 12 2011 T Horinouchi * LICENSE.txt: changed M ChangeLog M LICENSE.txt 2011-03-24 Takeshi Horinouchi (tag: ruby-fftw3-0_3) Thu Mar 24 2011 T Horinouchi * version 0.3 released (cvs tag ruby-fftw3-0_3) * LICENSE.txt: added M ChangeLog A LICENSE.txt 2004-06-07 Takeshi Horinouchi (tag: ruby-fftw3-0_2) *** empty log message *** D doc/fftw3.html D doc/fftw3.rd A doc/ruby-fftw3.html A doc/ruby-fftw3.rd 2004-06-07 Takeshi Horinouchi Mon Jun 7 2004 T Horinouchi < T Koshiro * version 0.2 released (cvs tag ruby-fftw3-0_2) * extconf.rb: improved M ChangeLog M extconf.rb 2004-06-07 Takeshi Horinouchi Initial revision A ChangeLog A ToDo A doc/fftw3.html A doc/fftw3.rd A extconf.rb A na_fftw3.c A test/complexFFT.rb ruby-fftw3-1.0.2/Gemfile0000644000175000017500000000013712752272276014666 0ustar uwabamiuwabamisource 'https://rubygems.org' # Specify your gem's dependencies in ruby-fftw3.gemspec gemspec