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,650 @@
1
+ /*
2
+ na_array.c
3
+ Numerical Array Extention for Ruby
4
+ (C) Copyright 1999-2008 by Masahiro TANAKA
5
+
6
+ This program is free software.
7
+ You can distribute/modify this program
8
+ under the same terms as Ruby itself.
9
+ NO WARRANTY.
10
+ */
11
+ #include <ruby.h>
12
+ #include "narray.h"
13
+ #include "narray_local.h"
14
+
15
+ /* Multi-Dimensional Array Investigation */
16
+ typedef struct {
17
+ int shape;
18
+ VALUE val;
19
+ } na_mdai_item_t;
20
+
21
+ typedef struct {
22
+ int n;
23
+ na_mdai_item_t *item;
24
+ int *type;
25
+ } na_mdai_t;
26
+
27
+
28
+ int na_object_type(VALUE v)
29
+ {
30
+ switch(TYPE(v)) {
31
+
32
+ case T_TRUE:
33
+ case T_FALSE:
34
+ return NA_BYTE;
35
+
36
+ case T_FIXNUM:
37
+ case T_BIGNUM:
38
+ return NA_LINT;
39
+
40
+ case T_FLOAT:
41
+ return NA_DFLOAT;
42
+
43
+ case T_NIL:
44
+ return NA_NONE;
45
+
46
+ default:
47
+ if (IsNArray(v))
48
+ return ((struct NARRAY *)(RDATA(v)->data))->type ;
49
+
50
+ if (CLASS_OF(v) == cComplex)
51
+ return NA_DCOMPLEX;
52
+ }
53
+ return NA_ROBJ;
54
+ }
55
+
56
+
57
+ static na_mdai_t *
58
+ na_alloc_mdai(VALUE ary)
59
+ {
60
+ int i, n=2;
61
+ na_mdai_t *mdai;
62
+
63
+ mdai = ALLOC(na_mdai_t);
64
+ mdai->n = n;
65
+ mdai->item = ALLOC_N( na_mdai_item_t, n );
66
+ for (i=0; i<n; ++i) {
67
+ mdai->item[i].shape = 0;
68
+ mdai->item[i].val = Qnil;
69
+ }
70
+ mdai->item[0].val = ary;
71
+ mdai->type = ALLOC_N( int, NA_NTYPES );
72
+ for (i=0; i<NA_NTYPES; ++i)
73
+ mdai->type[i]=0;
74
+
75
+ return mdai;
76
+ }
77
+
78
+ static void
79
+ na_realloc_mdai(na_mdai_t *mdai, int n_extra)
80
+ {
81
+ int i, n;
82
+
83
+ i = mdai->n;
84
+ mdai->n += n_extra;
85
+ n = mdai->n;
86
+ REALLOC_N( mdai->item, na_mdai_item_t, n );
87
+ for (; i<n; ++i) {
88
+ mdai->item[i].shape = 0;
89
+ mdai->item[i].val = Qnil;
90
+ }
91
+ }
92
+
93
+ static int *
94
+ na_free_mdai(na_mdai_t *mdai, int *rank, int *type)
95
+ {
96
+ int i, t, r;
97
+ int *shape;
98
+
99
+ for (t=i=NA_BYTE; i<NA_NTYPES; ++i) {
100
+ if ( mdai->type[i] > 0 )
101
+ t = na_upcast[t][i];
102
+ }
103
+ *type = t;
104
+ for (i=0; i < mdai->n && mdai->item[i].shape > 0; ++i) ;
105
+ *rank = r = i;
106
+ shape = ALLOC_N(int,r);
107
+ for (i=0; r-->0; ++i) {
108
+ shape[i] = mdai->item[r].shape;
109
+ }
110
+ xfree(mdai->type);
111
+ xfree(mdai->item);
112
+ xfree(mdai);
113
+ return shape;
114
+ }
115
+
116
+
117
+ #define EXCL(r) (RTEST(rb_funcall((r),na_id_exclude_end,0)))
118
+
119
+ /* Range as a Sequence of numbers */
120
+ static void
121
+ na_range_to_sequence(VALUE obj, int *n, int *beg, int *step)
122
+ {
123
+ int end,len;
124
+
125
+ *beg = NUM2INT(rb_funcall(obj, na_id_beg, 0));
126
+ end = NUM2INT(rb_funcall(obj, na_id_end, 0));
127
+ len = end - *beg;
128
+
129
+ /* direction */
130
+ if (len>0) {
131
+ *step = 1;
132
+ if (EXCL(obj)) --end; else ++len;
133
+ }
134
+ else if (len<0) {
135
+ len = -len;
136
+ *step = -1;
137
+ if (EXCL(obj)) ++end; else ++len;
138
+ }
139
+ else /*if(len==0)*/ {
140
+ *step = 0;
141
+ if (!EXCL(obj)) {
142
+ ++len;
143
+ }
144
+ }
145
+ *n = len;
146
+ }
147
+
148
+
149
+ /* investigate rank, shape, type of Array */
150
+ static int
151
+ na_do_mdai(na_mdai_t *mdai, int rank)
152
+ {
153
+ int i, j, len, length, start, dir;
154
+ VALUE v;
155
+ VALUE ary;
156
+
157
+ ary = mdai->item[rank-1].val;
158
+ len = RARRAY_LEN(ary);
159
+
160
+ for (i=0; i < RARRAY_LEN(ary); ++i) {
161
+
162
+ v = RARRAY_PTR(ary)[i];
163
+
164
+ if (TYPE(v) == T_ARRAY) {
165
+ /* check recursive array */
166
+ for (j=0; j<rank; ++j) {
167
+ if (mdai->item[j].val == v)
168
+ rb_raise(rb_eStandardError,"converting recursive Array to NArray");
169
+ }
170
+ if ( rank >= mdai->n ) {
171
+ na_realloc_mdai(mdai,2);
172
+ }
173
+ mdai->item[rank].val = v;
174
+ if ( na_do_mdai(mdai,rank+1) ) {
175
+ --len; /* Array is empty */
176
+ }
177
+ }
178
+ else
179
+ if ( rb_obj_is_kind_of(v, rb_cRange) ) {
180
+ na_range_to_sequence(v,&length,&start,&dir);
181
+ len += length-1;
182
+ mdai->type[ na_object_type(rb_funcall(v, na_id_beg, 0)) ] = 1;
183
+ mdai->type[ na_object_type(rb_funcall(v, na_id_end, 0)) ] = 1;
184
+ }
185
+ else {
186
+
187
+ mdai->type[ na_object_type(v) ] = 1;
188
+
189
+ if (IsNArray(v)) {
190
+ int r;
191
+ struct NARRAY *na; GetNArray(v,na);
192
+
193
+ if ( na->rank == 0 ) {
194
+ --len; /* NArray is empty */
195
+ } else {
196
+ if ( rank+na->rank > mdai->n ) {
197
+ na_realloc_mdai(mdai,((na->rank-1)/4+1)*4);
198
+ }
199
+ for ( j=na->rank, r=rank; j-- > 0 ; ++r ) {
200
+ if ( mdai->item[r].shape < na->shape[j] )
201
+ mdai->item[r].shape = na->shape[j];
202
+ }
203
+ }
204
+ }
205
+ }
206
+ }
207
+
208
+ if (len==0) return 1; /* this array is empty */
209
+ if (mdai->item[rank-1].shape < len) {
210
+ mdai->item[rank-1].shape = len;
211
+ }
212
+ return 0;
213
+ }
214
+
215
+
216
+ /* get index from multiple-index */
217
+ static int
218
+ na_index_pos(struct NARRAY *ary, int *idxs)
219
+ {
220
+ int i, idx, pos = 0;
221
+
222
+ for ( i = ary->rank; (i--)>0; ) {
223
+ idx = idxs[i];
224
+ if (idx < 0 || ary->shape[i] <= idx) {
225
+ abort();
226
+ rb_raise(rb_eRuntimeError,
227
+ "Subsctipt out of range: accessing shape[%i]=%i with %i",
228
+ i, ary->shape[i], idx );
229
+ }
230
+ pos = pos * ary->shape[i] + idx;
231
+ }
232
+ return pos;
233
+ }
234
+
235
+
236
+ static void
237
+ na_copy_nary_to_nary(VALUE obj, struct NARRAY *dst,
238
+ int thisrank, int *idx)
239
+ {
240
+ struct NARRAY *src;
241
+ struct slice *s;
242
+ int i, n;
243
+
244
+ GetNArray(obj,src);
245
+ n = thisrank - src->rank + 1;
246
+
247
+ s = ALLOCA_N(struct slice, dst->rank+1);
248
+ for (i=0; i < n; ++i) {
249
+ s[i].n = 1;
250
+ s[i].beg = 0;
251
+ s[i].step = 0;
252
+ s[i].idx = NULL;
253
+ }
254
+ for ( ; i <= thisrank; ++i) {
255
+ s[i].n = src->shape[i-n];
256
+ s[i].beg = 0;
257
+ s[i].step = 1;
258
+ s[i].idx = NULL;
259
+ }
260
+ for ( ; i < dst->rank; ++i) {
261
+ s[i].n = 1;
262
+ s[i].beg = idx[i];
263
+ s[i].step = 0;
264
+ s[i].idx = NULL;
265
+ }
266
+ na_aset_slice(dst,src,s);
267
+ }
268
+
269
+
270
+ /* copy Array to NArray */
271
+ static void
272
+ na_copy_ary_to_nary( VALUE ary, struct NARRAY *na,
273
+ int thisrank, int *idx, int type )
274
+ {
275
+ int i, j, pos, len, start, step, dir;
276
+ VALUE v;
277
+
278
+ if (thisrank==0) {
279
+ for (i = idx[0] = 0; i < RARRAY_LEN(ary); ++i) {
280
+ v = RARRAY_PTR(ary)[i];
281
+ if (rb_obj_is_kind_of(v, rb_cRange)) {
282
+ na_range_to_sequence(v,&len,&start,&dir);
283
+ if (len>0) {
284
+ pos = na_index_pos(na,idx);
285
+ IndGenFuncs[type](len, NA_PTR(na,pos),na_sizeof[type], start,dir);
286
+ idx[0] += len;
287
+ }
288
+ }
289
+ else if (TYPE(v) != T_ARRAY) {
290
+ /* NIL if empty */
291
+ if (v != Qnil) {
292
+ pos = na_index_pos(na,idx);
293
+ SetFuncs[type][NA_ROBJ]( 1, NA_PTR(na,pos), 0, &v, 0 );
294
+ /* copy here */
295
+ }
296
+ idx[0] ++;
297
+ }
298
+ }
299
+ }
300
+ else /* thisrank > 0 */
301
+ {
302
+ for (i = idx[thisrank] = 0; i < RARRAY_LEN(ary); ++i) {
303
+ v = RARRAY_PTR(ary)[i];
304
+ if (TYPE(v) == T_ARRAY) {
305
+ na_copy_ary_to_nary(v,na,thisrank-1,idx,type);
306
+ if (idx[thisrank-1]>0) ++idx[thisrank];
307
+ }
308
+ else if (IsNArray(v)) {
309
+ na_copy_nary_to_nary(v,na,thisrank-1,idx);
310
+ ++idx[thisrank];
311
+ }
312
+ else {
313
+ for (j=thisrank; j; ) idx[--j] = 0;
314
+
315
+ if (rb_obj_is_kind_of(v, rb_cRange)) {
316
+ na_range_to_sequence(v,&len,&start,&dir);
317
+ if (len>0) {
318
+ pos = na_index_pos(na,idx);
319
+ ++idx[thisrank];
320
+ step = na_index_pos(na,idx)-pos;
321
+ IndGenFuncs[type]( len, NA_PTR(na,pos), na_sizeof[type]*step,
322
+ start, dir );
323
+ idx[thisrank] += len-1;
324
+ }
325
+ }
326
+ else {
327
+ pos = na_index_pos(na,idx);
328
+ SetFuncs[type][NA_ROBJ]( 1, NA_PTR(na,pos), 0, &(RARRAY_PTR(ary)[i]), 0 );
329
+ ++idx[thisrank];
330
+ }
331
+ /* copy here */
332
+ }
333
+ }
334
+ }
335
+ }
336
+
337
+
338
+ static VALUE
339
+ na_ary_to_nary_w_type(VALUE ary, int type_spec, VALUE klass)
340
+ {
341
+ int i, rank;
342
+ int type = NA_BYTE;
343
+ int *shape, *idx;
344
+ na_mdai_t *mdai;
345
+ struct NARRAY *na;
346
+ VALUE v;
347
+
348
+ /* empty array */
349
+ if (RARRAY_LEN(ary) < 1) {
350
+ return na_make_empty( type, klass );
351
+ }
352
+
353
+ mdai = na_alloc_mdai(ary);
354
+ na_do_mdai(mdai,1);
355
+ shape = na_free_mdai(mdai,&rank,&type);
356
+
357
+ /*
358
+ printf("rank=%i\n", rank);
359
+ printf("type=%i\n", type);
360
+ for (i=0; i<rank; ++i) {
361
+ printf("shape[%i]=%i\n", i, shape[i]);
362
+ }
363
+ */
364
+
365
+ /* type specification */
366
+ if (type_spec!=NA_NONE)
367
+ type = type_spec;
368
+
369
+ /* empty array */
370
+ if (rank==0)
371
+ return na_make_empty( type, klass );
372
+
373
+ /* Create NArray */
374
+ v = na_make_object(type,rank,shape,klass);
375
+ xfree(shape);
376
+
377
+ GetNArray(v,na);
378
+ na_clear_data(na);
379
+
380
+ idx = ALLOCA_N(int,rank);
381
+ for (i=0; i<rank; ++i) idx[i]=0;
382
+
383
+ na_copy_ary_to_nary( ary, na, rank-1, idx, type );
384
+
385
+ return v;
386
+ }
387
+
388
+
389
+ VALUE
390
+ na_ary_to_nary(VALUE ary, VALUE klass)
391
+ {
392
+ return na_ary_to_nary_w_type( ary, NA_NONE, klass );
393
+ }
394
+
395
+
396
+ /* obj.kind_of?(NArray) == true */
397
+
398
+ VALUE
399
+ na_dup_w_type(VALUE v2, int type)
400
+ {
401
+ VALUE v1;
402
+ struct NARRAY *a1, *a2;
403
+
404
+ GetNArray(v2,a2);
405
+ v1 = na_make_object(type, a2->rank, a2->shape, CLASS_OF(v2));
406
+ GetNArray(v1,a1);
407
+ na_copy_nary(a1,a2);
408
+ return v1;
409
+ }
410
+
411
+
412
+ VALUE
413
+ na_change_type(VALUE obj, int type)
414
+ {
415
+ struct NARRAY *a2;
416
+
417
+ GetNArray(obj,a2);
418
+
419
+ if (a2->type == type)
420
+ return obj;
421
+
422
+ return na_dup_w_type(obj, type);
423
+ }
424
+
425
+
426
+ VALUE
427
+ na_upcast_type(VALUE obj, int type) /* na_upcast_narray */
428
+ {
429
+ int newtype;
430
+ struct NARRAY *a2;
431
+
432
+ GetNArray(obj,a2);
433
+ newtype = na_upcast[a2->type][type];
434
+
435
+ if (newtype == a2->type)
436
+ return obj;
437
+
438
+ return na_dup_w_type(obj, newtype);
439
+ }
440
+
441
+
442
+ /* obj.kind_of?(Object) == true */
443
+
444
+ VALUE
445
+ na_cast_object(VALUE obj, int type) /* na_cast_certain */
446
+ {
447
+ if (IsNArray(obj)) {
448
+ return na_change_type(obj,type);
449
+ }
450
+ if (TYPE(obj) == T_ARRAY) {
451
+ return na_ary_to_nary_w_type(obj,type,cNArray);
452
+ }
453
+ return na_make_scalar(obj,type);
454
+ }
455
+
456
+
457
+ VALUE
458
+ na_cast_unless_narray(VALUE obj, int type)
459
+ {
460
+ if (IsNArray(obj)) {
461
+ return obj;
462
+ }
463
+ if (TYPE(obj) == T_ARRAY) {
464
+ return na_ary_to_nary_w_type(obj,type,cNArray);
465
+ }
466
+ return na_make_scalar(obj,type);
467
+ }
468
+
469
+
470
+ VALUE
471
+ na_cast_unless_array(VALUE obj, int type)
472
+ {
473
+ if (IsNArray(obj)) {
474
+ return obj;
475
+ }
476
+ if (TYPE(obj) == T_ARRAY) {
477
+ return na_ary_to_nary(obj,cNArray);
478
+ }
479
+ return na_make_scalar(obj,type);
480
+ }
481
+
482
+
483
+ VALUE
484
+ na_upcast_object(VALUE obj, int type)
485
+ {
486
+ if (IsNArray(obj)) {
487
+ return na_upcast_type(obj,type);
488
+ }
489
+ if (TYPE(obj) == T_ARRAY) {
490
+ return na_ary_to_nary_w_type(obj,type,cNArray);
491
+ }
492
+ return na_make_scalar(obj,type);
493
+ }
494
+
495
+
496
+ /* :nodoc: */
497
+ VALUE
498
+ na_to_narray(VALUE obj)
499
+ {
500
+ if (IsNArray(obj)) {
501
+ return obj;
502
+ }
503
+ if (TYPE(obj) == T_ARRAY) {
504
+ return na_ary_to_nary(obj,cNArray);
505
+ }
506
+ return na_make_scalar(obj,na_object_type(obj));
507
+ }
508
+
509
+
510
+ /* convert NArray to Array */
511
+ static VALUE
512
+ na_to_array0(struct NARRAY* na, int *idx, int thisrank, void (*func)())
513
+ {
514
+ int i, elmsz;
515
+ char *ptr;
516
+ VALUE ary, val;
517
+
518
+ /* Create New Array */
519
+ ary = rb_ary_new2(na->shape[thisrank]);
520
+
521
+ if (thisrank == 0) {
522
+ ptr = NA_PTR( na, na_index_pos(na,idx) );
523
+ elmsz = na_sizeof[na->type];
524
+ for (i = na->shape[0]; i; --i) {
525
+ (*func)( 1, &val, 0, ptr, 0 );
526
+ ptr += elmsz;
527
+ rb_ary_push( ary, val );
528
+ }
529
+ }
530
+ else {
531
+ for (i = 0; i < na->shape[thisrank]; ++i) {
532
+ idx[thisrank] = i;
533
+ rb_ary_push( ary, na_to_array0(na,idx,thisrank-1,func) );
534
+ }
535
+ }
536
+ return ary;
537
+ }
538
+
539
+
540
+ /* method: to_a -- convert itself to Array */
541
+ VALUE
542
+ na_to_array(VALUE obj)
543
+ {
544
+ struct NARRAY *na;
545
+ int *idx, i;
546
+
547
+ GetNArray(obj,na);
548
+
549
+ if (na->rank<1)
550
+ return rb_ary_new();
551
+
552
+ idx = ALLOCA_N(int,na->rank);
553
+ for (i = 0; i<na->rank; ++i) idx[i] = 0;
554
+ return na_to_array0(na,idx,na->rank-1,SetFuncs[NA_ROBJ][na->type]);
555
+ }
556
+
557
+
558
+ static VALUE
559
+ na_inspect_col( int n, char *p2, int p2step, void (*tostr)(),
560
+ VALUE sep, int rank )
561
+ {
562
+ VALUE str=Qnil, tmp;
563
+ int max_col = 77;
564
+ int sep_len = RSTRING_LEN(sep);
565
+
566
+ if (n>0)
567
+ (*tostr)(&str,p2);
568
+
569
+ for (n--; n>0; --n) {
570
+ p2 += p2step;
571
+ (*tostr)(&tmp,p2);
572
+
573
+ if (!NIL_P(sep)) rb_str_concat(str, sep);
574
+
575
+ if (RSTRING_LEN(str) + RSTRING_LEN(tmp) + rank*4 + sep_len < max_col) {
576
+ rb_str_concat(str, tmp);
577
+ } else {
578
+ rb_str_cat(str,"...",3);
579
+ return str;
580
+ }
581
+ }
582
+ return str;
583
+ }
584
+
585
+
586
+ /*
587
+ * Create inspect string ... under construction
588
+ */
589
+
590
+ VALUE
591
+ na_make_inspect(VALUE val)
592
+ {
593
+ int i, ii, rank, count_line=0, max_line=10;
594
+ int *si;
595
+ struct NARRAY *ary;
596
+ struct slice *s1;
597
+
598
+ VALUE fs = rb_str_new(", ",2);
599
+
600
+ GetNArray(val,ary);
601
+ if (ary->total < 1) return rb_str_new(0, 0);
602
+
603
+ /* Allocate Structure */
604
+ rank = ary->rank;
605
+ s1 = ALLOCA_N(struct slice, rank+1);
606
+ si = ALLOCA_N(int,rank);
607
+ na_set_slice_1obj(rank,s1,ary->shape);
608
+
609
+ /* Iteration */
610
+ na_init_slice(s1, rank, ary->shape, na_sizeof[ary->type]);
611
+ i = rank;
612
+ s1[i].p = ary->ptr;
613
+ val = rb_str_new(0,0);
614
+ for(;;) {
615
+ /* set pointers */
616
+ while (i > 0) {
617
+ --i;
618
+ rb_str_cat(val, "[ ", 2);
619
+ s1[i].p = s1[i].pbeg + s1[i+1].p;
620
+ si[i] = s1[i].n;
621
+ }
622
+
623
+ rb_str_concat(val, na_inspect_col( s1[0].n, s1[0].p, s1[0].pstep,
624
+ InspFuncs[ary->type], fs, rank ));
625
+
626
+ /* rank up */
627
+ do {
628
+ rb_str_cat(val, " ]", 2);
629
+ if ( ++i == rank ) return val;
630
+ } while ( --si[i] == 0 );
631
+ s1[i].p += s1[i].pstep;
632
+
633
+ rb_str_concat(val, fs);
634
+ rb_str_cat(val, "\n", 1);
635
+
636
+ /* count check */
637
+ if (++count_line>=max_line) {
638
+ rb_str_cat(val, " ...", 4);
639
+ return val;
640
+ }
641
+ /* indent */
642
+ for (ii=i; ii<rank; ++ii)
643
+ rb_str_cat(val, " ", 2);
644
+ }
645
+ }
646
+
647
+
648
+ void Init_na_array() {
649
+ rb_define_method(cNArray, "to_a", na_to_array,0); //
650
+ }