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.
- checksums.yaml +7 -0
- data/ChangeLog +602 -0
- data/MANIFEST +54 -0
- data/README +41 -0
- data/README_NARRAY.en +49 -0
- data/README_NARRAY.ja +52 -0
- data/SPEC.en +327 -0
- data/SPEC.ja +307 -0
- data/ext/narray/depend +14 -0
- data/ext/narray/extconf.rb +123 -0
- data/ext/narray/mkmath.rb +792 -0
- data/ext/narray/mknafunc.rb +212 -0
- data/ext/narray/mkop.rb +734 -0
- data/ext/narray/na_array.c +659 -0
- data/ext/narray/na_func.c +1709 -0
- data/ext/narray/na_index.c +1021 -0
- data/ext/narray/na_linalg.c +635 -0
- data/ext/narray/na_random.c +444 -0
- data/ext/narray/narray.c +1341 -0
- data/ext/narray/narray.def +29 -0
- data/ext/narray/narray.h +231 -0
- data/ext/narray/narray_local.h +218 -0
- data/lib/narray.rb +4 -0
- data/lib/narray_ext.rb +362 -0
- data/lib/nmatrix.rb +248 -0
- metadata +94 -0
@@ -0,0 +1,635 @@
|
|
1
|
+
/*
|
2
|
+
* na_linalg.c
|
3
|
+
* Numerical Array Extention for Ruby
|
4
|
+
* (C) Copyright 2000-2008 by Masahiro TANAKA
|
5
|
+
*/
|
6
|
+
#include <ruby.h>
|
7
|
+
#include "narray.h"
|
8
|
+
#include "narray_local.h"
|
9
|
+
#define ARRAY_BUF
|
10
|
+
|
11
|
+
/*
|
12
|
+
a_ij == a[j,i]
|
13
|
+
j - >
|
14
|
+
i 11 21 31
|
15
|
+
| 12 22 32
|
16
|
+
v 13 23 33
|
17
|
+
*/
|
18
|
+
|
19
|
+
#define SWAPMEM(a,b,tmp,sz) \
|
20
|
+
{ memcpy(tmp,a,sz); memcpy(a,b,sz); memcpy(b,tmp,sz); }
|
21
|
+
|
22
|
+
typedef struct NARRAY_FUNCSET {
|
23
|
+
int elmsz;
|
24
|
+
char *zero;
|
25
|
+
char *one;
|
26
|
+
char *tiny;
|
27
|
+
void (*set)();
|
28
|
+
void (*neg)();
|
29
|
+
void (*rcp)();
|
30
|
+
void (*abs)();
|
31
|
+
void (*add)();
|
32
|
+
void (*sbt)();
|
33
|
+
void (*mul)();
|
34
|
+
void (*div)();
|
35
|
+
void (*mod)();
|
36
|
+
void (*muladd)();
|
37
|
+
void (*mulsbt)();
|
38
|
+
void (*cmp)();
|
39
|
+
int (*sort)();
|
40
|
+
void (*min)();
|
41
|
+
void (*max)();
|
42
|
+
} na_funcset_t;
|
43
|
+
|
44
|
+
VALUE cNMatrix, cNVector, cNMatrixLU;
|
45
|
+
static na_funcset_t na_funcset[NA_NTYPES];
|
46
|
+
static ID id_lu, id_pivot;
|
47
|
+
|
48
|
+
|
49
|
+
static void
|
50
|
+
na_loop_linalg( int nd, char *p1, char *p2, char *p3,
|
51
|
+
struct slice *s1, struct slice *s2, struct slice *s3,
|
52
|
+
void (*func)(), na_shape_t *shape, int type )
|
53
|
+
{
|
54
|
+
int i;
|
55
|
+
int ps1 = s1[0].pstep;
|
56
|
+
int ps2 = s2[0].pstep;
|
57
|
+
int ps3 = s3[0].pstep;
|
58
|
+
int *si;
|
59
|
+
|
60
|
+
if (nd==0) {
|
61
|
+
(*func)(1, p1, 0, p2, 0, p3, 0, shape, type);
|
62
|
+
return;
|
63
|
+
}
|
64
|
+
|
65
|
+
si = ALLOCA_N(int,nd);
|
66
|
+
i = nd;
|
67
|
+
s1[i].p = p1;
|
68
|
+
s2[i].p = p2;
|
69
|
+
s3[i].p = p3;
|
70
|
+
|
71
|
+
for(;;) {
|
72
|
+
/* set pointers */
|
73
|
+
while (i > 0) {
|
74
|
+
--i;
|
75
|
+
s3[i].p = s3[i].pbeg + s3[i+1].p;
|
76
|
+
s2[i].p = s2[i].pbeg + s2[i+1].p;
|
77
|
+
s1[i].p = s1[i].pbeg + s1[i+1].p;
|
78
|
+
si[i] = s1[i].n;
|
79
|
+
}
|
80
|
+
/* rank 0 loop */
|
81
|
+
(*func)(s2[0].n, s1[0].p, ps1, s2[0].p, ps2, s3[0].p, ps3, shape, type);
|
82
|
+
/* rank up */
|
83
|
+
do {
|
84
|
+
if ( ++i >= nd ) return;
|
85
|
+
} while ( --si[i] == 0 );
|
86
|
+
/* next point */
|
87
|
+
s1[i].p += s1[i].pstep;
|
88
|
+
s2[i].p += s2[i].pstep;
|
89
|
+
s3[i].p += s3[i].pstep;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
static na_shape_t
|
94
|
+
na_shape_total( int n, na_shape_t *shape )
|
95
|
+
{
|
96
|
+
na_shape_t total=1;
|
97
|
+
|
98
|
+
for (; n>0; --n)
|
99
|
+
total *= *(shape++);
|
100
|
+
|
101
|
+
return total;
|
102
|
+
}
|
103
|
+
|
104
|
+
static void
|
105
|
+
na_exec_linalg( struct NARRAY *a1, struct NARRAY *a2, struct NARRAY *a3,
|
106
|
+
int ncd1, int ncd2, int ncd3, void (*func)() )
|
107
|
+
{
|
108
|
+
int ndim, ncd, nsz1, nsz2, nsz3;
|
109
|
+
na_shape_t *itr, *shp1, *shp2, *shp3;
|
110
|
+
struct slice *s1, *s2, *s3;
|
111
|
+
|
112
|
+
ncd = NA_MAX3(ncd1,ncd2,ncd3); /* class dim */
|
113
|
+
ndim = NA_MAX3(a1->rank-ncd1, a2->rank-ncd2, a3->rank-ncd3) + ncd;
|
114
|
+
|
115
|
+
NA_ALLOC_SLICE(s1,(ndim+1)*3,shp1,ndim*4);
|
116
|
+
shp2 = &shp1[ndim];
|
117
|
+
shp3 = &shp2[ndim];
|
118
|
+
itr = &shp3[ndim];
|
119
|
+
s2 = &s1[ndim+1];
|
120
|
+
s3 = &s2[ndim+1];
|
121
|
+
|
122
|
+
na_shape_copy( ndim, shp1, a1 );
|
123
|
+
na_shape_copy( ndim, shp2, a2 );
|
124
|
+
na_shape_copy( ndim, shp3, a3 );
|
125
|
+
ndim -= ncd;
|
126
|
+
shp1 += ncd1;
|
127
|
+
shp2 += ncd2;
|
128
|
+
shp3 += ncd3;
|
129
|
+
na_shape_max3( ndim, itr, shp1, shp2, shp3 );
|
130
|
+
|
131
|
+
ndim = na_set_slice_3obj( ndim, s1, s2, s3, shp1, shp2, shp3, itr );
|
132
|
+
|
133
|
+
nsz1 = na_shape_total(a1->rank-ncd1,a1->shape+ncd1);
|
134
|
+
nsz2 = na_shape_total(a2->rank-ncd2,a2->shape+ncd2);
|
135
|
+
nsz3 = na_shape_total(a3->rank-ncd3,a3->shape+ncd3);
|
136
|
+
|
137
|
+
na_init_slice(s1, ndim, shp1, na_sizeof[a1->type]*nsz1 );
|
138
|
+
na_init_slice(s2, ndim, shp2, na_sizeof[a2->type]*nsz2 );
|
139
|
+
na_init_slice(s3, ndim, shp3, na_sizeof[a3->type]*nsz3 );
|
140
|
+
|
141
|
+
na_loop_linalg( ndim, a1->ptr, a2->ptr, a3->ptr,
|
142
|
+
s1, s2, s3, func, a2->shape, a2->type );
|
143
|
+
xfree(s1);
|
144
|
+
}
|
145
|
+
|
146
|
+
|
147
|
+
static int
|
148
|
+
na_lu_fact_func_body(int ni, char *a, char *idx, na_shape_t *shape, int type, char *buf)
|
149
|
+
{
|
150
|
+
na_shape_t i, j, k;
|
151
|
+
int imax;
|
152
|
+
|
153
|
+
char *amax, *rtmp;
|
154
|
+
char *aa, *aii, *aij, *ai0, *a0i, *a0j;
|
155
|
+
char *v, *vi;
|
156
|
+
|
157
|
+
na_funcset_t *f = &na_funcset[type];
|
158
|
+
na_funcset_t *r = &na_funcset[na_cast_real[type]];
|
159
|
+
|
160
|
+
int status = 0;
|
161
|
+
na_shape_t n = shape[0];
|
162
|
+
na_shape_t relmsz = r->elmsz;
|
163
|
+
na_shape_t felmsz = f->elmsz;
|
164
|
+
na_shape_t rowsz = felmsz*n;
|
165
|
+
na_shape_t matsz = rowsz*n;
|
166
|
+
na_shape_t diagsz = rowsz + felmsz;
|
167
|
+
|
168
|
+
v = buf + rowsz;
|
169
|
+
amax = v + relmsz*n;
|
170
|
+
|
171
|
+
while (ni-->0) {
|
172
|
+
|
173
|
+
aa = a;
|
174
|
+
vi = v;
|
175
|
+
|
176
|
+
/* v[j] = 1/max( abs( a[i,j] ) ) */
|
177
|
+
for (j=0;j<n;++j) {
|
178
|
+
f->abs(n, buf, relmsz, aa, felmsz);
|
179
|
+
|
180
|
+
r->set(1, amax,0, r->zero,0);
|
181
|
+
rtmp = buf;
|
182
|
+
for (i=0;i<n;++i) {
|
183
|
+
if (r->sort(rtmp, amax) == 1)
|
184
|
+
r->set(1, amax,0, rtmp,0);
|
185
|
+
rtmp += relmsz;
|
186
|
+
}
|
187
|
+
|
188
|
+
if (r->sort(amax,r->tiny) != 1)
|
189
|
+
status = 2; /* Singular Matrix */
|
190
|
+
|
191
|
+
r->rcp(1, vi,0, amax,0);
|
192
|
+
vi += relmsz;
|
193
|
+
}
|
194
|
+
|
195
|
+
ai0 = a0i = aii = a;
|
196
|
+
vi = v;
|
197
|
+
|
198
|
+
for (i=0;i<n;++i) {
|
199
|
+
|
200
|
+
f->set(n, buf, felmsz, ai0, rowsz);
|
201
|
+
|
202
|
+
aij = buf;
|
203
|
+
a0j = a;
|
204
|
+
/* a[i,j(<i)] -= sum(k<j){ a[i,k]*a[k,j] } */
|
205
|
+
for (j=1;j<i;++j) {
|
206
|
+
aij += felmsz;
|
207
|
+
a0j += rowsz;
|
208
|
+
f->mulsbt(j, aij, 0, buf, felmsz, a0j, felmsz);
|
209
|
+
}
|
210
|
+
/* a[i,j(>=i)] -= sum(k<i){ a[i,k]*a[k,j] } */
|
211
|
+
for ( ;j<n;++j) {
|
212
|
+
aij += felmsz;
|
213
|
+
a0j += rowsz;
|
214
|
+
f->mulsbt(i, aij, 0, buf, felmsz, a0j, felmsz);
|
215
|
+
}
|
216
|
+
f->set(n, ai0, rowsz, buf, felmsz);
|
217
|
+
|
218
|
+
/* pivoting
|
219
|
+
imax = max_idx( abs( a[i,j(>=i)] ) * v[j(>=i)] ) */
|
220
|
+
f->abs(n-i, buf, relmsz, aii, rowsz);
|
221
|
+
r->mul(n-i, buf, relmsz, vi, relmsz);
|
222
|
+
|
223
|
+
r->set(1, amax,0, r->zero,0);
|
224
|
+
rtmp = buf;
|
225
|
+
imax = 0;
|
226
|
+
for (j=i;j<n;++j) {
|
227
|
+
if (r->sort(rtmp,amax) == 1) {
|
228
|
+
r->set(1, amax,0, rtmp,0);
|
229
|
+
imax = j;
|
230
|
+
}
|
231
|
+
rtmp += relmsz;
|
232
|
+
}
|
233
|
+
|
234
|
+
if (r->sort(amax,r->tiny)!=1)
|
235
|
+
status = 1; /* Singular Matrix */
|
236
|
+
|
237
|
+
if (i != imax) {
|
238
|
+
/* a[*,i] <=> a[*,imax] */
|
239
|
+
SWAPMEM(a+i*rowsz, a+imax*rowsz, buf, rowsz);
|
240
|
+
/* v[i] <=> v[imax] */
|
241
|
+
SWAPMEM(vi, v+imax*relmsz, buf, relmsz);
|
242
|
+
NA_SWAP(((int32_t*)idx)[i],((int32_t*)idx)[imax],k);
|
243
|
+
}
|
244
|
+
|
245
|
+
/* a[i,j(>i)] = a[i,j]/a[i,i] */
|
246
|
+
f->div(n-i-1, aii+rowsz, rowsz, aii, 0);
|
247
|
+
|
248
|
+
ai0 += felmsz;
|
249
|
+
a0i += rowsz;
|
250
|
+
aii += diagsz;
|
251
|
+
vi += relmsz;
|
252
|
+
}
|
253
|
+
|
254
|
+
a += matsz;
|
255
|
+
idx += sizeof(int32_t)*n;
|
256
|
+
}
|
257
|
+
return status;
|
258
|
+
}
|
259
|
+
|
260
|
+
|
261
|
+
|
262
|
+
static int
|
263
|
+
na_lu_fact_func(int ni, char *a, char *idx, na_shape_t *shape, int type)
|
264
|
+
{
|
265
|
+
volatile VALUE val;
|
266
|
+
char *buf;
|
267
|
+
int status;
|
268
|
+
na_shape_t size, n=shape[0];
|
269
|
+
|
270
|
+
if (type==NA_ROBJ) {
|
271
|
+
VALUE *mem;
|
272
|
+
int i;
|
273
|
+
size = n*2+1;
|
274
|
+
mem = ALLOC_N(VALUE, size);
|
275
|
+
for (i=0; i<size; i++) mem[i] = Qnil;
|
276
|
+
val = rb_ary_new4(size, mem);
|
277
|
+
xfree(mem);
|
278
|
+
buf = (char*)((RARRAY_PTR(val)));
|
279
|
+
status = na_lu_fact_func_body( ni, a, idx, shape, type, buf );
|
280
|
+
} else {
|
281
|
+
size = na_sizeof[type]*n + na_sizeof[na_cast_real[type]]*(n+1);
|
282
|
+
buf = ALLOC_N(char, size);
|
283
|
+
status = na_lu_fact_func_body( ni, a, idx, shape, type, buf );
|
284
|
+
xfree(buf);
|
285
|
+
}
|
286
|
+
return status;
|
287
|
+
}
|
288
|
+
|
289
|
+
|
290
|
+
/* :nodoc: */
|
291
|
+
static VALUE
|
292
|
+
na_lu_fact_bang(VALUE self)
|
293
|
+
{
|
294
|
+
na_shape_t i, total, n;
|
295
|
+
int sz, stat;
|
296
|
+
struct NARRAY *ary;
|
297
|
+
VALUE piv;
|
298
|
+
char *ptr, *idx;
|
299
|
+
void (*func)();
|
300
|
+
|
301
|
+
GetNArray(self,ary);
|
302
|
+
|
303
|
+
/* shape & dimension check */
|
304
|
+
if (ary->rank<2)
|
305
|
+
rb_raise(rb_eTypeError,"dim(=%i) < 2", ary->rank);
|
306
|
+
|
307
|
+
n = ary->shape[0];
|
308
|
+
if (n != ary->shape[1])
|
309
|
+
rb_raise(rb_eTypeError,"not square matrix");
|
310
|
+
|
311
|
+
total=1;
|
312
|
+
for (i=2; i<ary->rank; ++i)
|
313
|
+
total *= ary->shape[i];
|
314
|
+
|
315
|
+
piv = na_make_object(NA_LINT, ary->rank-1, ary->shape+1, cNVector);
|
316
|
+
|
317
|
+
/* prepare pivot index */
|
318
|
+
func = IndGenFuncs[NA_LINT];
|
319
|
+
sz = na_sizeof[NA_LINT];
|
320
|
+
ptr = idx = ((struct NARRAY *)DATA_PTR(piv))->ptr;
|
321
|
+
for (i=0; i<total; ++i) {
|
322
|
+
func(n,ptr,sz,0,1);
|
323
|
+
ptr += n*sz;
|
324
|
+
}
|
325
|
+
|
326
|
+
stat = na_lu_fact_func(total, ary->ptr, idx, ary->shape, ary->type);
|
327
|
+
|
328
|
+
if (stat!=0)
|
329
|
+
rb_raise(rb_eZeroDivError,"singular matrix, status=%i",stat);
|
330
|
+
|
331
|
+
return rb_funcall(cNMatrixLU,na_id_new,2,self,piv);
|
332
|
+
}
|
333
|
+
|
334
|
+
|
335
|
+
/* :nodoc: */
|
336
|
+
static VALUE
|
337
|
+
na_lu_fact(VALUE self)
|
338
|
+
{
|
339
|
+
return na_lu_fact_bang( na_clone(self) );
|
340
|
+
}
|
341
|
+
|
342
|
+
|
343
|
+
static void
|
344
|
+
na_lu_pivot_func( int ni,
|
345
|
+
char *x, int ps1, char *y, int ps2, char *idx, int ps3,
|
346
|
+
na_shape_t *shape, int type )
|
347
|
+
{
|
348
|
+
int i, n, sz;
|
349
|
+
char *xi;
|
350
|
+
na_funcset_t *f = &na_funcset[type];
|
351
|
+
|
352
|
+
n = shape[1];
|
353
|
+
sz = f->elmsz * shape[0];
|
354
|
+
|
355
|
+
for (; ni>0; --ni) {
|
356
|
+
xi = x;
|
357
|
+
for (i=0; i<n; ++i) {
|
358
|
+
memcpy(xi, y+((int32_t*)idx)[i]*sz, sz);
|
359
|
+
xi += sz;
|
360
|
+
}
|
361
|
+
x += ps1;
|
362
|
+
y += ps2;
|
363
|
+
idx += ps3;
|
364
|
+
}
|
365
|
+
}
|
366
|
+
|
367
|
+
|
368
|
+
|
369
|
+
static void
|
370
|
+
na_lu_solve_func_body( int ni,
|
371
|
+
char *x, int ps1, char *a, int ps2,
|
372
|
+
na_shape_t *shape, int type, char *buf )
|
373
|
+
{
|
374
|
+
char *aii, *a0i, *xx, *xi;
|
375
|
+
na_shape_t i,k;
|
376
|
+
na_funcset_t *f = &na_funcset[type];
|
377
|
+
na_shape_t n = shape[1];
|
378
|
+
int sz = na_sizeof[type];
|
379
|
+
na_shape_t xsz = shape[0] * sz;
|
380
|
+
na_shape_t rowsz = sz * n;
|
381
|
+
na_shape_t matsz = rowsz * n;
|
382
|
+
na_shape_t diagsz = rowsz + sz;
|
383
|
+
|
384
|
+
for (; ni>0; --ni) {
|
385
|
+
|
386
|
+
xx = x;
|
387
|
+
|
388
|
+
for (k=shape[0]; k>0; --k) { /* once if x is vector */
|
389
|
+
|
390
|
+
f->set(n, buf,sz, xx,xsz);
|
391
|
+
|
392
|
+
xi = buf;
|
393
|
+
a0i = a;
|
394
|
+
|
395
|
+
/* solve Lx' = y' */
|
396
|
+
for (i=1; i<n; ++i) {
|
397
|
+
/* x[i] -= a[j(<i),i] * x[j(<i)] */
|
398
|
+
xi += sz;
|
399
|
+
a0i += rowsz;
|
400
|
+
f->mulsbt(i, xi, 0, a0i, sz, buf, sz);
|
401
|
+
}
|
402
|
+
|
403
|
+
xi = buf + sz*(n-1);
|
404
|
+
aii = a + (matsz-sz);
|
405
|
+
|
406
|
+
/* solve Ux = x' */
|
407
|
+
f->div(1, xi,0, aii,0);
|
408
|
+
for (i=n-1; i>0; --i) {
|
409
|
+
xi -= sz;
|
410
|
+
aii -= diagsz;
|
411
|
+
/* x[i] -= a[j(>i),i] * x[j(>i)] */
|
412
|
+
f->mulsbt(n-i, xi,0, aii+sz, sz, xi+sz, sz);
|
413
|
+
/* x[i] /= a[i,i] */
|
414
|
+
f->div(1, xi,0, aii,0);
|
415
|
+
}
|
416
|
+
|
417
|
+
f->set(n, xx,xsz, buf,sz);
|
418
|
+
|
419
|
+
xx += sz;
|
420
|
+
}
|
421
|
+
|
422
|
+
x += ps1;
|
423
|
+
a += ps2;
|
424
|
+
}
|
425
|
+
}
|
426
|
+
|
427
|
+
|
428
|
+
static void
|
429
|
+
na_lu_solve_func( int ni,
|
430
|
+
char *z, int ps, char *x, int ps1, char *a, int ps2,
|
431
|
+
na_shape_t *shape, int type )
|
432
|
+
{
|
433
|
+
volatile VALUE val;
|
434
|
+
char *buf;
|
435
|
+
na_shape_t size;
|
436
|
+
|
437
|
+
if (type==NA_ROBJ) {
|
438
|
+
VALUE *mem;
|
439
|
+
na_shape_t i;
|
440
|
+
size = shape[1];
|
441
|
+
mem = ALLOC_N(VALUE, size);
|
442
|
+
for (i=0; i<size; i++) mem[i] = Qnil;
|
443
|
+
val = rb_ary_new4(size, mem);
|
444
|
+
xfree(mem);
|
445
|
+
buf = (char*)((RARRAY_PTR(val)));
|
446
|
+
na_lu_solve_func_body( ni, x, ps1, a, ps2, shape, type, buf );
|
447
|
+
} else {
|
448
|
+
size = shape[1] * na_sizeof[type];
|
449
|
+
buf = ALLOC_N(char, size);
|
450
|
+
na_lu_solve_func_body( ni, x, ps1, a, ps2, shape, type, buf );
|
451
|
+
xfree(buf);
|
452
|
+
}
|
453
|
+
}
|
454
|
+
|
455
|
+
|
456
|
+
static void
|
457
|
+
na_shape_max2(int ndim, na_shape_t *shape, int n1, na_shape_t *shape1, int n2, na_shape_t *shape2)
|
458
|
+
{
|
459
|
+
na_shape_t *tmp;
|
460
|
+
int i;
|
461
|
+
|
462
|
+
if (n1 < n2) {
|
463
|
+
NA_SWAP(shape1,shape2,tmp);
|
464
|
+
}
|
465
|
+
|
466
|
+
for (i=0; i<n2; ++i) {
|
467
|
+
shape[i] = NA_MAX(shape1[i],shape2[i]);
|
468
|
+
}
|
469
|
+
for ( ; i<n1; ++i) {
|
470
|
+
shape[i] = shape1[i];
|
471
|
+
}
|
472
|
+
for ( ; i<ndim; ++i) {
|
473
|
+
shape[i] = 1;
|
474
|
+
}
|
475
|
+
}
|
476
|
+
|
477
|
+
|
478
|
+
|
479
|
+
/*
|
480
|
+
* call-seq:
|
481
|
+
* lu.solve(arg) -> result
|
482
|
+
*
|
483
|
+
* Solve with the result of LU factorization.
|
484
|
+
* arg should be NMatrix or NVector instance.
|
485
|
+
* Returns an instance of same class with arg.
|
486
|
+
*/
|
487
|
+
static VALUE
|
488
|
+
na_lu_solve(VALUE self, volatile VALUE other)
|
489
|
+
{
|
490
|
+
int ndim;
|
491
|
+
na_shape_t n, *shape;
|
492
|
+
struct NARRAY *a1, *a2, *l, *p;
|
493
|
+
VALUE pv, obj, klass;
|
494
|
+
volatile VALUE lu;
|
495
|
+
|
496
|
+
klass = CLASS_OF(other);
|
497
|
+
if (klass==cNVector)
|
498
|
+
other = na_newdim_ref(1,(VALUE*)na_funcset[NA_ROBJ].zero,other);
|
499
|
+
else if (klass!=cNMatrix)
|
500
|
+
rb_raise(rb_eTypeError,"neither NMatrix or NVector");
|
501
|
+
|
502
|
+
lu = rb_ivar_get(self, id_lu);
|
503
|
+
pv = rb_ivar_get(self, id_pivot);
|
504
|
+
|
505
|
+
GetNArray(lu,l);
|
506
|
+
|
507
|
+
other = na_upcast_object(other,l->type);
|
508
|
+
GetNArray(other,a1);
|
509
|
+
|
510
|
+
lu = na_upcast_type(lu,a1->type);
|
511
|
+
GetNArray(lu,l);
|
512
|
+
GetNArray(pv,p);
|
513
|
+
|
514
|
+
n = l->shape[0];
|
515
|
+
if (n != a1->shape[1])
|
516
|
+
rb_raise(rb_eTypeError,"size mismatch (%zd!=%zd)",n,a1->shape[1]);
|
517
|
+
|
518
|
+
ndim = NA_MAX(l->rank, a1->rank);
|
519
|
+
shape = ALLOCA_N(na_shape_t, ndim);
|
520
|
+
|
521
|
+
shape[0] = a1->shape[0];
|
522
|
+
na_shape_max2( ndim-1, shape+1, a1->rank-1, a1->shape+1,
|
523
|
+
l->rank-1, l->shape+1 );
|
524
|
+
obj = na_make_object( a1->type, ndim, shape, klass );
|
525
|
+
|
526
|
+
GetNArray(obj,a2);
|
527
|
+
|
528
|
+
na_exec_linalg( a2, a1, p, 2, 2, 1, na_lu_pivot_func );
|
529
|
+
na_exec_linalg( a2, a2, l, 2, 2, 2, na_lu_solve_func );
|
530
|
+
|
531
|
+
if (klass==cNVector) {
|
532
|
+
shape = ALLOC_N(na_shape_t, ndim-1);
|
533
|
+
memcpy(shape,a2->shape+1,sizeof(na_shape_t)*(ndim-1));
|
534
|
+
xfree(a2->shape);
|
535
|
+
a2->shape = shape;
|
536
|
+
--(a2->rank);
|
537
|
+
}
|
538
|
+
return obj;
|
539
|
+
}
|
540
|
+
|
541
|
+
|
542
|
+
/* :nodoc: */
|
543
|
+
static VALUE
|
544
|
+
na_lu_init(VALUE self, VALUE lu, VALUE piv)
|
545
|
+
{
|
546
|
+
int i;
|
547
|
+
struct NARRAY *l, *p;
|
548
|
+
|
549
|
+
if (CLASS_OF(lu)!=cNMatrix)
|
550
|
+
rb_raise(rb_eTypeError,"LU should be NMatrix");
|
551
|
+
if (CLASS_OF(piv)!=cNVector)
|
552
|
+
rb_raise(rb_eTypeError,"pivot should be NVector");
|
553
|
+
|
554
|
+
GetNArray(lu,l);
|
555
|
+
GetNArray(piv,p);
|
556
|
+
|
557
|
+
if (p->type != NA_LINT)
|
558
|
+
rb_raise(rb_eRuntimeError,"pivot type must be Integer");
|
559
|
+
|
560
|
+
if (l->rank != p->rank+1)
|
561
|
+
rb_raise(rb_eRuntimeError,"array dimension mismatch %i!=%i+1",
|
562
|
+
l->rank, p->rank);
|
563
|
+
|
564
|
+
if (l->shape[0] != l->shape[1])
|
565
|
+
rb_raise(rb_eRuntimeError,"LU matrix (%zd,%zd) is not square",
|
566
|
+
l->shape[0], l->shape[1]);
|
567
|
+
|
568
|
+
for (i=1; i<l->rank; ++i)
|
569
|
+
if (l->shape[i] != p->shape[i-1])
|
570
|
+
rb_raise(rb_eRuntimeError,"array size mismatch %zd!=%zd at %i",
|
571
|
+
l->shape[i], p->shape[i-1], i);
|
572
|
+
|
573
|
+
rb_ivar_set(self, id_lu, lu);
|
574
|
+
rb_ivar_set(self, id_pivot, piv);
|
575
|
+
return Qnil;
|
576
|
+
}
|
577
|
+
|
578
|
+
|
579
|
+
|
580
|
+
void Init_na_linalg()
|
581
|
+
{
|
582
|
+
static double tiny_d = 1e-15;
|
583
|
+
static float tiny_f = (float)1e-7;
|
584
|
+
int i, sz;
|
585
|
+
int32_t one=1, zero=0;
|
586
|
+
static VALUE zerov = INT2FIX(0);
|
587
|
+
static VALUE onev = INT2FIX(1);
|
588
|
+
char *a = malloc(NA_NTYPES*sizeof(dcomplex)*2);
|
589
|
+
|
590
|
+
for (i=1;i<NA_NTYPES;++i) {
|
591
|
+
sz = na_funcset[i].elmsz = na_sizeof[i];
|
592
|
+
sz = (sz>((int)sizeof(int))) ? sz : (int)sizeof(int);
|
593
|
+
SetFuncs[i][NA_LINT](1, a,0, &one, 0);
|
594
|
+
na_funcset[i].one = a;
|
595
|
+
a += sz;
|
596
|
+
SetFuncs[i][NA_LINT](1, a,0, &zero,0);
|
597
|
+
na_funcset[i].zero = a;
|
598
|
+
na_funcset[i].tiny = a;
|
599
|
+
a += sz;
|
600
|
+
na_funcset[i].set = SetFuncs[i][i];
|
601
|
+
na_funcset[i].neg = NegFuncs[i];
|
602
|
+
na_funcset[i].rcp = RcpFuncs[i];
|
603
|
+
na_funcset[i].abs = AbsFuncs[i];
|
604
|
+
na_funcset[i].add = AddUFuncs[i];
|
605
|
+
na_funcset[i].sbt = SbtUFuncs[i];
|
606
|
+
na_funcset[i].mul = MulUFuncs[i];
|
607
|
+
na_funcset[i].div = DivUFuncs[i];
|
608
|
+
na_funcset[i].mod = ModUFuncs[i];
|
609
|
+
na_funcset[i].muladd = MulAddFuncs[i];
|
610
|
+
na_funcset[i].mulsbt = MulSbtFuncs[i];
|
611
|
+
na_funcset[i].cmp = CmpFuncs[i];
|
612
|
+
na_funcset[i].min = MinFuncs[i];
|
613
|
+
na_funcset[i].max = MaxFuncs[i];
|
614
|
+
na_funcset[i].sort = SortFuncs[i];
|
615
|
+
}
|
616
|
+
na_funcset[NA_SFLOAT].tiny = (char*)&tiny_f;
|
617
|
+
na_funcset[NA_DFLOAT].tiny = (char*)&tiny_d;
|
618
|
+
na_funcset[NA_ROBJ].zero = (char*)&zerov;
|
619
|
+
na_funcset[NA_ROBJ].one = (char*)&onev;
|
620
|
+
|
621
|
+
cNVector = rb_define_class("NVector",cNArray);
|
622
|
+
cNMatrix = rb_define_class("NMatrix",cNArray);
|
623
|
+
cNMatrixLU = rb_define_class("NMatrixLU",rb_cObject);
|
624
|
+
|
625
|
+
rb_define_method(cNMatrix, "lu_fact!", na_lu_fact_bang, 0);
|
626
|
+
rb_define_alias(cNMatrix, "lu!","lu_fact!");
|
627
|
+
rb_define_method(cNMatrix, "lu_fact", na_lu_fact, 0);
|
628
|
+
rb_define_alias(cNMatrix, "lu","lu_fact");
|
629
|
+
|
630
|
+
rb_define_method(cNMatrixLU, "initialize", na_lu_init, 2);
|
631
|
+
rb_define_method(cNMatrixLU, "solve", na_lu_solve, 1);
|
632
|
+
|
633
|
+
id_lu = rb_intern("@lu");
|
634
|
+
id_pivot = rb_intern("@pivot");
|
635
|
+
}
|