narray-nmatrix 0.6.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,252 @@
1
+ # Numerical Array Extention for Ruby
2
+ # (C) Copyright 2000-2003 by Masahiro TANAKA
3
+ #
4
+
5
+ class NArray
6
+
7
+ #
8
+ # ------ NMatrix ------
9
+ #
10
+ class NMatrix < NArray
11
+ CLASS_DIMENSION = 2
12
+
13
+ def +(other)
14
+ case other
15
+ when NMatrix
16
+ return super(NArray.refer(other))
17
+ when NArray
18
+ unless other.instance_of?(NArray)
19
+ return other.coerce_rev( self, :+ )
20
+ end
21
+ end
22
+ raise TypeError,"Illegal operation: NMatrix + %s" % other.class
23
+ end
24
+
25
+ def -(other)
26
+ case other
27
+ when NMatrix
28
+ return super(NArray.refer(other))
29
+ when NArray
30
+ unless other.instance_of?(NArray)
31
+ return other.coerce_rev( self, :- )
32
+ end
33
+ end
34
+ raise TypeError,"Illegal operation: NMatrix - %s" % other.class
35
+ end
36
+
37
+ def *(other)
38
+ case other
39
+ when NMatrix
40
+ NMatrix.mul_add( NArray.refer(self).newdim!(0),other.newdim(2), 1 )
41
+ #NMatrix.mul_add( NArray.refer(self).newdim!(0),
42
+ # other.transpose(1,0).newdim!(2), 0 )
43
+ when NVector
44
+ NVector.mul_add( NArray.refer(self), other.newdim(1), 0 )
45
+ when NArray
46
+ if other.instance_of?(NArray)
47
+ NMatrix.mul( NArray.refer(self), other.newdim(0,0) )
48
+ else
49
+ other.coerce_rev( self, :* )
50
+ end
51
+ when Numeric
52
+ super
53
+ #NMatrix.mul( NArray.refer(self), other )
54
+ when Array
55
+ NMatrix.mul( self, NArray[*other].newdim!(0,0) )
56
+ else
57
+ raise TypeError,"Illegal operation: NMatrix * %s" % other.class
58
+ end
59
+ end
60
+
61
+ def /(other)
62
+ case other
63
+ when NMatrix
64
+ other.lu.solve(self)
65
+ when NVector
66
+ raise TypeError,"Illegal operation: NMatrix / %s" % other.class
67
+ when NArray
68
+ if other.instance_of?(NArray)
69
+ NMatrix.div( NArray.refer(self), other.newdim(0,0) )
70
+ else
71
+ other.coerce_rev( self, :/ )
72
+ end
73
+ when Numeric
74
+ NMatrix.div( NArray.refer(self), other )
75
+ when Array
76
+ NMatrix.div( self, NArray[*other].newdim!(0,0) )
77
+ else
78
+ raise TypeError,"Illegal operation: NMatrix / %s" % other.class
79
+ end
80
+ end
81
+
82
+ def **(n)
83
+ case n
84
+ when Integer
85
+ if n==0
86
+ return 1.0
87
+ elsif n<0
88
+ m = self.inverse
89
+ n = -n
90
+ else
91
+ m = self
92
+ end
93
+ (2..n).each{ m *= self }
94
+ m
95
+ else
96
+ raise TypeError,"Illegal operation: NMatrix ** %s" % other.class
97
+ end
98
+ end
99
+
100
+ def coerce_rev(other,id)
101
+ case id
102
+ when :*
103
+ if other.instance_of?(NArray)
104
+ return NMatrix.mul( other.newdim(0,0), self )
105
+ end
106
+ if other.instance_of?(NArrayScalar)
107
+ return NMatrix.mul( other.newdim(0), self )
108
+ end
109
+ when :/
110
+ if other.instance_of?(NArray)
111
+ return NMatrix.mul( other.newdim(0,0), self.inverse )
112
+ end
113
+ if other.instance_of?(NArrayScalar)
114
+ return NMatrix.mul( other.newdim(0), self.inverse )
115
+ end
116
+ end
117
+ raise TypeError,"Illegal operation: %s %s NMatrix" %
118
+ [other.class, id.id2name]
119
+ end
120
+
121
+ def inverse
122
+ self.lu.solve( NMatrix.new(self.typecode, *self.shape).fill!(0).unit )
123
+ end
124
+
125
+ def transpose(*arg)
126
+ if arg.size==0
127
+ super(1,0)
128
+ else
129
+ super
130
+ end
131
+ end
132
+
133
+ def diagonal!(val=1)
134
+ shp = self.shape
135
+ idx = NArray.int(shp[0..1].min).indgen! * (shp[0]+1)
136
+ ref = reshape(shp[0]*shp[1],true)
137
+ if val.kind_of?(Numeric)
138
+ ref[idx,true] = val
139
+ else
140
+ val = NArray.to_na(val)
141
+ raise ArgumentError, "must be 1-d array" if val.dim!=1
142
+ ref[idx,true] = val.newdim!(-1)
143
+ end
144
+ self
145
+ end
146
+
147
+ def diagonal(val)
148
+ self.dup.diagonal!(val)
149
+ end
150
+
151
+ def unit
152
+ diagonal!
153
+ end
154
+ alias identity unit
155
+ alias I unit
156
+
157
+ end # class NMatrix
158
+
159
+
160
+ #
161
+ # ------ NVector ------
162
+ #
163
+ class NVector < NArray
164
+ CLASS_DIMENSION = 1
165
+
166
+ def +(other)
167
+ case other
168
+ when NVector
169
+ return super(NArray.refer(other))
170
+ when NArray
171
+ unless other.instance_of?(NArray)
172
+ return other.coerce_rev( self, :+ )
173
+ end
174
+ end
175
+ raise TypeError,"Illegal operation: NVector + %s" % other.class
176
+ end
177
+
178
+ def -(other)
179
+ case other
180
+ when NVector
181
+ return super(NArray.refer(other))
182
+ when NArray
183
+ unless other.instance_of?(NArray)
184
+ return other.coerce_rev( self, :- )
185
+ end
186
+ end
187
+ raise TypeError,"Illegal operation: NVector - %s" % other.class
188
+ end
189
+
190
+ def *(other)
191
+ case other
192
+ when NMatrix
193
+ NVector.mul_add( NArray.refer(self).newdim!(0), other, 1 )
194
+ when NVector
195
+ NArray.mul_add( NArray.refer(self), other, 0 ) # inner product
196
+ when NArray
197
+ if other.instance_of?(NArray)
198
+ NVector.mul( NArray.refer(self), other.newdim(0) )
199
+ else
200
+ other.coerce_rev( self, :* )
201
+ end
202
+ when Numeric
203
+ NVector.mul( NArray.refer(self), other )
204
+ else
205
+ raise TypeError,"Illegal operation: NVector * %s" % other.class
206
+ end
207
+ end
208
+
209
+ def /(other)
210
+ case other
211
+ when NMatrix
212
+ other.lu.solve(self)
213
+ when NVector
214
+ raise TypeError,"Illegal operation: NVector / %s" % other.class
215
+ when NArray
216
+ if other.instance_of?(NArray)
217
+ NVector.div( NArray.refer(self), other.newdim(0) )
218
+ else
219
+ other.coerce_rev( self, :/ )
220
+ end
221
+ when Numeric
222
+ NVector.div( NArray.refer(self), other )
223
+ else
224
+ raise TypeError,"Illegal operation: NVector / %s" % other.class
225
+ end
226
+ end
227
+
228
+ def **(n)
229
+ if n==2
230
+ self*self
231
+ else
232
+ raise ArgumentError,"Only v**2 is implemented"
233
+ end
234
+ end
235
+
236
+ def coerce_rev(other,id)
237
+ case id
238
+ when :*
239
+ if other.instance_of?(NArray)
240
+ return NVector.mul( other.newdim(0), self )
241
+ end
242
+ if other.instance_of?(NArrayScalar)
243
+ return NVector.mul( other, self )
244
+ end
245
+ end
246
+ raise TypeError,"Illegal operation: %s %s NVector" %
247
+ [other.class, id.id2name]
248
+ end
249
+
250
+ end # class NVector
251
+
252
+ end # class NArray
@@ -0,0 +1,784 @@
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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]*4 +
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, int i1, char *p2, int i2)
573
+ {
574
+ for (; n; --n) {
575
+ OPERATION
576
+ p1+=i1; p2+=i2;
577
+ }
578
+ }
579
+ "
580
+ mkfuncs('Rcp', $data_types, $data_types,
581
+ [nil] +
582
+ ["*p1 = 1/(*p2);"]*5 +
583
+ ["*p1 = recip#C((type1*)p2);"]*2 +
584
+ ["*p1 = rb_funcall(INT2FIX(1),na_id_div,1,*p2);"]
585
+ )
586
+
587
+
588
+ #
589
+ # Power
590
+ #
591
+ def mkpowfuncs(name,funcs)
592
+
593
+ print "
594
+ /* ------------------------- #{name} --------------------------- */\n"
595
+ c = $type_codes
596
+ n = $type_codes.size
597
+ td = $data_types
598
+ tr = $real_types
599
+
600
+ # Function Definition
601
+
602
+ for i in 0...n
603
+ for j in 0...n
604
+ funcs.each do |k|
605
+ if c[i]=~k[0] && c[j]=~k[1]
606
+ tu = $data_types[$upcast[i][j]]
607
+ f = k[2].
608
+ gsub(/p1->/,"((#{tu}*)p1)->").
609
+ gsub(/p2->/,"((#{td[i]}*)p2)->").
610
+ gsub(/p3->/,"((#{td[j]}*)p3)->").
611
+ gsub(/\*p1/,"*(#{tu}*)p1").
612
+ gsub(/\*p2/,"*(#{td[i]}*)p2").
613
+ gsub(/\*p3/,"*(#{td[j]}*)p3").
614
+ gsub(/typed/,td[i]).
615
+ gsub(/typef/,tr[i])
616
+ puts $func_body.
617
+ gsub(/#name/,name).
618
+ sub(/OPERATION/,f).
619
+ gsub(/#CC/,c[i]+c[j]).
620
+ gsub(/#C/, c[i])
621
+ end
622
+ end
623
+ end
624
+ end
625
+
626
+ # function pointer array
627
+ print "\nna_setfunc_t "+name+"Funcs = {\n"
628
+ m = []
629
+ for i in 0...n
630
+ l = []
631
+ for j in 0...n
632
+ f = true
633
+ for k in funcs
634
+ if c[i]=~k[0] && c[j]=~k[1]
635
+ l += [name+c[i]+c[j]]
636
+ f = false
637
+ break
638
+ end
639
+ end
640
+ if f
641
+ l += ['TpErr']
642
+ end
643
+ end
644
+ m += [' { '+l.join(', ')+' }']
645
+ end
646
+ print m.join(",\n")+"\n};\n"
647
+
648
+ end
649
+
650
+ $func_body =
651
+ "static void #name#CC(int n, char *p1, int i1, char *p2, int i2, char *p3, int i3)
652
+ {
653
+ for (; n; --n) {
654
+ OPERATION
655
+ p1+=i1; p2+=i2; p3+=i3;
656
+ }
657
+ }
658
+ "
659
+ mkpowfuncs('Pow',
660
+ [
661
+ [/[O]/,/[O]/, "*p1 = rb_funcall(*p2,na_id_power,1,*p3);"],
662
+ [/[BIL]/,/[BIL]/, "*p1 = powInt(*p2,*p3);"],
663
+ [/[FD]/,/[BIL]/, "*p1 = pow#Ci(*p2,*p3);"],
664
+ [/[BILFD]/,/[FD]/,"*p1 = pow(*p2,*p3);"],
665
+ [/[XC]/,/[BIL]/, "*p1 = pow#Ci((typed*)p2,*p3);"],
666
+ [/[XC]/,/[FD]/,
667
+ "typed r;
668
+ if (*p3==0)
669
+ { p1->r=1; p1->i=0; } else
670
+ if (p2->r==0 && p2->i==0 && *p3>0)
671
+ { p1->r=0; p1->i=0; } else {
672
+ log#C(&r, p2);
673
+ r.r *= *p3;
674
+ r.i *= *p3;
675
+ exp#C(p1, &r); }"],
676
+ [/[XC]/,/[XC]/,
677
+ "typed l, r;
678
+ if (p3->r==0 && p3->i==0)
679
+ { p1->r=1; p1->i=0; } else
680
+ if (p2->r==0 && p2->i==0 && p3->r>0 && p3->i==0)
681
+ { p1->r=0; p1->i=0; } else {
682
+ log#C(&l, p2);
683
+ r.r = p3->r * l.r - p3->i * l.i;
684
+ r.i = p3->r * l.i + p3->i * l.r;
685
+ exp#C(p1, &r); }"]
686
+ ])
687
+
688
+
689
+ # Execution
690
+ print <<EOM
691
+
692
+
693
+ /* ------------------------- Execution -------------------------- */
694
+
695
+ static void
696
+ na_exec_math(struct NARRAY *a1, struct NARRAY *a2, void (*func)())
697
+ {
698
+ int i, s1, s2;
699
+ char *p1, *p2;
700
+
701
+ s1 = na_sizeof[a1->type];
702
+ s2 = na_sizeof[a2->type];
703
+ p1 = a1->ptr;
704
+ p2 = a2->ptr;
705
+ for (i=a1->total; i ; i--) {
706
+ (*func)( p1, p2 );
707
+ p1 += s1;
708
+ p2 += s2;
709
+ }
710
+ }
711
+
712
+
713
+ static VALUE
714
+ na_math_func(volatile VALUE self, na_mathfunc_t funcs)
715
+ {
716
+ struct NARRAY *a1, *a2;
717
+ VALUE ans;
718
+
719
+ if (TYPE(self) == T_ARRAY) {
720
+ self = na_ary_to_nary(self,cNArray);
721
+ } else
722
+ if (!IsNArray(self)) {
723
+ self = na_make_scalar(self,na_object_type(self));
724
+ }
725
+
726
+ GetNArray(self,a2);
727
+ if (NA_IsINTEGER(a2)) {
728
+ self = na_upcast_type(self,NA_DFLOAT);
729
+ GetNArray(self,a2);
730
+ }
731
+ ans = na_make_object(a2->type, a2->rank, a2->shape, CLASS_OF(self));
732
+ GetNArray(ans,a1);
733
+
734
+ na_exec_math(a1, a2, funcs[a2->type]);
735
+
736
+ if (CLASS_OF(self) == cNArrayScalar)
737
+ SetFuncs[NA_ROBJ][a1->type](1,&ans,0,a1->ptr,0);
738
+
739
+ return ans;
740
+ }
741
+ EOM
742
+
743
+
744
+ # Module Methods
745
+ print <<EOM
746
+
747
+ /* ------------------------- Module Methods -------------------------- */
748
+ EOM
749
+ for i in data
750
+ bsname=i[0]
751
+ name=bsname
752
+ print <<EOM
753
+
754
+ /*
755
+ * call-seq:
756
+ * NMath.#{name}(arg) -> narray
757
+ */
758
+ static VALUE na_math_#{bsname}(VALUE obj, VALUE x)
759
+ { return na_math_func(x,#{name}Funcs); }
760
+ EOM
761
+ end
762
+
763
+
764
+
765
+ # Initializer
766
+ print <<EOM
767
+
768
+
769
+ /* Initialization of NMath module */
770
+ void Init_nmath(void)
771
+ {
772
+ /* define ExtMath module */
773
+ rb_mNMath = rb_define_module_under(cNArray,"NMath");
774
+
775
+ /* methods */
776
+ EOM
777
+
778
+ for i in data
779
+ print " rb_define_module_function(rb_mNMath,\"#{i[0]}\",na_math_#{i[0]},1);\n"
780
+ end
781
+
782
+ print <<EOM
783
+ }
784
+ EOM