本ライブラリは,現段階(ver. 0.0.2a, 02/02/12 現在)では以下の環境で製作,動作確認をしている.
Ruby 1.6.5 (2001-10-05) [i386-linux]
gcc version 2.95.2 20000220 (Debian GNU/Linux)
Debian GNU/Linux 2.2 (potato)
入出力ライブラリ
高速フーリエ変換ライブラリ
本ライブラリのインストールに際しては,これらのライブラリを先にインストールしておく必要がある.個々のライブラリのインストール方法については,それぞれの付属ドキュメントに譲る.
FFTWを利用する際には,次の関数を用いている.
ソースコードは,以下のような構成になっている.
以下に,fft_fftw.cソースコード全文を示す.
#include "na_fft.h" #include <fftw.h> #include <rfftw.h> #ifdef FFTW_ENABLE_FLOAT # define NA_FFTW_REAL NA_SFLOAT # define NA_FFTW_COMP NA_SCOMPLEX # define COMP_T scomplex #else # define NA_FFTW_REAL NA_DFLOAT # define NA_FFTW_COMP NA_DCOMPLEX # define COMP_T dcomplex #endif typedef enum { FFT_NO, FFT_YES } DOING_FFT_DIM_FLAG; /**** prototype declaration ****/ VALUE fft_fftw(int argc, VALUE *argv, VALUE self); VALUE ffti_fftw(int argc, VALUE *argv, VALUE self); static NA *fft_sub(int argc, VALUE *argv, VALUE self, fftw_direction dir); static NA *fft_DCOMPLEX(int arg_c, int *arg_v, NA *na, fftw_direction dir); static NA *fft_SCOMPLEX(int arg_c, int *arg_v, NA *na, fftw_direction dir); static void check_argv(int argc, int *argv, int rank); /**** end prototype ****/ VALUE fft_fftw(int argc, VALUE *argv, VALUE self) { NA *na; na=ALLOC(NA); na=fft_sub(argc, argv, self, FFTW_FORWARD); return Data_Wrap_Struct(cNArray, 0, na_free, na); } VALUE ffti_fftw(int argc, VALUE *argv, VALUE self) { NA *na; na=ALLOC(NA); na=fft_sub(argc, argv, self, FFTW_BACKWARD); return Data_Wrap_Struct(cNArray, 0, na_free, na); } NA * fft_sub(int argc, VALUE *argv, VALUE self, fftw_direction dir) { NA *na; int *arg_v, arg_c, *temp_argv; int n; /* functions used in this function */ static NA *fft_DCOMPLEX(); static NA *fft_SCOMPLEX(); static void check_argv(); GetNArray(self, na); if(argc){ temp_argv=ALLOCA_N(int,argc); for(n=0 ; n<argc ; n++){ temp_argv[n]=NUM2INT(argv[n]); } } /* 引数が一個以上のときチェック。以下の条件でエラーをレイズ。 ・一個で、引数の中身が rank 以上のとき ・二個以上で、 * 負の数を含むとき * 引数の中身が rank 以上のとき */ check_argv(argc, temp_argv, na->rank); /* VALUE argv[] => FFT_OP arg_v[rank] */ arg_v=ALLOCA_N(int,na->rank); for(n=0 ; n<(na->rank) ; n++) arg_v[n] = FFT_NO ; /* initializing int arg_v[rank] */ if(argc==0){ /* 引数 なし */ for(n=0 ; n<(na->rank) ; n++){ arg_v[n] = FFT_YES ; } }else if(argc==1){ if(*temp_argv<0){ /* 引数一個 で、負のとき */ for(n=0 ; n<(na->rank) ; n++){ arg_v[n] = FFT_YES; } }else{ /* 引数一個 で、正のとき */ arg_v[ *temp_argv ] = FFT_YES ; } } else{ /* 引数 二個以上 */ for(n=0 ; n<argc ;n++) arg_v[ temp_argv[n] ] = FFT_YES ; } switch(na->type){ case NA_DCOMPLEX: return fft_DCOMPLEX(arg_c, arg_v, na, dir); case NA_SCOMPLEX: return fft_SCOMPLEX(arg_c, arg_v, na, dir); default: rb_raise(rb_eTypeError, "operand is not valid type"); } } NA * fft_DCOMPLEX(int arg_c, int *arg_v, NA *na, fftw_direction dir) { fftw_plan p; int n, m, rank,total, howmany, dim, length; dcomplex *ptr; char *new_ptr; int idist, istride; NA *ret_na; rank = na->rank; total = na->total; ptr = (dcomplex *)na->ptr; new_ptr = ALLOC_N( char , sizeof(fftw_complex) * na->total ); for(dim=0 ; dim<(na->rank) ; dim++){ if(arg_v[dim]==FFT_YES){ if(dim == 0){ p = fftw_create_plan(na->shape[dim], dir, FFTW_ESTIMATE); if(p==NULL) rb_raise(rb_eRuntimeError,"cannot allocate FFTW plan"); idist = na->shape[0]; istride = 1; howmany = total / na->shape[0]; fftw(p, howmany, (fftw_complex *)ptr , istride, idist, (fftw_complex *)new_ptr, istride, idist); fftw_destroy_plan(p); }else if(dim == rank - 1){ p = fftw_create_plan(na->shape[dim], dir, FFTW_ESTIMATE); if(p==NULL) rb_raise(rb_eRuntimeError,"cannot allocate FFTW plan"); idist = 1; istride = howmany = total / na->shape[rank - 1]; fftw(p, howmany, (fftw_complex *)ptr , istride, idist, (fftw_complex *)new_ptr, istride, idist); fftw_destroy_plan(p); }else{ idist = 1; istride = 1; /* initialize */ for(m=0 ; m<dim ; m++) istride = istride * na->shape[m]; howmany = istride; length = istride * na->shape[dim]; p = fftw_create_plan(na->shape[dim], dir, FFTW_ESTIMATE); if(p==NULL) rb_raise(rb_eRuntimeError,"cannot allocate FFTW plan"); for(m=0 ; m<total ; m += length){ fftw(p, howmany, (fftw_complex *)&ptr[m] , istride, idist, (fftw_complex *)&new_ptr[m], istride, idist); } fftw_destroy_plan(p); } } } ret_na = na_alloc_struct(NA_FFTW_COMP, rank, na->shape); ret_na->ptr = new_ptr; return ret_na; } NA * fft_SCOMPLEX(int arg_c, int *arg_v, NA *na, fftw_direction dir) { int n; NA *dcmp_na; dcomplex *dcmp_ptr; scomplex *scmp_ptr; dcmp_na = na_alloc_struct(NA_DCOMPLEX, na->rank, na->shape); dcmp_ptr = ALLOC_N(dcomplex ,na->total); scmp_ptr = (scomplex *)na->ptr; for(n=0 ; n<(na->total) ; n++){ dcmp_ptr[n].r = scmp_ptr[n].r; dcmp_ptr[n].i = scmp_ptr[n].i; } dcmp_na->ptr = (char *)dcmp_ptr; return fft_DCOMPLEX(arg_c, arg_v, dcmp_na, dir); } static void check_argv(int argc, int *argv, int rank) { int n; if(argc>rank) rb_raise(rb_eArgError, "too many arguments"); if(argc==1){ if( (*argv)>(rank-1) ) rb_raise(rb_eArgError, "invalid value"); }else if(argc>1){ for(n=0 ; n<argc ; n++){ if( argv[n]>(rank-1) || argv[n]<0 ) rb_raise(rb_eArgError, "invalid value"); } } return; } void Init_fft(void) { rb_define_method(cNArray, "fft" ,fft_fftw , -1); rb_define_method(cNArray, "ffti" ,ffti_fftw , -1); /*rb_define_method(cNArray, "rfft" ,rfft_fftw , -1); */ /*rb_define_method(cNArray, "rffti" ,rffti_fftw , -1); */ } |
以下に,na_fft.h全文を示す.
#include <ruby.h> enum NArray_Types { NA_NONE, NA_BYTE, /* 1 */ NA_SINT, /* 2 */ NA_LINT, /* 3 */ NA_SFLOAT, /* 4 */ NA_DFLOAT, /* 5 */ NA_SCOMPLEX, /* 6 */ NA_DCOMPLEX, /* 7 */ NA_ROBJ, /* 8 */ NA_NTYPES /* 9 */ }; struct NARRAY { int rank; /* # of dimension */ int total; /* # of total element */ int type; /* data type */ int *shape; char *ptr; /* pointer to data */ VALUE ref; /* NArray object wrapping this structure */ }; typedef struct { float r,i; } scomplex; typedef struct { double r,i; } dcomplex; typedef struct NARRAY NA; /* fft_fftw.c */ VALUE cNArray; VALUE fft_fftw(int argc, VALUE *argv, VALUE self); VALUE ffti_fftw(int argc, VALUE *argv, VALUE self); void Init_fft(void); /* fft_narray.c */ struct NARRAY *na_alloc_struct(int type, int rank, int *shape); void na_free(struct NARRAY *ary); /* copy from narray.h */ #define GetNArray(obj,var) Data_Get_Struct(obj, struct NARRAY, var) |
本ライブラリは,未だ開発の途上であり,さらなる拡張の余地を残している.現在のバージョンでは,FFTWライブラリの複素フーリエ正変換および逆変換に対応しているのみで,実数正変換,および逆変換には対応しておらず,ISPACKについては完全に未実装である.
今後の予定としては,以下のようになっている.
次回リリースでは,ISPACKによるサイン変換,コサイン変換を組みこむこと,NArrayライブラリに対するパッチの形式でリリースすることの二点を目指して開発を続けて行きたい.