narray-nmatrix 0.6.1.0.pre

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.
@@ -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