numo-narray-alt 0.9.3

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.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +14 -0
  3. data/LICENSE +30 -0
  4. data/README.md +71 -0
  5. data/Rakefile +24 -0
  6. data/ext/numo/narray/SFMT-params.h +97 -0
  7. data/ext/numo/narray/SFMT-params19937.h +48 -0
  8. data/ext/numo/narray/SFMT.c +602 -0
  9. data/ext/numo/narray/SFMT.h +147 -0
  10. data/ext/numo/narray/array.c +575 -0
  11. data/ext/numo/narray/data.c +958 -0
  12. data/ext/numo/narray/extconf.rb +84 -0
  13. data/ext/numo/narray/index.c +1092 -0
  14. data/ext/numo/narray/kwargs.c +142 -0
  15. data/ext/numo/narray/math.c +133 -0
  16. data/ext/numo/narray/narray.c +1976 -0
  17. data/ext/numo/narray/narray.def +28 -0
  18. data/ext/numo/narray/ndloop.c +1840 -0
  19. data/ext/numo/narray/numo/compat.h +23 -0
  20. data/ext/numo/narray/numo/intern.h +115 -0
  21. data/ext/numo/narray/numo/narray.h +480 -0
  22. data/ext/numo/narray/numo/ndloop.h +93 -0
  23. data/ext/numo/narray/numo/template.h +149 -0
  24. data/ext/numo/narray/numo/types/bit.h +38 -0
  25. data/ext/numo/narray/numo/types/complex.h +404 -0
  26. data/ext/numo/narray/numo/types/complex_macro.h +384 -0
  27. data/ext/numo/narray/numo/types/dcomplex.h +42 -0
  28. data/ext/numo/narray/numo/types/dfloat.h +44 -0
  29. data/ext/numo/narray/numo/types/float_def.h +34 -0
  30. data/ext/numo/narray/numo/types/float_macro.h +202 -0
  31. data/ext/numo/narray/numo/types/int16.h +27 -0
  32. data/ext/numo/narray/numo/types/int32.h +23 -0
  33. data/ext/numo/narray/numo/types/int64.h +23 -0
  34. data/ext/numo/narray/numo/types/int8.h +23 -0
  35. data/ext/numo/narray/numo/types/int_macro.h +66 -0
  36. data/ext/numo/narray/numo/types/real_accum.h +481 -0
  37. data/ext/numo/narray/numo/types/robj_macro.h +78 -0
  38. data/ext/numo/narray/numo/types/robject.h +25 -0
  39. data/ext/numo/narray/numo/types/scomplex.h +42 -0
  40. data/ext/numo/narray/numo/types/sfloat.h +45 -0
  41. data/ext/numo/narray/numo/types/uint16.h +24 -0
  42. data/ext/numo/narray/numo/types/uint32.h +20 -0
  43. data/ext/numo/narray/numo/types/uint64.h +20 -0
  44. data/ext/numo/narray/numo/types/uint8.h +20 -0
  45. data/ext/numo/narray/numo/types/uint_macro.h +57 -0
  46. data/ext/numo/narray/numo/types/xint_macro.h +166 -0
  47. data/ext/numo/narray/rand.c +40 -0
  48. data/ext/numo/narray/src/t_bit.c +3236 -0
  49. data/ext/numo/narray/src/t_dcomplex.c +6776 -0
  50. data/ext/numo/narray/src/t_dfloat.c +9417 -0
  51. data/ext/numo/narray/src/t_int16.c +5757 -0
  52. data/ext/numo/narray/src/t_int32.c +5757 -0
  53. data/ext/numo/narray/src/t_int64.c +5759 -0
  54. data/ext/numo/narray/src/t_int8.c +5355 -0
  55. data/ext/numo/narray/src/t_robject.c +5567 -0
  56. data/ext/numo/narray/src/t_scomplex.c +6731 -0
  57. data/ext/numo/narray/src/t_sfloat.c +9374 -0
  58. data/ext/numo/narray/src/t_uint16.c +5753 -0
  59. data/ext/numo/narray/src/t_uint32.c +5753 -0
  60. data/ext/numo/narray/src/t_uint64.c +5755 -0
  61. data/ext/numo/narray/src/t_uint8.c +5351 -0
  62. data/ext/numo/narray/step.c +266 -0
  63. data/ext/numo/narray/struct.c +814 -0
  64. data/lib/numo/narray/extra.rb +1266 -0
  65. data/lib/numo/narray.rb +4 -0
  66. metadata +106 -0
