numru-narray 1.0.0

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