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.
- checksums.yaml +7 -0
- data/ChangeLog +809 -0
- data/MANIFEST +53 -0
- data/README.en +51 -0
- data/README.ja +52 -0
- data/SPEC.en +327 -0
- data/SPEC.ja +307 -0
- data/depend +14 -0
- data/extconf.rb +100 -0
- data/lib/narray.rb +18 -0
- data/lib/narray/narray.rb +5 -0
- data/lib/narray_ext.rb +362 -0
- data/lib/nmatrix.rb +252 -0
- data/mkmath.rb +784 -0
- data/mknafunc.rb +192 -0
- data/mkop.rb +648 -0
- data/na_array.c +650 -0
- data/na_func.c +1705 -0
- data/na_index.c +1011 -0
- data/na_linalg.c +633 -0
- data/na_random.c +416 -0
- data/narray.c +1321 -0
- data/narray.def +29 -0
- data/narray.h +186 -0
- data/narray_local.h +218 -0
- metadata +92 -0
data/na_index.c
ADDED
@@ -0,0 +1,1011 @@
|
|
1
|
+
/*
|
2
|
+
na_index.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
|
+
#define EXCL(r) (RTEST(rb_funcall((r),na_id_exclude_end,0)))
|
16
|
+
|
17
|
+
static int
|
18
|
+
na_index_range(VALUE obj, int size, struct slice *sl)
|
19
|
+
{
|
20
|
+
int beg,end,len,step;
|
21
|
+
VALUE vbeg, vend;
|
22
|
+
|
23
|
+
sl->idx = NULL;
|
24
|
+
|
25
|
+
/* Beginning */
|
26
|
+
vbeg = rb_funcall(obj, na_id_beg, 0);
|
27
|
+
if (vbeg==Qnil) /* First is nil */
|
28
|
+
beg = 0;
|
29
|
+
else
|
30
|
+
beg = NUM2INT(vbeg);
|
31
|
+
if (beg<0) beg += size;
|
32
|
+
|
33
|
+
/* End */
|
34
|
+
vend = rb_funcall(obj, na_id_end, 0);
|
35
|
+
if (vend==Qnil) { /* Last is nil */
|
36
|
+
sl->beg = beg;
|
37
|
+
sl->step = 1;
|
38
|
+
return sl->n = 0;
|
39
|
+
}
|
40
|
+
else
|
41
|
+
end = NUM2INT(vend);
|
42
|
+
if (end<0) end += size;
|
43
|
+
|
44
|
+
/* length */
|
45
|
+
len = end-beg;
|
46
|
+
|
47
|
+
/* direction */
|
48
|
+
if (len>0) {
|
49
|
+
step = 1;
|
50
|
+
if (EXCL(obj)) --end; else ++len;
|
51
|
+
}
|
52
|
+
else if (len<0) {
|
53
|
+
len = -len;
|
54
|
+
step = -1;
|
55
|
+
if (EXCL(obj)) ++end; else ++len;
|
56
|
+
}
|
57
|
+
else /*if(len==0)*/ {
|
58
|
+
if (EXCL(obj))
|
59
|
+
rb_raise(rb_eIndexError, "empty range");
|
60
|
+
else {
|
61
|
+
++len;
|
62
|
+
step = 1; /* or 0 ? depend on whether removing rank */
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
if ( beg<0 || beg>=size || end<0 || end>=size )
|
67
|
+
rb_raise(rb_eIndexError, "index out of range");
|
68
|
+
|
69
|
+
sl->n = len;
|
70
|
+
sl->beg = beg;
|
71
|
+
sl->step = step;
|
72
|
+
return len;
|
73
|
+
}
|
74
|
+
|
75
|
+
|
76
|
+
static int
|
77
|
+
na_index_scalar(int idx, int size, struct slice *sl)
|
78
|
+
{
|
79
|
+
if (idx<0) idx+=size;
|
80
|
+
if (idx<0 || idx>=size)
|
81
|
+
rb_raise(rb_eIndexError, "index out of range");
|
82
|
+
sl->n = 1;
|
83
|
+
sl->beg = idx;
|
84
|
+
sl->step = 0;
|
85
|
+
sl->idx = NULL;
|
86
|
+
return 1;
|
87
|
+
}
|
88
|
+
|
89
|
+
|
90
|
+
static int
|
91
|
+
na_ary_to_index(struct NARRAY *a1, int size, struct slice *s)
|
92
|
+
{
|
93
|
+
int i;
|
94
|
+
na_index_t idx, *p;
|
95
|
+
|
96
|
+
/* Empty Array */
|
97
|
+
if (a1->total==0) {
|
98
|
+
s->n = 0;
|
99
|
+
s->beg = 0;
|
100
|
+
s->step = 1;
|
101
|
+
s->idx = NULL;
|
102
|
+
}
|
103
|
+
else
|
104
|
+
/* single element */
|
105
|
+
if (a1->total==1) {
|
106
|
+
SetFuncs[NA_LINT][a1->type](1, &idx, 0, a1->ptr, 0);
|
107
|
+
if ( idx<0 ) idx += size;
|
108
|
+
if ( idx<0 || idx>=size )
|
109
|
+
rb_raise(rb_eIndexError, "index %i out of range %i", idx, size);
|
110
|
+
s->n = 1;
|
111
|
+
s->beg = idx;
|
112
|
+
s->step = 1;
|
113
|
+
s->idx = NULL;
|
114
|
+
}
|
115
|
+
else {
|
116
|
+
/* Copy index array */
|
117
|
+
s->n = a1->total;
|
118
|
+
s->step = 1;
|
119
|
+
s->idx = p = ALLOC_N(na_index_t, a1->total);
|
120
|
+
SetFuncs[NA_LINT][a1->type]( s->n,
|
121
|
+
s->idx, na_sizeof[NA_LINT],
|
122
|
+
a1->ptr, na_sizeof[a1->type] );
|
123
|
+
for ( i=a1->total; i>0; --i ) {
|
124
|
+
if ( *p<0 ) *p += size;
|
125
|
+
if ( *p<0 || *p>=size )
|
126
|
+
rb_raise(rb_eIndexError, "index %i out of range %i", *p, size);
|
127
|
+
++p;
|
128
|
+
}
|
129
|
+
s->beg = s->idx[0];
|
130
|
+
}
|
131
|
+
|
132
|
+
return s->n;
|
133
|
+
}
|
134
|
+
|
135
|
+
|
136
|
+
static struct NARRAY *
|
137
|
+
na_flatten_temporarily(struct NARRAY *dst, struct NARRAY *src)
|
138
|
+
{
|
139
|
+
/* Not normal construction !! Do not wrap as object ! */
|
140
|
+
dst->shape = &(dst->total);
|
141
|
+
dst->rank = 1;
|
142
|
+
dst->total = src->total;
|
143
|
+
dst->type = src->type;
|
144
|
+
dst->ptr = src->ptr;
|
145
|
+
dst->ref = src->ref;
|
146
|
+
return dst;
|
147
|
+
}
|
148
|
+
#define na_flatten_temp(ary) \
|
149
|
+
{ary = na_flatten_temporarily(ALLOCA_N(struct NARRAY,1), ary);}
|
150
|
+
|
151
|
+
|
152
|
+
/* free index memory */
|
153
|
+
static void na_free_slice_index(struct slice *s, int n)
|
154
|
+
{
|
155
|
+
while (n-->0)
|
156
|
+
if (s[n].idx != NULL) xfree(s[n].idx);
|
157
|
+
}
|
158
|
+
|
159
|
+
|
160
|
+
static int na_index_test(volatile VALUE idx, int shape, struct slice *sl)
|
161
|
+
{
|
162
|
+
int size;
|
163
|
+
struct NARRAY *na;
|
164
|
+
|
165
|
+
switch(TYPE(idx)) {
|
166
|
+
|
167
|
+
case T_FIXNUM:
|
168
|
+
/* scalar slice */
|
169
|
+
na_index_scalar(FIX2LONG(idx),shape,sl);
|
170
|
+
return 1;
|
171
|
+
|
172
|
+
case T_FLOAT:
|
173
|
+
/* scalar slice */
|
174
|
+
na_index_scalar(NUM2LONG(idx),shape,sl);
|
175
|
+
return 1;
|
176
|
+
|
177
|
+
case T_NIL:
|
178
|
+
case T_TRUE:
|
179
|
+
/* entire slice */
|
180
|
+
sl->n = shape;
|
181
|
+
sl->beg = 0;
|
182
|
+
sl->step = 1;
|
183
|
+
sl->idx = NULL;
|
184
|
+
return shape;
|
185
|
+
|
186
|
+
case T_ARRAY:
|
187
|
+
/* Array Index */
|
188
|
+
idx = na_cast_object(idx,NA_LINT);
|
189
|
+
GetNArray(idx,na);
|
190
|
+
size = na_ary_to_index(na,shape,sl);
|
191
|
+
return size;
|
192
|
+
|
193
|
+
default:
|
194
|
+
/* Range object */
|
195
|
+
if (rb_obj_is_kind_of(idx, rb_cRange)) {
|
196
|
+
size = na_index_range(idx,shape,sl);
|
197
|
+
}
|
198
|
+
else
|
199
|
+
/* NArray index */
|
200
|
+
if (NA_IsNArray(idx)) {
|
201
|
+
GetNArray(idx,na);
|
202
|
+
size = na_ary_to_index(na,shape,sl);
|
203
|
+
}
|
204
|
+
else
|
205
|
+
/* NO ALLOWED */
|
206
|
+
if (TYPE(idx)==T_BIGNUM) {
|
207
|
+
rb_raise(rb_eIndexError, "BigNum is not allowed");
|
208
|
+
}
|
209
|
+
else
|
210
|
+
rb_raise(rb_eIndexError, "not allowed type");
|
211
|
+
}
|
212
|
+
return size;
|
213
|
+
}
|
214
|
+
|
215
|
+
|
216
|
+
static int
|
217
|
+
na_index_analysis(int nidx, VALUE *idx, struct NARRAY *ary, struct slice *sl)
|
218
|
+
{
|
219
|
+
int i, j, k, total=1, size;
|
220
|
+
int multi_ellip=0;
|
221
|
+
|
222
|
+
for (i=j=0; i<nidx; ++i) {
|
223
|
+
if (TYPE(idx[i])==T_FALSE) {
|
224
|
+
if (multi_ellip!=0)
|
225
|
+
rb_raise(rb_eIndexError, "multiple ellipsis-dimension is not allowd");
|
226
|
+
for (k=ary->rank-nidx+1; k>0; --k,++j) {
|
227
|
+
size = na_index_test( Qtrue, ary->shape[j], &sl[j] );
|
228
|
+
if (size != 1)
|
229
|
+
total *= size;
|
230
|
+
}
|
231
|
+
multi_ellip = 1;
|
232
|
+
} else {
|
233
|
+
if (j < ary->rank) {
|
234
|
+
size = na_index_test( idx[i], ary->shape[j], &sl[j] );
|
235
|
+
if (size != 1)
|
236
|
+
total *= size;
|
237
|
+
}
|
238
|
+
++j;
|
239
|
+
}
|
240
|
+
}
|
241
|
+
if (j != ary->rank)
|
242
|
+
rb_raise(rb_eIndexError, "# of index=%i != ary.dim=%i", j, ary->rank);
|
243
|
+
|
244
|
+
return total;
|
245
|
+
}
|
246
|
+
|
247
|
+
|
248
|
+
/* -------------------- Class Dimension -------------------- */
|
249
|
+
int
|
250
|
+
na_shrink_class(int class_dim, int *shrink)
|
251
|
+
{
|
252
|
+
int i;
|
253
|
+
|
254
|
+
for (i=0; i<class_dim; ++i) {
|
255
|
+
if (shrink[i]==0) /* non-trim dimention */
|
256
|
+
return 0;
|
257
|
+
}
|
258
|
+
return 1; /* all trim */
|
259
|
+
}
|
260
|
+
|
261
|
+
|
262
|
+
/* remove single-element rank */
|
263
|
+
VALUE
|
264
|
+
na_shrink_rank(VALUE obj, int class_dim, int *shrink)
|
265
|
+
{
|
266
|
+
int i, j;
|
267
|
+
struct NARRAY *ary;
|
268
|
+
|
269
|
+
GetNArray(obj,ary);
|
270
|
+
|
271
|
+
if (ary->rank < class_dim)
|
272
|
+
return obj;
|
273
|
+
|
274
|
+
for (j=i=0; i<class_dim; ++i) {
|
275
|
+
if (ary->shape[i]!=1 || shrink[i]==0) /* not trim */
|
276
|
+
++j;
|
277
|
+
}
|
278
|
+
|
279
|
+
if (j>0) /* if non-trim dimensions exist, */
|
280
|
+
j = class_dim; /* then do not trim class_dimension. */
|
281
|
+
/* if (j==0) then all trim. */
|
282
|
+
|
283
|
+
for (i=class_dim; i<ary->rank; ++i) {
|
284
|
+
if (ary->shape[i]!=1 || shrink[i]==0) { /* not trim */
|
285
|
+
if (i>j) ary->shape[j] = ary->shape[i];
|
286
|
+
++j;
|
287
|
+
}
|
288
|
+
}
|
289
|
+
ary->rank = j;
|
290
|
+
|
291
|
+
if (j==0 && ary->total==1) {
|
292
|
+
SetFuncs[NA_ROBJ][ary->type](1, &obj, 0, ary->ptr, 0);
|
293
|
+
}
|
294
|
+
return obj;
|
295
|
+
}
|
296
|
+
|
297
|
+
|
298
|
+
/* ------------------- bracket methods ------------------ */
|
299
|
+
/*
|
300
|
+
[] -- Reference method
|
301
|
+
*/
|
302
|
+
|
303
|
+
static VALUE
|
304
|
+
na_aref_slice(struct NARRAY *a2, struct slice *s2, VALUE klass, int flag)
|
305
|
+
{
|
306
|
+
int i, ndim, class_dim, *shape, *shrink;
|
307
|
+
VALUE extr;
|
308
|
+
struct NARRAY *a1;
|
309
|
+
struct slice *s1;
|
310
|
+
|
311
|
+
ndim = a2->rank;
|
312
|
+
shape = ALLOCA_N(int,ndim);
|
313
|
+
shrink = ALLOCA_N(int,ndim);
|
314
|
+
|
315
|
+
for (i=0; i<ndim; ++i) {
|
316
|
+
shape[i] = s2[i].n;
|
317
|
+
if (shape[i]==1 && s2[i].step==0) /* shrink? */
|
318
|
+
shrink[i] = 1;
|
319
|
+
else
|
320
|
+
shrink[i] = 0;
|
321
|
+
}
|
322
|
+
|
323
|
+
class_dim = na_class_dim(klass);
|
324
|
+
|
325
|
+
if (ndim < class_dim)
|
326
|
+
rb_raise(rb_eRuntimeError,
|
327
|
+
"dimension(%i) is smaller than CLASS_DIMENSION(%i)",
|
328
|
+
ndim, class_dim);
|
329
|
+
|
330
|
+
if ((!flag) && class_dim>0 && na_shrink_class(class_dim,shrink))
|
331
|
+
klass = cNArray;
|
332
|
+
|
333
|
+
extr = na_make_object( a2->type, ndim, shape, klass );
|
334
|
+
GetNArray(extr,a1);
|
335
|
+
|
336
|
+
s1 = ALLOC_N(struct slice, ndim+1);
|
337
|
+
na_set_slice_1obj(ndim,s1,a1->shape);
|
338
|
+
|
339
|
+
na_init_slice( s1, ndim, shape, na_sizeof[a2->type] );
|
340
|
+
na_init_slice( s2, ndim, a2->shape, na_sizeof[a2->type] );
|
341
|
+
na_loop_index_ref( a1, a2, s1, s2, SetFuncs[a2->type][a2->type] );
|
342
|
+
|
343
|
+
xfree(s1);
|
344
|
+
if (!flag)
|
345
|
+
extr = na_shrink_rank(extr,class_dim,shrink);
|
346
|
+
|
347
|
+
return extr;
|
348
|
+
}
|
349
|
+
|
350
|
+
|
351
|
+
|
352
|
+
static VALUE
|
353
|
+
na_aref_single_dim_array(VALUE self, volatile VALUE vidx)
|
354
|
+
{
|
355
|
+
int total;
|
356
|
+
struct NARRAY *a1, *a2, *aidx;
|
357
|
+
struct slice *s1, *s2;
|
358
|
+
VALUE v;
|
359
|
+
|
360
|
+
GetNArray( self, a1 );
|
361
|
+
vidx = na_cast_object( vidx, NA_LINT );
|
362
|
+
GetNArray(vidx,aidx);
|
363
|
+
|
364
|
+
/* make Slice from index */
|
365
|
+
s1 = ALLOCA_N(struct slice, 2);
|
366
|
+
total = na_ary_to_index( aidx, a1->total, s1 );
|
367
|
+
|
368
|
+
if (total==0) {
|
369
|
+
return na_make_empty(a1->type,cNArray);
|
370
|
+
}
|
371
|
+
else {
|
372
|
+
/* create New NArray & 1-dimentionize */
|
373
|
+
v = na_make_object( a1->type, aidx->rank, aidx->shape, CLASS_OF(vidx) );
|
374
|
+
GetNArray(v,a2);
|
375
|
+
if (a2->rank>1) na_flatten_temp(a2);
|
376
|
+
if (a1->rank>1) na_flatten_temp(a1);
|
377
|
+
|
378
|
+
/* Slice for Destination array */
|
379
|
+
s2 = ALLOCA_N(struct slice, 2);
|
380
|
+
na_set_slice_1obj(1,s2,a2->shape);
|
381
|
+
|
382
|
+
/* Iteration */
|
383
|
+
na_init_slice( s2, 1, a2->shape, na_sizeof[a1->type] );
|
384
|
+
na_init_slice( s1, 1, a1->shape, na_sizeof[a1->type] );
|
385
|
+
na_loop_index_ref( a2, a1, s2, s1, SetFuncs[a1->type][a1->type] );
|
386
|
+
}
|
387
|
+
|
388
|
+
na_free_slice_index(s1,1);
|
389
|
+
return v;
|
390
|
+
}
|
391
|
+
|
392
|
+
|
393
|
+
static VALUE
|
394
|
+
na_aref_single_dim(VALUE self, VALUE idx, int flag)
|
395
|
+
{
|
396
|
+
int size;
|
397
|
+
VALUE v;
|
398
|
+
struct NARRAY *ary, *arynew;
|
399
|
+
struct slice *sl;
|
400
|
+
|
401
|
+
GetNArray(self,ary);
|
402
|
+
|
403
|
+
sl = ALLOCA_N(struct slice, 2);
|
404
|
+
size = na_index_test(idx, ary->total, sl);
|
405
|
+
|
406
|
+
if ( size == 1 ) {
|
407
|
+
if (flag || sl->step!=0) {
|
408
|
+
/* single-element NArray */
|
409
|
+
v = na_make_object(ary->type,1,&size,cNArray);
|
410
|
+
GetNArray(v,arynew);
|
411
|
+
SetFuncs[ary->type][ary->type](1, arynew->ptr,0, NA_PTR(ary,sl->beg),0);
|
412
|
+
} else {
|
413
|
+
SetFuncs[NA_ROBJ][ary->type](1, &v,0, NA_PTR(ary,sl->beg),0);
|
414
|
+
}
|
415
|
+
}
|
416
|
+
else
|
417
|
+
if ( size > 1 ) {
|
418
|
+
if ( ary->rank > 1 ) /* 1-dimensional serial index */
|
419
|
+
na_flatten_temp(ary);
|
420
|
+
v = na_aref_slice(ary, sl, CLASS_OF(self), flag);
|
421
|
+
}
|
422
|
+
else /* size < 1 */ {
|
423
|
+
v = na_make_empty(ary->type,cNArray);
|
424
|
+
}
|
425
|
+
/* na_free_slice_index(sl,1); free index memory */
|
426
|
+
return v;
|
427
|
+
}
|
428
|
+
|
429
|
+
|
430
|
+
static VALUE
|
431
|
+
na_aref_multi_dim_single_elm(VALUE self, struct slice *sl, int flag)
|
432
|
+
{
|
433
|
+
int i, rank, pos, *shape;
|
434
|
+
struct NARRAY *ary, *arynew;
|
435
|
+
VALUE v;
|
436
|
+
|
437
|
+
ary = (struct NARRAY *)DATA_PTR(self); /* type is already checked */
|
438
|
+
|
439
|
+
/* check rank-shrink; whether return NArray or Element */
|
440
|
+
if (flag==0) {
|
441
|
+
rank = 0; /* [] */
|
442
|
+
for ( i=ary->rank; (i--)>0; ) {
|
443
|
+
if (sl[i].step!=0) ++rank;
|
444
|
+
}
|
445
|
+
}
|
446
|
+
else {
|
447
|
+
rank = ary->rank; /* slice() */
|
448
|
+
}
|
449
|
+
/* get position */
|
450
|
+
pos = 0;
|
451
|
+
for ( i=ary->rank; i-->0; ) {
|
452
|
+
pos = pos * ary->shape[i] + sl[i].beg;
|
453
|
+
}
|
454
|
+
if (rank==0) {
|
455
|
+
SetFuncs[NA_ROBJ][ary->type](1, &v, 0, NA_PTR(ary,pos), 0);
|
456
|
+
} else {
|
457
|
+
VALUE klass;
|
458
|
+
int class_dim;
|
459
|
+
klass = CLASS_OF(self);
|
460
|
+
class_dim = na_class_dim(klass);
|
461
|
+
if (rank < class_dim) rank = class_dim;
|
462
|
+
shape = ALLOCA_N(int, rank);
|
463
|
+
for (i=0;i<rank;++i) shape[i]=1;
|
464
|
+
v = na_make_object(ary->type,rank,shape,klass);
|
465
|
+
GetNArray(v,arynew);
|
466
|
+
SetFuncs[ary->type][ary->type](1, arynew->ptr, 0, NA_PTR(ary,pos), 0);
|
467
|
+
}
|
468
|
+
return v;
|
469
|
+
}
|
470
|
+
|
471
|
+
|
472
|
+
static VALUE
|
473
|
+
na_aref_multi_dim(VALUE self, int nidx, VALUE *idx, int flag)
|
474
|
+
{
|
475
|
+
VALUE v;
|
476
|
+
int size;
|
477
|
+
struct NARRAY *ary;
|
478
|
+
struct slice *sl;
|
479
|
+
|
480
|
+
GetNArray(self,ary);
|
481
|
+
|
482
|
+
if (ary->rank==0)
|
483
|
+
rb_raise(rb_eIndexError, "Cannot extract from Empty NArray");
|
484
|
+
|
485
|
+
/* make Slice */
|
486
|
+
sl = ALLOC_N(struct slice, ary->rank+1);
|
487
|
+
size = na_index_analysis(nidx, idx, ary, sl);
|
488
|
+
|
489
|
+
if ( size == 1 ) { /* return Single Element */
|
490
|
+
v = na_aref_multi_dim_single_elm(self, sl, flag);
|
491
|
+
}
|
492
|
+
else
|
493
|
+
if ( size > 1 ) {
|
494
|
+
v = na_aref_slice(ary, sl, CLASS_OF(self), flag);
|
495
|
+
}
|
496
|
+
else /* size < 1 */ {
|
497
|
+
v = na_make_empty(ary->type,cNArray);
|
498
|
+
}
|
499
|
+
na_free_slice_index(sl,ary->rank); /* free index memory */
|
500
|
+
xfree(sl);
|
501
|
+
return v;
|
502
|
+
}
|
503
|
+
|
504
|
+
|
505
|
+
/* vvv mask vvv */
|
506
|
+
static int
|
507
|
+
na_count_true_body(VALUE self)
|
508
|
+
{
|
509
|
+
struct NARRAY *ary;
|
510
|
+
int n, count=0;
|
511
|
+
u_int8_t *ptr;
|
512
|
+
|
513
|
+
GetNArray(self,ary);
|
514
|
+
|
515
|
+
if ( ary->type == NA_BYTE ) {
|
516
|
+
ptr = (u_int8_t *)ary->ptr;
|
517
|
+
n = ary->total;
|
518
|
+
for (; n; --n) {
|
519
|
+
if (*ptr++) ++count;
|
520
|
+
}
|
521
|
+
} else
|
522
|
+
rb_raise(rb_eTypeError,"cannot count_true NArray except BYTE type");
|
523
|
+
return count;
|
524
|
+
}
|
525
|
+
|
526
|
+
/*
|
527
|
+
* call-seq:
|
528
|
+
* narray.count_true -> int
|
529
|
+
*
|
530
|
+
* Returns the number of true (non-zero) in narray
|
531
|
+
*/
|
532
|
+
VALUE
|
533
|
+
na_count_true(VALUE self)
|
534
|
+
{
|
535
|
+
return( INT2NUM(na_count_true_body(self)) );
|
536
|
+
}
|
537
|
+
|
538
|
+
static int
|
539
|
+
na_count_false_body(VALUE self)
|
540
|
+
{
|
541
|
+
struct NARRAY *ary;
|
542
|
+
int n, count=0;
|
543
|
+
u_int8_t *ptr;
|
544
|
+
|
545
|
+
GetNArray(self,ary);
|
546
|
+
|
547
|
+
if ( ary->type == NA_BYTE ) {
|
548
|
+
ptr = (u_int8_t *)ary->ptr;
|
549
|
+
n = ary->total;
|
550
|
+
for (; n; --n) {
|
551
|
+
if (!*ptr++) ++count;
|
552
|
+
}
|
553
|
+
} else
|
554
|
+
rb_raise(rb_eTypeError,"cannot count_false NArray except BYTE type");
|
555
|
+
return count;
|
556
|
+
}
|
557
|
+
|
558
|
+
/*
|
559
|
+
* call-seq:
|
560
|
+
* narray.count_false -> int
|
561
|
+
*
|
562
|
+
* Returns the number of false (zero-value) in narray
|
563
|
+
*/
|
564
|
+
VALUE
|
565
|
+
na_count_false(VALUE self)
|
566
|
+
{
|
567
|
+
return( INT2NUM(na_count_false_body(self)) );
|
568
|
+
}
|
569
|
+
|
570
|
+
/* :nodoc: */
|
571
|
+
VALUE
|
572
|
+
na_aref_mask(VALUE self, VALUE mask)
|
573
|
+
{
|
574
|
+
int total, i;
|
575
|
+
struct NARRAY *a1, *am, *a2;
|
576
|
+
VALUE v;
|
577
|
+
|
578
|
+
GetNArray( self, a1 );
|
579
|
+
GetNArray( mask, am );
|
580
|
+
|
581
|
+
if (a1->total != am->total)
|
582
|
+
rb_raise(rb_eTypeError,"self.size(=%i) != mask.size(=%i)",
|
583
|
+
a1->total, am->total);
|
584
|
+
if (a1->rank != am->rank)
|
585
|
+
rb_raise(rb_eTypeError,"self.rank(=%i) != mask.rank(=%i)",
|
586
|
+
a1->rank, am->rank);
|
587
|
+
for (i=0; i<a1->rank; ++i)
|
588
|
+
if (a1->shape[i] != am->shape[i])
|
589
|
+
rb_raise(rb_eTypeError,"self.shape[%i](=%i) != mask.shape[%i](=%i)",
|
590
|
+
i, a1->shape[i], i, am->shape[i]);
|
591
|
+
|
592
|
+
total = na_count_true_body(mask);
|
593
|
+
|
594
|
+
v = na_make_object( a1->type, 1, &total, CLASS_OF(self) );
|
595
|
+
GetNArray(v,a2);
|
596
|
+
|
597
|
+
RefMaskFuncs[a1->type]
|
598
|
+
( a1->total, a2->ptr, na_sizeof[a2->type], a1->ptr,
|
599
|
+
na_sizeof[a1->type], am->ptr, 1 );
|
600
|
+
|
601
|
+
return(v);
|
602
|
+
}
|
603
|
+
|
604
|
+
/* ^^^ mask ^^^ */
|
605
|
+
|
606
|
+
|
607
|
+
/* method: [](idx1,idx2,...,idxN) */
|
608
|
+
static VALUE
|
609
|
+
na_aref_body(int nidx, VALUE *idx, VALUE self, int flag)
|
610
|
+
{
|
611
|
+
if (nidx==0) {
|
612
|
+
return na_clone(self);
|
613
|
+
}
|
614
|
+
if (nidx==1) {
|
615
|
+
if ( NA_IsNArray(idx[0]) ) {
|
616
|
+
if( NA_TYPE(idx[0]) == NA_BYTE ) /* then supposed to be a mask */
|
617
|
+
return na_aref_mask(self, idx[0]);
|
618
|
+
}
|
619
|
+
if ( na_class_dim(CLASS_OF(self)) != 1 ) {
|
620
|
+
if ( NA_IsArray(idx[0]) ) /* Array Index ? */
|
621
|
+
return na_aref_single_dim_array( self, idx[0] );
|
622
|
+
else
|
623
|
+
return na_aref_single_dim( self, idx[0], flag );
|
624
|
+
}
|
625
|
+
}
|
626
|
+
/* if (nidx>1) */
|
627
|
+
return na_aref_multi_dim( self, nidx, idx, flag );
|
628
|
+
}
|
629
|
+
|
630
|
+
/* method: [](idx1,idx2,...,idxN) */
|
631
|
+
VALUE na_aref(int argc, VALUE *argv, VALUE self)
|
632
|
+
{ return na_aref_body(argc, argv, self, 0); }
|
633
|
+
|
634
|
+
/* method: slice(idx1,idx2,...,idxN) */
|
635
|
+
VALUE na_slice(int argc, VALUE *argv, VALUE self)
|
636
|
+
{ return na_aref_body(argc, argv, self, 1); }
|
637
|
+
|
638
|
+
|
639
|
+
|
640
|
+
/*
|
641
|
+
[]= -- Set elements to specified indices
|
642
|
+
*/
|
643
|
+
|
644
|
+
/* make slice for array-set: a[0..-1,1..2] = 1 */
|
645
|
+
static void
|
646
|
+
na_make_slice_aset_fill(int rank, struct NARRAY *src_ary,
|
647
|
+
struct slice *src_slc, int *src_shape,
|
648
|
+
struct slice *dst_slc)
|
649
|
+
{
|
650
|
+
int i;
|
651
|
+
|
652
|
+
for (i=0; i<rank; ++i) {
|
653
|
+
src_shape[i] = 1; /* all 1 */
|
654
|
+
if ( (src_slc[i].n = dst_slc[i].n) < 1 )
|
655
|
+
rb_raise(rb_eIndexError, "dst_slice[%i].n=%i ???", i, dst_slc[i].n);
|
656
|
+
src_slc[i].beg = 0;
|
657
|
+
src_slc[i].idx = NULL;
|
658
|
+
src_slc[i].step = 0;
|
659
|
+
}
|
660
|
+
}
|
661
|
+
|
662
|
+
|
663
|
+
/* make slice for array-set */
|
664
|
+
static void
|
665
|
+
na_make_slice_aset(struct NARRAY *dst, struct NARRAY *src,
|
666
|
+
struct slice *s1, struct slice *s2, int *src_shape)
|
667
|
+
{
|
668
|
+
int i, j, idx_end;
|
669
|
+
|
670
|
+
/* count range index */
|
671
|
+
for (j=i=0; i<dst->rank; ++i) {
|
672
|
+
|
673
|
+
if ( s1[i].step !=0 ) { /* Range index */
|
674
|
+
|
675
|
+
/* rank check */
|
676
|
+
if ( j >= src->rank )
|
677
|
+
rb_raise(rb_eIndexError, "dst.range-dim=%i > src.dim=%i",
|
678
|
+
j+1, src->rank);
|
679
|
+
|
680
|
+
if ( s1[i].n == 0 ) {
|
681
|
+
/* Size is NOT specified:
|
682
|
+
a[0..nil] = other_array
|
683
|
+
a[0] = other_array
|
684
|
+
*/
|
685
|
+
s1[i].n = src->shape[j];
|
686
|
+
|
687
|
+
idx_end = s1[i].beg + (s1[i].n-1) * s1[i].step;
|
688
|
+
if ( idx_end < 0 || idx_end >= dst->shape[i] )
|
689
|
+
rb_raise(rb_eIndexError, "end-index=%i is out of dst.shape[%i]=%i",
|
690
|
+
idx_end, i, dst->shape[i]);
|
691
|
+
|
692
|
+
} else
|
693
|
+
/* Size is specified:
|
694
|
+
a[0..10] = other
|
695
|
+
*/
|
696
|
+
if ( src->shape[j] >1 && s1[i].n != src->shape[j] ) {
|
697
|
+
rb_raise(rb_eIndexError, "dst.shape[%i]=%i != src.shape[%i]=%i",
|
698
|
+
i, s1[i].n, j, src->shape[j]);
|
699
|
+
}
|
700
|
+
/* copy source shape */
|
701
|
+
src_shape[i] = src->shape[j++];
|
702
|
+
|
703
|
+
}
|
704
|
+
else /* if ( s1[i].n==1 )
|
705
|
+
Scalar index:
|
706
|
+
a[0, 0..-1] = other --- first rank is skipped.
|
707
|
+
*/
|
708
|
+
src_shape[i] = 1; /* insert dummy rank */
|
709
|
+
|
710
|
+
s2[i].beg = 0;
|
711
|
+
s2[i].idx = NULL;
|
712
|
+
s2[i].n = s1[i].n; /* repeate number is same as a1 index */
|
713
|
+
|
714
|
+
if ( s1[i].n >1 && src_shape[i]==1 ) /* Extensible index */
|
715
|
+
s2[i].step = 0;
|
716
|
+
else
|
717
|
+
s2[i].step = 1;
|
718
|
+
}
|
719
|
+
|
720
|
+
/* rank check */
|
721
|
+
if ( j != src->rank )
|
722
|
+
rb_raise(rb_eIndexError, "dst.range-dim=%i < src.dim=%i", j, src->rank);
|
723
|
+
}
|
724
|
+
|
725
|
+
|
726
|
+
|
727
|
+
/* Iterate with bifinc, src has extensible index */
|
728
|
+
void
|
729
|
+
na_aset_slice(struct NARRAY *dst, struct NARRAY *src, struct slice *dst_slc)
|
730
|
+
{
|
731
|
+
int rank = dst->rank;
|
732
|
+
int *src_shape;
|
733
|
+
struct slice *src_slc;
|
734
|
+
|
735
|
+
/* rank check */
|
736
|
+
if (rank < src->rank)
|
737
|
+
rb_raise(rb_eIndexError, "%i dst.ranks < %i src.ranks", rank, src->rank);
|
738
|
+
if (src->rank == 0)
|
739
|
+
rb_raise(rb_eIndexError, "cannot store empty array");
|
740
|
+
|
741
|
+
/* extend rank */
|
742
|
+
src_shape = ALLOCA_N(int, rank);
|
743
|
+
src_slc = ALLOC_N(struct slice, rank+1);
|
744
|
+
|
745
|
+
if (src->total==1)
|
746
|
+
na_make_slice_aset_fill( rank, src, src_slc, src_shape, dst_slc );
|
747
|
+
else
|
748
|
+
na_make_slice_aset( dst, src, dst_slc, src_slc, src_shape );
|
749
|
+
|
750
|
+
/* Iteration */
|
751
|
+
na_init_slice( dst_slc, rank, dst->shape, na_sizeof[dst->type] );
|
752
|
+
na_init_slice( src_slc, rank, src_shape, na_sizeof[src->type] );
|
753
|
+
na_loop_general( dst,src, dst_slc,src_slc, SetFuncs[dst->type][src->type] );
|
754
|
+
xfree(src_slc);
|
755
|
+
}
|
756
|
+
|
757
|
+
|
758
|
+
static void
|
759
|
+
na_aset_array_index( VALUE self, volatile VALUE idx, volatile VALUE val )
|
760
|
+
{
|
761
|
+
int i, total;
|
762
|
+
struct NARRAY *aidx, *src, *dst;
|
763
|
+
struct slice *sl;
|
764
|
+
|
765
|
+
GetNArray(self,dst);
|
766
|
+
idx = na_cast_object(idx,NA_LINT);
|
767
|
+
GetNArray(idx,aidx);
|
768
|
+
val = na_cast_unless_narray(val,dst->type);
|
769
|
+
GetNArray(val,src);
|
770
|
+
|
771
|
+
/* empty index -- do nothing */
|
772
|
+
if (aidx->total==0 && (src->total==0 || src->total==1))
|
773
|
+
return;
|
774
|
+
|
775
|
+
/* check rank */
|
776
|
+
if (aidx->rank != src->rank)
|
777
|
+
rb_raise( rb_eIndexError, "idx.rank=%i != src.rank=%i",
|
778
|
+
aidx->rank, src->rank );
|
779
|
+
/* check shape */
|
780
|
+
for (i=0;i<src->rank;++i)
|
781
|
+
if (aidx->shape[i] != src->shape[i] && src->shape[i] != 1)
|
782
|
+
rb_raise( rb_eIndexError, "idx.shape[%i]=%i != src.shape[%i]=%i",
|
783
|
+
i, aidx->shape[i], i, src->shape[i] );
|
784
|
+
|
785
|
+
/* make Slice from index */
|
786
|
+
sl = ALLOCA_N(struct slice,2);
|
787
|
+
total = na_ary_to_index( NA_STRUCT(idx), dst->total, sl );
|
788
|
+
|
789
|
+
/* 1-dimensionize */
|
790
|
+
if (dst->rank > 1) {
|
791
|
+
na_flatten_temp(dst);
|
792
|
+
}
|
793
|
+
if (src->rank > 1) {
|
794
|
+
na_flatten_temp(src);
|
795
|
+
}
|
796
|
+
|
797
|
+
na_aset_slice( dst, src, sl );
|
798
|
+
na_free_slice_index( sl, 1 ); /* free index memory */
|
799
|
+
}
|
800
|
+
|
801
|
+
|
802
|
+
static void
|
803
|
+
na_aset_single_dim(VALUE self, VALUE idx, volatile VALUE val)
|
804
|
+
{
|
805
|
+
int size;
|
806
|
+
struct NARRAY *src, *dst;
|
807
|
+
struct slice *sl;
|
808
|
+
|
809
|
+
GetNArray(self,dst);
|
810
|
+
if (dst->total==0)
|
811
|
+
rb_raise(rb_eRuntimeError, "cannot set value to empty array");
|
812
|
+
|
813
|
+
sl = ALLOCA_N(struct slice, 2);
|
814
|
+
size = na_index_test(idx, dst->total, sl);
|
815
|
+
|
816
|
+
if ( size == 1 ) {
|
817
|
+
if (NA_IsNArray(val)) {
|
818
|
+
GetNArray(val,src);
|
819
|
+
if ( src->total == 1 ) {
|
820
|
+
SetFuncs[dst->type][src->type](1, NA_PTR(dst,sl->beg),0, src->ptr,0);
|
821
|
+
return;
|
822
|
+
}
|
823
|
+
}
|
824
|
+
else if (TYPE(val)!=T_ARRAY) {
|
825
|
+
/* Storing single element:
|
826
|
+
a[1] = 1
|
827
|
+
*/
|
828
|
+
SetFuncs[dst->type][NA_ROBJ](1, NA_PTR(dst,sl->beg),0, &val,0);
|
829
|
+
return;
|
830
|
+
}
|
831
|
+
/* Beginning index:
|
832
|
+
a[1] = [1,2,3]
|
833
|
+
*/
|
834
|
+
sl[0].n = 0;
|
835
|
+
sl[0].step = 1;
|
836
|
+
}
|
837
|
+
else if ( size == 0 ) return; /* Empty index */
|
838
|
+
|
839
|
+
if ( dst->rank > 1 ) { /* 1-dimensionize */
|
840
|
+
na_flatten_temp(dst);
|
841
|
+
}
|
842
|
+
val = na_cast_unless_narray(val,dst->type);
|
843
|
+
GetNArray(val,src);
|
844
|
+
na_aset_slice( dst, src, sl );
|
845
|
+
|
846
|
+
na_free_slice_index(sl,1); /* free index memory */
|
847
|
+
}
|
848
|
+
|
849
|
+
|
850
|
+
static void
|
851
|
+
na_aset_multi_dim(VALUE self, int nidx, VALUE *idx, volatile VALUE val)
|
852
|
+
{
|
853
|
+
int i, pos, size;
|
854
|
+
struct NARRAY *dst, *src;
|
855
|
+
struct slice *sl;
|
856
|
+
|
857
|
+
GetNArray(self,dst);
|
858
|
+
if (dst->total==0)
|
859
|
+
rb_raise(rb_eRuntimeError, "cannot set value to empty array");
|
860
|
+
|
861
|
+
/* make Slice from index-argv */
|
862
|
+
sl = ALLOC_N(struct slice, dst->rank+1);
|
863
|
+
size = na_index_analysis( nidx, idx, dst, sl );
|
864
|
+
|
865
|
+
if ( size == 0 ) { xfree(sl); return; } /* Empty index */
|
866
|
+
if ( size == 1 ) {
|
867
|
+
if (NA_IsArray(val)) {
|
868
|
+
/* Beginning index:
|
869
|
+
a[2,3,4] = other
|
870
|
+
*/
|
871
|
+
val = na_cast_unless_narray(val,dst->type);
|
872
|
+
GetNArray(val,src);
|
873
|
+
if (src->total > 1)
|
874
|
+
for( i=0; i<src->rank; ++i ) {
|
875
|
+
sl[i].n = 0;
|
876
|
+
sl[i].step = 1;
|
877
|
+
}
|
878
|
+
}
|
879
|
+
else {
|
880
|
+
/* Single Element:
|
881
|
+
a[2,3,4] = 5
|
882
|
+
*/
|
883
|
+
for ( pos=0, i=dst->rank; i-->0; )
|
884
|
+
pos = pos * dst->shape[i] + sl[i].beg;
|
885
|
+
SetFuncs[dst->type][NA_ROBJ](1, NA_PTR(dst,pos), 0, &val, 0 );
|
886
|
+
xfree(sl);
|
887
|
+
return;
|
888
|
+
}
|
889
|
+
}
|
890
|
+
else
|
891
|
+
val = na_cast_unless_narray(val,dst->type);
|
892
|
+
GetNArray(val,src);
|
893
|
+
|
894
|
+
/* if ( size>1 ) */
|
895
|
+
/* Range index:
|
896
|
+
a[0..9,0] = other
|
897
|
+
*/
|
898
|
+
na_aset_slice( dst, src, sl );
|
899
|
+
|
900
|
+
na_free_slice_index(sl,nidx); /* free index memory */
|
901
|
+
xfree(sl);
|
902
|
+
}
|
903
|
+
|
904
|
+
|
905
|
+
|
906
|
+
static void
|
907
|
+
na_aset_fill(VALUE self, volatile VALUE val)
|
908
|
+
{
|
909
|
+
struct NARRAY *dst, *src;
|
910
|
+
struct slice *sl;
|
911
|
+
|
912
|
+
GetNArray(self,dst);
|
913
|
+
if (dst->total==0)
|
914
|
+
rb_raise(rb_eRuntimeError, "cannot set value to empty array");
|
915
|
+
|
916
|
+
if ( NA_IsArray(val) ) { /* store Array? */
|
917
|
+
sl = ALLOC_N(struct slice, dst->rank+1);
|
918
|
+
na_set_slice_1obj(dst->rank,sl,dst->shape);
|
919
|
+
|
920
|
+
val = na_cast_unless_narray(val,dst->type);
|
921
|
+
GetNArray(val,src);
|
922
|
+
na_aset_slice( dst, src, sl );
|
923
|
+
xfree(sl);
|
924
|
+
}
|
925
|
+
else {
|
926
|
+
na_fill( self, val ); /* Simple filling */
|
927
|
+
}
|
928
|
+
}
|
929
|
+
|
930
|
+
|
931
|
+
/* --- mask --- */
|
932
|
+
void
|
933
|
+
na_aset_mask(VALUE self, VALUE mask, VALUE val)
|
934
|
+
{
|
935
|
+
int size, step, i;
|
936
|
+
struct NARRAY *a1, *am, *a2;
|
937
|
+
|
938
|
+
GetNArray( self, a1 );
|
939
|
+
GetNArray( mask, am );
|
940
|
+
|
941
|
+
if (a1->total != am->total)
|
942
|
+
rb_raise(rb_eTypeError,"self.size(=%i) != mask.size(=%i)",
|
943
|
+
a1->total, am->total);
|
944
|
+
if (a1->rank != am->rank)
|
945
|
+
rb_raise(rb_eTypeError,"self.rank(=%i) != mask.rank(=%i)",
|
946
|
+
a1->rank, am->rank);
|
947
|
+
for (i=0; i<a1->rank; ++i)
|
948
|
+
if (a1->shape[i] != am->shape[i])
|
949
|
+
rb_raise(rb_eTypeError,"self.shape[%i](=%i) != mask.shape[%i](=%i)",
|
950
|
+
i, a1->shape[i], i, am->shape[i]);
|
951
|
+
|
952
|
+
size = na_count_true_body(mask);
|
953
|
+
|
954
|
+
val = na_cast_object(val,a1->type);
|
955
|
+
GetNArray( val, a2 );
|
956
|
+
if (a2->total == 1) {
|
957
|
+
step = 0;
|
958
|
+
} else if (a2->total == size) {
|
959
|
+
step = na_sizeof[a2->type];
|
960
|
+
} else {
|
961
|
+
rb_raise(rb_eTypeError,"val.length != mask.count_true");
|
962
|
+
}
|
963
|
+
|
964
|
+
SetMaskFuncs[a1->type]
|
965
|
+
( a1->total, a1->ptr, na_sizeof[a1->type],
|
966
|
+
a2->ptr, step, am->ptr, 1 );
|
967
|
+
}
|
968
|
+
|
969
|
+
/* method: []=(idx1,idx2,...,idxN,val) */
|
970
|
+
VALUE
|
971
|
+
na_aset(int nidx, VALUE *idx, VALUE self)
|
972
|
+
{
|
973
|
+
--nidx;
|
974
|
+
|
975
|
+
if (nidx==0) {
|
976
|
+
na_aset_fill( self, idx[0] );
|
977
|
+
}
|
978
|
+
else
|
979
|
+
if (nidx==1) {
|
980
|
+
if ( NA_IsNArray(idx[0]) ) {
|
981
|
+
if( NA_TYPE(idx[0]) == NA_BYTE ) { /* then supposed to be a mask */
|
982
|
+
na_aset_mask(self, idx[0], idx[1]);
|
983
|
+
return(idx[1]);
|
984
|
+
}
|
985
|
+
}
|
986
|
+
if ( NA_IsArray(idx[0]) ) /* Array Index ? */
|
987
|
+
na_aset_array_index( self, idx[0], idx[1] );
|
988
|
+
else
|
989
|
+
na_aset_single_dim( self, idx[0], idx[1] );
|
990
|
+
}
|
991
|
+
else
|
992
|
+
if (nidx>1) {
|
993
|
+
na_aset_multi_dim( self, nidx, idx, idx[nidx] );
|
994
|
+
}
|
995
|
+
else /* if (nidx<0) */
|
996
|
+
rb_raise( rb_eArgError, "No value specified" );
|
997
|
+
|
998
|
+
return idx[nidx];
|
999
|
+
}
|
1000
|
+
|
1001
|
+
|
1002
|
+
void Init_na_index() {
|
1003
|
+
/* slice */
|
1004
|
+
rb_define_method(cNArray, "[]", na_aref,-1);
|
1005
|
+
rb_define_method(cNArray, "[]=", na_aset,-1);
|
1006
|
+
rb_define_method(cNArray, "slice", na_slice,-1);
|
1007
|
+
/* mask */
|
1008
|
+
rb_define_method(cNArray, "count_false", na_count_false, 0);
|
1009
|
+
rb_define_method(cNArray, "count_true", na_count_true, 0);
|
1010
|
+
rb_define_method(cNArray, "mask", na_aref_mask, 1);
|
1011
|
+
}
|