narray-nmatrix 0.6.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }