narray-bigmem 0.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.
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