ruby-fftw3-0.4/0000755000175000017500000000000011553222346013670 5ustar horinouthorinoutruby-fftw3-0.4/ChangeLog0000644000175000017500000000150311553222314015434 0ustar horinouthorinoutTue 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-0.4/LICENSE.txt0000644000175000017500000000326511553216025015516 0ustar horinouthorinoutRuby-FFTW3 is copyrighted free software by Takeshi Horinouchi and GFD Dennou Club (http://www.gfd-dennou.org/). Copyright 2001 (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-0.4/test/0000755000175000017500000000000011553222346014647 5ustar horinouthorinoutruby-fftw3-0.4/test/complexFFT.rb0000644000175000017500000000162011553220212017170 0ustar horinouthorinoutrequire "numru/fftw3" include NumRu print "\n**TEST** all dimensions\n\n" na = NArray.float(8,4).fill(1) # will be corced to complex na[1,1]=5 p na fc = FFTW3.fft(na, -1)/na.length p fc p fc.real p FFTW3.fft(fc, 1).real print "\n**TEST** single float (treated as single if lib fftw3f exits)\n" print " --- see http://www.fftw.org/fftw3_doc/Precision.html for more info\n\n" na = NArray.sfloat(8,4).indgen! fc = FFTW3.fft(na, -1)/na.length p fc p FFTW3.fft(fc, 1).real print "\n**TEST** dimension selection\n\n" fc = FFTW3.fft(na, -1, 0)/na.shape[0] p fc p FFTW3.fft(fc, 1, 0).real fc = FFTW3.fft(na, -1, 1)/na.shape[1] p fc p FFTW3.fft(fc, 1, 1).real na = NArray.float(4,3,8,3) na[1,1,1,0]= 1 p( fc=FFTW3.fft(na, -1, 0,2) / (na.shape[0]*na.shape[2]) ) p( fc=FFTW3.fft(na, -1, 1) / na.shape[1] ) p( fc=FFTW3.fft(na, -1, 0,1,2) / (na.shape[0]*na.shape[1]*na.shape[2]) ) p FFTW3.fft(fc, 1, 0,1,2).real ruby-fftw3-0.4/na_fftw3.c0000644000175000017500000001643011553220212015535 0ustar horinouthorinout/* 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: fftw(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, ib, 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: fftw(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, ib, 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; } 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: fftw(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 void Init_fftw3() { rb_require("narray"); mNumRu = rb_define_module("NumRu"); rb_mFFTW3 = rb_define_module_under(mNumRu, "FFTW3"); rb_define_module_function(rb_mFFTW3, "fft", na_fftw3, -1); } ruby-fftw3-0.4/extconf.rb0000644000175000017500000000217610061045606015664 0ustar horinouthorinoutrequire "mkmf" dir_config('narray',$sitearchdir,$sitearchdir) dir_config('fftw3','/usr/local') 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 <)) Ver.3. Takeshi Horinouchi (C) Takeshi Horinouchi / GFD Dennou Club, 2003 NO WARRANTY ==Features * Uses (()). * Multi-dimensional complex FFT. (Real data are coerced to complex). * Supports both double and single float transforms. * Not normalized as in FFTW ==Features yet to be introduced * Sine / cosine transforms * User choice of optimization levels (i.e., FFTW_MEASURE etc in addition to FFTW_ESTIMATE). * Multi-threaded FFT3 support -- don't know whether it's really feasible. ==Installation * Install (()) Ver.3. * NOTE: To activate the single-float transform, you have to install FFTW3 with the single-float compilation, in addition to the default double-float version. This can be done by configuring FFTW3 with the --enable-float option, and install it again. The single-float version will coexist with the double-float version. If you do not install the single-float version, FFT is always done with the double precision, which is not bad if you are not time- and memory-conscious. * Install (()). * Then, install this library as follows (replace "version" with the actual version number): % tar xvzf fftw3-version.tar.gz % cd fftw3-version % ruby extconf.rb % make % make site-install Or % make install (If you are using Ruby 1.8, make install is the same make site-install.) ==How to use See the following peice of code. (Install this library and copy and paste the following to the interactive shell irb). require "numru/fftw3" include NumRu na = NArray.float(8,6) # float -> will be corced to complex na[1,1]=1 # fc = FFTW3.fft(na, -1)/na.length # forward 2D FFT and normalization nc = FFTW3.fft(fc, 1) # backward 2D FFT (complex) --> nb = nc.real # should be equal to na except round errors # fc = FFTW3.fft(na, -1, 0) / na.shape[0] # forward FFT with the first dim # fc = FFTW3.fft(na, -1, 1) / na.shape[1] # forward FFT with the second dim ==API Reference ===Module methods ---fft(narray, dir [,dim,dim,...]) Complex FFT. The 3rd, 4th,... arguments are optional. 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 (-1 or 1) : forward transform if -1; backward transform if 1. * 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. ruby-fftw3-0.4/doc/ruby-fftw3.html0000644000175000017500000001161211553222276017336 0ustar horinouthorinout ruby-fftw3.rd

module NumRu::FFTW3

Fast Fourier Transforms by using FFTW Ver.3.

Takeshi Horinouchi

(C) Takeshi Horinouchi / GFD Dennou Club, 2003

NO WARRANTY

Features

  • Uses NArray.
  • Multi-dimensional complex FFT. (Real data are coerced to complex).
  • Supports both double and single float transforms.
  • Not normalized as in FFTW

Features yet to be introduced

  • Sine / cosine transforms
  • User choice of optimization levels (i.e., FFTW_MEASURE etc in addition to FFTW_ESTIMATE).
  • Multi-threaded FFT3 support -- don't know whether it's really feasible.

Installation

  • Install FFTW Ver.3.
    • NOTE: To activate the single-float transform, you have to install FFTW3 with the single-float compilation, in addition to the default double-float version. This can be done by configuring FFTW3 with the --enable-float option, and install it again. The single-float version will coexist with the double-float version. If you do not install the single-float version, FFT is always done with the double precision, which is not bad if you are not time- and memory-conscious.
  • Install NArray.
  • Then, install this library as follows (replace "version" with the actual version number):

    % tar xvzf fftw3-version.tar.gz
    % cd fftw3-version
    % ruby extconf.rb
    % make
    % make site-install

    Or

    % make install

    (If you are using Ruby 1.8, make install is the same make site-install.)

How to use

See the following peice of code. (Install this library and copy and paste the following to the interactive shell irb).

require "numru/fftw3"
include NumRu

na = NArray.float(8,6)   # float -> will be corced to complex
na[1,1]=1

# <example 1>
fc = FFTW3.fft(na, -1)/na.length  # forward 2D FFT and normalization
nc = FFTW3.fft(fc, 1)       # backward 2D FFT (complex) --> 
nb = nc.real                # should be equal to na except round errors  

# <example 2>
fc = FFTW3.fft(na, -1, 0) / na.shape[0]  # forward FFT with the first dim

# <example 3>
fc = FFTW3.fft(na, -1, 1) / na.shape[1]  # forward FFT with the second dim

API Reference

Module methods

fft(narray, dir [,dim,dim,...])

Complex FFT.

The 3rd, 4th,... arguments are optional.

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 (-1 or 1) : forward transform if -1; backward transform if 1.
  • 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.
ruby-fftw3-0.4/ToDo0000644000175000017500000000017110061044456014454 0ustar horinouthorinout2003/11/18 * enable users to choose FFTW_MEASURE etc * support real-to-real tranforms (esp. sine and cosine transforms)