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