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.
- checksums.yaml +7 -0
- data/ChangeLog +809 -0
- data/MANIFEST +53 -0
- data/README.en +51 -0
- data/README.ja +52 -0
- data/SPEC.en +327 -0
- data/SPEC.ja +307 -0
- data/depend +14 -0
- data/extconf.rb +100 -0
- data/lib/narray.rb +18 -0
- data/lib/narray/narray.rb +5 -0
- data/lib/narray_ext.rb +362 -0
- data/lib/nmatrix.rb +252 -0
- data/mkmath.rb +784 -0
- data/mknafunc.rb +192 -0
- data/mkop.rb +648 -0
- data/na_array.c +650 -0
- data/na_func.c +1705 -0
- data/na_index.c +1011 -0
- data/na_linalg.c +633 -0
- data/na_random.c +416 -0
- data/narray.c +1321 -0
- data/narray.def +29 -0
- data/narray.h +186 -0
- data/narray_local.h +218 -0
- metadata +92 -0
data/lib/nmatrix.rb
ADDED
@@ -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
|
data/mkmath.rb
ADDED
@@ -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
|