numru-narray 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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(VALUE mNumRu)
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_under(mNumRu, "NVector",cNArray);
622
+ cNMatrix = rb_define_class_under(mNumRu, "NMatrix",cNArray);
623
+ cNMatrixLU = rb_define_class_under(mNumRu, "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
+ }