narray-bigmem 0.0.0

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,1709 @@
1
+ /*
2
+ na_func.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
+ void
16
+ na_shape_max3(int ndim, na_shape_t *max_shp, na_shape_t *shp1, na_shape_t *shp2, na_shape_t *shp3)
17
+ {
18
+ int i;
19
+
20
+ for (i=0; i<ndim; ++i) {
21
+ max_shp[i] = NA_MAX3(shp1[i], shp2[i], shp3[i]);
22
+ }
23
+ }
24
+
25
+
26
+ /* initialize slice structure */
27
+ void na_init_slice( struct slice *s, int rank, na_shape_t *shape, int elmsz )
28
+ {
29
+ int r, b;
30
+ na_shape_t i, *idx;
31
+
32
+ /*
33
+ if (rank<1)
34
+ rb_raise(rb_eRuntimeError,"cannot execute for empty array");
35
+ */
36
+
37
+ /* set strides and clear index */
38
+ s[0].stride = 1;
39
+ for (r=1; r<rank; ++r)
40
+ s[r].stride = s[r-1].stride * shape[r-1];
41
+
42
+ for (r=0; r<rank; ++r) {
43
+ if ( s[r].idx == NULL )
44
+ /* regular interval */
45
+ s[r].pstep = s[r].step * s[r].stride * elmsz;
46
+ else {
47
+ /* index */
48
+ s[r].pstep = b = s[r].stride * elmsz;
49
+ /* convert index to byte-unit */
50
+ for (i=0; i<16; ++i)
51
+ if ( (1<<i) == b ) { b=i; break; }
52
+ if (i==16)
53
+ for (idx=s[r].idx,i=s[r].n; i-->0; ) { *(idx++)*=b; }
54
+ else
55
+ for (idx=s[r].idx,i=s[r].n; i-->0; ) { *(idx++)<<=b; }
56
+ }
57
+ }
58
+
59
+ /* set termination mark */
60
+ s[rank].n = 0;
61
+ s[rank].idx = NULL;
62
+
63
+ for (r=rank-1;r>=0;--r) {
64
+ /* set beginning pointers */
65
+ if ( s[r].idx == NULL )
66
+ s[r].pbeg = s[r].stride * s[r].beg * elmsz;
67
+ else
68
+ s[r].pbeg = s[r].idx[0];
69
+ }
70
+ }
71
+
72
+
73
+ static void
74
+ na_do_loop_unary( int nd, char *p1, char *p2,
75
+ struct slice *s1, struct slice *s2, void (*func)() )
76
+ {
77
+ int *si;
78
+ int i;
79
+ na_shape_t ps1 = s1[0].pstep;
80
+ na_shape_t ps2 = s2[0].pstep;
81
+
82
+ i = nd;
83
+ si = ALLOCA_N(int,nd);
84
+ s1[i].p = p1;
85
+ s2[i].p = p2;
86
+
87
+ for(;;) {
88
+ /* set pointers */
89
+ while (i > 0) {
90
+ --i;
91
+ s2[i].p = s2[i].pbeg + s2[i+1].p;
92
+ s1[i].p = s1[i].pbeg + s1[i+1].p;
93
+ si[i] = s1[i].n;
94
+ }
95
+ (*func)(s2[0].n, s1[0].p, ps1, s2[0].p, ps2);
96
+ /* rank up */
97
+ do {
98
+ if ( ++i >= nd ) return;
99
+ } while ( --si[i] == 0 );
100
+ /* next point */
101
+ s1[i].p += s1[i].pstep;
102
+ s2[i].p += s2[i].pstep;
103
+ }
104
+ }
105
+
106
+
107
+ static void
108
+ na_do_loop_binary( int nd, char *p1, char *p2, char *p3,
109
+ struct slice *s1, struct slice *s2, struct slice *s3,
110
+ void (*func)() )
111
+ {
112
+ int i;
113
+ na_shape_t ps1 = s1[0].pstep;
114
+ na_shape_t ps2 = s2[0].pstep;
115
+ na_shape_t ps3 = s3[0].pstep;
116
+ int *si;
117
+
118
+ si = ALLOCA_N(int,nd);
119
+ i = nd;
120
+ s1[i].p = p1;
121
+ s2[i].p = p2;
122
+ s3[i].p = p3;
123
+
124
+ for(;;) {
125
+ /* set pointers */
126
+ while (i > 0) {
127
+ --i;
128
+ s3[i].p = s3[i].pbeg + s3[i+1].p;
129
+ s2[i].p = s2[i].pbeg + s2[i+1].p;
130
+ s1[i].p = s1[i].pbeg + s1[i+1].p;
131
+ si[i] = s1[i].n;
132
+ }
133
+ /* rank 0 loop */
134
+ (*func)(s2[0].n, s1[0].p, ps1, s2[0].p, ps2, s3[0].p, ps3);
135
+ /* rank up */
136
+ do {
137
+ if ( ++i >= nd ) return;
138
+ } while ( --si[i] == 0 );
139
+ /* next point */
140
+ s1[i].p += s1[i].pstep;
141
+ s2[i].p += s2[i].pstep;
142
+ s3[i].p += s3[i].pstep;
143
+ }
144
+ }
145
+
146
+
147
+
148
+ void na_loop_index_ref( struct NARRAY *a1, struct NARRAY *a2,
149
+ struct slice *s1, struct slice *s2, void (*func)() )
150
+ {
151
+ char *p1, *p2;
152
+ int nr, i;
153
+ na_shape_t ii;
154
+ na_shape_t ps1 = s1[0].pstep;
155
+ na_shape_t ps2 = s2[0].pstep;
156
+ int *si;
157
+ na_shape_t *idx;
158
+
159
+ /*
160
+ int copy;
161
+ if (a1->type==a2->type && s1[0].step==1 && s2[0].step==1)
162
+ copy = s1[0].n * na_sizeof[a1->type];
163
+ else
164
+ copy = 0;
165
+ */
166
+
167
+ /* Initialize */
168
+ nr = i = a1->rank;
169
+ si = ALLOCA_N(int,nr);
170
+ s1[i].p = a1->ptr;
171
+ s2[i].p = a2->ptr;
172
+
173
+ for(;;) {
174
+ /* set pointers */
175
+ while (i > 0) {
176
+ --i;
177
+ s2[i].p = s2[i].pbeg + s2[i+1].p;
178
+ s1[i].p = s1[i].pbeg + s1[i+1].p;
179
+ si[i] = 0;
180
+ }
181
+
182
+ /* rank 0 loop */
183
+ if ( s2[0].idx == NULL ) {
184
+ /* regular interval */
185
+ /*
186
+ if (copy) {
187
+ memcpy(s1[0].p, s2[0].p, copy);
188
+ } else
189
+ */
190
+ (*func)(s2[0].n, s1[0].p, ps1, s2[0].p, ps2);
191
+ } else {
192
+ /* a2 has index */
193
+ p1 = s1[0].p;
194
+ p2 = s2[1].p;
195
+ for ( idx=s2[0].idx, ii=s2[0].n; ii-->0;) {
196
+ (*func)( 1, p1, 0, p2+*(idx++), 0 );
197
+ p1 += ps1;
198
+ }
199
+ }
200
+ /* rank up */
201
+ do {
202
+ if ( ++i >= nr ) return;
203
+ } while ( ++si[i] == s1[i].n );
204
+ /* next point */
205
+ s1[i].p += s1[i].pstep;
206
+ /* array2 may have index */
207
+ if ( s2[i].idx == NULL )
208
+ s2[i].p += s2[i].pstep;
209
+ else
210
+ s2[i].p = s2[i+1].p + s2[i].idx[si[i]]; /* * s2[i].pstep; */
211
+ }
212
+ }
213
+
214
+
215
+ void na_loop_general( struct NARRAY *a1, struct NARRAY *a2,
216
+ struct slice *s1, struct slice *s2, void (*func)() )
217
+ {
218
+ char *p1, *p2;
219
+ int nr, i, ii;
220
+ na_shape_t ps1 = s1[0].pstep;
221
+ na_shape_t ps2 = s2[0].pstep;
222
+ int *si;
223
+ na_shape_t *idx1, *idx2;
224
+
225
+ /* Initialize */
226
+ nr = i = a1->rank;
227
+ si = ALLOCA_N(int,nr);
228
+ s1[i].p = a1->ptr;
229
+ s2[i].p = a2->ptr;
230
+
231
+ for(;;) {
232
+ /* set pointers */
233
+ while (i > 0) {
234
+ --i;
235
+ s2[i].p = s2[i].pbeg + s2[i+1].p;
236
+ s1[i].p = s1[i].pbeg + s1[i+1].p;
237
+ si[i] = 0;
238
+ }
239
+
240
+ /* rank 0 loop */
241
+ if ( s1[0].idx == NULL ) {
242
+ if ( s2[0].idx == NULL ) {
243
+ /* normal interval */
244
+ (*func)(s2[0].n, s1[0].p, ps1, s2[0].p, ps2);
245
+ } else {
246
+ /* s2 has index */
247
+ p1 = s1[0].p;
248
+ p2 = s2[1].p;
249
+ for ( idx2=s2[0].idx, ii=s2[0].n; ii-->0; ) {
250
+ (*func)( 1, p1, 0, p2+*(idx2++), 0 );
251
+ p1 += ps1;
252
+ }
253
+ }
254
+ } else {
255
+ if ( s2[0].idx == NULL ) {
256
+ /* s1 has index */
257
+ p1 = s1[1].p;
258
+ p2 = s2[0].p;
259
+ for ( idx1=s1[0].idx, ii=s2[0].n; ii-->0; ) {
260
+ (*func)( 1, p1+*(idx1++), 0, p2, 0 );
261
+ p2 += ps2;
262
+ }
263
+ } else {
264
+ /* s1 & s2 has index */
265
+ p1 = s1[1].p;
266
+ p2 = s2[1].p;
267
+ for ( idx1=s1[0].idx, idx2=s2[0].idx, ii=s2[0].n; ii-->0; ) {
268
+ (*func)( 1, p1+*(idx1++), 0, p2+*(idx2++), 0 );
269
+ }
270
+ }
271
+ }
272
+
273
+ /* rank up */
274
+ do {
275
+ if ( ++i >= nr ) return;
276
+ } while ( ++si[i] == s1[i].n );
277
+
278
+ /* next point for a1 */
279
+ if ( s1[i].idx == NULL )
280
+ s1[i].p += s1[i].pstep;
281
+ else
282
+ s1[i].p = s1[i+1].p + s1[i].idx[si[i]];
283
+ /* next point for a2 */
284
+ if ( s2[i].idx == NULL )
285
+ s2[i].p += s2[i].pstep;
286
+ else
287
+ s2[i].p = s2[i+1].p + s2[i].idx[si[i]];
288
+ }
289
+ }
290
+
291
+
292
+ void
293
+ na_shape_copy( int ndim, na_shape_t *shape, struct NARRAY *a )
294
+ {
295
+ int i;
296
+
297
+ for (i=0; i<a->rank; ++i)
298
+ shape[i] = a->shape[i];
299
+ for ( ; i<ndim; ++i)
300
+ shape[i] = 1;
301
+ }
302
+
303
+
304
+ void
305
+ na_set_slice_1obj( int ndim, struct slice *slc, na_shape_t *shape )
306
+ {
307
+ int i;
308
+
309
+ /* for normal access */
310
+ for (i=0; i<ndim; ++i) {
311
+ slc[i].n = shape[i];
312
+ slc[i].beg = 0;
313
+ slc[i].step = 1;
314
+ slc[i].idx = NULL;
315
+ }
316
+ }
317
+
318
+
319
+
320
+ static int
321
+ na_set_slice_2obj( int ndim, struct slice *s1, struct slice *s2,
322
+ na_shape_t *shp1, na_shape_t *shp2 )
323
+ {
324
+ int i, j;
325
+
326
+ for (i=j=0; i<ndim; ++i) {
327
+
328
+ if ( shp1[i]==1 && shp2[i]>1 ) {
329
+ s1[j].n =
330
+ s2[j].n = shp2[i];
331
+ s1[j].step = 0;
332
+ s2[j].step = 1;
333
+ } else
334
+ if ( shp2[i]==1 && shp1[i]>1 ) {
335
+ s1[j].n =
336
+ s2[j].n = shp1[i];
337
+ s1[j].step = 1;
338
+ s2[j].step = 0;
339
+ } else
340
+ if ( shp1[i] == shp2[i] ) {
341
+ s1[j].n =
342
+ s2[j].n = shp1[i];
343
+ s1[j].step = 1;
344
+ s2[j].step = 1;
345
+ } else
346
+ rb_raise(rb_eRuntimeError, "Array size mismatch: %zd != %zd in %i-th dim",
347
+ shp1[i], shp2[i], i);
348
+
349
+ if (j<i) {
350
+ shp1[j] = shp1[i];
351
+ shp2[j] = shp2[i];
352
+ }
353
+
354
+ if (j>0)
355
+ if ( s1[j].step == s1[j-1].step &&
356
+ s2[j].step == s2[j-1].step ) { /* contract dimension */
357
+ s1[j-1].n =
358
+ s2[j-1].n *= s2[j].n;
359
+ shp1[j-1] *= shp1[j];
360
+ shp2[j-1] *= shp2[j];
361
+ continue;
362
+ }
363
+ s1[j].beg =
364
+ s2[j].beg = 0;
365
+ s1[j].idx =
366
+ s2[j].idx = NULL;
367
+ ++j;
368
+ }
369
+
370
+ return j;
371
+ }
372
+
373
+
374
+ static int
375
+ na_set_slice_check(na_shape_t ary_sz, na_shape_t itr_sz, int i)
376
+ {
377
+ if ( ary_sz == itr_sz )
378
+ return 1;
379
+ else if ( ary_sz == 1 )
380
+ return 0;
381
+ else
382
+ rb_raise(rb_eRuntimeError, "Array size mismatch: %zd != %zd at %i-th dim",
383
+ ary_sz, itr_sz, i);
384
+ }
385
+
386
+
387
+ int
388
+ na_set_slice_3obj( int ndim,
389
+ struct slice *s1, struct slice *s2, struct slice *s3,
390
+ na_shape_t *shp1, na_shape_t *shp2, na_shape_t *shp3, na_shape_t *shape )
391
+ {
392
+ int i, j;
393
+
394
+ /* for repetitous access */
395
+ for (i=j=0; i<ndim; ++i) {
396
+
397
+ s1[j].step = na_set_slice_check(shp1[i],shape[i],i);
398
+ s2[j].step = na_set_slice_check(shp2[i],shape[i],i);
399
+ s3[j].step = na_set_slice_check(shp3[i],shape[i],i);
400
+
401
+ if (j<i) {
402
+ shp1[j] = shp1[i];
403
+ shp2[j] = shp2[i];
404
+ shp3[j] = shp3[i];
405
+ }
406
+
407
+ if (j>0) {
408
+ if ( s1[j].step == s1[j-1].step &&
409
+ s2[j].step == s2[j-1].step &&
410
+ s3[j].step == s3[j-1].step ) /* contract dimension */
411
+ {
412
+ s1[j-1].n =
413
+ s2[j-1].n =
414
+ s3[j-1].n *= shape[i];
415
+
416
+ shp1[j-1] *= shp1[j];
417
+ shp2[j-1] *= shp2[j];
418
+ shp3[j-1] *= shp3[j];
419
+ continue;
420
+ }
421
+ }
422
+
423
+ s1[j].n =
424
+ s2[j].n =
425
+ s3[j].n = shape[i];
426
+
427
+ s1[j].beg =
428
+ s2[j].beg =
429
+ s3[j].beg = 0;
430
+
431
+ s1[j].idx =
432
+ s2[j].idx =
433
+ s3[j].idx = NULL;
434
+
435
+ ++j;
436
+ }
437
+
438
+ return j;
439
+ }
440
+
441
+
442
+ static void
443
+ na_exec_unary(struct NARRAY *a1, struct NARRAY *a2, void (*func)())
444
+ {
445
+ int ndim;
446
+ na_shape_t *shp1, *shp2;
447
+ struct slice *s1, *s2;
448
+
449
+ /* empty check */
450
+ if ( a1->total==0 || a2->total==0 )
451
+ /* rb_raise( rb_eTypeError, "cannot execute for empty array" ); */
452
+ return; /* do nothing */
453
+
454
+ ndim = NA_MAX(a1->rank,a2->rank);
455
+
456
+ NA_ALLOC_SLICE(s1,(ndim+1)*2,shp1,ndim*2);
457
+ shp2 = &shp1[ndim];
458
+ s2 = &s1[ndim+1];
459
+
460
+ na_shape_copy( ndim, shp1, a1 );
461
+ na_shape_copy( ndim, shp2, a2 );
462
+
463
+ ndim = na_set_slice_2obj( ndim, s1, s2, shp1, shp2 );
464
+ na_init_slice( s1, ndim, shp1, na_sizeof[a1->type] );
465
+ na_init_slice( s2, ndim, shp2, na_sizeof[a2->type] );
466
+
467
+ na_do_loop_unary( ndim, a1->ptr, a2->ptr, s1, s2, func );
468
+
469
+ xfree(s1);
470
+ }
471
+
472
+
473
+ /* a1 and/or a2 and/or a3 have extensible index */
474
+ static void
475
+ na_exec_binary( struct NARRAY *a1, struct NARRAY *a2,
476
+ struct NARRAY *a3, void (*func)() )
477
+ {
478
+ int ndim;
479
+ na_shape_t *itr, *shp1, *shp2, *shp3;
480
+ struct slice *s1, *s2, *s3;
481
+
482
+ /* empty check */
483
+ if (a1->total==0) return; /* do nothing */
484
+
485
+ ndim = NA_MAX3(a1->rank, a2->rank, a3->rank);
486
+
487
+ NA_ALLOC_SLICE(s1,(ndim+1)*3,shp1,ndim*4);
488
+ shp2 = &shp1[ndim];
489
+ shp3 = &shp2[ndim];
490
+ itr = &shp3[ndim];
491
+ s2 = &s1[ndim+1];
492
+ s3 = &s2[ndim+1];
493
+
494
+ na_shape_copy( ndim, shp1, a1 );
495
+ na_shape_copy( ndim, shp2, a2 );
496
+ na_shape_copy( ndim, shp3, a3 );
497
+ na_shape_max3( ndim, itr, shp1, shp2, shp3 );
498
+
499
+ ndim = na_set_slice_3obj( ndim, s1, s2, s3, shp1, shp2, shp3, itr );
500
+
501
+ na_init_slice(s1, ndim, shp1, na_sizeof[a1->type] );
502
+ na_init_slice(s2, ndim, shp2, na_sizeof[a2->type] );
503
+ na_init_slice(s3, ndim, shp3, na_sizeof[a3->type] );
504
+
505
+ na_do_loop_binary( ndim, a1->ptr, a2->ptr, a3->ptr, s1, s2, s3, func );
506
+ xfree(s1);
507
+ }
508
+
509
+
510
+ static void
511
+ na_shape_max_2obj(int ndim, na_shape_t *shape, struct NARRAY *a1, struct NARRAY *a2)
512
+ {
513
+ struct NARRAY *tmp;
514
+ int i;
515
+
516
+ /* empty check */
517
+ if ( a1->total==0 || a2->total==0 )
518
+ rb_raise( rb_eTypeError, "cannot execute for empty array" );
519
+
520
+ if (a1->rank < a2->rank) {
521
+ NA_SWAP(a1,a2,tmp);
522
+ }
523
+
524
+ for (i=0; i<a2->rank; ++i) {
525
+ shape[i] = NA_MAX(a1->shape[i],a2->shape[i]);
526
+ }
527
+ for ( ; i<a1->rank; ++i) {
528
+ shape[i] = a1->shape[i];
529
+ }
530
+ for ( ; i<ndim; ++i) {
531
+ shape[i] = 1;
532
+ }
533
+ }
534
+
535
+
536
+ static VALUE
537
+ na_make_object_extend(struct NARRAY *a1, struct NARRAY *a2,
538
+ int type, VALUE klass)
539
+ {
540
+ int ndim;
541
+ na_shape_t *shape;
542
+
543
+ /* empty check */
544
+ if ( a1->total==0 || a2->total==0 )
545
+ return na_make_empty(type, klass); /* return empty */
546
+
547
+ ndim = NA_MAX(a1->rank, a2->rank);
548
+ shape = ALLOCA_N(na_shape_t, ndim);
549
+ na_shape_max_2obj( ndim, shape, a1, a2 );
550
+
551
+ return na_make_object( type, ndim, shape, klass );
552
+ }
553
+
554
+
555
+ static ID na_bifunc_to_id(na_bifunc_t funcs)
556
+ {
557
+ if (funcs==AddBFuncs) return na_id_add;
558
+ if (funcs==SbtBFuncs) return na_id_sbt;
559
+ if (funcs==MulBFuncs) return na_id_mul;
560
+ if (funcs==DivBFuncs) return na_id_div;
561
+ if (funcs==ModBFuncs) return na_id_mod;
562
+ return 0;
563
+ /* if (funcs==PowFuncs) return na_id_power;
564
+ rb_raise(rb_eRuntimeError, "coerce_rev: function not soppurted");
565
+ */
566
+ }
567
+
568
+
569
+ static VALUE
570
+ na_bifunc_class(VALUE klass1, VALUE klass2)
571
+ {
572
+ if ( klass2==cNArray || klass2==cNArrayScalar ) {
573
+ if ( klass1==cNArrayScalar ) return cNArray;
574
+ else return klass1;
575
+ }
576
+ return Qnil;
577
+ }
578
+
579
+
580
+ static VALUE
581
+ na_bifunc(VALUE obj1, VALUE obj2, VALUE klass, na_bifunc_t funcs)
582
+ {
583
+ VALUE obj3;
584
+ ID id;
585
+ int type;
586
+
587
+ Check_Type(obj1, T_DATA);
588
+ obj2 = na_upcast_object(obj2,NA_STRUCT(obj1)->type);
589
+ obj1 = na_upcast_type(obj1,type=NA_STRUCT(obj2)->type);
590
+
591
+ if (klass==Qnil) {
592
+ klass = na_bifunc_class(CLASS_OF(obj1),CLASS_OF(obj2));
593
+
594
+ if (klass==Qnil) { /* coerce_rev */
595
+ if ((id=na_bifunc_to_id(funcs))!=0)
596
+ return rb_funcall( obj2, na_id_coerce_rev, 2, obj1, ID2SYM(id) );
597
+ else
598
+ klass = cNArray;
599
+ }
600
+ }
601
+
602
+ obj3 = na_make_object_extend(NA_STRUCT(obj1),NA_STRUCT(obj2),type,klass);
603
+
604
+ na_exec_binary( NA_STRUCT(obj3), NA_STRUCT(obj1), NA_STRUCT(obj2),
605
+ funcs[type] );
606
+
607
+ return obj3;
608
+ }
609
+
610
+
611
+ static VALUE
612
+ na_power(VALUE val1, VALUE val2)
613
+ {
614
+ volatile VALUE obj1, obj2, obj3;
615
+ struct NARRAY *a1, *a2;
616
+
617
+ obj1 = val1;
618
+ obj2 = val2;
619
+ GetNArray(obj1,a1);
620
+ obj2 = na_to_narray(obj2);
621
+ GetNArray(obj2,a2);
622
+
623
+ if (a1->type==NA_ROBJ && a2->type!=NA_ROBJ) {
624
+ obj2 = na_change_type(obj2,NA_ROBJ);
625
+ GetNArray(obj2,a2);
626
+ } else
627
+ if (a2->type==NA_ROBJ && a1->type!=NA_ROBJ) {
628
+ obj1 = na_change_type(obj1,NA_ROBJ);
629
+ GetNArray(obj1,a1);
630
+ } else
631
+ if (!NA_IsCOMPLEX(a1) && NA_IsCOMPLEX(a2)) {
632
+ obj1 = na_upcast_type(obj1,a2->type);
633
+ GetNArray(obj1,a1);
634
+ }
635
+
636
+ obj3 = na_make_object_extend( a1, a2, na_upcast[a1->type][a2->type],
637
+ CLASS_OF(obj1) );
638
+
639
+ na_exec_binary( NA_STRUCT(obj3), a1, a2,
640
+ PowFuncs[a1->type][a2->type] );
641
+
642
+ return obj3;
643
+ }
644
+
645
+
646
+ static VALUE
647
+ na_set_func(VALUE obj1, volatile VALUE obj2, na_ufunc_t funcs)
648
+ {
649
+ struct NARRAY *a1;
650
+
651
+ GetNArray(obj1,a1);
652
+ obj2 = na_cast_object(obj2,a1->type);
653
+
654
+ na_exec_unary( NA_STRUCT(obj1), NA_STRUCT(obj2), funcs[a1->type] );
655
+
656
+ return obj1;
657
+ }
658
+
659
+
660
+ static VALUE
661
+ na_imag_set(VALUE obj1, volatile VALUE obj2)
662
+ {
663
+ struct NARRAY *a1;
664
+
665
+ GetNArray(obj1,a1);
666
+ obj2 = na_cast_object(obj2, na_cast_real[a1->type]);
667
+
668
+ na_exec_unary( NA_STRUCT(obj1), NA_STRUCT(obj2), ImgSetFuncs[a1->type] );
669
+
670
+ return obj1;
671
+ }
672
+
673
+
674
+ static VALUE
675
+ na_unary_func(VALUE self, const int *cast, na_ufunc_t funcs)
676
+ {
677
+ VALUE ans;
678
+ struct NARRAY *a2;
679
+
680
+ GetNArray(self,a2);
681
+ ans = na_make_object(cast[a2->type], a2->rank, a2->shape, CLASS_OF(self));
682
+
683
+ na_exec_unary( NA_STRUCT(ans), a2, funcs[a2->type] );
684
+ return ans;
685
+ }
686
+
687
+
688
+
689
+ /* local function for comparison */
690
+ static VALUE
691
+ na_compare_func(VALUE self, VALUE other, na_bifunc_t funcs)
692
+ {
693
+ VALUE ans;
694
+ int type;
695
+
696
+ Check_Type(self, T_DATA);
697
+ /*if (NA_IsComplex(a1)) rb_raise();*/
698
+ other = na_upcast_object(other,NA_STRUCT(self)->type);
699
+ self = na_upcast_type(self,type=NA_STRUCT(other)->type);
700
+
701
+ ans = na_make_object_extend( NA_STRUCT(self), NA_STRUCT(other),
702
+ NA_BYTE, cNArray );
703
+
704
+ na_exec_binary( NA_STRUCT(ans), NA_STRUCT(self), NA_STRUCT(other),
705
+ funcs[type] );
706
+ return ans;
707
+ }
708
+
709
+
710
+ /* method: self + other */
711
+ static VALUE na_add(VALUE obj1, VALUE obj2)
712
+ { return na_bifunc( obj1, obj2, Qnil, AddBFuncs ); }
713
+
714
+ /* method: self - other */
715
+ static VALUE na_sbt(VALUE obj1, VALUE obj2)
716
+ { return na_bifunc( obj1, obj2, Qnil, SbtBFuncs ); }
717
+
718
+ /* method: self * other */
719
+ static VALUE na_mul(VALUE obj1, VALUE obj2)
720
+ { return na_bifunc( obj1, obj2, Qnil, MulBFuncs ); }
721
+
722
+ /* method: self / other */
723
+ static VALUE na_div(VALUE obj1, VALUE obj2)
724
+ { return na_bifunc( obj1, obj2, Qnil, DivBFuncs ); }
725
+
726
+ /* method: self / other */
727
+ static VALUE na_mod(VALUE obj1, VALUE obj2)
728
+ { return na_bifunc( obj1, obj2, Qnil, ModBFuncs ); }
729
+
730
+ /* method: self & other */
731
+ static VALUE na_bit_and(VALUE obj1, VALUE obj2)
732
+ { return na_bifunc( obj1, obj2, Qnil, BAnFuncs ); }
733
+
734
+ /* method: self | other */
735
+ static VALUE na_bit_or(VALUE obj1, VALUE obj2)
736
+ { return na_bifunc( obj1, obj2, Qnil, BOrFuncs ); }
737
+
738
+ /* method: self ^ other */
739
+ static VALUE na_bit_xor(VALUE obj1, VALUE obj2)
740
+ { return na_bifunc( obj1, obj2, Qnil, BXoFuncs ); }
741
+
742
+ /* method: atan2(y,x) */
743
+ static VALUE na_math_atan2(VALUE module, volatile VALUE y, volatile VALUE x)
744
+ {
745
+ VALUE ans;
746
+ struct NARRAY *ya, *xa, *aa;
747
+
748
+ if (TYPE(y) == T_ARRAY) {
749
+ y = na_ary_to_nary(y,cNArray);
750
+ } else
751
+ if (!IsNArray(y)) {
752
+ y = na_make_scalar(y,na_object_type(y));
753
+ }
754
+
755
+ if (TYPE(x) == T_ARRAY) {
756
+ x = na_ary_to_nary(x,cNArray);
757
+ } else
758
+ if (!IsNArray(x)) {
759
+ x = na_make_scalar(x,na_object_type(x));
760
+ }
761
+
762
+ GetNArray(y,ya);
763
+ GetNArray(x,xa);
764
+ if (NA_IsINTEGER(ya) && NA_IsINTEGER(xa)) {
765
+ y = na_upcast_type(y,NA_DFLOAT);
766
+ x = na_upcast_type(x,NA_DFLOAT);
767
+ }
768
+
769
+ ans = na_bifunc( y, x, Qnil, atan2Funcs );
770
+ GetNArray(ans,aa);
771
+
772
+ if (CLASS_OF(y) == cNArrayScalar && CLASS_OF(x) == cNArrayScalar)
773
+ SetFuncs[NA_ROBJ][aa->type](1,&ans,0,aa->ptr,0);
774
+
775
+ return ans;
776
+ }
777
+
778
+
779
+
780
+ /* singleton method: NArray.mul( obj1, obj2 ) */
781
+ static VALUE
782
+ na_s_mul(VALUE klass, VALUE obj1, VALUE obj2)
783
+ { return na_bifunc( obj1, obj2, klass, MulBFuncs ); }
784
+
785
+ /* singleton method: NArray.div( obj1, obj2 ) */
786
+ static VALUE
787
+ na_s_div(VALUE klass, VALUE obj1, VALUE obj2)
788
+ { return na_bifunc( obj1, obj2, klass, DivBFuncs ); }
789
+
790
+
791
+
792
+ /* method: self.add!(other) */
793
+ static VALUE na_add_bang(VALUE obj1, VALUE obj2)
794
+ { return na_set_func( obj1, obj2, AddUFuncs ); }
795
+
796
+ /* method: self.sbt!(other) */
797
+ static VALUE na_sbt_bang(VALUE obj1, VALUE obj2)
798
+ { return na_set_func( obj1, obj2, SbtUFuncs ); }
799
+
800
+ /* method: self.div!(other) */
801
+ static VALUE na_div_bang(VALUE obj1, VALUE obj2)
802
+ { return na_set_func( obj1, obj2, DivUFuncs ); }
803
+
804
+ /* method: self.mul!(other) */
805
+ static VALUE na_mul_bang(VALUE obj1, VALUE obj2)
806
+ { return na_set_func( obj1, obj2, MulUFuncs ); }
807
+
808
+ /* method: self.mod!(other) */
809
+ static VALUE na_mod_bang(VALUE obj1, VALUE obj2)
810
+ { return na_set_func( obj1, obj2, ModUFuncs ); }
811
+
812
+ /* method: self.conj! */
813
+ static VALUE na_conj_bang(VALUE self)
814
+ { return na_set_func( self, self, ConjFuncs ); }
815
+
816
+
817
+ /* method: self.swap_byte */
818
+ static VALUE na_swap_byte(VALUE self)
819
+ { return na_unary_func( self, na_no_cast, SwpFuncs ); }
820
+
821
+ /* method: self.hton , self.ntoh */
822
+ static VALUE na_hton(VALUE self)
823
+ { return na_unary_func( self, na_no_cast, H2NFuncs ); }
824
+
825
+ /* method: self.htov , self.vtoh */
826
+ static VALUE na_htov(VALUE self)
827
+ { return na_unary_func( self, na_no_cast, H2VFuncs ); }
828
+
829
+ /* method: ~self */
830
+ static VALUE na_bit_rev(VALUE self)
831
+ { return na_unary_func( self, na_no_cast, BRvFuncs ); }
832
+
833
+ /* method: -self */
834
+ static VALUE na_neg(VALUE self)
835
+ { return na_unary_func( self, na_no_cast, NegFuncs ); }
836
+
837
+ /* method: self.recip */
838
+ static VALUE na_recip(VALUE self)
839
+ { return na_unary_func( self, na_no_cast, RcpFuncs ); }
840
+
841
+ /* method: self.abs */
842
+ static VALUE na_abs(VALUE self)
843
+ { return na_unary_func( self, na_cast_real, AbsFuncs ); }
844
+
845
+ /* method: self.real */
846
+ static VALUE na_real(VALUE self)
847
+ { return na_unary_func( self, na_cast_real, RealFuncs ); }
848
+
849
+ /* method: self.imag */
850
+ static VALUE na_imag(VALUE self)
851
+ { return na_unary_func( self, na_cast_real, ImagFuncs ); }
852
+
853
+ /* method: self.imag */
854
+ static VALUE na_angle(VALUE self)
855
+ { return na_unary_func( self, na_cast_real, AnglFuncs ); }
856
+
857
+ /* method: self.im */
858
+ static VALUE na_imag_mul(VALUE self)
859
+ { return na_unary_func( self, na_cast_comp, ImagMulFuncs ); }
860
+
861
+ /* method: self.conj */
862
+ static VALUE na_conj(VALUE self)
863
+ { return na_unary_func( self, na_no_cast, ConjFuncs ); }
864
+
865
+ /* method: self.floor */
866
+ static VALUE na_floor(VALUE self)
867
+ { return na_unary_func( self, na_cast_round, FloorFuncs ); }
868
+
869
+ /* method: self.ceil */
870
+ static VALUE na_ceil(VALUE self)
871
+ { return na_unary_func( self, na_cast_round, CeilFuncs ); }
872
+
873
+ /* method: self.round */
874
+ static VALUE na_round(VALUE self)
875
+ { return na_unary_func( self, na_cast_round, RoundFuncs ); }
876
+
877
+ /* method: self.not */
878
+ static VALUE na_not(VALUE self)
879
+ { return na_unary_func( self, na_cast_byte, NotFuncs ); }
880
+
881
+
882
+ /* method: self.and other */
883
+ static VALUE
884
+ na_cond_and(VALUE obj1, VALUE obj2)
885
+ { return na_compare_func( obj1, obj2, AndFuncs ); }
886
+
887
+ /* method: self.or other */
888
+ static VALUE
889
+ na_cond_or(VALUE obj1, VALUE obj2)
890
+ { return na_compare_func( obj1, obj2, Or_Funcs ); }
891
+
892
+ /* method: self.xor other */
893
+ static VALUE
894
+ na_cond_xor(VALUE obj1, VALUE obj2)
895
+ { return na_compare_func( obj1, obj2, XorFuncs ); }
896
+
897
+
898
+
899
+ /* method: self <=> other */
900
+ static VALUE
901
+ na_compare(VALUE obj1, VALUE obj2)
902
+ { return na_compare_func( obj1, obj2, CmpFuncs ); }
903
+
904
+
905
+
906
+ /* method: self.eq(other) */
907
+ static VALUE
908
+ na_equal(VALUE obj1, VALUE obj2)
909
+ {
910
+ return na_compare_func( obj1, obj2, EqlFuncs );
911
+ }
912
+
913
+ /* method: self.ne(other) */
914
+ static VALUE
915
+ na_not_equal(VALUE obj1, VALUE obj2)
916
+ {
917
+ VALUE obj;
918
+ na_shape_t i; char *p;
919
+ struct NARRAY *a;
920
+
921
+ obj = na_compare_func( obj1, obj2, EqlFuncs );
922
+ GetNArray(obj,a);
923
+ p = a->ptr;
924
+ for( i=a->total; i-->0; ) {
925
+ *p = *p==0 ? 1 : 0;
926
+ ++p;
927
+ }
928
+ return obj;
929
+ }
930
+
931
+ /* method: self > other */
932
+ static VALUE
933
+ na_greater_than(VALUE self, VALUE obj2)
934
+ {
935
+ na_shape_t i; char *p;
936
+ struct NARRAY *a;
937
+
938
+ self = na_compare_func( self, obj2, CmpFuncs );
939
+ GetNArray(self,a);
940
+ p = a->ptr;
941
+ for( i=a->total; i-->0; ) {
942
+ if (*p!=1) *p=0;
943
+ ++p;
944
+ }
945
+ return self;
946
+ }
947
+
948
+ /* method: self >= other */
949
+ static VALUE
950
+ na_greater_equal(VALUE obj1, VALUE obj2)
951
+ {
952
+ VALUE obj;
953
+ na_shape_t i; char *p;
954
+ struct NARRAY *a;
955
+
956
+ obj = na_compare_func( obj1, obj2, CmpFuncs );
957
+ GetNArray(obj,a);
958
+ p = a->ptr;
959
+ for( i=a->total; i-->0; ) {
960
+ if (*p==1 || *p==0) *p=1;
961
+ else *p=0;
962
+ ++p;
963
+ }
964
+ return obj;
965
+ }
966
+
967
+ /* method: self < other */
968
+ static VALUE
969
+ na_less_than(VALUE obj1, VALUE obj2)
970
+ {
971
+ VALUE obj;
972
+ na_shape_t i; char *p;
973
+ struct NARRAY *a;
974
+
975
+ obj = na_compare_func( obj1, obj2, CmpFuncs );
976
+ GetNArray(obj,a);
977
+ p = a->ptr;
978
+ for( i=a->total; i-->0; ) {
979
+ if (*p==2) *p=1;
980
+ else *p=0;
981
+ ++p;
982
+ }
983
+ return obj;
984
+ }
985
+
986
+ /* method: self <= other */
987
+ static VALUE
988
+ na_less_equal(VALUE obj1, VALUE obj2)
989
+ {
990
+ VALUE obj;
991
+ na_shape_t i; char *p;
992
+ struct NARRAY *a;
993
+
994
+ obj = na_compare_func( obj1, obj2, CmpFuncs );
995
+ GetNArray(obj,a);
996
+ p = a->ptr;
997
+ for( i=a->total; i-->0; ) {
998
+ if (*p==2 || *p==0) *p=1;
999
+ else *p=0;
1000
+ ++p;
1001
+ }
1002
+ return obj;
1003
+ }
1004
+
1005
+
1006
+
1007
+
1008
+ /*
1009
+ ------- Sum, Min, Max, Transpose --------
1010
+ */
1011
+ VALUE
1012
+ rb_range_beg_len(VALUE range, na_shape_t *begp, na_shape_t *lenp, na_shape_t len, int err );
1013
+
1014
+ static int
1015
+ na_arg_to_rank(int argc, VALUE *argv, int rankc, int *rankv, int flag)
1016
+ /* e.g.: argv=[1,3..5]
1017
+ if flag==0
1018
+ rankv = [0,1,0,1,1,1,0,..]
1019
+ else
1020
+ rankv = [1,3,4,5]
1021
+ */
1022
+ {
1023
+ int i, j, c=0;
1024
+ na_shape_t r, n;
1025
+ VALUE v;
1026
+
1027
+ if (flag==0)
1028
+ MEMZERO(rankv,int,rankc);
1029
+
1030
+ for (i=0;i<argc;++i) {
1031
+ if ( c >= rankc )
1032
+ rb_raise(rb_eArgError, "too many ranks");
1033
+
1034
+ v = argv[i];
1035
+
1036
+ if (TYPE(v)==T_FIXNUM) {
1037
+ r = NUM2SHAPE(v);
1038
+ if (r<0) r += rankc; /* negative for from end */
1039
+ if (r<0 || r>=rankc)
1040
+ rb_raise(rb_eArgError, "rank %ld out of range", r);
1041
+ if (flag)
1042
+ rankv[c] = r;
1043
+ else
1044
+ rankv[r] = 1;
1045
+ ++c;
1046
+ }
1047
+ else
1048
+ if (CLASS_OF(v)==rb_cRange) {
1049
+ rb_range_beg_len( v, &r, &n, rankc, 1 );
1050
+ if ( c+n > rankc )
1051
+ rb_raise(rb_eArgError, "too many ranks");
1052
+ if (flag) {
1053
+ for(j=0; j<n; ++j)
1054
+ rankv[c++] = r++;
1055
+ } else {
1056
+ for(j=0; j<n; ++j) {
1057
+ rankv[r++] = 1;
1058
+ ++c;
1059
+ }
1060
+ }
1061
+ }
1062
+ else
1063
+ rb_raise(rb_eArgError, "wrong type");
1064
+ }
1065
+ return c;
1066
+ }
1067
+
1068
+
1069
+
1070
+ /* Transpose procedure */
1071
+ static struct NARRAY *
1072
+ na_transpose_bifunc(struct NARRAY *a1, struct NARRAY *a2, int *trans)
1073
+ {
1074
+ int i, ndim=a2->rank;
1075
+ struct slice *s1, *s2;
1076
+
1077
+ s1 = ALLOC_N(struct slice, (ndim+1)*2);
1078
+ s2 = &s1[ndim+1];
1079
+
1080
+ /* for Source array -- s1 is temporarily used */
1081
+ na_set_slice_1obj(a2->rank,s1,a2->shape);
1082
+ na_init_slice( s1, ndim, a2->shape, na_sizeof[a2->type] );
1083
+
1084
+ /* Transpose Slice */
1085
+ for (i=0; i<ndim; ++i)
1086
+ s2[i] = s1[trans[i]];
1087
+ s2[ndim] = s1[ndim];
1088
+
1089
+ /* for Destination */
1090
+ na_set_slice_1obj(a1->rank,s1,a1->shape);
1091
+ na_init_slice( s1, ndim, a1->shape, na_sizeof[a1->type] );
1092
+
1093
+ /* Loop */
1094
+ na_do_loop_unary( ndim, a1->ptr, a2->ptr, s1, s2,
1095
+ SetFuncs[a1->type][a2->type] );
1096
+ xfree(s1);
1097
+ return a1;
1098
+ }
1099
+
1100
+
1101
+ /* method: self.transpose( ... ) */
1102
+ static VALUE
1103
+ na_transpose(int argc, VALUE *argv, VALUE self)
1104
+ {
1105
+ struct NARRAY *a2;
1106
+ int i, rankc, *rankv;
1107
+ na_shape_t *shape;
1108
+ VALUE obj;
1109
+
1110
+ GetNArray(self,a2);
1111
+
1112
+ /* Parse Argument */
1113
+ rankv = ALLOC_N( int, NA_MAX_RANK);
1114
+ shape = ALLOC_N( na_shape_t, NA_MAX_RANK);
1115
+ rankc = na_arg_to_rank( argc, argv, a2->rank, rankv, 1 );
1116
+ if (rankc > a2->rank)
1117
+ rb_raise(rb_eArgError, "too many args");
1118
+ for ( ;rankc<a2->rank; ++rankc)
1119
+ rankv[rankc] = rankc;
1120
+
1121
+ /* Argument Check */
1122
+ MEMZERO(shape,na_shape_t,rankc);
1123
+ for (i=0; i<rankc; ++i) {
1124
+ if (shape[rankv[i]] != 0)
1125
+ rb_raise(rb_eArgError,"rank doublebooking");
1126
+ shape[rankv[i]] = 1;
1127
+ }
1128
+
1129
+ for (i=0; i<a2->rank; ++i)
1130
+ shape[i] = a2->shape[rankv[i]];
1131
+
1132
+ obj = na_make_object(a2->type, a2->rank, shape, CLASS_OF(self));
1133
+
1134
+ na_transpose_bifunc( NA_STRUCT(obj), a2, rankv );
1135
+ xfree(rankv);
1136
+ xfree(shape);
1137
+ return obj;
1138
+ }
1139
+
1140
+
1141
+
1142
+
1143
+ static void
1144
+ na_accum_set_shape(na_shape_t *itr_shape, int rank, na_shape_t *ary_shape,
1145
+ int rankc, int *rankv)
1146
+ {
1147
+ int i;
1148
+
1149
+ if (rankc==0) {
1150
+ /* Accumulate all elements */
1151
+ for (i=0; i<rank; ++i) {
1152
+ itr_shape[i] = 1;
1153
+ rankv[i] = 1;
1154
+ }
1155
+ } else {
1156
+ /* Select Accumulate ranks */
1157
+ for (i=0; i<rank; ++i) {
1158
+ if (rankv[i]==1)
1159
+ itr_shape[i] = 1;
1160
+ else
1161
+ itr_shape[i] = ary_shape[i];
1162
+ }
1163
+ }
1164
+ }
1165
+
1166
+
1167
+ static void
1168
+ na_zero_obj(struct NARRAY *ary)
1169
+ {
1170
+ na_shape_t i;
1171
+ VALUE zero = INT2FIX(0);
1172
+ VALUE *v = (VALUE*)ary->ptr;
1173
+
1174
+ for (i=ary->total; i>0; --i)
1175
+ *(v++) = zero;
1176
+ }
1177
+
1178
+ static void
1179
+ na_zero_data(struct NARRAY *ary)
1180
+ {
1181
+ if (ary->type==NA_ROBJ)
1182
+ na_zero_obj(ary);
1183
+ else
1184
+ na_clear_data(ary);
1185
+ }
1186
+
1187
+ static VALUE
1188
+ na_sum_body(int argc, VALUE *argv, VALUE self, int flag)
1189
+ {
1190
+ na_shape_t *shape;
1191
+ int rankc, *rankv, cl_dim;
1192
+ struct NARRAY *a1, *a2;
1193
+ VALUE obj, klass;
1194
+
1195
+ GetNArray(self,a1);
1196
+
1197
+ rankv = ALLOC_N(int,a1->rank);
1198
+ rankc = na_arg_to_rank( argc, argv, a1->rank, rankv, 0 );
1199
+
1200
+ shape = ALLOC_N(na_shape_t,a1->rank);
1201
+ na_accum_set_shape( shape, a1->rank, a1->shape, rankc, rankv );
1202
+
1203
+ klass = CLASS_OF(self);
1204
+ cl_dim = na_class_dim(klass);
1205
+ if (flag==0 && cl_dim>0 && na_shrink_class(cl_dim,rankv))
1206
+ klass = cNArray;
1207
+
1208
+ obj = na_make_object(a1->type,a1->rank,shape,klass);
1209
+ GetNArray(obj,a2);
1210
+
1211
+ na_zero_data(a2);
1212
+ na_exec_unary( a2, a1, AddUFuncs[a1->type] );
1213
+
1214
+ if (flag==0)
1215
+ obj = na_shrink_rank(obj,cl_dim,rankv);
1216
+
1217
+ xfree(rankv);
1218
+ xfree(shape);
1219
+ return obj;
1220
+ }
1221
+
1222
+ /* method: sum( rank, ... ) */
1223
+ static VALUE
1224
+ na_sum(int argc, VALUE *argv, VALUE self)
1225
+ { return na_sum_body(argc,argv,self,0); }
1226
+
1227
+ /* method: accum( rank, ... ) */
1228
+ static VALUE
1229
+ na_accum(int argc, VALUE *argv, VALUE self)
1230
+ { return na_sum_body(argc,argv,self,1); }
1231
+
1232
+
1233
+
1234
+ static VALUE
1235
+ na_prod_body(int argc, VALUE *argv, VALUE self, int flag)
1236
+ {
1237
+ na_shape_t *shape;
1238
+ int rankc, *rankv, cl_dim;
1239
+ struct NARRAY *a1, *a2;
1240
+ VALUE obj, klass;
1241
+ int32_t one = 1;
1242
+
1243
+ GetNArray(self,a1);
1244
+
1245
+ rankv = ALLOC_N(int,a1->rank);
1246
+ rankc = na_arg_to_rank( argc, argv, a1->rank, rankv, 0 );
1247
+
1248
+ shape = ALLOC_N(na_shape_t,a1->rank);
1249
+ na_accum_set_shape( shape, a1->rank, a1->shape, rankc, rankv );
1250
+
1251
+ klass = CLASS_OF(self);
1252
+ cl_dim = na_class_dim(klass);
1253
+ if (flag==0 && cl_dim>0 && na_shrink_class(cl_dim,rankv))
1254
+ klass = cNArray;
1255
+
1256
+ obj = na_make_object(a1->type,a1->rank,shape,klass);
1257
+ GetNArray(obj,a2);
1258
+
1259
+ SetFuncs[a2->type][NA_SIZE](a2->total, a2->ptr, na_sizeof[a2->type], &one, 0);
1260
+
1261
+ na_exec_unary( a2, a1, MulUFuncs[a1->type] );
1262
+
1263
+ if (flag==0)
1264
+ obj = na_shrink_rank(obj,cl_dim,rankv);
1265
+
1266
+ xfree(rankv);
1267
+ xfree(shape);
1268
+ return obj;
1269
+ }
1270
+
1271
+ /* method: prod( rank, ... ) */
1272
+ static VALUE
1273
+ na_prod(int argc, VALUE *argv, VALUE self)
1274
+ { return na_prod_body(argc,argv,self,0); }
1275
+
1276
+
1277
+ static VALUE
1278
+ na_mul_add_body(int argc, VALUE *argv, volatile VALUE self, volatile VALUE other,
1279
+ VALUE wrap_klass, int flag)
1280
+ {
1281
+ VALUE ans, op_klass;
1282
+ int rank, cl_dim;
1283
+ na_shape_t *dst_shape, *max_shape;
1284
+ int rankc, *rankv;
1285
+ int type;
1286
+ struct NARRAY *a1, *a2;
1287
+
1288
+ GetNArray(self,a1);
1289
+ other = na_upcast_object(other,a1->type);
1290
+ GetNArray(other,a2);
1291
+ self = na_upcast_type(self,type=a2->type);
1292
+ GetNArray(self,a1);
1293
+
1294
+ rank = NA_MAX(a1->rank,a2->rank);
1295
+
1296
+ rankv = ALLOC_N(int,rank);
1297
+ rankc = na_arg_to_rank( argc, argv, rank, rankv, 0 );
1298
+
1299
+ max_shape = ALLOC_N(na_shape_t,rank*2);
1300
+ na_shape_max_2obj(rank,max_shape,a1,a2);
1301
+
1302
+ dst_shape = &max_shape[rank];
1303
+ na_accum_set_shape( dst_shape, rank, max_shape, rankc, rankv );
1304
+
1305
+ op_klass = na_bifunc_class(CLASS_OF(self),CLASS_OF(other));
1306
+ if (op_klass==Qnil) /* coerce_rev --- unsupported */
1307
+ op_klass = cNArray;
1308
+
1309
+ cl_dim = na_class_dim(op_klass);
1310
+ if (flag==0 && cl_dim>0 && na_shrink_class(cl_dim,rankv))
1311
+ op_klass = cNArray;
1312
+
1313
+ ans = na_make_object( type, rank, dst_shape,
1314
+ (wrap_klass==Qnil) ? op_klass : wrap_klass);
1315
+
1316
+ na_zero_data( NA_STRUCT(ans) );
1317
+ na_exec_binary( NA_STRUCT(ans), a1, a2, MulAddFuncs[type] );
1318
+
1319
+ if (flag==0)
1320
+ ans = na_shrink_rank(ans,cl_dim,rankv);
1321
+
1322
+ xfree(rankv);
1323
+ xfree(max_shape);
1324
+ return ans;
1325
+ }
1326
+
1327
+
1328
+
1329
+ /* method: mul_add( other, rank, ... ) */
1330
+ static VALUE
1331
+ na_mul_add(int argc, VALUE *argv, VALUE self)
1332
+ {
1333
+ if (argc<2)
1334
+ rb_raise(rb_eArgError, "wrong # of arguments (%d for >=2)", argc);
1335
+ return na_mul_add_body(argc-1,argv+1,self,argv[0],Qnil,0);
1336
+ }
1337
+
1338
+ /* method: mul_accum( other, rank, ... ) */
1339
+ static VALUE
1340
+ na_mul_accum(int argc, VALUE *argv, VALUE self)
1341
+ {
1342
+ if (argc<2)
1343
+ rb_raise(rb_eArgError, "wrong # of arguments (%d for >=2)", argc);
1344
+ return na_mul_add_body(argc-1,argv+1,self,argv[0],Qnil,1);
1345
+ }
1346
+
1347
+ /* singleton method: NArray.mul_add( obj1, obj2, rank, ... ) */
1348
+ static VALUE
1349
+ na_s_mul_add(int argc, VALUE *argv, VALUE klass)
1350
+ {
1351
+ if (argc<3)
1352
+ rb_raise(rb_eArgError, "wrong # of arguments (%d for >=3)", argc);
1353
+ return na_mul_add_body(argc-2,argv+2,argv[0],argv[1],klass,0);
1354
+ }
1355
+
1356
+
1357
+ /* cumsum!
1358
+ [1 2 3 4 5] -> [1 3 6 10 15]
1359
+ */
1360
+ static VALUE
1361
+ na_cumsum_bang(VALUE self)
1362
+ {
1363
+ struct NARRAY *a;
1364
+ int step;
1365
+
1366
+ GetNArray(self,a);
1367
+
1368
+ if ( a->rank != 1 )
1369
+ rb_raise( rb_eTypeError, "only for 1-dimensional array" );
1370
+ if ( a->total < 2 )
1371
+ return self; /* do nothing */
1372
+
1373
+ step = na_sizeof[a->type];
1374
+ AddUFuncs[a->type](a->total-1, a->ptr+step,step, a->ptr,step);
1375
+
1376
+ return self;
1377
+ }
1378
+
1379
+ /* cumsum */
1380
+ static VALUE
1381
+ na_cumsum(VALUE self)
1382
+ {
1383
+ return na_cumsum_bang(na_clone(self));
1384
+ }
1385
+
1386
+
1387
+ /* cumprod!
1388
+ [1 2 3 4 5] -> [1 3 6 10 15]
1389
+ */
1390
+ static VALUE
1391
+ na_cumprod_bang(VALUE self)
1392
+ {
1393
+ struct NARRAY *a;
1394
+ int step;
1395
+
1396
+ GetNArray(self,a);
1397
+
1398
+ if ( a->rank != 1 )
1399
+ rb_raise( rb_eTypeError, "only for 1-dimensional array" );
1400
+ if ( a->total < 2 )
1401
+ return self; /* do nothing */
1402
+
1403
+ step = na_sizeof[a->type];
1404
+ MulUFuncs[a->type](a->total-1, a->ptr+step,step, a->ptr,step);
1405
+
1406
+ return self;
1407
+ }
1408
+
1409
+ /* cumprod */
1410
+ static VALUE
1411
+ na_cumprod(VALUE self)
1412
+ {
1413
+ return na_cumprod_bang(na_clone(self));
1414
+ }
1415
+
1416
+
1417
+ /* Copy element of idx=0 from a2 to a1, as start of accumulation */
1418
+ /* a1->rank <= a2->rank is assumed */
1419
+ static void
1420
+ na_minmax_copy0(struct NARRAY *a1, struct NARRAY *a2)
1421
+ {
1422
+ int i, ndim=a2->rank; /* a2 has larger rank */
1423
+ struct slice *s1, *s2;
1424
+
1425
+ /* Allocate Structure */
1426
+ s1 = ALLOC_N(struct slice, (ndim+1)*2);
1427
+ s2 = &s1[ndim+1];
1428
+
1429
+ na_set_slice_1obj(a1->rank,s1,a1->shape);
1430
+ for (i=0; i<ndim; ++i) {
1431
+ s2[i].n = a1->shape[i]; /* no-repeat if a1->shape[i]==1 */
1432
+ s2[i].beg = 0; /* copy idx=0 */
1433
+ s2[i].step = 1;
1434
+ s2[i].idx = NULL;
1435
+ }
1436
+
1437
+ /* Initialize */
1438
+ na_init_slice(s1, ndim, a1->shape, na_sizeof[a1->type] );
1439
+ na_init_slice(s2, ndim, a2->shape, na_sizeof[a2->type] );
1440
+ /* Loop */
1441
+ na_do_loop_unary( ndim, a1->ptr, a2->ptr, s1, s2,
1442
+ SetFuncs[a1->type][a2->type] );
1443
+ xfree(s1);
1444
+ }
1445
+
1446
+
1447
+ static VALUE
1448
+ na_minmax_func(int argc, VALUE *argv, VALUE self, na_ufunc_t funcs)
1449
+ {
1450
+ VALUE obj, klass;
1451
+ na_shape_t *shape;
1452
+ int rankc, *rankv, cl_dim;
1453
+ struct NARRAY *a1, *a2;
1454
+
1455
+ GetNArray(self,a1);
1456
+
1457
+ rankv = ALLOC_N(int,a1->rank);
1458
+ rankc = na_arg_to_rank( argc, argv, a1->rank, rankv, 0 );
1459
+
1460
+ shape = ALLOC_N(na_shape_t,a1->rank);
1461
+ na_accum_set_shape( shape, a1->rank, a1->shape, rankc, rankv );
1462
+
1463
+ klass = CLASS_OF(self);
1464
+ cl_dim = na_class_dim(klass);
1465
+ if (na_shrink_class(cl_dim,rankv)) klass = cNArray;
1466
+
1467
+ obj = na_make_object(a1->type,a1->rank,shape,klass);
1468
+ GetNArray(obj,a2);
1469
+
1470
+ na_minmax_copy0( a2, a1 );
1471
+ na_exec_unary( a2, a1, funcs[a1->type] );
1472
+
1473
+ obj = na_shrink_rank(obj, cl_dim, rankv);
1474
+
1475
+ xfree(rankv);
1476
+ xfree(shape);
1477
+ return obj;
1478
+ }
1479
+
1480
+
1481
+ /* method: min( rank, ... ) */
1482
+ static VALUE
1483
+ na_min(int argc, VALUE *argv, VALUE self)
1484
+ { return na_minmax_func(argc,argv,self,MinFuncs); }
1485
+
1486
+ /* method: max( rank, ... ) */
1487
+ static VALUE
1488
+ na_max(int argc, VALUE *argv, VALUE self)
1489
+ { return na_minmax_func(argc,argv,self,MaxFuncs); }
1490
+
1491
+
1492
+
1493
+ static int
1494
+ na_sort_number(int argc, VALUE *argv, struct NARRAY *a1)
1495
+ {
1496
+ int i, rank;
1497
+ na_shape_t nsort;
1498
+
1499
+ if (argc==0) {
1500
+ rank = a1->rank-1;
1501
+ } else {
1502
+ rank = NUM2INT(argv[0]);
1503
+ if (rank >= a1->rank || rank < -a1->rank)
1504
+ rb_raise(rb_eArgError,"illeagal rank:%i out of %i",rank,a1->rank);
1505
+ if (rank < 0) rank += a1->rank;
1506
+ }
1507
+
1508
+ nsort = 1;
1509
+ for (i=0; i<=rank; ++i)
1510
+ nsort *= a1->shape[i];
1511
+ return nsort;
1512
+ }
1513
+
1514
+
1515
+ /* method: sort([rank]) */
1516
+ static VALUE
1517
+ na_sort(int argc, VALUE *argv, VALUE self)
1518
+ {
1519
+ struct NARRAY *a1, *a2;
1520
+ VALUE obj;
1521
+ int (*func)(const void*, const void*);
1522
+ na_shape_t i, size, step, nloop, nsort;
1523
+ char *ptr;
1524
+
1525
+ GetNArray(self,a1);
1526
+
1527
+ nsort = na_sort_number(argc,argv,a1);
1528
+ nloop = a1->total/nsort;
1529
+
1530
+ obj = na_make_object(a1->type,a1->rank,a1->shape,CLASS_OF(self));
1531
+ GetNArray(obj,a2);
1532
+ memcpy(a2->ptr, a1->ptr, a1->total*na_sizeof[a1->type]);
1533
+ func = SortFuncs[a2->type];
1534
+ size = na_sizeof[a2->type];
1535
+ ptr = a2->ptr;
1536
+ step = size * nsort;
1537
+
1538
+ for (i=0; i<nloop; ++i) {
1539
+ qsort( ptr, nsort, size, func );
1540
+ ptr += step;
1541
+ }
1542
+ return obj;
1543
+ }
1544
+
1545
+
1546
+ /* method: sort!([rank]) */
1547
+ static VALUE
1548
+ na_sort_bang(int argc, VALUE *argv, VALUE self)
1549
+ {
1550
+ struct NARRAY *a1;
1551
+ int (*func)(const void*, const void*);
1552
+ na_shape_t i, size, step, nloop, nsort;
1553
+ char *ptr;
1554
+
1555
+ GetNArray(self,a1);
1556
+
1557
+ nsort = na_sort_number(argc,argv,a1);
1558
+ nloop = a1->total/nsort;
1559
+
1560
+ func = SortFuncs[a1->type];
1561
+ size = na_sizeof[a1->type];
1562
+ ptr = a1->ptr;
1563
+ step = size * nsort;
1564
+
1565
+ for (i=0; i<nloop; ++i) {
1566
+ qsort( ptr, nsort, size, func );
1567
+ ptr += step;
1568
+ }
1569
+ return self;
1570
+ }
1571
+
1572
+
1573
+ /* method: sort_index([rank]) */
1574
+ static VALUE
1575
+ na_sort_index(int argc, VALUE *argv, VALUE self)
1576
+ {
1577
+ struct NARRAY *a1, *a2;
1578
+ VALUE obj;
1579
+ int (*func)(const void*, const void*);
1580
+ na_shape_t i, size, nloop, nsort;
1581
+ char **ptr_ptr, **ptr_p;
1582
+ char *ptr_ary, *ptr_a;
1583
+
1584
+ GetNArray(self,a1);
1585
+
1586
+ nsort = na_sort_number(argc,argv,a1);
1587
+ nloop = a1->total/nsort;
1588
+
1589
+ size = na_sizeof[a1->type];
1590
+ ptr_p = ptr_ptr = ALLOC_N(char*, a1->total);
1591
+ ptr_a = ptr_ary = a1->ptr;
1592
+
1593
+ for (i=a1->total; i>0; --i) {
1594
+ *(ptr_p++) = ptr_a;
1595
+ ptr_a += size;
1596
+ }
1597
+
1598
+ func = SortIdxFuncs[a1->type];
1599
+ ptr_p = ptr_ptr;
1600
+
1601
+ for (i=0; i<nloop; ++i) {
1602
+ qsort( ptr_p, nsort, sizeof(char*), func );
1603
+ ptr_p += nsort;
1604
+ }
1605
+
1606
+ obj = na_make_object(NA_SIZE,a1->rank,a1->shape,CLASS_OF(self));
1607
+ GetNArray(obj,a2);
1608
+ ptr_p = ptr_ptr;
1609
+ if ( NA_SIZE == NA_LINT ) {
1610
+ int32_t *ptr_i;
1611
+ ptr_i = (int32_t*)(a2->ptr);
1612
+ for (i=a2->total; i>0; --i) {
1613
+ *(ptr_i++) = (int32_t)(*(ptr_p++)-ptr_ary)/size;
1614
+ }
1615
+ } else if ( NA_SIZE == NA_LLINT ) {
1616
+ int64_t *ptr_i;
1617
+ ptr_i = (int64_t*)(a2->ptr);
1618
+ for (i=a2->total; i>0; --i) {
1619
+ *(ptr_i++) = (int64_t)(*(ptr_p++)-ptr_ary)/size;
1620
+ }
1621
+ }
1622
+ xfree(ptr_ptr);
1623
+ return obj;
1624
+ }
1625
+
1626
+
1627
+
1628
+ void Init_na_funcs(void)
1629
+ {
1630
+ rb_define_method(cNArray, "+", na_add, 1);
1631
+ rb_define_method(cNArray, "-", na_sbt, 1);
1632
+ rb_define_method(cNArray, "*", na_mul, 1);
1633
+ rb_define_method(cNArray, "/", na_div, 1);
1634
+ rb_define_method(cNArray, "%", na_mod, 1);
1635
+ rb_define_alias (cNArray, "mod", "%");
1636
+ rb_define_method(cNArray, "&", na_bit_and, 1);
1637
+ rb_define_method(cNArray, "|", na_bit_or, 1);
1638
+ rb_define_method(cNArray, "^", na_bit_xor, 1);
1639
+ rb_define_method(cNArray, "**", na_power, 1);
1640
+
1641
+ rb_define_method(cNArray, "add!", na_add_bang, 1);
1642
+ rb_define_method(cNArray, "sbt!", na_sbt_bang, 1);
1643
+ rb_define_method(cNArray, "mul!", na_mul_bang, 1);
1644
+ rb_define_method(cNArray, "div!", na_div_bang, 1);
1645
+ rb_define_method(cNArray, "mod!", na_mod_bang, 1);
1646
+ rb_define_method(cNArray, "imag=",na_imag_set, 1);
1647
+
1648
+ rb_define_method(cNArray, "swap_byte", na_swap_byte, 0);
1649
+ rb_define_method(cNArray, "hton", na_hton, 0);
1650
+ rb_define_alias (cNArray, "ntoh", "hton");
1651
+ rb_define_method(cNArray, "htov", na_htov, 0);
1652
+ rb_define_alias (cNArray, "vtoh", "htov");
1653
+ rb_define_method(cNArray, "-@", na_neg, 0);
1654
+ rb_define_method(cNArray, "recip",na_recip, 0);
1655
+ rb_define_method(cNArray, "abs", na_abs, 0);
1656
+ rb_define_method(cNArray, "real", na_real, 0);
1657
+ rb_define_method(cNArray, "imag", na_imag, 0);
1658
+ rb_define_alias (cNArray, "image", "imag");
1659
+ rb_define_method(cNArray, "angle", na_angle, 0);
1660
+ rb_define_alias (cNArray, "arg", "angle");
1661
+ rb_define_method(cNArray, "conj", na_conj, 0);
1662
+ rb_define_alias (cNArray, "conjugate", "conj");
1663
+ rb_define_method(cNArray, "conj!", na_conj_bang, 0);
1664
+ rb_define_alias (cNArray, "conjugate!", "conj!");
1665
+ rb_define_method(cNArray, "im", na_imag_mul, 0);
1666
+ rb_define_method(cNArray, "floor",na_floor, 0);
1667
+ rb_define_method(cNArray, "ceil", na_ceil, 0);
1668
+ rb_define_method(cNArray, "round",na_round, 0);
1669
+ rb_define_method(cNArray, "~", na_bit_rev, 0);
1670
+ rb_define_method(cNArray, "not", na_not, 0);
1671
+
1672
+ rb_define_method(cNArray, "<=>", na_compare, 1);
1673
+ rb_define_method(cNArray, "eq", na_equal, 1);
1674
+ rb_define_method(cNArray, "ne", na_not_equal, 1);
1675
+ rb_define_method(cNArray, "gt", na_greater_than, 1);
1676
+ rb_define_alias (cNArray, ">", "gt");
1677
+ rb_define_method(cNArray, "ge", na_greater_equal, 1);
1678
+ rb_define_alias (cNArray, ">=", "ge");
1679
+ rb_define_method(cNArray, "lt", na_less_than, 1);
1680
+ rb_define_alias (cNArray, "<", "lt");
1681
+ rb_define_method(cNArray, "le", na_less_equal, 1);
1682
+ rb_define_alias (cNArray, "<=", "le");
1683
+ rb_define_method(cNArray, "and", na_cond_and, 1);
1684
+ rb_define_method(cNArray, "or", na_cond_or, 1);
1685
+ rb_define_method(cNArray, "xor", na_cond_xor, 1);
1686
+
1687
+ rb_define_method(cNArray, "mul_add", na_mul_add, -1);
1688
+ rb_define_method(cNArray, "mul_accum", na_mul_accum, -1);
1689
+
1690
+ rb_define_method(cNArray, "sum", na_sum, -1);
1691
+ rb_define_method(cNArray, "accum", na_accum, -1);
1692
+ rb_define_method(cNArray, "prod", na_prod, -1);
1693
+ rb_define_method(cNArray, "min", na_min, -1);
1694
+ rb_define_method(cNArray, "max", na_max, -1);
1695
+ rb_define_method(cNArray, "cumsum!", na_cumsum_bang, 0);
1696
+ rb_define_method(cNArray, "cumsum", na_cumsum, 0);
1697
+ rb_define_method(cNArray, "cumprod!", na_cumprod_bang, 0);
1698
+ rb_define_method(cNArray, "cumprod", na_cumprod, 0);
1699
+ rb_define_method(cNArray, "sort", na_sort, -1);
1700
+ rb_define_method(cNArray, "sort!", na_sort_bang, -1);
1701
+ rb_define_method(cNArray, "sort_index", na_sort_index, -1);
1702
+ rb_define_method(cNArray, "transpose", na_transpose, -1);
1703
+
1704
+ rb_define_singleton_method(cNArray,"mul",na_s_mul,2);
1705
+ rb_define_singleton_method(cNArray,"div",na_s_div,2);
1706
+ rb_define_singleton_method(cNArray,"mul_add",na_s_mul_add,-1);
1707
+
1708
+ rb_define_module_function(rb_mNMath,"atan2",na_math_atan2,2);
1709
+ }