@@ -0,0 +1,958 @@
1
+ /*
2
+ data.c
3
+ Ruby/Numo::NArray - Numerical Array class for Ruby
4
+ Copyright (C) 1999-2020 Masahiro TANAKA
5
+ */
6
+ #include <ruby.h>
7
+
8
+ #include "numo/narray.h"
9
+ #include "numo/template.h"
10
+
11
+ static ID id_mulsum;
12
+ static ID id_store;
13
+ static ID id_swap_byte;
14
+
15
+ // ---------------------------------------------------------------------
16
+
17
+ #define LOOP_UNARY_PTR(lp, proc) \
18
+ { \
19
+ size_t i; \
20
+ ssize_t s1, s2; \
21
+ char *p1, *p2; \
22
+ size_t *idx1, *idx2; \
23
+ INIT_COUNTER(lp, i); \
24
+ INIT_PTR_IDX(lp, 0, p1, s1, idx1); \
25
+ INIT_PTR_IDX(lp, 1, p2, s2, idx2); \
26
+ if (idx1) { \
27
+ if (idx2) { \
28
+ for (; i--;) { \
29
+ proc((p1 + *idx1), (p2 + *idx2)); \
30
+ idx1++; \
31
+ idx2++; \
32
+ } \
33
+ } else { \
34
+ for (; i--;) { \
35
+ proc((p1 + *idx1), p2); \
36
+ idx1++; \
37
+ p2 += s2; \
38
+ } \
39
+ } \
40
+ } else { \
41
+ if (idx2) { \
42
+ for (; i--;) { \
43
+ proc(p1, (p1 + *idx2)); \
44
+ p1 += s1; \
45
+ idx2++; \
46
+ } \
47
+ } else { \
48
+ for (; i--;) { \
49
+ proc(p1, p2); \
50
+ p1 += s1; \
51
+ p2 += s2; \
52
+ } \
53
+ } \
54
+ } \
55
+ }
56
+
57
+ #define m_memcpy(src, dst) memcpy(dst, src, e)
58
+ static void iter_copy_bytes(na_loop_t* const lp) {
59
+ size_t e;
60
+ e = lp->args[0].elmsz;
61
+ LOOP_UNARY_PTR(lp, m_memcpy);
62
+ }
63
+
64
+ VALUE
65
+ na_copy(VALUE self) {
66
+ VALUE v;
67
+ ndfunc_arg_in_t ain[1] = {{Qnil, 0}};
68
+ ndfunc_arg_out_t aout[1] = {{INT2FIX(0), 0}};
69
+ ndfunc_t ndf = {iter_copy_bytes, FULL_LOOP, 1, 1, ain, aout};
70
+
71
+ v = na_ndloop(&ndf, 1, self);
72
+ return v;
73
+ }
74
+
75
+ VALUE
76
+ na_store(VALUE self, VALUE src) {
77
+ return rb_funcall(self, id_store, 1, src);
78
+ }
79
+
80
+ // ---------------------------------------------------------------------
81
+
82
+ #define m_swap_byte(q1, q2) \
83
+ { \
84
+ size_t j; \
85
+ memcpy(b1, q1, e); \
86
+ for (j = 0; j < e; j++) { \
87
+ b2[e - 1 - j] = b1[j]; \
88
+ } \
89
+ memcpy(q2, b2, e); \
90
+ }
91
+
92
+ static void iter_swap_byte(na_loop_t* const lp) {
93
+ char *b1, *b2;
94
+ size_t e;
95
+
96
+ e = lp->args[0].elmsz;
97
+ b1 = ALLOCA_N(char, e);
98
+ b2 = ALLOCA_N(char, e);
99
+ LOOP_UNARY_PTR(lp, m_swap_byte);
100
+ }
101
+
102
+ static VALUE nary_swap_byte(VALUE self) {
103
+ VALUE v;
104
+ ndfunc_arg_in_t ain[1] = {{Qnil, 0}};
105
+ ndfunc_arg_out_t aout[1] = {{INT2FIX(0), 0}};
106
+ ndfunc_t ndf = {iter_swap_byte, FULL_LOOP | NDF_ACCEPT_BYTESWAP, 1, 1, ain, aout};
107
+
108
+ v = na_ndloop(&ndf, 1, self);
109
+ if (self != v) {
110
+ na_copy_flags(self, v);
111
+ }
112
+ REVERSE_ENDIAN(v);
113
+ return v;
114
+ }
115
+
116
+ static VALUE nary_to_network(VALUE self) {
117
+ if (TEST_BIG_ENDIAN(self)) {
118
+ return self;
119
+ }
120
+ return rb_funcall(self, id_swap_byte, 0);
121
+ }
122
+
123
+ static VALUE nary_to_vacs(VALUE self) {
124
+ if (TEST_LITTLE_ENDIAN(self)) {
125
+ return self;
126
+ }
127
+ return rb_funcall(self, id_swap_byte, 0);
128
+ }
129
+
130
+ static VALUE nary_to_host(VALUE self) {
131
+ if (TEST_HOST_ORDER(self)) {
132
+ return self;
133
+ }
134
+ return rb_funcall(self, id_swap_byte, 0);
135
+ }
136
+
137
+ static VALUE nary_to_swapped(VALUE self) {
138
+ if (TEST_BYTE_SWAPPED(self)) {
139
+ return self;
140
+ }
141
+ return rb_funcall(self, id_swap_byte, 0);
142
+ }
143
+
144
+ //----------------------------------------------------------------------
145
+
146
+ static inline int check_axis(int axis, int ndim) {
147
+ if (axis < -ndim || axis >= ndim) {
148
+ rb_raise(nary_eDimensionError, "invalid axis (%d for %d-dimension)", axis, ndim);
149
+ }
150
+ if (axis < 0) {
151
+ axis += ndim;
152
+ }
153
+ return axis;
154
+ }
155
+
156
+ /*
157
+ Interchange two axes.
158
+ @overload swapaxes(axis1,axis2)
159
+ @param [Integer] axis1
160
+ @param [Integer] axis2
161
+ @return [Numo::NArray] view of NArray.
162
+ @example
163
+ x = Numo::Int32[[1,2,3]]
164
+
165
+ x.swapaxes(0,1)
166
+ # => Numo::Int32(view)#shape=[3,1]
167
+ # [[1],
168
+ # [2],
169
+ # [3]]
170
+
171
+ x = Numo::Int32[[[0,1],[2,3]],[[4,5],[6,7]]]
172
+ # => Numo::Int32#shape=[2,2,2]
173
+ # [[[0, 1],
174
+ # [2, 3]],
175
+ # [[4, 5],
176
+ # [6, 7]]]
177
+
178
+ x.swapaxes(0,2)
179
+ # => Numo::Int32(view)#shape=[2,2,2]
180
+ # [[[0, 4],
181
+ # [2, 6]],
182
+ # [[1, 5],
183
+ # [3, 7]]]
184
+ */
185
+ static VALUE na_swapaxes(VALUE self, VALUE a1, VALUE a2) {
186
+ int i, j, ndim;
187
+ size_t tmp_shape;
188
+ stridx_t tmp_stridx;
189
+ narray_view_t* na;
190
+ volatile VALUE view;
191
+
192
+ view = na_make_view(self);
193
+ GetNArrayView(view, na);
194
+
195
+ ndim = na->base.ndim;
196
+ i = check_axis(NUM2INT(a1), ndim);
197
+ j = check_axis(NUM2INT(a2), ndim);
198
+
199
+ tmp_shape = na->base.shape[i];
200
+ tmp_stridx = na->stridx[i];
201
+ na->base.shape[i] = na->base.shape[j];
202
+ na->stridx[i] = na->stridx[j];
203
+ na->base.shape[j] = tmp_shape;
204
+ na->stridx[j] = tmp_stridx;
205
+
206
+ return view;
207
+ }
208
+
209
+ static VALUE na_transpose_map(VALUE self, int* map) {
210
+ int i, ndim;
211
+ size_t* shape;
212
+ stridx_t* stridx;
213
+ narray_view_t* na;
214
+ volatile VALUE view;
215
+
216
+ view = na_make_view(self);
217
+ GetNArrayView(view, na);
218
+
219
+ ndim = na->base.ndim;
220
+ shape = ALLOCA_N(size_t, ndim);
221
+ stridx = ALLOCA_N(stridx_t, ndim);
222
+
223
+ for (i = 0; i < ndim; i++) {
224
+ shape[i] = na->base.shape[i];
225
+ stridx[i] = na->stridx[i];
226
+ }
227
+ for (i = 0; i < ndim; i++) {
228
+ na->base.shape[i] = shape[map[i]];
229
+ na->stridx[i] = stridx[map[i]];
230
+ }
231
+ return view;
232
+ }
233
+
234
+ #define SWAP(a, b, tmp) \
235
+ { \
236
+ tmp = a; \
237
+ a = b; \
238
+ b = tmp; \
239
+ }
240
+
241
+ static VALUE na_transpose(int argc, VALUE* argv, VALUE self) {
242
+ int ndim, *map, *permute;
243
+ int i, d;
244
+ bool is_positive, is_negative;
245
+ narray_t* na1;
246
+
247
+ GetNArray(self, na1);
248
+ ndim = na1->ndim;
249
+ if (ndim < 2) {
250
+ if (argc > 0) {
251
+ rb_raise(rb_eArgError, "unnecessary argument for 1-d array");
252
+ }
253
+ return na_make_view(self);
254
+ }
255
+ map = ALLOCA_N(int, ndim);
256
+ if (argc == 0) {
257
+ for (i = 0; i < ndim; i++) {
258
+ map[i] = ndim - 1 - i;
259
+ }
260
+ return na_transpose_map(self, map);
261
+ }
262
+ // with argument
263
+ if (argc > ndim) {
264
+ rb_raise(rb_eArgError, "more arguments than ndim");
265
+ }
266
+ for (i = 0; i < ndim; i++) {
267
+ map[i] = i;
268
+ }
269
+ permute = ALLOCA_N(int, argc);
270
+ for (i = 0; i < argc; i++) {
271
+ permute[i] = 0;
272
+ }
273
+ is_positive = is_negative = 0;
274
+ for (i = 0; i < argc; i++) {
275
+ if (TYPE(argv[i]) != T_FIXNUM) {
276
+ rb_raise(rb_eArgError, "invalid argument");
277
+ }
278
+ d = FIX2INT(argv[i]);
279
+ if (d >= 0) {
280
+ if (d >= argc) {
281
+ rb_raise(rb_eArgError, "out of dimension range");
282
+ }
283
+ if (is_negative) {
284
+ rb_raise(rb_eArgError, "dimension must be non-negative only or negative only");
285
+ }
286
+ if (permute[d]) {
287
+ rb_raise(rb_eArgError, "not permutation");
288
+ }
289
+ map[i] = d;
290
+ permute[d] = 1;
291
+ is_positive = 1;
292
+ } else {
293
+ if (d < -argc) {
294
+ rb_raise(rb_eArgError, "out of dimension range");
295
+ }
296
+ if (is_positive) {
297
+ rb_raise(rb_eArgError, "dimension must be non-negative only or negative only");
298
+ }
299
+ if (permute[argc + d]) {
300
+ rb_raise(rb_eArgError, "not permutation");
301
+ }
302
+ map[ndim - argc + i] = ndim + d;
303
+ permute[argc + d] = 1;
304
+ is_negative = 1;
305
+ }
306
+ }
307
+ return na_transpose_map(self, map);
308
+ }
309
+
310
+ //----------------------------------------------------------------------
311
+
312
+ static void na_check_reshape(int argc, VALUE* argv, VALUE self, size_t* shape) {
313
+ int i, unfixed = -1;
314
+ size_t total = 1;
315
+ narray_t* na;
316
+
317
+ if (argc == 0) {
318
+ rb_raise(rb_eArgError, "No argrument");
319
+ }
320
+ GetNArray(self, na);
321
+ if (NA_SIZE(na) == 0) {
322
+ rb_raise(rb_eRuntimeError, "cannot reshape empty array");
323
+ }
324
+
325
+ /* get shape from argument */
326
+ for (i = 0; i < argc; ++i) {
327
+ switch (TYPE(argv[i])) {
328
+ case T_FIXNUM:
329
+ total *= shape[i] = NUM2INT(argv[i]);
330
+ break;
331
+ case T_NIL:
332
+ case T_TRUE:
333
+ if (unfixed >= 0) {
334
+ rb_raise(rb_eArgError, "multiple unfixed dimension");
335
+ }
336
+ unfixed = i;
337
+ break;
338
+ default:
339
+ rb_raise(rb_eArgError, "illegal type");
340
+ }
341
+ }
342
+
343
+ if (unfixed >= 0) {
344
+ if (NA_SIZE(na) % total != 0) {
345
+ rb_raise(rb_eArgError, "Total size size must be divisor");
346
+ }
347
+ shape[unfixed] = NA_SIZE(na) / total;
348
+ } else if (total != NA_SIZE(na)) {
349
+ rb_raise(rb_eArgError, "Total size must be same");
350
+ }
351
+ }
352
+
353
+ /*
354
+ Change the shape of self NArray without coping.
355
+ Raise exception if self is non-contiguous.
356
+
357
+ @overload reshape!(size0,size1,...)
358
+ @param sizeN [Integer] new shape
359
+ @return [Numo::NArray] return self.
360
+ @example
361
+ */
362
+ static VALUE na_reshape_bang(int argc, VALUE* argv, VALUE self) {
363
+ size_t* shape;
364
+ narray_t* na;
365
+ narray_view_t* na2;
366
+ ssize_t stride;
367
+ stridx_t* stridx;
368
+ int i;
369
+
370
+ if (na_check_contiguous(self) == Qfalse) {
371
+ rb_raise(rb_eStandardError, "cannot change shape of non-contiguous NArray");
372
+ }
373
+ shape = ALLOCA_N(size_t, argc);
374
+ na_check_reshape(argc, argv, self, shape);
375
+
376
+ GetNArray(self, na);
377
+ if (na->type == NARRAY_VIEW_T) {
378
+ GetNArrayView(self, na2);
379
+ if (na->ndim < argc) {
380
+ stridx = ALLOC_N(stridx_t, argc);
381
+ } else {
382
+ stridx = na2->stridx;
383
+ }
384
+ stride = SDX_GET_STRIDE(na2->stridx[na->ndim - 1]);
385
+ for (i = argc; i--;) {
386
+ SDX_SET_STRIDE(stridx[i], stride);
387
+ stride *= shape[i];
388
+ }
389
+ if (stridx != na2->stridx) {
390
+ xfree(na2->stridx);
391
+ na2->stridx = stridx;
392
+ }
393
+ }
394
+ na_setup_shape(na, argc, shape);
395
+ return self;
396
+ }
397
+
398
+ /*
399
+ Copy and change the shape of NArray.
400
+ Returns a copied NArray.
401
+
402
+ @overload reshape(size0,size1,...)
403
+ @param sizeN [Integer] new shape
404
+ @return [Numo::NArray] return self.
405
+ @example
406
+ */
407
+ static VALUE na_reshape(int argc, VALUE* argv, VALUE self) {
408
+ size_t* shape;
409
+ narray_t* na;
410
+ VALUE copy;
411
+
412
+ shape = ALLOCA_N(size_t, argc);
413
+ na_check_reshape(argc, argv, self, shape);
414
+
415
+ copy = rb_funcall(self, rb_intern("dup"), 0);
416
+ GetNArray(copy, na);
417
+ na_setup_shape(na, argc, shape);
418
+ return copy;
419
+ }
420
+
421
+ //----------------------------------------------------------------------
422
+
423
+ VALUE
424
+ na_flatten_dim(VALUE self, int sd) {
425
+ int i, nd, fd;
426
+ size_t j, ofs;
427
+ size_t *c, *pos, *idx1, *idx2;
428
+ size_t stride;
429
+ size_t *shape, size;
430
+ stridx_t sdx;
431
+ narray_t* na;
432
+ narray_view_t *na1, *na2;
433
+ volatile VALUE view;
434
+
435
+ GetNArray(self, na);
436
+ nd = na->ndim;
437
+
438
+ if (nd == 0) {
439
+ return na_make_view(self);
440
+ }
441
+ if (sd < 0 || sd >= nd) {
442
+ rb_bug("na_flaten_dim: start_dim (%d) out of range", sd);
443
+ }
444
+
445
+ // new shape
446
+ shape = ALLOCA_N(size_t, sd + 1);
447
+ for (i = 0; i < sd; i++) {
448
+ shape[i] = na->shape[i];
449
+ }
450
+ size = 1;
451
+ for (i = sd; i < nd; i++) {
452
+ size *= na->shape[i];
453
+ }
454
+ shape[sd] = size;
455
+
456
+ // new object
457
+ view = na_s_allocate_view(rb_obj_class(self));
458
+ na_copy_flags(self, view);
459
+ GetNArrayView(view, na2);
460
+
461
+ // new stride
462
+ na_setup_shape((narray_t*)na2, sd + 1, shape);
463
+ na2->stridx = ALLOC_N(stridx_t, sd + 1);
464
+
465
+ switch (na->type) {
466
+ case NARRAY_DATA_T:
467
+ case NARRAY_FILEMAP_T:
468
+ stride = nary_element_stride(self);
469
+ for (i = sd + 1; i--;) {
470
+ SDX_SET_STRIDE(na2->stridx[i], stride);
471
+ stride *= shape[i];
472
+ }
473
+ na2->offset = 0;
474
+ na2->data = self;
475
+ break;
476
+ case NARRAY_VIEW_T:
477
+ GetNArrayView(self, na1);
478
+ na2->data = na1->data;
479
+ na2->offset = na1->offset;
480
+ for (i = 0; i < sd; i++) {
481
+ if (SDX_IS_INDEX(na1->stridx[i])) {
482
+ idx1 = SDX_GET_INDEX(na1->stridx[i]);
483
+ idx2 = ALLOC_N(size_t, shape[i]);
484
+ for (j = 0; j < shape[i]; j++) {
485
+ idx2[j] = idx1[j];
486
+ }
487
+ SDX_SET_INDEX(na2->stridx[i], idx2);
488
+ } else {
489
+ na2->stridx[i] = na1->stridx[i];
490
+ }
491
+ }
492
+ // flat dimension == last dimension
493
+ if (RTEST(na_check_ladder(self, sd))) {
494
+ na2->stridx[sd] = na1->stridx[nd - 1];
495
+ } else {
496
+ // set index
497
+ idx2 = ALLOC_N(size_t, (shape[sd] == 0) ? 1 : shape[sd]);
498
+ SDX_SET_INDEX(na2->stridx[sd], idx2);
499
+ // init for md-loop
500
+ fd = nd - sd;
501
+ c = ALLOCA_N(size_t, fd);
502
+ for (i = 0; i < fd; i++) c[i] = 0;
503
+ pos = ALLOCA_N(size_t, fd + 1);
504
+ pos[0] = 0;
505
+ // md-loop
506
+ for (i = j = 0;;) {
507
+ for (; i < fd; i++) {
508
+ sdx = na1->stridx[i + sd];
509
+ if (SDX_IS_INDEX(sdx)) {
510
+ if (SDX_GET_INDEX(sdx)) {
511
+ ofs = SDX_GET_INDEX(sdx)[c[i]];
512
+ } else {
513
+ ofs = 0;
514
+ }
515
+ } else {
516
+ ofs = SDX_GET_STRIDE(sdx) * c[i];
517
+ }
518
+ pos[i + 1] = pos[i] + ofs;
519
+ }
520
+ idx2[j++] = pos[i];
521
+ for (;;) {
522
+ if (i == 0) goto loop_end;
523
+ i--;
524
+ c[i]++;
525
+ if (c[i] < na1->base.shape[i + sd]) break;
526
+ c[i] = 0;
527
+ }
528
+ }
529
+ loop_end:;
530
+ }
531
+ break;
532
+ }
533
+ return view;
534
+ }
535
+
536
+ VALUE
537
+ na_flatten(VALUE self) {
538
+ return na_flatten_dim(self, 0);
539
+ }
540
+
541
+ //----------------------------------------------------------------------
542
+
543
+ #define MIN(a, b) (((a) < (b)) ? (a) : (b))
544
+
545
+ /*
546
+ Returns a diagonal view of NArray
547
+ @overload diagonal([offset,axes])
548
+ @param [Integer] offset Diagonal offset from the main diagonal.
549
+ The default is 0. k>0 for diagonals above the main diagonal,
550
+ and k<0 for diagonals below the main diagonal.
551
+ @param [Array] axes Array of axes to be used as the 2-d sub-arrays
552
+ from which the diagonals should be taken. Defaults to last-two
553
+ axes ([-2,-1]).
554
+ @return [Numo::NArray] diagonal view of NArray.
555
+ @example
556
+ a = Numo::DFloat.new(4,5).seq
557
+ # => Numo::DFloat#shape=[4,5]
558
+ # [[0, 1, 2, 3, 4],
559
+ # [5, 6, 7, 8, 9],
560
+ # [10, 11, 12, 13, 14],
561
+ # [15, 16, 17, 18, 19]]
562
+ b = a.diagonal(1)
563
+ # => Numo::DFloat(view)#shape=[4]
564
+ # [1, 7, 13, 19]
565
+
566
+ b.store(0)
567
+ a
568
+ # => Numo::DFloat#shape=[4,5]
569
+ # [[0, 0, 2, 3, 4],
570
+ # [5, 6, 0, 8, 9],
571
+ # [10, 11, 12, 0, 14],
572
+ # [15, 16, 17, 18, 0]]
573
+
574
+ b.store([1,2,3,4])
575
+ a
576
+ # => Numo::DFloat#shape=[4,5]
577
+ # [[0, 1, 2, 3, 4],
578
+ # [5, 6, 2, 8, 9],
579
+ # [10, 11, 12, 3, 14],
580
+ # [15, 16, 17, 18, 4]]
581
+ */
582
+ static VALUE na_diagonal(int argc, VALUE* argv, VALUE self) {
583
+ int i, k, nd;
584
+ size_t j;
585
+ size_t *idx0, *idx1, *diag_idx;
586
+ size_t* shape;
587
+ size_t diag_size;
588
+ ssize_t stride, stride0, stride1;
589
+ narray_t* na;
590
+ narray_view_t *na1, *na2;
591
+ VALUE view;
592
+ VALUE vofs = 0, vaxes = 0;
593
+ ssize_t kofs;
594
+ size_t k0, k1;
595
+ int ax[2];
596
+
597
+ // check arguments
598
+ if (argc > 2) {
599
+ rb_raise(rb_eArgError, "too many arguments (%d for 0..2)", argc);
600
+ }
601
+
602
+ for (i = 0; i < argc; i++) {
603
+ switch (TYPE(argv[i])) {
604
+ case T_FIXNUM:
605
+ if (vofs) {
606
+ rb_raise(rb_eArgError, "offset is given twice");
607
+ }
608
+ vofs = argv[i];
609
+ break;
610
+ case T_ARRAY:
611
+ if (vaxes) {
612
+ rb_raise(rb_eArgError, "axes-array is given twice");
613
+ }
614
+ vaxes = argv[i];
615
+ break;
616
+ }
617
+ }
618
+
619
+ if (vofs) {
620
+ kofs = NUM2SSIZET(vofs);
621
+ } else {
622
+ kofs = 0;
623
+ }
624
+
625
+ GetNArray(self, na);
626
+ nd = na->ndim;
627
+ if (nd < 2) {
628
+ rb_raise(nary_eDimensionError, "less than 2-d array");
629
+ }
630
+
631
+ if (vaxes) {
632
+ if (RARRAY_LEN(vaxes) != 2) {
633
+ rb_raise(rb_eArgError, "axes must be 2-element array");
634
+ }
635
+ ax[0] = NUM2INT(RARRAY_AREF(vaxes, 0));
636
+ ax[1] = NUM2INT(RARRAY_AREF(vaxes, 1));
637
+ if (ax[0] < -nd || ax[0] >= nd || ax[1] < -nd || ax[1] >= nd) {
638
+ rb_raise(rb_eArgError, "axis out of range:[%d,%d]", ax[0], ax[1]);
639
+ }
640
+ if (ax[0] < 0) {
641
+ ax[0] += nd;
642
+ }
643
+ if (ax[1] < 0) {
644
+ ax[1] += nd;
645
+ }
646
+ if (ax[0] == ax[1]) {
647
+ rb_raise(rb_eArgError, "same axes:[%d,%d]", ax[0], ax[1]);
648
+ }
649
+ } else {
650
+ ax[0] = nd - 2;
651
+ ax[1] = nd - 1;
652
+ }
653
+
654
+ // Diagonal offset from the main diagonal.
655
+ if (kofs >= 0) {
656
+ k0 = 0;
657
+ k1 = kofs;
658
+ if (k1 >= na->shape[ax[1]]) {
659
+ rb_raise(rb_eArgError,
660
+ "invalid diagonal offset(%" SZF "d) for "
661
+ "last dimension size(%" SZF "d)",
662
+ kofs, na->shape[ax[1]]);
663
+ }
664
+ } else {
665
+ k0 = -kofs;
666
+ k1 = 0;
667
+ if (k0 >= na->shape[ax[0]]) {
668
+ rb_raise(rb_eArgError,
669
+ "invalid diagonal offset(=%" SZF "d) for "
670
+ "last-1 dimension size(%" SZF "d)",
671
+ kofs, na->shape[ax[0]]);
672
+ }
673
+ }
674
+
675
+ diag_size = MIN(na->shape[ax[0]] - k0, na->shape[ax[1]] - k1);
676
+
677
+ // new shape
678
+ shape = ALLOCA_N(size_t, nd - 1);
679
+ for (i = k = 0; i < nd; i++) {
680
+ if (i != ax[0] && i != ax[1]) {
681
+ shape[k++] = na->shape[i];
682
+ }
683
+ }
684
+ shape[k] = diag_size;
685
+
686
+ // new object
687
+ view = na_s_allocate_view(rb_obj_class(self));
688
+ na_copy_flags(self, view);
689
+ GetNArrayView(view, na2);
690
+
691
+ // new stride
692
+ na_setup_shape((narray_t*)na2, nd - 1, shape);
693
+ na2->stridx = ALLOC_N(stridx_t, nd - 1);
694
+
695
+ switch (na->type) {
696
+ case NARRAY_DATA_T:
697
+ case NARRAY_FILEMAP_T:
698
+ na2->offset = 0;
699
+ na2->data = self;
700
+ stride = stride0 = stride1 = nary_element_stride(self);
701
+ for (i = nd, k = nd - 2; i--;) {
702
+ if (i == ax[1]) {
703
+ stride1 = stride;
704
+ if (kofs > 0) {
705
+ na2->offset = kofs * stride;
706
+ }
707
+ } else if (i == ax[0]) {
708
+ stride0 = stride;
709
+ if (kofs < 0) {
710
+ na2->offset = (-kofs) * stride;
711
+ }
712
+ } else {
713
+ SDX_SET_STRIDE(na2->stridx[--k], stride);
714
+ }
715
+ stride *= na->shape[i];
716
+ }
717
+ SDX_SET_STRIDE(na2->stridx[nd - 2], stride0 + stride1);
718
+ break;
719
+
720
+ case NARRAY_VIEW_T:
721
+ GetNArrayView(self, na1);
722
+ na2->data = na1->data;
723
+ na2->offset = na1->offset;
724
+ for (i = k = 0; i < nd; i++) {
725
+ if (i != ax[0] && i != ax[1]) {
726
+ if (SDX_IS_INDEX(na1->stridx[i])) {
727
+ idx0 = SDX_GET_INDEX(na1->stridx[i]);
728
+ idx1 = ALLOC_N(size_t, na->shape[i]);
729
+ for (j = 0; j < na->shape[i]; j++) {
730
+ idx1[j] = idx0[j];
731
+ }
732
+ SDX_SET_INDEX(na2->stridx[k], idx1);
733
+ } else {
734
+ na2->stridx[k] = na1->stridx[i];
735
+ }
736
+ k++;
737
+ }
738
+ }
739
+ if (SDX_IS_INDEX(na1->stridx[ax[0]])) {
740
+ idx0 = SDX_GET_INDEX(na1->stridx[ax[0]]);
741
+ diag_idx = ALLOC_N(size_t, diag_size);
742
+ if (SDX_IS_INDEX(na1->stridx[ax[1]])) {
743
+ idx1 = SDX_GET_INDEX(na1->stridx[ax[1]]);
744
+ for (j = 0; j < diag_size; j++) {
745
+ diag_idx[j] = idx0[j + k0] + idx1[j + k1];
746
+ }
747
+ } else {
748
+ stride1 = SDX_GET_STRIDE(na1->stridx[ax[1]]);
749
+ for (j = 0; j < diag_size; j++) {
750
+ diag_idx[j] = idx0[j + k0] + stride1 * (j + k1);
751
+ }
752
+ }
753
+ SDX_SET_INDEX(na2->stridx[nd - 2], diag_idx);
754
+ } else {
755
+ stride0 = SDX_GET_STRIDE(na1->stridx[ax[0]]);
756
+ if (SDX_IS_INDEX(na1->stridx[ax[1]])) {
757
+ idx1 = SDX_GET_INDEX(na1->stridx[ax[1]]);
758
+ diag_idx = ALLOC_N(size_t, diag_size);
759
+ for (j = 0; j < diag_size; j++) {
760
+ diag_idx[j] = stride0 * (j + k0) + idx1[j + k1];
761
+ }
762
+ SDX_SET_INDEX(na2->stridx[nd - 2], diag_idx);
763
+ } else {
764
+ stride1 = SDX_GET_STRIDE(na1->stridx[ax[1]]);
765
+ na2->offset += stride0 * k0 + stride1 * k1;
766
+ SDX_SET_STRIDE(na2->stridx[nd - 2], stride0 + stride1);
767
+ }
768
+ }
769
+ break;
770
+ }
771
+ return view;
772
+ }
773
+
774
+ //----------------------------------------------------------------------
775
+
776
+ #if 0
777
+ #ifdef SWAP
778
+ #undef SWAP
779
+ #endif
780
+ #define SWAP(a, b, t) \
781
+ { \
782
+ t = a; \
783
+ a = b; \
784
+ b = t; \
785
+ }
786
+
787
+ static VALUE
788
+ na_new_dimension_for_dot(VALUE self, int pos, int len, bool transpose)
789
+ {
790
+ int i, k, l, nd;
791
+ size_t j;
792
+ size_t *idx1, *idx2;
793
+ size_t *shape;
794
+ ssize_t stride;
795
+ narray_t *na;
796
+ narray_view_t *na1, *na2;
797
+ size_t shape_n;
798
+ stridx_t stridx_n;
799
+ volatile VALUE view;
800
+
801
+ GetNArray(self,na);
802
+ nd = na->ndim;
803
+
804
+ view = na_s_allocate_view(rb_obj_class(self));
805
+
806
+ na_copy_flags(self, view);
807
+ GetNArrayView(view, na2);
808
+
809
+ // new dimension
810
+ if (pos < 0) pos += nd;
811
+ if (pos > nd || pos < 0) {
812
+ rb_raise(rb_eRangeError,"new dimension is out of range");
813
+ }
814
+ nd += len;
815
+ shape = ALLOCA_N(size_t,nd);
816
+ na2->stridx = ALLOC_N(stridx_t,nd);
817
+
818
+ switch(na->type) {
819
+ case NARRAY_DATA_T:
820
+ case NARRAY_FILEMAP_T:
821
+ i = k = 0;
822
+ while (i < nd) {
823
+ if (i == pos && len > 0) {
824
+ for (l=0; l<len; l++) {
825
+ shape[i++] = 1;
826
+ }
827
+ } else {
828
+ shape[i++] = na->shape[k++];
829
+ }
830
+ }
831
+ na_setup_shape((narray_t*)na2, nd, shape);
832
+ stride = nary_element_stride(self);
833
+ for (i=nd; i--;) {
834
+ SDX_SET_STRIDE(na2->stridx[i], stride);
835
+ stride *= shape[i];
836
+ }
837
+ na2->offset = 0;
838
+ na2->data = self;
839
+ break;
840
+ case NARRAY_VIEW_T:
841
+ GetNArrayView(self, na1);
842
+ i = k = 0;
843
+ while (i < nd) {
844
+ if (i == pos && len > 0) {
845
+ if (SDX_IS_INDEX(na1->stridx[k])) {
846
+ stride = SDX_GET_INDEX(na1->stridx[k])[0];
847
+ } else {
848
+ stride = SDX_GET_STRIDE(na1->stridx[k]);
849
+ }
850
+ for (l=0; l<len; l++) {
851
+ shape[i] = 1;
852
+ SDX_SET_STRIDE(na2->stridx[i], stride);
853
+ i++;
854
+ }
855
+ } else {
856
+ shape[i] = na1->base.shape[k];
857
+ if (SDX_IS_INDEX(na1->stridx[k])) {
858
+ idx1 = SDX_GET_INDEX(na1->stridx[k]);
859
+ idx2 = ALLOC_N(size_t,na1->base.shape[k]);
860
+ for (j=0; j<na1->base.shape[k]; j++) {
861
+ idx2[j] = idx1[j];
862
+ }
863
+ SDX_SET_INDEX(na2->stridx[i], idx2);
864
+ } else {
865
+ na2->stridx[i] = na1->stridx[k];
866
+ }
867
+ i++; k++;
868
+ }
869
+ }
870
+ na_setup_shape((narray_t*)na2, nd, shape);
871
+ na2->offset = na1->offset;
872
+ na2->data = na1->data;
873
+ break;
874
+ }
875
+
876
+ if (transpose) {
877
+ SWAP(na2->base.shape[nd-1], na2->base.shape[nd-2], shape_n);
878
+ SWAP(na2->stridx[nd-1], na2->stridx[nd-2], stridx_n);
879
+ }
880
+
881
+ return view;
882
+ }
883
+
884
+
885
+ //----------------------------------------------------------------------
886
+
887
+ /*
888
+ * call-seq:
889
+ * narray.dot(other) => narray
890
+ *
891
+ * Returns dot product.
892
+ *
893
+ */
894
+
895
+ static VALUE
896
+ numo_na_dot(VALUE self, VALUE other)
897
+ {
898
+ volatile VALUE a1=self, a2=other;
899
+ narray_t *na1, *na2;
900
+
901
+ if (!rb_respond_to(a1, id_mulsum)) {
902
+ rb_raise(rb_eNoMethodError,"requires mulsum method for dot method");
903
+ }
904
+ GetNArray(a1,na1);
905
+ GetNArray(a2,na2);
906
+ if (na1->ndim==0 || na2->ndim==0) {
907
+ rb_raise(nary_eDimensionError,"zero dimensional narray");
908
+ }
909
+ if (na2->ndim > 1) {
910
+ if (na1->shape[na1->ndim-1] != na2->shape[na2->ndim-2]) {
911
+ rb_raise(nary_eShapeError,"shape mismatch: self.shape[-1](=%"SZF"d) != other.shape[-2](=%"SZF"d)",
912
+ na1->shape[na1->ndim-1], na2->shape[na2->ndim-2]);
913
+ }
914
+ // insert new axis [ ..., last-1-dim, newaxis*other.ndim, last-dim ]
915
+ a1 = na_new_dimension_for_dot(a1, na1->ndim-1, na2->ndim-1, 0);
916
+ // insert & transpose [ newaxis*self.ndim, ..., last-dim, last-1-dim ]
917
+ a2 = na_new_dimension_for_dot(a2, 0, na1->ndim-1, 1);
918
+ }
919
+ return rb_funcall(a1,id_mulsum,2,a2,INT2FIX(-1));
920
+ }
921
+ #endif
922
+
923
+ void Init_nary_data(void) {
924
+ rb_define_method(cNArray, "copy", na_copy, 0); // deprecated
925
+
926
+ rb_define_method(cNArray, "flatten", na_flatten, 0);
927
+ rb_define_method(cNArray, "swapaxes", na_swapaxes, 2);
928
+ rb_define_method(cNArray, "transpose", na_transpose, -1);
929
+
930
+ rb_define_method(cNArray, "reshape", na_reshape, -1);
931
+ rb_define_method(cNArray, "reshape!", na_reshape_bang, -1);
932
+ /*
933
+ rb_define_alias(cNArray, "shape=","reshape!");
934
+ */
935
+ rb_define_method(cNArray, "diagonal", na_diagonal, -1);
936
+
937
+ rb_define_method(cNArray, "swap_byte", nary_swap_byte, 0);
938
+ #ifdef DYNAMIC_ENDIAN
939
+ #else
940
+ #ifdef WORDS_BIGENDIAN
941
+ #else // LITTLE_ENDIAN
942
+ rb_define_alias(cNArray, "hton", "swap_byte");
943
+ rb_define_alias(cNArray, "network_order?", "byte_swapped?");
944
+ rb_define_alias(cNArray, "little_endian?", "host_order?");
945
+ rb_define_alias(cNArray, "vacs_order?", "host_order?");
946
+ #endif
947
+ #endif
948
+ rb_define_method(cNArray, "to_network", nary_to_network, 0);
949
+ rb_define_method(cNArray, "to_vacs", nary_to_vacs, 0);
950
+ rb_define_method(cNArray, "to_host", nary_to_host, 0);
951
+ rb_define_method(cNArray, "to_swapped", nary_to_swapped, 0);
952
+
953
+ // rb_define_method(cNArray, "dot", numo_na_dot, 1);
954
+
955
+ id_mulsum = rb_intern("mulsum");
956
+ id_store = rb_intern("store");
957
+ id_swap_byte = rb_intern("swap_byte");
958
+ }