narray-bigmem 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/SPEC.ja ADDED
@@ -0,0 +1,307 @@
1
+
2
+ Ruby/NArray ver 0.6.0.7 (2013-02-01) by Masahiro TANAKA
3
+
4
+
5
+ クラスメソッド:
6
+ NArray.new(typecode, size, ...) 配列を生成する。要素は0で初期化。
7
+
8
+ NArray.byte(size,...) 1 byte unsigned integer
9
+ NArray.sint(size,...) 2 byte signed integer
10
+ NArray.int(size,...) 4 byte signed integer
11
+ NArray.sfloat(size,...) single precision float
12
+ NArray.float(size,...) double precision float
13
+ NArray.scomplex(size,...) single precision complex
14
+ NArray.complex(size,...) double precision complex
15
+ NArray.object(size,...) Ruby object
16
+ 以上要素は0またはnilで初期化。
17
+
18
+ NArray.to_na(array) NArrayに変換
19
+ NArray.to_na(string,type[,size,..])
20
+ NArray[...]
21
+ NArray[1,5,10.0] #=> NArray.float(3):[1.0, 5.0, 10.0]
22
+ NArray[1..10] #=> NArray.int(10):[1,2,3,4,5,6,7,8,9,10]
23
+
24
+
25
+ クラス変数:
26
+ CLASS_DIMENSION データとして扱われる次元。
27
+ NArrayは0。NVectorは1。NMatrixは2。
28
+
29
+ 配列情報参照
30
+ self.dim 次元(インデックスの数)を返す。
31
+ self.rank 次元(インデックスの数)を返す。
32
+ self.shape 次元ごとのサイズを返す。
33
+ self.total 全要素数を返す。
34
+
35
+ インデックス参照
36
+ self[ dim0, dim1, ... ]
37
+
38
+ -- インデックス引数に指定できるもの: 数値、範囲、配列、true, false
39
+ -- インデックスの順序: FORTRAN 型
40
+ -- 添字引数が1つの場合、多次元配列はflattenされた1次元配列とみなされる。
41
+ 例: a が 3x3 配列のとき、a[3] は a[0,1] の要素を指す。
42
+
43
+ a[ 1, 2, -1 ] 要素の取り出し。負数は最後から数える(-1が最後)
44
+ 要素指定の次元は縮約される。
45
+ a[ 0..3, 4..1 ] 範囲取り出し。範囲の最後が最初より前ならば逆順になる。
46
+ a[ [1,4,2] ] インデックス配列。要素が[a[1],a[4],a[2]]のNArrayが返る。
47
+ a[] a.dup と同じ。
48
+ a[ 0, true ] a[0, 0..-1] と同じ。
49
+ a[ 0, false ] aが3次元のとき、a[0,true,true] と同じ。
50
+ 省略された次元すべてにtrueを指定したのと同じ。
51
+ a[ mask ] マスキング. mask は長さが a と等しい byte 型
52
+ NArray. mask の各要素の値に応じて、a のそれぞ
53
+ れは落される(0の場合)か、保持される(0以外の場合)。
54
+ 例:
55
+ a=NArray.float(2,2).indgen!
56
+ p a[ a.lt 3 ]
57
+ --> [ 0.0, 1.0, 2.0 ]
58
+ (a.lt 3 は byte 型 NArray を返す)
59
+ (同じことは a[ (a.lt 3).where ] でも出来る)
60
+
61
+ -- self.slice(...) self[...] と同じだが、長さが1になった次元を落
62
+ さず(self[]は落す)、もとのランクを保つ。但し、
63
+ 1次元インデックス付けとマスキングは例外([]と同
64
+ じ)。
65
+
66
+ インデックス代入。-- 取出しとほぼ同じルール。
67
+
68
+ a[ 1, 2, 3 ] = 1
69
+ a[ 0..3, 1..4, 2..5 ] = 2
70
+ a[ [1,3,2,4], true ] = 3
71
+ a[] = 4 a.fill!(4) と同じ。
72
+
73
+ a[0..2] = b[1..5] --> 要素数が異なるのでエラー。
74
+ a[1,2] = b[0..2,1..3] [1,2]を始点として代入。
75
+ a[0..2,0..3] = b[0..2,1] 繰り返し代入。
76
+ ( a[0,0]=b[0,1],..,a[0,3]=b[0,1] )
77
+
78
+ 行・列の削除 -- インデックス取り出しの逆
79
+
80
+ self.delete_at(...) 引数はインデクス参照と同じ。
81
+ 参照: https://github.com/masa16/narray/issues/5
82
+
83
+ 値のセット。
84
+ self.indgen!([start[,step]]) startからstepづつ増加した値をセット。
85
+ self.fill!(value) すべての要素にvalueをセット。
86
+ self.random!(max) 0<=x<max の一様なランダム値を生成。
87
+ using MT19337
88
+ self.randomn 平均0、分散1の正規分布のランダム値を生成。
89
+ (Box-Muller)
90
+ NArray.srand([seed]) 乱数のシードを設定。
91
+ 省略時は時刻から自動生成。
92
+
93
+ 演算: 要素ごとにおこなう。
94
+ a = NArray.float(3,3).indgen
95
+ b = NArray.float(3,3).fill(10)
96
+ c = a*b # --> NArray.float(3,3)
97
+
98
+ a = NArray.float(3,1).indgen
99
+ b = NArray.float(1,3).fill(10)
100
+ c = a*b # --> NArray.float(3,3) -- size=1の次元は拡張する。
101
+
102
+ 算術演算子
103
+ -self
104
+ self + other
105
+ self - other
106
+ self * other
107
+ self / other
108
+ self % other
109
+ self ** other
110
+ self.abs
111
+
112
+ self.add! other
113
+ self.sbt! other
114
+ self.mul! other
115
+ self.div! other
116
+ self.mod! other
117
+
118
+ self.mul_add(other,dim,...) (self * other).sum(dim,...)とほぼ同じ。
119
+ ただし途中で配列を作らない。
120
+
121
+ ビット演算子(整数のみ可能)
122
+ ~self
123
+ self & other
124
+ self | other
125
+ self ^ other
126
+
127
+ 比較
128
+ -- 要素ごとに値を比較し、結果をBYTE型 NArrayを返す。
129
+ true/falseでないことに注意。
130
+ self.eq other ( == とは異なることに注意)
131
+ self.ne other
132
+ self.gt other
133
+ self > other
134
+ self.ge other
135
+ self >= other
136
+ self.lt other
137
+ self < other
138
+ self.le other
139
+ self <= other
140
+
141
+ self.and other 要素ごとの条件比較。
142
+ self.or other
143
+ self.xor other
144
+ self.not other
145
+
146
+ self.all? 要素がすべて真ならば真。
147
+ self.any? 要素のどれかが真ならば真。
148
+ self.none? 要素のどれかが真ならば真。
149
+ self.where 要素が真のインデックス配列を返す。
150
+ self.where2 要素が真と偽のインデックス配列を含む(Ruby)配列を返す。
151
+
152
+ 例: idx_t,idx_f = (a>12).where2
153
+
154
+ 同値性
155
+ NArray[1] == NArray[1] #=> true
156
+ NArray[1] == NArray[1.0] #=> true
157
+ NArray[1].eql? NArray[1] #=> true
158
+ NArray[1].eql? NArray[1.0] #=> false
159
+ NArray[1].equal? NArray[1] #=> false
160
+ a=b=NArray[1]; a.equal? b #=> true
161
+
162
+ 統計
163
+ self.sum(dim,..) 指定した次元の和
164
+ self.cumsum 累積和(1次元配列のみ)
165
+ self.prod(dim,..) 指定した次元の積
166
+ self.cumprod 累積積(1次元配列のみ)
167
+ self.mean(dim,..) 指定した次元の平均。
168
+ self.stddev(dim,..) 指定した次元の標準偏差(標本標準偏差)。
169
+ self.rms(dim,..) 指定した次元のroot mean square。
170
+ self.rmsdev(dim,..) 指定した次元のroot mean square deviation。
171
+ self.min(dim,..) 指定した次元の最小。
172
+ self.max(dim,..) 指定した次元の最大。
173
+ (省略時は全ての次元。Range指定可。)
174
+ self.median(dim) 0..dimの次元の中央値。省略時はすべての次元。
175
+
176
+ ソート
177
+ self.sort(dim) 0..dimの次元でソート。省略時はすべての次元。
178
+ self.sort_index(dim) ソートしたインデックスを返す。
179
+ self[self.sort_index] は self.sort と同等。
180
+
181
+ 転置
182
+ self.transpose( dim0, dim1, .. )
183
+ 配列の転置。selfの第(dim0)次元が新しい配列の第0次元になる。
184
+ 負数は後からの順番。
185
+ transpose(-1,1..-2,0) で最初と最後を入れ換え。
186
+
187
+ インデックスの変更 (要素数は不変)
188
+ self.reshape!(size,...)
189
+ self.shape= size,...
190
+ self.newdim!(dim,...) 指定位置にサイズ1の次元を挿入する。
191
+
192
+ データの参照
193
+ self.refer selfのデータを参照する別のオブジェクトを作成。
194
+ self.reshape(size,...) self.refer.reshape! と同様。
195
+ self.newdim(dim,...) self.refer.newdim! と同様。
196
+
197
+ 反転・回転
198
+ self.reverse([dim,...]) 指定した次元を逆順にする
199
+ self.rot90([k]) 2次元配列の90度の回転をk回行う
200
+
201
+ 型変換
202
+ self.floor selfより小さい最大の整数を返す。
203
+ self.ceil selfより大きい最小の整数を返す。
204
+ self.round selfにもっとも近い整数を返す。
205
+ self.to_f 値を浮動小数点数に変換する。
206
+ self.to_i 値を整数に変換する。
207
+ self.to_a 値をRubyの配列に変換する。
208
+ self.to_s バイナリデータをそのままRubyの文字列データに変換する。
209
+ self.to_string 各要素を文字列に変換する。
210
+
211
+ イテレータ
212
+ self.each {|i| ...}
213
+ self.collect {|i| ...}
214
+ self.collect! {|i| ...}
215
+
216
+ バイトスワップ
217
+ self.swap_byte バイトスワップ
218
+ self.hton ネットワークバイトオーダーに変換
219
+ self.ntoh
220
+ self.htov VAXバイトオーダーに変換
221
+ self.vtoh
222
+
223
+ Boolean / マスク関係
224
+ self.count_false 値 == 0 の要素数 (byte型のみ)
225
+ self.count_true 値 == 1 の要素数 (byte型のみ)
226
+ self.mask( mask ) self[ mask ] と同じだかマスキング専用.
227
+ [] と違い int, sint のマスクも使える.
228
+
229
+ 複素数
230
+ self.real
231
+ self.imag
232
+ self.conj
233
+ self.conj!
234
+ self.angle atan2(self.imag, self.real)
235
+ self.imag= other 虚数部分にotherをセット。
236
+ self.im 虚数倍。
237
+
238
+ NMath モジュール
239
+ sqrt(x)
240
+ exp(x)
241
+ log(x)
242
+ log10(x)
243
+ log2(x)
244
+ atan2(x,y)
245
+ sin,cos,tan
246
+ sinh,cosh,tanh
247
+ asin,acos,atan
248
+ asinh,acosh,atanh
249
+ csc,sec,cot
250
+ csch,sech,coth
251
+ acsc,asec,acot
252
+ acsch,asech,acoth
253
+ covariance
254
+
255
+
256
+ FFTW モジュール (fftw-2.1.3をshared libでコンパイルしたもので確認)
257
+ (別モジュール)
258
+ fftw(x,[1|-1])
259
+ convol(a,b) FFTWを用いた畳み込み。
260
+
261
+
262
+ NMatrix
263
+
264
+ NArrayのサブクラス。最初の2次元をMatrixとして用いる。
265
+ 残りの次元は多次元配列として扱われる。
266
+ 次元の順序は、数学での表記とは逆: a_ij => a[j,i]
267
+
268
+ メソッド:
269
+ +,- 相手が NMatrix のときに演算可。
270
+ * 相手が NMatrix または NVector のときは Matrix積。
271
+ 相手が Numeric または NArray のときは Scalar積。
272
+ 例: NMatrix[[1,2],[3,4]] * [1,10]
273
+ == NMatrix[ [[1,2],[3,4]], [[10,20],[30,40]] ]
274
+ / 相手が Numeric または NArray のときはScalar除算。
275
+ 相手が square NMatrix のときはLUにより線形方程式を解く。
276
+ a/b == b.lu.solve(a)
277
+
278
+ transpose 引数を省略した場合は、最初のMatrix次元を交換。
279
+ diagonal(other)
280
+ diagonal!(other) 対角要素に値をセット。引数省略時は1をセット。
281
+ I 対角要素に値に1をセット。
282
+ inverse 逆行列
283
+ lu LU分解を計算。NMatrixLU クラスのインスタンスを返す。
284
+
285
+
286
+ NVector
287
+
288
+ NArrayのサブクラス。最初の1次元をVectorとして用いる。
289
+ 残りの次元は多次元配列として扱われる。
290
+
291
+ メソッド:
292
+ +,- 相手が NVector のときに演算可。
293
+ * 相手が NMatrix のときは Matrix積。
294
+ 相手が NVector のときは 内積。
295
+ 相手が Numeric または NArray のときは Scalar積。
296
+ / 相手が Numeric または NArray のときは Scalar除算。
297
+ 相手が square NMatrix のときはLUにより線形方程式を解く。
298
+ v/m == m.lu.solve(v)
299
+
300
+ NMatrixLU
301
+
302
+ NMatrix#lu メソッドにより作られる。
303
+ LU (NMatrix) と pivot (NVector) を含む。
304
+
305
+ メソッド:
306
+ solve(other) LU分解の結果を使って other を解く。
307
+ other は NMatrix または NVector のインスタンス。
@@ -0,0 +1,14 @@
1
+ na_op.c: mknafunc.rb mkop.rb
2
+ $(RUBY) -I$(srcdir) $(srcdir)/mkop.rb
3
+
4
+ na_op.o: na_op.c narray.h $(hdrdir)/ruby.h
5
+
6
+
7
+ na_math.c: mknafunc.rb mkmath.rb
8
+ $(RUBY) -I$(srcdir) $(srcdir)/mkmath.rb
9
+
10
+ na_math.o: na_math.c narray.h $(hdrdir)/ruby.h
11
+
12
+
13
+ cleanall: clean
14
+ @$(RM) -r Makefile narray_config.h na_op.c na_math.c src pkg
@@ -0,0 +1,123 @@
1
+ require "mkmf"
2
+
3
+ def have_type(type, header=nil)
4
+ printf "checking for %s... ", type
5
+ STDOUT.flush
6
+ src = <<"SRC"
7
+ #include <ruby.h>
8
+ SRC
9
+ unless header.nil?
10
+ src << <<"SRC"
11
+ #include <#{header}>
12
+ SRC
13
+ end
14
+ r = try_link(src + <<"SRC")
15
+ int main() { return 0; }
16
+ int t() { #{type} a; return 0; }
17
+ SRC
18
+ unless r
19
+ print "no\n"
20
+ return false
21
+ end
22
+ $defs.push(format("-DHAVE_%s", type.upcase))
23
+ print "yes\n"
24
+ return true
25
+ end
26
+
27
+ def create_conf_h(file)
28
+ print "creating #{file}\n"
29
+ hfile = open(file, "w")
30
+ for line in $defs
31
+ line =~ /^-D(.*)/
32
+ hfile.printf "#define %s 1\n", $1
33
+ end
34
+ hfile.close
35
+ end
36
+
37
+ if RUBY_VERSION < '1.8'
38
+ alias __install_rb :install_rb
39
+ def install_rb(mfile, dest, srcdir = nil)
40
+ __install_rb(mfile, dest, srcdir)
41
+ archdir = dest.sub(/sitelibdir/,"sitearchdir").sub(/rubylibdir/,"archdir")
42
+ path = ['$(srcdir)/narray.h','narray_config.h']
43
+ path << ['libnarray.a'] if /cygwin|mingw/ =~ RUBY_PLATFORM
44
+ for f in path
45
+ mfile.printf "\t@$(RUBY) -r ftools -e 'File::install(ARGV[0], ARGV[1], 0644, true)' %s %s\n", f, archdir
46
+ end
47
+ end
48
+ else
49
+ $INSTALLFILES = [['narray.h', '$(archdir)'], ['narray_config.h', '$(archdir)']]
50
+ if /cygwin|mingw/ =~ RUBY_PLATFORM
51
+ $INSTALLFILES << ['libnarray.a', '$(archdir)']
52
+ end
53
+ end
54
+
55
+ if /cygwin|mingw/ =~ RUBY_PLATFORM
56
+ if RUBY_VERSION >= '1.9.0'
57
+ $DLDFLAGS << " -Wl,--export-all,--out-implib=libnarray.a"
58
+ elsif RUBY_VERSION > '1.8.0'
59
+ $DLDFLAGS << ",--out-implib=libnarray.a"
60
+ elsif RUBY_VERSION > '1.8'
61
+ CONFIG["DLDFLAGS"] << ",--out-implib=libnarray.a"
62
+ system("touch libnarray.a")
63
+ else
64
+ CONFIG["DLDFLAGS"] << " --output-lib libnarray.a"
65
+ end
66
+ end
67
+
68
+
69
+ case RbConfig::CONFIG["CC"]
70
+ when "gcc"
71
+ omp_opt = "-fopenmp"
72
+ else
73
+ omp_opt = nil
74
+ end
75
+ omp_opt = arg_config("--openmp", omp_opt)
76
+
77
+ omp_opt = nil if omp_opt.to_s.empty?
78
+
79
+ if omp_opt
80
+ $CFLAGS << " " << omp_opt
81
+ $DLDFLAGS << " " << omp_opt
82
+ warn "OpenMP support: ON"
83
+ else
84
+ warn "OpenMP support: OFF"
85
+ warn "if you want to enable openmp, set --openmp=compile_option"
86
+ end
87
+
88
+ #$DEBUG = true
89
+ #$CFLAGS = ["-Wall",$CFLAGS].join(" ")
90
+
91
+ srcs = %w(
92
+ narray
93
+ na_array
94
+ na_func
95
+ na_index
96
+ na_random
97
+ na_op
98
+ na_math
99
+ na_linalg
100
+ )
101
+
102
+ header = "stdint.h"
103
+ unless have_header(header)
104
+ header = "sys/types.h"
105
+ unless have_header(header)
106
+ header = nil
107
+ end
108
+ end
109
+
110
+ have_type("u_int8_t", header)
111
+ have_type("uint8_t", header)
112
+ have_type("int16_t", header)
113
+ have_type("int32_t", header)
114
+ have_type("int64_t", header)
115
+ have_type("u_int32_t", header)
116
+ have_type("uint32_t", header)
117
+ have_type("u_int64_t", header)
118
+ have_type("uint64_t", header)
119
+
120
+ $objs = srcs.collect{|i| i+".o"}
121
+
122
+ create_conf_h("narray_config.h")
123
+ create_makefile("narray/narray")
@@ -0,0 +1,792 @@
1
+ require "mknafunc"
2
+
3
+ # File name
4
+ fname = "na_math.c"
5
+ $> = open(fname,"w")
6
+
7
+ print <<EOM
8
+ /*
9
+ #{fname}
10
+ Automatically generated code
11
+ Numerical Array Extention for Ruby
12
+ (C) Copyright 1999-2008 by Masahiro TANAKA
13
+
14
+ This program is free software.
15
+ You can distribute/modify this program
16
+ under the same terms as Ruby itself.
17
+ NO WARRANTY.
18
+ */
19
+ #include <ruby.h>
20
+ #include "narray.h"
21
+ #include "narray_local.h"
22
+
23
+ #ifndef M_LOG2E
24
+ #define M_LOG2E 1.4426950408889634074
25
+ #endif
26
+ #ifndef M_LOG10E
27
+ #define M_LOG10E 0.43429448190325182765
28
+ #endif
29
+
30
+ VALUE rb_mNMath;
31
+
32
+ static void TpErr(void) {
33
+ rb_raise(rb_eTypeError,"illegal operation with this type");
34
+ }
35
+
36
+ #if 0
37
+ void sincos(double x, double *s, double *c)
38
+ {
39
+ *s=sin(x); *c=cos(x);
40
+ }
41
+
42
+ #ifndef HAVE_ACOSH
43
+ static double rb_log1p (const double x)
44
+ {
45
+ double y;
46
+ y = 1+x;
47
+
48
+ if (y==1)
49
+ return x;
50
+ else
51
+ return log(y)*(x/(y-1));
52
+ }
53
+
54
+ static double zero=0;
55
+
56
+ static double acosh(double x)
57
+ {
58
+ /* acosh(x) = log(x+sqrt(x*x-1)) */
59
+ if (x>2) {
60
+ return log(2*x-1/(sqrt(x*x-1)+x));
61
+ } else if (x>=1) {
62
+ x-=1;
63
+ return rb_log1p(x+sqrt(2*x+x*x));
64
+ }
65
+ return zero/(x-x); /* x<1: NaN */
66
+ }
67
+
68
+ static double asinh(double x)
69
+ {
70
+ double a, x2;
71
+ int neg;
72
+
73
+ /* asinh(x) = log(x+sqrt(x*x+1)) */
74
+ neg = x<0;
75
+ if (neg) {x=-x;}
76
+ x2 = x*x;
77
+
78
+ if (x>2) {
79
+ a = log(2*x+1/(x+sqrt(x2+1)));
80
+ } else {
81
+ a = rb_log1p(x+x2/(1+sqrt(x2+1)));
82
+ }
83
+ if (neg) {a=-a;}
84
+ return a;
85
+ }
86
+
87
+ static double atanh(double x)
88
+ {
89
+ double a, x2;
90
+ int neg;
91
+
92
+ /* atanh(x) = 0.5*log((1+x)/(1-x)) */
93
+ neg = x<0;
94
+ if (neg) {x=-x;}
95
+ x2 = x*2;
96
+
97
+ if (x<0.5) {
98
+ a = 0.5*rb_log1p(x2+x2*x/(1-x));
99
+ } else if (x<1) {
100
+ a = 0.5*rb_log1p(x2/(1-x));
101
+ } else if (x==1) {
102
+ a = 1/zero; /* Infinity */
103
+ } else {
104
+ return zero/(x-x); /* x>1: NaN */
105
+ }
106
+ if (neg) {a=-a;}
107
+ return a;
108
+ }
109
+ #endif
110
+ #endif
111
+
112
+ static void squareX(scomplex *x) {
113
+ float r=x->r;
114
+ x->r = r*r - x->i*x->i;
115
+ x->i = 2*r*x->i;
116
+ }
117
+
118
+ static void squareC(dcomplex *x) {
119
+ double r=x->r;
120
+ x->r = r*r - x->i*x->i;
121
+ x->i = 2*r*x->i;
122
+ }
123
+
124
+
125
+ static void mulX(scomplex *x, scomplex *y) {
126
+ scomplex z=*x;
127
+ x->r = z.r*y->r - z.i*y->i;
128
+ x->i = z.r*y->i + z.i*y->r;
129
+ }
130
+
131
+ static void mulC(dcomplex *x, dcomplex *y) {
132
+ dcomplex z=*x;
133
+ x->r = z.r*y->r - z.i*y->i;
134
+ x->i = z.r*y->i + z.i*y->r;
135
+ }
136
+
137
+
138
+ static void divX(scomplex *p1, scomplex *p2) {
139
+ scomplex x = *p1;
140
+ float a = p2->r*p2->r + p2->i*p2->i;
141
+ p1->r = (x.r*p2->r + x.i*p2->i)/a;
142
+ p1->i = (x.i*p2->r - x.r*p2->i)/a;
143
+ }
144
+
145
+ static void divC(dcomplex *p1, dcomplex *p2) {
146
+ dcomplex x = *p1;
147
+ double a = p2->r*p2->r + p2->i*p2->i;
148
+ p1->r = (x.r*p2->r + x.i*p2->i)/a;
149
+ p1->i = (x.i*p2->r - x.r*p2->i)/a;
150
+ }
151
+
152
+
153
+ static scomplex recipX(scomplex z)
154
+ {
155
+ scomplex r;
156
+ float n;
157
+
158
+ if ( (z.r<0 ? -z.r:z.r) > (z.i<0 ? -z.i:z.i) ) {
159
+ r.i = z.i/z.r;
160
+ n = (1+r.i*r.i)*z.r;
161
+ r.r = 1/n;
162
+ r.i /= -n;
163
+ } else {
164
+ r.r = z.r/z.i;
165
+ n = (1+r.r*r.r)*z.i;
166
+ r.r /= n;
167
+ r.i = -1/n;
168
+ }
169
+ return r;
170
+ }
171
+
172
+ static dcomplex recipC(dcomplex z)
173
+ {
174
+ dcomplex r;
175
+ double n;
176
+
177
+ if ( (z.r<0 ? -z.r:z.r) > (z.i<0 ? -z.i:z.i) ) {
178
+ r.i = z.i/z.r;
179
+ n = (1+r.i*r.i)*z.r;
180
+ r.r = 1/n;
181
+ r.i /= -n;
182
+ } else {
183
+ r.r = z.r/z.i;
184
+ n = (1+r.r*r.r)*z.i;
185
+ r.r /= n;
186
+ r.i = -1/n;
187
+ }
188
+ return r;
189
+ }
190
+
191
+
192
+ static int powInt(int x, int p)
193
+ {
194
+ int r=1;
195
+
196
+ switch(p) {
197
+ case 2: return x*x;
198
+ case 3: return x*x*x;
199
+ case 1: return x;
200
+ case 0: return 1;
201
+ }
202
+ if (p<0) return 0;
203
+ /* if(p>3) */
204
+ while (p) {
205
+ if ( (p%2) == 1 ) r *= x;
206
+ x *= x;
207
+ p /= 2;
208
+ }
209
+ return r;
210
+ }
211
+
212
+
213
+ static float powFi(float x, int p)
214
+ {
215
+ float r=1;
216
+
217
+ switch(p) {
218
+ case 2: return x*x;
219
+ case 3: return x*x*x;
220
+ case 1: return x;
221
+ case 0: return 1;
222
+ }
223
+ if (p<0) return 1/powFi(x,-p);
224
+ /* if(p>3) */
225
+ while (p) {
226
+ if ( (p%2) == 1 ) r *= x;
227
+ x *= x;
228
+ p /= 2;
229
+ }
230
+ return r;
231
+ }
232
+
233
+
234
+ static double powDi(double x, int p)
235
+ {
236
+ double r=1;
237
+
238
+ switch(p) {
239
+ case 2: return x*x;
240
+ case 3: return x*x*x;
241
+ case 1: return x;
242
+ case 0: return 1;
243
+ }
244
+ if (p<0) return 1/powDi(x,-p);
245
+ /* if(p>3) */
246
+ while (p) {
247
+ if ( (p%2) == 1 ) r *= x;
248
+ x *= x;
249
+ p /= 2;
250
+ }
251
+ return r;
252
+ }
253
+
254
+
255
+ static scomplex powXi(scomplex *x, int p)
256
+ {
257
+ scomplex y=*x, r={1,0};
258
+
259
+ if (p==2) { squareX(&y); return y; }
260
+ if (p==1) { return y; }
261
+ if (p==0) { return r; }
262
+ if (p<0) {
263
+ y = powXi(x,-p);
264
+ return recipX(y);
265
+ }
266
+ /* if (p>2) */
267
+ while (p) {
268
+ if ( (p%2) == 1 ) mulX(&r,&y);
269
+ squareX(&y);
270
+ p /= 2;
271
+ }
272
+ return r;
273
+ }
274
+
275
+ static dcomplex powCi(dcomplex *x, int p)
276
+ {
277
+ dcomplex y=*x, r={1,0};
278
+
279
+ if (p==2) { squareC(&y); return y; }
280
+ if (p==1) { return y; }
281
+ if (p==0) { return r; }
282
+ if (p<0) {
283
+ y = powCi(x,-p);
284
+ return recipC(y);
285
+ }
286
+ /* if (p>2) */
287
+ while (p) {
288
+ if ( (p%2) == 1 ) mulC(&r,&y);
289
+ squareC(&y);
290
+ p /= 2;
291
+ }
292
+ return r;
293
+ }
294
+
295
+
296
+ EOM
297
+
298
+ data = [
299
+ ['sqrt',
300
+ [nil]*5 +
301
+ ["{ *p1 = sqrt(*p2); }"]*2 +
302
+ ["{
303
+ typer xr=p2->r/2, xi=p2->i/2, r=hypot(xr,xi);
304
+ if (xr>0) {
305
+ p1->r = sqrt(r+xr);
306
+ p1->i = xi/p1->r;
307
+ } else if ( (r-=xr) ) {
308
+ p1->i = (xi>=0) ? sqrt(r):-sqrt(r);
309
+ p1->r = xi/p1->i;
310
+ } else {
311
+ p1->r = p1->i = 0;
312
+ }
313
+ }"]*2 +
314
+ [nil] ],
315
+
316
+ ['sin',
317
+ [nil]*5 +
318
+ ["{ *p1 = sin(*p2); }"]*2 +
319
+ ["{
320
+ p1->r = sin(p2->r)*cosh(p2->i);
321
+ p1->i = cos(p2->r)*sinh(p2->i); }"]*2 +
322
+ [nil] ],
323
+
324
+ ['cos',
325
+ [nil]*5 +
326
+ ["{ *p1 = cos(*p2); }"]*2 +
327
+ ["{
328
+ p1->r = cos(p2->r)*cosh(p2->i);
329
+ p1->i = -sin(p2->r)*sinh(p2->i); }"]*2 +
330
+ [nil] ],
331
+
332
+ ['tan',
333
+ [nil]*5 +
334
+ ["{ *p1 = tan(*p2); }"]*2 +
335
+ ["{
336
+ typer d, th;
337
+ p1->i = th = tanh(2*p2->i);
338
+ p1->r = sqrt(1-th*th); /* sech */
339
+ d = 1 + cos(2*p2->r) * p1->r;
340
+ p1->r *= sin(2*p2->r)/d;
341
+ p1->i /= d;
342
+ }"]*2 +
343
+ [nil] ],
344
+
345
+ ['sinh',
346
+ [nil]*5 +
347
+ ["{ *p1 = sinh(*p2); }"]*2 +
348
+ ["{
349
+ p1->r = sinh(p2->r)*cos(p2->i);
350
+ p1->i = cosh(p2->r)*sin(p2->i);
351
+ }"]*2 +
352
+ [nil] ],
353
+
354
+ ['cosh',
355
+ [nil]*5 +
356
+ ["{ *p1 = cosh(*p2); }"]*2 +
357
+ ["{
358
+ p1->r = cosh(p2->r)*cos(p2->i);
359
+ p1->i = sinh(p2->r)*sin(p2->i);
360
+ }"]*2 +
361
+ [nil] ],
362
+
363
+ ['tanh',
364
+ [nil]*5 +
365
+ ["{ *p1 = tanh(*p2); }"]*2 +
366
+ ["{
367
+ typer d, th;
368
+ p1->r = th = tanh(2*p2->r);
369
+ p1->i = sqrt(1-th*th); /* sech */
370
+ d = 1 + cos(2*p2->i) * p1->i;
371
+ p1->r /= d;
372
+ p1->i *= sin(2*p2->i)/d;
373
+ }"]*2 +
374
+ [nil] ],
375
+
376
+ ['exp',
377
+ [nil]*5 +
378
+ ["{ *p1 = exp(*p2); }"]*2 +
379
+ ["{
380
+ typer a = exp(p2->r);
381
+ p1->r = a*cos(p2->i);
382
+ p1->i = a*sin(p2->i);
383
+ }"]*2 +
384
+ [nil] ],
385
+
386
+ ['log',
387
+ [nil]*5 +
388
+ ["{ *p1 = log(*p2); }"]*2 +
389
+ ["{
390
+ typed x = *p2;
391
+ p1->r = log(hypot(x.r, x.i));
392
+ p1->i = atan2(x.i, x.r);
393
+ }"]*2 +
394
+ [nil] ],
395
+
396
+ ['log10',
397
+ [nil]*5 +
398
+ ["{ *p1 = log10(*p2); }"]*2 +
399
+ ["{
400
+ log#code(p1,p2);
401
+ p1->r *= (typer)M_LOG10E;
402
+ p1->i *= (typer)M_LOG10E;
403
+ }"]*2 +
404
+ [nil] ],
405
+
406
+
407
+ ['log2',
408
+ [nil]*5 +
409
+ ["{ *p1 = log(*p2)*M_LOG2E; }"]*2 +
410
+ ["{
411
+ log#code(p1,p2);
412
+ p1->r *= (typer)M_LOG2E;
413
+ p1->i *= (typer)M_LOG2E;
414
+ }"]*2 +
415
+ [nil] ],
416
+
417
+
418
+ ['asin',
419
+ [nil]*5 +
420
+ ["{ *p1 = asin(*p2); }"]*2 +
421
+ # -i * log( sqrt(1-x**2) + x*i )
422
+ ["{
423
+ typed x = *p2;
424
+ square#code(&x);
425
+ x.r = 1 - x.r;
426
+ x.i = - x.i;
427
+ sqrt#code(&x,&x);
428
+ x.r -= p2->i;
429
+ x.i += p2->r;
430
+ log#code(&x,&x);
431
+ p1->r = x.i;
432
+ p1->i = -x.r;
433
+ }"]*2 +
434
+ [nil]*1 ],
435
+
436
+ ['asinh',
437
+ [nil]*5 +
438
+ ["{ *p1 = asinh(*p2); }"]*2 +
439
+ # log(sqrt(x**2+1)+x)
440
+ ["{
441
+ typed x = *p2;
442
+ square#code(&x);
443
+ x.r += 1;
444
+ sqrt#code(&x,&x);
445
+ x.r += p2->r;
446
+ x.i += p2->i;
447
+ log#code(p1,&x);
448
+ }"]*2 +
449
+ [nil]*1 ],
450
+
451
+ ['acos',
452
+ [nil]*5 +
453
+ ["{ *p1 = acos(*p2); }"]*2 +
454
+ # -i * log( sqrt(1-x**2)*i + x )
455
+ ["{
456
+ typed x = *p2;
457
+ typer tmp;
458
+ square#code(&x);
459
+ x.r = 1 - x.r;
460
+ x.i = - x.i;
461
+ sqrt#code(&x,&x);
462
+ tmp = x.r + p2->i;
463
+ x.r = -x.i + p2->r;
464
+ x.i = tmp;
465
+ log#code(&x,&x);
466
+ p1->r = x.i;
467
+ p1->i = -x.r;
468
+ }"]*2 +
469
+ [nil]*1 ],
470
+
471
+ ['acosh',
472
+ [nil]*5 +
473
+ ["{ *p1 = acosh(*p2); }"]*2 +
474
+ # log(x+sqrt(x**2-1))
475
+ ["{
476
+ typed x = *p2;
477
+ square#code(&x);
478
+ x.r -= 1;
479
+ sqrt#code(&x,&x);
480
+ x.r += p2->r;
481
+ x.i += p2->i;
482
+ log#code(p1,&x);
483
+ }"]*2 +
484
+ [nil]*1 ],
485
+
486
+ ['atan',
487
+ [nil]*5 +
488
+ ["{ *p1 = atan(*p2); }"]*2 +
489
+ # i/2 * log((i+x)/(i-x))
490
+ ["{
491
+ typed x,y;
492
+ x.r=-p2->r; x.i=1-p2->i;
493
+ y.r= p2->r; y.i=1+p2->i;
494
+ div#code((void*)&y,(void*)&x);
495
+ log#code((void*)&x,(void*)&y);
496
+ p1->r = -x.i/2;
497
+ p1->i = x.r/2;
498
+ }"]*2 +
499
+ [nil]*1 ],
500
+
501
+ ['atanh',
502
+ [nil]*5 +
503
+ ["{ *p1 = atanh(*p2); }"]*2 +
504
+ # 1/2 * log((1+x)/(1-x))
505
+ ["{
506
+ typed x,y;
507
+ x.r=1-p2->r; x.i=-p2->i;
508
+ y.r=1+p2->r; y.i= p2->i;
509
+ div#code((void*)&y,(void*)&x);
510
+ log#code((void*)&x,(void*)&y);
511
+ p1->r = x.r/2;
512
+ p1->i = x.i/2;
513
+ }"]*2 +
514
+ [nil]*1 ] ]
515
+
516
+
517
+
518
+ def mkmathfuncs(bsname,func)
519
+
520
+ print "
521
+ /* ------------------------- #{bsname} --------------------------- */\n"
522
+ c = $type_codes
523
+ tr = $real_types
524
+ td = $data_types
525
+ name = bsname
526
+
527
+ # Function Definition
528
+ head = "static void #{name}#code(void *p1, void *p2)"
529
+ for i in 0...c.size
530
+ if func[i] != nil && func[i]=~/^\{/
531
+ f = func[i].
532
+ gsub(/p1->/,"((#{td[i]}*)p1)->").
533
+ gsub(/p2->/,"((#{td[i]}*)p2)->").
534
+ gsub(/\*p1/,"*(#{td[i]}*)p1").
535
+ gsub(/\*p2/,"*(#{td[i]}*)p2").
536
+ gsub(/typer/, tr[i]).
537
+ gsub(/typed/, td[i])
538
+ puts( (head+f).gsub(/#code/,c[i]) )
539
+ end
540
+ end
541
+
542
+ # Function Array
543
+
544
+ print "\nna_mathfunc_t #{name}Funcs =\n{ "
545
+ m = []
546
+ for i in 0...c.size
547
+ if func[i] == nil
548
+ m += ['TpErr']
549
+ elsif func[i]=='copy'
550
+ m += ['Set'+c[i]*2]
551
+ elsif !( func[i] =~ /^\{/ )
552
+ m += [func[i]]
553
+ else
554
+ m += [name+c[i]]
555
+ end
556
+ end
557
+ print m.join(", ")+" };\n"
558
+
559
+ end
560
+
561
+
562
+ # Function Definitions
563
+ for i in data
564
+ mkmathfuncs( i[0], i[1] )
565
+ end
566
+
567
+
568
+ #
569
+ # Recip
570
+ #
571
+ $func_body =
572
+ "static void #name#C(int n, char *p1_0, int i1, char *p2_0, int i2)
573
+ {
574
+ type1* p1 = (type1*) p1_0;
575
+ typec* p2 = (typec*) p2_0;
576
+ int i;
577
+
578
+ #pragma omp parallel for
579
+ for (i=0; i<n; i++) {
580
+ OPERATION
581
+ }
582
+ }
583
+ "
584
+ mkfuncs('Rcp', $data_types, $data_types,
585
+ [nil] +
586
+ ["p1[i] = 1/(p2[i]);"]*6 +
587
+ ["p1[i] = recip#C(p2[i]);"]*2 +
588
+ ["p1[i] = rb_funcall(INT2FIX(1),na_id_div,1,p2[i]);"]
589
+ )
590
+
591
+
592
+ #
593
+ # Power
594
+ #
595
+ def mkpowfuncs(name,funcs)
596
+
597
+ print "
598
+ /* ------------------------- #{name} --------------------------- */\n"
599
+ c = $type_codes
600
+ n = $type_codes.size
601
+ td = $data_types
602
+ tr = $real_types
603
+
604
+ # Function Definition
605
+
606
+ for i in 0...n
607
+ for j in 0...n
608
+ funcs.each do |k|
609
+ if c[i]=~k[0] && c[j]=~k[1]
610
+ tu = $data_types[$upcast[i][j]]
611
+ f = k[2].
612
+ gsub(/p1->/,"((#{tu}*)p1)->").
613
+ gsub(/p2->/,"((#{td[i]}*)p2)->").
614
+ gsub(/p3->/,"((#{td[j]}*)p3)->").
615
+ gsub(/\*p1/,"*(#{tu}*)p1").
616
+ gsub(/\*p2/,"*(#{td[i]}*)p2").
617
+ gsub(/\*p3/,"*(#{td[j]}*)p3").
618
+ gsub(/typed/,td[i]).
619
+ gsub(/typef/,tr[i])
620
+ puts $func_body.
621
+ gsub(/#t1/,tu).
622
+ gsub(/#t2/,td[i]).
623
+ gsub(/#t3/,td[j]).
624
+ gsub(/#name/,name).
625
+ sub(/OPERATION/,f).
626
+ gsub(/#CC/,c[i]+c[j]).
627
+ gsub(/#C/, c[i])
628
+ end
629
+ end
630
+ end
631
+ end
632
+
633
+ # function pointer array
634
+ print "\nna_setfunc_t "+name+"Funcs = {\n"
635
+ m = []
636
+ for i in 0...n
637
+ l = []
638
+ for j in 0...n
639
+ f = true
640
+ for k in funcs
641
+ if c[i]=~k[0] && c[j]=~k[1]
642
+ l += [name+c[i]+c[j]]
643
+ f = false
644
+ break
645
+ end
646
+ end
647
+ if f
648
+ l += ['TpErr']
649
+ end
650
+ end
651
+ m += [' { '+l.join(', ')+' }']
652
+ end
653
+ print m.join(",\n")+"\n};\n"
654
+
655
+ end
656
+
657
+ $func_body =
658
+ "static void #name#CC(int n, char *p1, int i1, char *p2, int i2, char *p3, int i3)
659
+ {
660
+ for (; n; --n) {
661
+ OPERATION
662
+ p1+=i1; p2+=i2; p3+=i3;
663
+ }
664
+ }
665
+ "
666
+ mkpowfuncs('Pow',
667
+ [
668
+ [/[O]/,/[O]/, "*p1 = rb_funcall(*p2,na_id_power,1,*p3);"],
669
+ [/[BILG]/,/[BILG]/,"*p1 = powInt(*p2,*p3);"],
670
+ [/[FD]/,/[BILG]/, "*p1 = pow#Ci(*p2,*p3);"],
671
+ [/[BILGFD]/,/[FD]/,"*p1 = pow(*p2,*p3);"],
672
+ [/[XC]/,/[BILG]/, "*p1 = pow#Ci((typed*)p2,*p3);"],
673
+ [/[XC]/,/[FD]/,
674
+ "typed r;
675
+ if (*p3==0)
676
+ { p1->r=1; p1->i=0; } else
677
+ if (p2->r==0 && p2->i==0 && *p3>0)
678
+ { p1->r=0; p1->i=0; } else {
679
+ log#C(&r, p2);
680
+ r.r *= *p3;
681
+ r.i *= *p3;
682
+ exp#C(p1, &r); }"],
683
+ [/[XC]/,/[XC]/,
684
+ "typed l, r;
685
+ if (p3->r==0 && p3->i==0)
686
+ { p1->r=1; p1->i=0; } else
687
+ if (p2->r==0 && p2->i==0 && p3->r>0 && p3->i==0)
688
+ { p1->r=0; p1->i=0; } else {
689
+ log#C(&l, p2);
690
+ r.r = p3->r * l.r - p3->i * l.i;
691
+ r.i = p3->r * l.i + p3->i * l.r;
692
+ exp#C(p1, &r); }"]
693
+ ])
694
+
695
+
696
+ # Execution
697
+ print <<EOM
698
+
699
+
700
+ /* ------------------------- Execution -------------------------- */
701
+
702
+ static void
703
+ na_exec_math(struct NARRAY *a1, struct NARRAY *a2, void (*func)())
704
+ {
705
+ na_shape_t i;
706
+ int s1, s2;
707
+ char *p1, *p2;
708
+
709
+ s1 = na_sizeof[a1->type];
710
+ s2 = na_sizeof[a2->type];
711
+ p1 = a1->ptr;
712
+ p2 = a2->ptr;
713
+
714
+ #pragma omp parallel for
715
+ for (i=0;i<a1->total; i++) {
716
+ (*func)( p1+s1*i, p2+s2*i );
717
+ }
718
+ }
719
+
720
+
721
+ static VALUE
722
+ na_math_func(volatile VALUE self, na_mathfunc_t funcs)
723
+ {
724
+ struct NARRAY *a1, *a2;
725
+ VALUE ans;
726
+
727
+ if (TYPE(self) == T_ARRAY) {
728
+ self = na_ary_to_nary(self,cNArray);
729
+ } else
730
+ if (!IsNArray(self)) {
731
+ self = na_make_scalar(self,na_object_type(self));
732
+ }
733
+
734
+ GetNArray(self,a2);
735
+ if (NA_IsINTEGER(a2)) {
736
+ self = na_upcast_type(self,NA_DFLOAT);
737
+ GetNArray(self,a2);
738
+ }
739
+ ans = na_make_object(a2->type, a2->rank, a2->shape, CLASS_OF(self));
740
+ GetNArray(ans,a1);
741
+
742
+ na_exec_math(a1, a2, funcs[a2->type]);
743
+
744
+ if (CLASS_OF(self) == cNArrayScalar)
745
+ SetFuncs[NA_ROBJ][a1->type](1,&ans,0,a1->ptr,0);
746
+
747
+ return ans;
748
+ }
749
+ EOM
750
+
751
+
752
+ # Module Methods
753
+ print <<EOM
754
+
755
+ /* ------------------------- Module Methods -------------------------- */
756
+ EOM
757
+ for i in data
758
+ bsname=i[0]
759
+ name=bsname
760
+ print <<EOM
761
+
762
+ /*
763
+ * call-seq:
764
+ * NMath.#{name}(arg) -> narray
765
+ */
766
+ static VALUE na_math_#{bsname}(VALUE obj, VALUE x)
767
+ { return na_math_func(x,#{name}Funcs); }
768
+ EOM
769
+ end
770
+
771
+
772
+
773
+ # Initializer
774
+ print <<EOM
775
+
776
+
777
+ /* Initialization of NMath module */
778
+ void Init_nmath(void)
779
+ {
780
+ /* define ExtMath module */
781
+ rb_mNMath = rb_define_module("NMath");
782
+
783
+ /* methods */
784
+ EOM
785
+
786
+ for i in data
787
+ print " rb_define_module_function(rb_mNMath,\"#{i[0]}\",na_math_#{i[0]},1);\n"
788
+ end
789
+
790
+ print <<EOM
791
+ }
792
+ EOM