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,633 @@
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)(), int *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 int
94
+ na_shape_total( int n, int *shape )
95
+ {
96
+ int 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
+ int *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, int *shape, int type, char *buf)
149
+ {
150
+ int 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
+ int n = shape[0];
162
+ int relmsz = r->elmsz;
163
+ int felmsz = f->elmsz;
164
+ int rowsz = felmsz*n;
165
+ int matsz = rowsz*n;
166
+ int 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, int *shape, int type)
264
+ {
265
+ volatile VALUE val;
266
+ char *buf;
267
+ int status, size, n=shape[0];
268
+
269
+ if (type==NA_ROBJ) {
270
+ VALUE *mem;
271
+ int i;
272
+ size = n*2+1;
273
+ mem = ALLOC_N(VALUE, size);
274
+ for (i=0; i<size; i++) mem[i] = Qnil;
275
+ val = rb_ary_new4(size, mem);
276
+ xfree(mem);
277
+ buf = (char*)((RARRAY_PTR(val)));
278
+ status = na_lu_fact_func_body( ni, a, idx, shape, type, buf );
279
+ } else {
280
+ size = na_sizeof[type]*n + na_sizeof[na_cast_real[type]]*(n+1);
281
+ buf = ALLOC_N(char, size);
282
+ status = na_lu_fact_func_body( ni, a, idx, shape, type, buf );
283
+ xfree(buf);
284
+ }
285
+ return status;
286
+ }
287
+
288
+
289
+ /* :nodoc: */
290
+ static VALUE
291
+ na_lu_fact_bang(VALUE self)
292
+ {
293
+ int i, total, n, sz, stat;
294
+ struct NARRAY *ary;
295
+ VALUE piv;
296
+ char *ptr, *idx;
297
+ void (*func)();
298
+
299
+ GetNArray(self,ary);
300
+
301
+ /* shape & dimension check */
302
+ if (ary->rank<2)
303
+ rb_raise(rb_eTypeError,"dim(=%i) < 2", ary->rank);
304
+
305
+ n = ary->shape[0];
306
+ if (n != ary->shape[1])
307
+ rb_raise(rb_eTypeError,"not square matrix");
308
+
309
+ total=1;
310
+ for (i=2; i<ary->rank; ++i)
311
+ total *= ary->shape[i];
312
+
313
+ piv = na_make_object(NA_LINT, ary->rank-1, ary->shape+1, cNVector);
314
+
315
+ /* prepare pivot index */
316
+ func = IndGenFuncs[NA_LINT];
317
+ sz = na_sizeof[NA_LINT];
318
+ ptr = idx = ((struct NARRAY *)DATA_PTR(piv))->ptr;
319
+ for (i=0; i<total; ++i) {
320
+ func(n,ptr,sz,0,1);
321
+ ptr += n*sz;
322
+ }
323
+
324
+ stat = na_lu_fact_func(total, ary->ptr, idx, ary->shape, ary->type);
325
+
326
+ if (stat!=0)
327
+ rb_raise(rb_eZeroDivError,"singular matrix, status=%i",stat);
328
+
329
+ return rb_funcall(cNMatrixLU,na_id_new,2,self,piv);
330
+ }
331
+
332
+
333
+ /* :nodoc: */
334
+ static VALUE
335
+ na_lu_fact(VALUE self)
336
+ {
337
+ return na_lu_fact_bang( na_clone(self) );
338
+ }
339
+
340
+
341
+ static void
342
+ na_lu_pivot_func( int ni,
343
+ char *x, int ps1, char *y, int ps2, char *idx, int ps3,
344
+ int *shape, int type )
345
+ {
346
+ int i, n, sz;
347
+ char *xi;
348
+ na_funcset_t *f = &na_funcset[type];
349
+
350
+ n = shape[1];
351
+ sz = f->elmsz * shape[0];
352
+
353
+ for (; ni>0; --ni) {
354
+ xi = x;
355
+ for (i=0; i<n; ++i) {
356
+ memcpy(xi, y+((int32_t*)idx)[i]*sz, sz);
357
+ xi += sz;
358
+ }
359
+ x += ps1;
360
+ y += ps2;
361
+ idx += ps3;
362
+ }
363
+ }
364
+
365
+
366
+
367
+ static void
368
+ na_lu_solve_func_body( int ni,
369
+ char *x, int ps1, char *a, int ps2,
370
+ int *shape, int type, char *buf )
371
+ {
372
+ char *aii, *a0i, *xx, *xi;
373
+ int i,k;
374
+ na_funcset_t *f = &na_funcset[type];
375
+ int n = shape[1];
376
+ int sz = na_sizeof[type];
377
+ int xsz = shape[0] * sz;
378
+ int rowsz = sz * n;
379
+ int matsz = rowsz * n;
380
+ int diagsz = rowsz + sz;
381
+
382
+ for (; ni>0; --ni) {
383
+
384
+ xx = x;
385
+
386
+ for (k=shape[0]; k>0; --k) { /* once if x is vector */
387
+
388
+ f->set(n, buf,sz, xx,xsz);
389
+
390
+ xi = buf;
391
+ a0i = a;
392
+
393
+ /* solve Lx' = y' */
394
+ for (i=1; i<n; ++i) {
395
+ /* x[i] -= a[j(<i),i] * x[j(<i)] */
396
+ xi += sz;
397
+ a0i += rowsz;
398
+ f->mulsbt(i, xi, 0, a0i, sz, buf, sz);
399
+ }
400
+
401
+ xi = buf + sz*(n-1);
402
+ aii = a + (matsz-sz);
403
+
404
+ /* solve Ux = x' */
405
+ f->div(1, xi,0, aii,0);
406
+ for (i=n-1; i>0; --i) {
407
+ xi -= sz;
408
+ aii -= diagsz;
409
+ /* x[i] -= a[j(>i),i] * x[j(>i)] */
410
+ f->mulsbt(n-i, xi,0, aii+sz, sz, xi+sz, sz);
411
+ /* x[i] /= a[i,i] */
412
+ f->div(1, xi,0, aii,0);
413
+ }
414
+
415
+ f->set(n, xx,xsz, buf,sz);
416
+
417
+ xx += sz;
418
+ }
419
+
420
+ x += ps1;
421
+ a += ps2;
422
+ }
423
+ }
424
+
425
+
426
+ static void
427
+ na_lu_solve_func( int ni,
428
+ char *z, int ps, char *x, int ps1, char *a, int ps2,
429
+ int *shape, int type )
430
+ {
431
+ volatile VALUE val;
432
+ char *buf;
433
+ int size;
434
+
435
+ if (type==NA_ROBJ) {
436
+ VALUE *mem;
437
+ int i;
438
+ size = shape[1];
439
+ mem = ALLOC_N(VALUE, size);
440
+ for (i=0; i<size; i++) mem[i] = Qnil;
441
+ val = rb_ary_new4(size, mem);
442
+ xfree(mem);
443
+ buf = (char*)((RARRAY_PTR(val)));
444
+ na_lu_solve_func_body( ni, x, ps1, a, ps2, shape, type, buf );
445
+ } else {
446
+ size = shape[1] * na_sizeof[type];
447
+ buf = ALLOC_N(char, size);
448
+ na_lu_solve_func_body( ni, x, ps1, a, ps2, shape, type, buf );
449
+ xfree(buf);
450
+ }
451
+ }
452
+
453
+
454
+ static void
455
+ na_shape_max2(int ndim, int *shape, int n1, int *shape1, int n2, int *shape2)
456
+ {
457
+ int *tmp;
458
+ int i;
459
+
460
+ if (n1 < n2) {
461
+ NA_SWAP(shape1,shape2,tmp);
462
+ }
463
+
464
+ for (i=0; i<n2; ++i) {
465
+ shape[i] = NA_MAX(shape1[i],shape2[i]);
466
+ }
467
+ for ( ; i<n1; ++i) {
468
+ shape[i] = shape1[i];
469
+ }
470
+ for ( ; i<ndim; ++i) {
471
+ shape[i] = 1;
472
+ }
473
+ }
474
+
475
+
476
+
477
+ /*
478
+ * call-seq:
479
+ * lu.solve(arg) -> result
480
+ *
481
+ * Solve with the result of LU factorization.
482
+ * arg should be NMatrix or NVector instance.
483
+ * Returns an instance of same class with arg.
484
+ */
485
+ static VALUE
486
+ na_lu_solve(VALUE self, volatile VALUE other)
487
+ {
488
+ int n, ndim;
489
+ int *shape;
490
+ struct NARRAY *a1, *a2, *l, *p;
491
+ VALUE pv, obj, klass;
492
+ volatile VALUE lu;
493
+
494
+ klass = CLASS_OF(other);
495
+ if (klass==cNVector)
496
+ other = na_newdim_ref(1,(VALUE*)na_funcset[NA_ROBJ].zero,other);
497
+ else if (klass!=cNMatrix)
498
+ rb_raise(rb_eTypeError,"neither NMatrix or NVector");
499
+
500
+ lu = rb_ivar_get(self, id_lu);
501
+ pv = rb_ivar_get(self, id_pivot);
502
+
503
+ GetNArray(lu,l);
504
+
505
+ other = na_upcast_object(other,l->type);
506
+ GetNArray(other,a1);
507
+
508
+ lu = na_upcast_type(lu,a1->type);
509
+ GetNArray(lu,l);
510
+ GetNArray(pv,p);
511
+
512
+ n = l->shape[0];
513
+ if (n != a1->shape[1])
514
+ rb_raise(rb_eTypeError,"size mismatch (%i!=%i)",n,a1->shape[1]);
515
+
516
+ ndim = NA_MAX(l->rank, a1->rank);
517
+ shape = ALLOCA_N(int, ndim);
518
+
519
+ shape[0] = a1->shape[0];
520
+ na_shape_max2( ndim-1, shape+1, a1->rank-1, a1->shape+1,
521
+ l->rank-1, l->shape+1 );
522
+ obj = na_make_object( a1->type, ndim, shape, klass );
523
+
524
+ GetNArray(obj,a2);
525
+
526
+ na_exec_linalg( a2, a1, p, 2, 2, 1, na_lu_pivot_func );
527
+ na_exec_linalg( a2, a2, l, 2, 2, 2, na_lu_solve_func );
528
+
529
+ if (klass==cNVector) {
530
+ shape = ALLOC_N(int, ndim-1);
531
+ memcpy(shape,a2->shape+1,sizeof(int)*(ndim-1));
532
+ xfree(a2->shape);
533
+ a2->shape = shape;
534
+ --(a2->rank);
535
+ }
536
+ return obj;
537
+ }
538
+
539
+
540
+ /* :nodoc: */
541
+ static VALUE
542
+ na_lu_init(VALUE self, VALUE lu, VALUE piv)
543
+ {
544
+ int i;
545
+ struct NARRAY *l, *p;
546
+
547
+ if (CLASS_OF(lu)!=cNMatrix)
548
+ rb_raise(rb_eTypeError,"LU should be NMatrix");
549
+ if (CLASS_OF(piv)!=cNVector)
550
+ rb_raise(rb_eTypeError,"pivot should be NVector");
551
+
552
+ GetNArray(lu,l);
553
+ GetNArray(piv,p);
554
+
555
+ if (p->type != NA_LINT)
556
+ rb_raise(rb_eRuntimeError,"pivot type must be Integer");
557
+
558
+ if (l->rank != p->rank+1)
559
+ rb_raise(rb_eRuntimeError,"array dimension mismatch %i!=%i+1",
560
+ l->rank, p->rank);
561
+
562
+ if (l->shape[0] != l->shape[1])
563
+ rb_raise(rb_eRuntimeError,"LU matrix (%i,%i) is not square",
564
+ l->shape[0], l->shape[1]);
565
+
566
+ for (i=1; i<l->rank; ++i)
567
+ if (l->shape[i] != p->shape[i-1])
568
+ rb_raise(rb_eRuntimeError,"array size mismatch %i!=%i at %i",
569
+ l->shape[i], p->shape[i-1], i);
570
+
571
+ rb_ivar_set(self, id_lu, lu);
572
+ rb_ivar_set(self, id_pivot, piv);
573
+ return Qnil;
574
+ }
575
+
576
+
577
+
578
+ void Init_na_linalg()
579
+ {
580
+ static double tiny_d = 1e-15;
581
+ static float tiny_f = (float)1e-7;
582
+ int i, sz;
583
+ int32_t one=1, zero=0;
584
+ static VALUE zerov = INT2FIX(0);
585
+ static VALUE onev = INT2FIX(1);
586
+ char *a = malloc(NA_NTYPES*sizeof(dcomplex)*2);
587
+
588
+ for (i=1;i<NA_NTYPES;++i) {
589
+ sz = na_funcset[i].elmsz = na_sizeof[i];
590
+ sz = (sz>((int)sizeof(int))) ? sz : (int)sizeof(int);
591
+ SetFuncs[i][NA_LINT](1, a,0, &one, 0);
592
+ na_funcset[i].one = a;
593
+ a += sz;
594
+ SetFuncs[i][NA_LINT](1, a,0, &zero,0);
595
+ na_funcset[i].zero = a;
596
+ na_funcset[i].tiny = a;
597
+ a += sz;
598
+ na_funcset[i].set = SetFuncs[i][i];
599
+ na_funcset[i].neg = NegFuncs[i];
600
+ na_funcset[i].rcp = RcpFuncs[i];
601
+ na_funcset[i].abs = AbsFuncs[i];
602
+ na_funcset[i].add = AddUFuncs[i];
603
+ na_funcset[i].sbt = SbtUFuncs[i];
604
+ na_funcset[i].mul = MulUFuncs[i];
605
+ na_funcset[i].div = DivUFuncs[i];
606
+ na_funcset[i].mod = ModUFuncs[i];
607
+ na_funcset[i].muladd = MulAddFuncs[i];
608
+ na_funcset[i].mulsbt = MulSbtFuncs[i];
609
+ na_funcset[i].cmp = CmpFuncs[i];
610
+ na_funcset[i].min = MinFuncs[i];
611
+ na_funcset[i].max = MaxFuncs[i];
612
+ na_funcset[i].sort = SortFuncs[i];
613
+ }
614
+ na_funcset[NA_SFLOAT].tiny = (char*)&tiny_f;
615
+ na_funcset[NA_DFLOAT].tiny = (char*)&tiny_d;
616
+ na_funcset[NA_ROBJ].zero = (char*)&zerov;
617
+ na_funcset[NA_ROBJ].one = (char*)&onev;
618
+
619
+ cNVector = rb_define_class_under(cNArray, "NVector",cNArray);
620
+ cNMatrix = rb_define_class_under(cNArray, "NMatrix",cNArray);
621
+ cNMatrixLU = rb_define_class_under(cNArray, "NMatrixLU",rb_cObject);
622
+
623
+ rb_define_method(cNMatrix, "lu_fact!", na_lu_fact_bang, 0);
624
+ rb_define_alias(cNMatrix, "lu!","lu_fact!");
625
+ rb_define_method(cNMatrix, "lu_fact", na_lu_fact, 0);
626
+ rb_define_alias(cNMatrix, "lu","lu_fact");
627
+
628
+ rb_define_method(cNMatrixLU, "initialize", na_lu_init, 2);
629
+ rb_define_method(cNMatrixLU, "solve", na_lu_solve, 1);
630
+
631
+ id_lu = rb_intern("@lu");
632
+ id_pivot = rb_intern("@pivot");
633
+ }