carray 3.0.3 → 3.0.4

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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +1 -6
  7. data/ext/ca_axis_group.c +27 -27
  8. data/ext/ca_binop_dispatch.c +1 -29
  9. data/ext/ca_binop_dispatch.h +0 -1
  10. data/ext/ca_categorical_iterator.c +205 -134
  11. data/ext/ca_compare.c +7 -18
  12. data/ext/ca_group_iter.c +16 -17
  13. data/ext/ca_kernel_iterator.c +1234 -1994
  14. data/ext/ca_kernel_iterator.h +391 -437
  15. data/ext/ca_monop_dispatch.c +82 -59
  16. data/ext/ca_monop_dispatch.h +1 -0
  17. data/ext/ca_obj_array.c +96 -39
  18. data/ext/ca_obj_bincmp.c +24 -21
  19. data/ext/ca_obj_binop.c +15 -26
  20. data/ext/ca_obj_bitarray.c +3 -2
  21. data/ext/ca_obj_bitfield.c +5 -6
  22. data/ext/ca_obj_block.c +18 -9
  23. data/ext/ca_obj_byte_swap.c +5 -6
  24. data/ext/ca_obj_const_string.c +173 -19
  25. data/ext/ca_obj_face.c +238 -57
  26. data/ext/ca_obj_face.h +19 -0
  27. data/ext/ca_obj_fake.c +15 -29
  28. data/ext/ca_obj_farray.c +6 -3
  29. data/ext/ca_obj_field.c +17 -5
  30. data/ext/ca_obj_fixlen_string.c +2 -3
  31. data/ext/ca_obj_grid.c +406 -132
  32. data/ext/ca_obj_meld.c +172 -34
  33. data/ext/ca_obj_moncmp.c +23 -8
  34. data/ext/ca_obj_monop.c +67 -57
  35. data/ext/ca_obj_object.c +157 -51
  36. data/ext/ca_obj_record.c +12 -7
  37. data/ext/ca_obj_reduce.c +13 -8
  38. data/ext/ca_obj_refer.c +25 -27
  39. data/ext/ca_obj_remap.c +30 -9
  40. data/ext/ca_obj_repeat.c +9 -10
  41. data/ext/ca_obj_roll.c +6 -5
  42. data/ext/ca_obj_select.c +14 -9
  43. data/ext/ca_obj_select_axis.c +15 -47
  44. data/ext/ca_obj_shift.c +11 -1
  45. data/ext/ca_obj_stack.c +179 -34
  46. data/ext/ca_obj_stride.c +162 -115
  47. data/ext/ca_obj_string.c +71 -4
  48. data/ext/ca_obj_tile.c +6 -5
  49. data/ext/ca_obj_time.c +22 -6
  50. data/ext/ca_obj_timedelta.c +22 -6
  51. data/ext/ca_obj_transpose.c +5 -3
  52. data/ext/ca_obj_triop.c +23 -32
  53. data/ext/ca_obj_window.c +190 -26
  54. data/ext/ca_sweep_engine.c +2 -2
  55. data/ext/caframe_csv_reader.c +80 -1
  56. data/ext/carray.h +181 -75
  57. data/ext/carray_access.c +184 -96
  58. data/ext/carray_address_basis.c +343 -87
  59. data/ext/carray_attribute.c +89 -6
  60. data/ext/carray_bincount.c +10 -8
  61. data/ext/carray_broadcast.c +13 -8
  62. data/ext/carray_build_flags.h +3 -0
  63. data/ext/carray_call_cfunc.c +108 -0
  64. data/ext/carray_cast.c +142 -24
  65. data/ext/carray_cast_func.rb +46 -6
  66. data/ext/carray_class.c +4 -3
  67. data/ext/carray_config.h +28 -0
  68. data/ext/carray_conversion.c +16 -7
  69. data/ext/carray_copy.c +51 -14
  70. data/ext/carray_core.c +147 -55
  71. data/ext/carray_count.c +50 -20
  72. data/ext/carray_element.c +76 -33
  73. data/ext/carray_factorize.c +118 -64
  74. data/ext/carray_generate.c +191 -50
  75. data/ext/carray_histogram.c +62 -17
  76. data/ext/carray_hold.c +12 -15
  77. data/ext/carray_index_classifier.c +388 -176
  78. data/ext/carray_internal.h +336 -29
  79. data/ext/carray_kernels_bincmp.c +4453 -0
  80. data/ext/carray_kernels_binop.c +11368 -0
  81. data/ext/carray_kernels_init.c +1734 -0
  82. data/ext/carray_kernels_moncmp.c +2104 -0
  83. data/ext/carray_kernels_monop.c +18369 -0
  84. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  85. data/ext/carray_kernels_reduce_boolean.c +406 -0
  86. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  87. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  88. data/ext/carray_kernels_reduce_variance.c +3849 -0
  89. data/ext/carray_kernels_scan.c +4302 -0
  90. data/ext/carray_kernels_search.c +33829 -0
  91. data/ext/carray_kernels_sort.c +10906 -0
  92. data/ext/carray_kernels_triop.c +1864 -0
  93. data/ext/carray_key_windows.c +216 -0
  94. data/ext/carray_lazy.c +170 -111
  95. data/ext/carray_mask.c +292 -72
  96. data/ext/carray_median_percentile.c +82 -28
  97. data/ext/carray_memory_view.c +669 -561
  98. data/ext/carray_operator.c +124 -47
  99. data/ext/carray_order.c +384 -76
  100. data/ext/carray_partition.c +28 -27
  101. data/ext/carray_random.c +67 -13
  102. data/ext/carray_round.c +273 -0
  103. data/ext/carray_scatter.c +63 -38
  104. data/ext/carray_segment.c +3 -3
  105. data/ext/carray_slab.c +91 -28
  106. data/ext/carray_sort.c +35 -35
  107. data/ext/carray_struct.c +19 -18
  108. data/ext/carray_test.c +26 -5
  109. data/ext/carray_undef.c +4 -0
  110. data/ext/carray_utils.c +246 -45
  111. data/ext/mk_call_cfunc.rb +19 -2
  112. data/ext/mkkernel.rb +198 -240
  113. data/ext/ruby_carray.c +10 -4
  114. data/ext/version.h +4 -4
  115. data/lib/carray/attribute.rb +126 -22
  116. data/lib/carray/autoload_carray.rb +8 -31
  117. data/lib/carray/autoload_method_extension.rb +14 -5
  118. data/lib/carray/axis_group.rb +255 -106
  119. data/lib/carray/basics.rb +78 -10
  120. data/lib/carray/bincount_nd.rb +12 -2
  121. data/lib/carray/block_iterator.rb +126 -23
  122. data/lib/carray/boolean_reduce.rb +17 -17
  123. data/lib/carray/categorical.rb +165 -43
  124. data/lib/carray/categorical_iterator.rb +130 -27
  125. data/lib/carray/complex.rb +5 -5
  126. data/lib/carray/conditional.rb +67 -18
  127. data/lib/carray/const_string.rb +14 -5
  128. data/lib/carray/construct.rb +15 -11
  129. data/lib/carray/data_type_extension.rb +1 -0
  130. data/lib/carray/distance_limit.rb +77 -0
  131. data/lib/carray/fixlen_string.rb +7 -1
  132. data/lib/carray/frame/column_verbs.rb +70 -0
  133. data/lib/carray/frame/convert.rb +69 -0
  134. data/lib/carray/frame/csv_parser.rb +111 -17
  135. data/lib/carray/frame/describe.rb +3 -2
  136. data/lib/carray/frame/frame.rb +246 -21
  137. data/lib/carray/frame/group.rb +510 -95
  138. data/lib/carray/frame/io.rb +115 -28
  139. data/lib/carray/frame/join.rb +312 -51
  140. data/lib/carray/frame/records.rb +83 -7
  141. data/lib/carray/frame/reshape.rb +42 -35
  142. data/lib/carray/frame/sort.rb +7 -19
  143. data/lib/carray/frame/verbs.rb +188 -48
  144. data/lib/carray/frame/windows.rb +117 -0
  145. data/lib/carray/frame.rb +2 -0
  146. data/lib/carray/fuse_source.rb +11 -4
  147. data/lib/carray/fusion.rb +40 -16
  148. data/lib/carray/histogram.rb +6 -1
  149. data/lib/carray/inspect.rb +31 -8
  150. data/lib/carray/iterator.rb +85 -7
  151. data/lib/carray/key_windows.rb +620 -0
  152. data/lib/carray/lazy.rb +182 -183
  153. data/lib/carray/mask_gap_fill.rb +63 -57
  154. data/lib/carray/meld_reduce.rb +12 -14
  155. data/lib/carray/methods/bin.rb +26 -18
  156. data/lib/carray/methods/bincount.rb +16 -0
  157. data/lib/carray/methods/bit_string.rb +1 -1
  158. data/lib/carray/methods/choose.rb +16 -3
  159. data/lib/carray/methods/composition.rb +3 -1
  160. data/lib/carray/methods/gather_nd.rb +14 -5
  161. data/lib/carray/methods/insert_block.rb +2 -2
  162. data/lib/carray/methods/is_between.rb +59 -0
  163. data/lib/carray/methods/is_in.rb +53 -36
  164. data/lib/carray/methods/join.rb +1 -6
  165. data/lib/carray/methods/lag.rb +49 -0
  166. data/lib/carray/methods/locate_addr.rb +47 -51
  167. data/lib/carray/methods/mode.rb +1 -1
  168. data/lib/carray/methods/nunique.rb +11 -6
  169. data/lib/carray/methods/resize.rb +3 -3
  170. data/lib/carray/methods/value_counts.rb +4 -11
  171. data/lib/carray/record_order.rb +3 -3
  172. data/lib/carray/rng.rb +3 -0
  173. data/lib/carray/runtime.rb +53 -8
  174. data/lib/carray/segment_iterator.rb +313 -82
  175. data/lib/carray/serialize.rb +24 -10
  176. data/lib/carray/slab_iterator.rb +50 -0
  177. data/lib/carray/string.rb +105 -5
  178. data/lib/carray/string_operation_extension.rb +8 -1
  179. data/lib/carray/struct.rb +9 -21
  180. data/lib/carray/struct_builder.rb +19 -8
  181. data/lib/carray/time.rb +726 -104
  182. data/lib/carray/window_iterator.rb +122 -16
  183. data/lib/carray.rb +7 -0
  184. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  185. data/yard-stubs/ca_obj_field.rb +4 -0
  186. data/yard-stubs/ca_obj_grid.rb +21 -10
  187. data/yard-stubs/ca_obj_refer.rb +2 -1
  188. data/yard-stubs/ca_obj_roll.rb +2 -2
  189. data/yard-stubs/ca_obj_shift.rb +5 -1
  190. data/yard-stubs/ca_obj_tile.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +8 -3
  192. data/yard-stubs/carray_access.rb +6 -1
  193. data/yard-stubs/carray_attribute.rb +0 -5
  194. data/yard-stubs/carray_cast.rb +10 -0
  195. data/yard-stubs/carray_conversion.rb +2 -1
  196. data/yard-stubs/carray_copy.rb +4 -2
  197. data/yard-stubs/carray_count.rb +4 -4
  198. data/yard-stubs/carray_element.rb +10 -4
  199. data/yard-stubs/carray_generate.rb +21 -1
  200. data/yard-stubs/carray_mask.rb +26 -2
  201. data/yard-stubs/carray_math.rb +27 -1
  202. data/yard-stubs/carray_median_percentile.rb +5 -2
  203. data/yard-stubs/carray_memory_view.rb +40 -23
  204. data/yard-stubs/carray_order.rb +29 -18
  205. data/yard-stubs/carray_random.rb +13 -4
  206. data/yard-stubs/carray_scatter.rb +14 -9
  207. data/yard-stubs/carray_slab.rb +9 -2
  208. data/yard-stubs/carray_sort.rb +6 -5
  209. data/yard-stubs/carray_test.rb +5 -3
  210. metadata +25 -3
  211. data/lib/carray/arrow_tensor.rb +0 -401
  212. data/lib/carray/table.rb +0 -108
@@ -14,7 +14,7 @@
14
14
 
15
15
  #include "ruby.h"
16
16
  #include "carray.h"
17
- #include "carray_internal.h" /* ca_axis_integer */
17
+ #include "carray_internal.h" /* ca_normalize_axis_arg */
18
18
  #include "ca_kernel_iterator.h" /* CA_FOR_EACH_FIBER_INOUT */
19
19
  #include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE */
20
20
  #include "ca_sort_kernels.h" /* ca_partition_quick_* / ca_partition_nan_* */
@@ -155,7 +155,7 @@ rb_ca_partition_copy_c (VALUE self, VALUE vkth, VALUE vaxis)
155
155
  }
156
156
 
157
157
  /* Normalize axis. */
158
- int axis = rb_ca_normalize_axis_for_ndim(ca_axis_integer(vaxis, NULL), cat->ndim, NULL);
158
+ int axis = ca_normalize_axis_arg(vaxis, cat->ndim, NULL);
159
159
 
160
160
  ca_size_t fiber_n = cat->dim[axis];
161
161
  ca_size_t kth = partition_kth(fiber_n, vkth);
@@ -166,14 +166,9 @@ rb_ca_partition_copy_c (VALUE self, VALUE vkth, VALUE vaxis)
166
166
  * but the cost is the per-pair rb_funcall, not an architectural
167
167
  * penalty. */
168
168
  if ( cat->data_type == CA_OBJECT ) {
169
- static ID id_partition_index_ki = 0;
170
- static ID id_take_along_axis = 0;
171
- static ID id_axis_sym = 0;
172
- if ( !id_partition_index_ki ) {
173
- id_partition_index_ki = rb_intern("partition_index_ki");
174
- id_take_along_axis = rb_intern("take_along_axis");
175
- id_axis_sym = rb_intern("axis");
176
- }
169
+ ID id_partition_index_ki = rb_intern("partition_index_ki");
170
+ ID id_take_along_axis = rb_intern("take_along_axis");
171
+ ID id_axis_sym = rb_intern("axis");
177
172
  VALUE idx = rb_funcall(target, id_partition_index_ki, 2,
178
173
  INT2NUM(axis), SIZET2NUM(kth));
179
174
  VALUE kw = rb_hash_new();
@@ -297,8 +292,7 @@ rb_ca_partition_copy_c_mp (VALUE self, VALUE vkth, VALUE vaxis, int masked_last)
297
292
  /* Check axis and kth here, so a bad one is reported as partition_copy's
298
293
  rather than as the partition this delegates to. */
299
294
  {
300
- int axis = rb_ca_normalize_axis_for_ndim(ca_axis_integer(vaxis, NULL),
301
- ca->ndim, NULL);
295
+ int axis = ca_normalize_axis_arg(vaxis, ca->ndim, NULL);
302
296
  partition_kth(ca->dim[axis], vkth);
303
297
  }
304
298
  /* rb_ca_partitioned_view's rb_scan_args "1:" pattern needs call-frame
@@ -337,26 +331,30 @@ rb_ca_partition_copy_body (int argc, VALUE *argv, VALUE self)
337
331
  int masked_last = NIL_P(vmasked_position) ? 1
338
332
  : ca_symbol_choice(vmasked_position, "masked_position", "first", "last", NULL);
339
333
 
340
- /* Face gate, the same policy as the sort family's: a fixlen storage
341
- partitions by memcmp, a numeric storage only when ORDERABLE (its order
342
- is the surface order). The selection runs on the storage and the Face
343
- is put back on the result. Without this the surface fixlen bytes were
344
- selected by memcmp, which is not the order of a little-endian integer
345
- (CATime) and not the label order of a code (CACategorical). */
334
+ /* Face gate, the same policy as the sort family's. An ORDERABLE Face
335
+ is selected on its storage and put back on the result. A Face that
336
+ orders by itself (ca_face_orders_by_itself) is partitioned by the view,
337
+ which orders by that order (ca_order_key), and its copy is the answer.
338
+ Any other Face raises. */
346
339
  volatile VALUE face = Qnil;
347
340
  {
348
341
  CArray *ca;
349
342
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
350
343
  if ( ca_is_face(ca) ) {
351
- VALUE st = rb_ca_strip_face_value(self);
352
- CArray *sc;
353
- TypedData_Get_Struct(st, CArray, &carray_data_type, sc);
354
- if ( sc->data_type != CA_FIXLEN
355
- && ! ca_test_flag(ca, CA_FLAG_FACE_ORDERABLE_STORAGE) ) {
356
- ca_face_refuse_order("partition_copy", self, "order");
344
+ if ( ca_face_orders_by_itself(self) ) {
345
+ VALUE kw = rb_hash_new();
346
+ VALUE pv_argv[2];
347
+ rb_hash_aset(kw, ID2SYM(rb_intern("axis")), vaxis);
348
+ rb_hash_aset(kw, ID2SYM(rb_intern("masked_position")),
349
+ masked_last ? ID2SYM(rb_intern("last")) : ID2SYM(rb_intern("first")));
350
+ pv_argv[0] = vkth;
351
+ pv_argv[1] = kw;
352
+ return rb_ca_copy(rb_funcallv_kw(self, rb_intern("partition"), 2, pv_argv,
353
+ RB_PASS_KEYWORDS));
357
354
  }
355
+ ca_face_require_orderable(self, "partition_copy", "order");
358
356
  face = self;
359
- self = st;
357
+ self = rb_ca_strip_face_value(self);
360
358
  }
361
359
  }
362
360
 
@@ -418,7 +416,8 @@ rb_ca_partitioned_view (int argc, VALUE *argv, VALUE self)
418
416
  suitable for direct ca_remap_new wrap; the remap gather carries
419
417
  target's mask bits through so masked cells stay masked at their
420
418
  clustered position (no extra output-mask step needed here). */
421
- volatile VALUE sigma_addr = rb_ca_partition_addr_ki_mp(target, vaxis, vkth, masked_last);
419
+ volatile VALUE sigma_addr =
420
+ rb_ca_partition_addr_ki_mp(target, vaxis, vkth, masked_last);
422
421
  {
423
422
  VALUE obj = rb_ca_remap_new(target, sigma_addr);
424
423
  CA_FACE_LIFT_IF_FACE(obj, self, ca);
@@ -443,7 +442,9 @@ static VALUE
443
442
  rb_ca_partition_copy (int argc, VALUE *argv, VALUE self)
444
443
  {
445
444
  pc_call_t c = { argc, argv, self };
446
- return ca_answer_as_caller(pc_answer_body, (VALUE) &c);
445
+ VALUE out = ca_answer_as_caller(pc_answer_body, (VALUE) &c);
446
+ rb_ca_inherit_attr(out, self);
447
+ return out;
447
448
  }
448
449
 
449
450
  void
data/ext/carray_random.c CHANGED
@@ -88,16 +88,18 @@ typedef struct {
88
88
  long low_long;
89
89
  unsigned long limit;
90
90
  int axis; /* shuffle!: -1 = all cells */
91
+ CArray *mask; /* shuffle!: self's mask, moved with the values */
91
92
  } ca_random_ctx_t;
92
93
 
93
94
  static void
94
95
  ca_random_run (ca_random_ctx_t *c, VALUE rng, VALUE (*fill)(VALUE))
95
96
  {
96
- CArray *list[2];
97
+ CArray *list[3];
97
98
  ca_rng_resolve(rng, &c->source);
98
99
  list[0] = c->ca;
99
100
  list[1] = c->source.state;
100
- ca_attach_window(2, list, "ww", fill, (VALUE) c);
101
+ list[2] = c->mask;
102
+ ca_attach_window(c->mask ? 3 : 2, list, "www", fill, (VALUE) c);
101
103
  }
102
104
 
103
105
  /* The state is attached once the window is open. */
@@ -359,19 +361,55 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
359
361
  int is_integer_type = (ca->data_type >= CA_INT8
360
362
  && ca->data_type <= CA_UINT64);
361
363
  if (is_integer_type) {
362
- low_long = NUM2LONG(low_val);
363
- high_long = NUM2LONG(high_val);
364
- if (high_is_closed) high_long += 1;
365
- if (low_long >= high_long) {
364
+ /* The bounds stay Ruby Integers until they are known to fit: the
365
+ last value drawn is high (closed) or high - 1, and every value
366
+ from low to it must be one of the type's. The draw is low plus
367
+ an offset up to last - low, which holds even the whole int64 or
368
+ uint64 range. */
369
+ VALUE last, type_min, type_max;
370
+ if (!RB_INTEGER_TYPE_P(low_val) || !RB_INTEGER_TYPE_P(high_val)) {
371
+ rb_raise(rb_eTypeError,
372
+ "random: an integer array takes Integer bounds "
373
+ "(got %"PRIsVALUE", %"PRIsVALUE")",
374
+ rb_inspect(low_val), rb_inspect(high_val));
375
+ }
376
+ last = high_is_closed ? high_val
377
+ : rb_funcall(high_val, '-', 1, INT2FIX(1));
378
+ if (RTEST(rb_funcall(low_val, '>', 1, last))) {
366
379
  rb_raise(rb_eArgError,
367
380
  "random: low must be less than high "
368
- "(got low=%ld, high=%ld)",
369
- low_long, high_long);
381
+ "(got low=%"PRIsVALUE", high=%"PRIsVALUE")",
382
+ low_val, high_val);
383
+ }
384
+ switch (ca->data_type) {
385
+ case CA_INT8: type_min = INT2FIX(INT8_MIN); type_max = INT2FIX(INT8_MAX); break;
386
+ case CA_UINT8: type_min = INT2FIX(0); type_max = INT2FIX(UINT8_MAX); break;
387
+ case CA_INT16: type_min = INT2FIX(INT16_MIN); type_max = INT2FIX(INT16_MAX); break;
388
+ case CA_UINT16: type_min = INT2FIX(0); type_max = INT2FIX(UINT16_MAX); break;
389
+ case CA_INT32: type_min = LL2NUM(INT32_MIN); type_max = LL2NUM(INT32_MAX); break;
390
+ case CA_UINT32: type_min = INT2FIX(0); type_max = ULL2NUM(UINT32_MAX); break;
391
+ case CA_INT64: type_min = LL2NUM(INT64_MIN); type_max = LL2NUM(INT64_MAX); break;
392
+ default: type_min = INT2FIX(0); type_max = ULL2NUM(UINT64_MAX); break;
393
+ }
394
+ if (RTEST(rb_funcall(low_val, '<', 1, type_min)) ||
395
+ RTEST(rb_funcall(last, '>', 1, type_max))) {
396
+ rb_raise(rb_eRangeError,
397
+ "random: the values %"PRIsVALUE"..%"PRIsVALUE" are not all %s "
398
+ "(%"PRIsVALUE"..%"PRIsVALUE")",
399
+ low_val, last, ca_type_name[ca->data_type], type_min, type_max);
370
400
  }
371
- limit = (unsigned long)(high_long - low_long) - 1;
401
+ low_long = RTEST(rb_funcall(low_val, '<', 1, INT2FIX(0)))
402
+ ? (long) NUM2LL(low_val) : (long) NUM2ULL(low_val);
403
+ limit = (unsigned long) NUM2ULL(rb_funcall(last, '-', 1, low_val));
404
+ (void) high_long;
372
405
  } else {
373
406
  low_dbl = NUM2DBL(low_val);
374
407
  high_dbl = NUM2DBL(high_val);
408
+ if (!isfinite(low_dbl) || !isfinite(high_dbl)) {
409
+ rb_raise(rb_eArgError,
410
+ "random: the bounds are finite numbers "
411
+ "(got low=%g, high=%g)", low_dbl, high_dbl);
412
+ }
375
413
  if (low_dbl >= high_dbl) {
376
414
  rb_raise(rb_eArgError,
377
415
  "random: low must be less than high "
@@ -382,7 +420,7 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
382
420
  }
383
421
 
384
422
  {
385
- ca_random_ctx_t c;
423
+ ca_random_ctx_t c = { 0 };
386
424
  c.ca = ca;
387
425
  c.n = ca->elements;
388
426
  c.is_default = is_default;
@@ -392,6 +430,8 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
392
430
  c.limit = limit;
393
431
  ca_random_run(&c, rng, ca_random_bang_fill);
394
432
  }
433
+ /* Every cell now holds a value, as after seq! or fill. */
434
+ ca_clear_mask(ca);
395
435
  return self;
396
436
  }
397
437
 
@@ -560,11 +600,13 @@ rb_ca_randomn_bang(int argc, VALUE *argv, VALUE self)
560
600
  }
561
601
 
562
602
  {
563
- ca_random_ctx_t c;
603
+ ca_random_ctx_t c = { 0 };
564
604
  c.ca = ca;
565
605
  c.n = ca->elements;
566
606
  ca_random_run(&c, rng, ca_randomn_bang_fill);
567
607
  }
608
+ /* Every cell now holds a value, as after seq! or fill. */
609
+ ca_clear_mask(ca);
568
610
  return self;
569
611
  }
570
612
 
@@ -600,12 +642,16 @@ ca_shuffle_bang_fill (VALUE arg)
600
642
  ca_size_t elem_bytes = ca->bytes;
601
643
  char *tmp = ALLOCV_N(char, tmp_holder, elem_bytes);
602
644
  char *p = ca->ptr;
645
+ char *m = c->mask ? c->mask->ptr : NULL;
603
646
 
604
647
  n = ca->elements;
605
648
  for (ca_size_t i = n - 1; i > 0; i--) {
606
649
  unsigned long j = ca_random_ulong_limited(&c->source, (unsigned long)i);
607
650
  if ((ca_size_t)j != i) {
608
651
  swap_chunks(p + i * elem_bytes, p + j * elem_bytes, elem_bytes, tmp);
652
+ if ( m ) {
653
+ char b = m[i]; m[i] = m[j]; m[j] = b;
654
+ }
609
655
  }
610
656
  }
611
657
  ALLOCV_END(tmp_holder);
@@ -630,12 +676,16 @@ ca_shuffle_bang_fill (VALUE arg)
630
676
 
631
677
  for (ca_size_t o = 0; o < outer; o++) {
632
678
  char *base = ca->ptr + o * stride;
679
+ char *mbase = c->mask ? c->mask->ptr + o * n * inner : NULL;
633
680
  for (ca_size_t i = n - 1; i > 0; i--) {
634
681
  unsigned long j = ca_random_ulong_limited(&c->source, (unsigned long)i);
635
682
  if ((ca_size_t)j != i) {
636
683
  swap_chunks(base + i * chunk_bytes,
637
684
  base + j * chunk_bytes,
638
685
  chunk_bytes, tmp);
686
+ if ( mbase ) {
687
+ swap_chunks(mbase + i * inner, mbase + j * inner, inner, tmp);
688
+ }
639
689
  }
640
690
  }
641
691
  }
@@ -650,7 +700,7 @@ rb_ca_shuffle_bang(int argc, VALUE *argv, VALUE self)
650
700
  CArray *ca;
651
701
  VALUE opts = Qnil, v_axis = Qnil;
652
702
  int axis = -1;
653
- ca_random_ctx_t c;
703
+ ca_random_ctx_t c = { 0 };
654
704
 
655
705
  rb_scan_args(argc, argv, "0:", &opts);
656
706
  VALUE rng = Qnil;
@@ -662,7 +712,7 @@ rb_ca_shuffle_bang(int argc, VALUE *argv, VALUE self)
662
712
  if (ca->elements <= 1) return self;
663
713
 
664
714
  if (!NIL_P(v_axis)) {
665
- axis = rb_ca_normalize_axis_for_ndim(ca_axis_integer(v_axis, NULL), ca->ndim, NULL);
715
+ axis = ca_normalize_axis_arg(v_axis, ca->ndim, NULL);
666
716
  if (ca->dim[axis] <= 1) {
667
717
  return self;
668
718
  }
@@ -670,6 +720,10 @@ rb_ca_shuffle_bang(int argc, VALUE *argv, VALUE self)
670
720
 
671
721
  c.ca = ca;
672
722
  c.axis = axis;
723
+ /* The mask moves with the values: a masked cell stays masked wherever
724
+ it lands. */
725
+ ca_update_mask(ca);
726
+ c.mask = ca->mask;
673
727
  ca_random_run(&c, rng, ca_shuffle_bang_fill);
674
728
  return self;
675
729
  }
@@ -0,0 +1,273 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ CArray#round(ndigits) and #round!(ndigits): each element rounded as Ruby's
4
+ Float#round(ndigits) and Integer#round(ndigits) round it, half away from
5
+ zero. The argument-free forms are the generated monop kernels; this file
6
+ takes over the method and hands them the calls without an argument.
7
+
8
+ ---------------------------------------------------------------------------- */
9
+
10
+ #include <math.h>
11
+ #include <float.h>
12
+
13
+ #include "carray.h"
14
+ #include "carray_internal.h"
15
+ #include "ca_obj_face.h"
16
+
17
+ VALUE rb_ca_round (VALUE self); /* generated: round without digits */
18
+ VALUE rb_ca_round_bang (VALUE self);
19
+
20
+ static ID id_round;
21
+
22
+ /* The rounding of Float#round for ndigits > 0 (numeric.c, round_half_up
23
+ with its check for a product that came out one short). */
24
+ static double
25
+ ca_round_half_up (double x, double s)
26
+ {
27
+ double f, xs = x * s;
28
+
29
+ f = round(xs);
30
+ if ( x > 0 ) {
31
+ if ( (double)((f + 0.5) / s) <= x ) f += 1;
32
+ x = f;
33
+ }
34
+ else {
35
+ if ( (double)((f - 0.5) / s) >= x ) f -= 1;
36
+ x = f;
37
+ }
38
+ return x;
39
+ }
40
+
41
+ /* numeric.c: float_round_overflow / float_round_underflow. When the first
42
+ holds, number * 10**ndigits is already an integer and the number is its
43
+ own answer; when the second holds, the answer is 0. */
44
+ static int
45
+ ca_round_overflow (long ndigits, int binexp)
46
+ {
47
+ enum { float_dig = DBL_DIG + 2 };
48
+ return ndigits >= float_dig - (binexp > 0 ? binexp / 4 : binexp / 3 - 1);
49
+ }
50
+
51
+ static int
52
+ ca_round_underflow (long ndigits, int binexp)
53
+ {
54
+ return ndigits < - (binexp > 0 ? binexp / 3 + 1 : binexp / 4);
55
+ }
56
+
57
+ /* An integer |x| rounded to a multiple of 10**k (k >= 1), half away from
58
+ zero, as Integer#round(-k). Returns 0 when the answer does not fit in
59
+ 64 bits, and sets *overflow. */
60
+ static uint64_t
61
+ ca_round_uint64 (uint64_t ax, long k, int *overflow)
62
+ {
63
+ uint64_t y = 1, q, rem, r;
64
+ long i;
65
+
66
+ *overflow = 0;
67
+ if ( k > 19 ) { /* 10**20 / 2 exceeds every 64-bit value */
68
+ return 0;
69
+ }
70
+ for (i = 0; i < k; i++) {
71
+ y *= 10;
72
+ }
73
+ q = ax / y;
74
+ rem = ax % y;
75
+ r = q * y;
76
+ if ( rem >= y - y / 2 ) { /* rem * 2 >= y, without overflow */
77
+ if ( r > UINT64_MAX - y ) {
78
+ *overflow = 1;
79
+ return 0;
80
+ }
81
+ r += y;
82
+ }
83
+ return r;
84
+ }
85
+
86
+ /* x rounded as Float#round(ndigits) rounds it, for ndigits != 0. NaN and
87
+ the infinities are their own answer (Float#round raises for them when
88
+ ndigits <= 0; an array of floats keeps them as values). */
89
+ static double
90
+ ca_round_double (double x, long ndigits)
91
+ {
92
+ int binexp;
93
+
94
+ if ( x == 0.0 || ! isfinite(x) ) {
95
+ return x;
96
+ }
97
+ if ( ndigits > 0 ) {
98
+ frexp(x, &binexp);
99
+ if ( ca_round_overflow(ndigits, binexp) ) {
100
+ return x;
101
+ }
102
+ if ( ca_round_underflow(ndigits, binexp) ) {
103
+ return 0.0;
104
+ }
105
+ if ( ndigits > 14 ) {
106
+ /* pow(10, ndigits) may not be exact; Ruby rounds through a Rational. */
107
+ return NUM2DBL(rb_funcall(DBL2NUM(x), id_round, 1, LONG2NUM(ndigits)));
108
+ }
109
+ {
110
+ double f = pow(10, (double) ndigits);
111
+ return ca_round_half_up(x, f) / f;
112
+ }
113
+ }
114
+ else {
115
+ /* Ruby truncates to an Integer, then rounds the Integer. */
116
+ double t = trunc(x);
117
+ if ( fabs(t) < 18446744073709551616.0 ) { /* 2**64 */
118
+ int overflow;
119
+ uint64_t r = ca_round_uint64((uint64_t) fabs(t), -ndigits, &overflow);
120
+ if ( ! overflow ) {
121
+ return ( t < 0 ) ? -(double) r : (double) r;
122
+ }
123
+ }
124
+ return NUM2DBL(rb_funcall(DBL2NUM(x), id_round, 1, LONG2NUM(ndigits)));
125
+ }
126
+ }
127
+
128
+ #define ROUND_INT_LOOP(type, lo, hi, is_signed) \
129
+ { \
130
+ type *p = (type *) ca->ptr; \
131
+ for (i = 0; i < ca->elements; i++) { \
132
+ int neg, overflow; \
133
+ uint64_t ax, r; \
134
+ if ( m && m[i] ) continue; \
135
+ neg = ( is_signed ) && ( (int64_t) p[i] < 0 ); \
136
+ ax = neg ? (uint64_t) 0 - (uint64_t)(int64_t) p[i] : (uint64_t) p[i]; \
137
+ r = ca_round_uint64(ax, -ndigits, &overflow); \
138
+ if ( overflow || ( neg ? r > (uint64_t) 0 - (uint64_t)(int64_t)(lo) \
139
+ : r > (uint64_t)(hi) ) ) { \
140
+ rb_raise(rb_eRangeError, \
141
+ "round: a value rounded to %ld digits does not fit " \
142
+ "data_type %s", ndigits, ca_type_name[ca->data_type]); \
143
+ } \
144
+ p[i] = neg ? (type)((uint64_t) 0 - r) : (type) r; \
145
+ } \
146
+ }
147
+
148
+ /* Rounds the cells of the entity `ca` in place; masked cells are left. */
149
+ static void
150
+ ca_round_entity (CArray *ca, long ndigits)
151
+ {
152
+ boolean8_t *m = NULL;
153
+ ca_size_t i;
154
+
155
+ if ( ca->mask ) {
156
+ m = (boolean8_t *) ca->mask->ptr;
157
+ }
158
+
159
+ switch ( ca->data_type ) {
160
+ case CA_INT8: ROUND_INT_LOOP(int8_t, INT8_MIN, INT8_MAX, 1); break;
161
+ case CA_UINT8: ROUND_INT_LOOP(uint8_t, 0, UINT8_MAX, 0); break;
162
+ case CA_INT16: ROUND_INT_LOOP(int16_t, INT16_MIN, INT16_MAX, 1); break;
163
+ case CA_UINT16: ROUND_INT_LOOP(uint16_t, 0, UINT16_MAX, 0); break;
164
+ case CA_INT32: ROUND_INT_LOOP(int32_t, INT32_MIN, INT32_MAX, 1); break;
165
+ case CA_UINT32: ROUND_INT_LOOP(uint32_t, 0, UINT32_MAX, 0); break;
166
+ case CA_INT64: ROUND_INT_LOOP(int64_t, INT64_MIN, INT64_MAX, 1); break;
167
+ case CA_UINT64: ROUND_INT_LOOP(uint64_t, 0, UINT64_MAX, 0); break;
168
+ case CA_FLOAT32: {
169
+ float32_t *p = (float32_t *) ca->ptr;
170
+ for (i = 0; i < ca->elements; i++) {
171
+ if ( m && m[i] ) continue;
172
+ p[i] = (float32_t) ca_round_double((double) p[i], ndigits);
173
+ }
174
+ break;
175
+ }
176
+ case CA_FLOAT64: {
177
+ float64_t *p = (float64_t *) ca->ptr;
178
+ for (i = 0; i < ca->elements; i++) {
179
+ if ( m && m[i] ) continue;
180
+ p[i] = ca_round_double(p[i], ndigits);
181
+ }
182
+ break;
183
+ }
184
+ case CA_OBJECT: {
185
+ VALUE *p = (VALUE *) ca->ptr;
186
+ volatile VALUE nd = LONG2NUM(ndigits);
187
+ for (i = 0; i < ca->elements; i++) {
188
+ if ( m && m[i] ) continue;
189
+ p[i] = rb_funcall(p[i], id_round, 1, nd);
190
+ }
191
+ break;
192
+ }
193
+ default:
194
+ rb_raise(rb_eCADataTypeError, "round: not defined for data_type %s",
195
+ ca_type_name[ca->data_type]);
196
+ }
197
+ }
198
+
199
+ /* The array to round: a boolean is rounded as its 0/1 int64 values, as
200
+ round without digits does. */
201
+ static VALUE
202
+ ca_round_source (VALUE self, VALUE vdigits, long *ndigits)
203
+ {
204
+ CArray *ca;
205
+ *ndigits = ca_integer_arg(vdigits, "ndigits", "round");
206
+ ca_face_refuse_numeric(self, "round", rb_eCADataTypeError);
207
+ GetCArray(self, ca);
208
+ if ( ca->data_type == CA_BOOLEAN ) {
209
+ self = rb_ca_wrap_readonly(self, INT2NUM(CA_INT64));
210
+ }
211
+ return self;
212
+ }
213
+
214
+ /* A copy of `src` rounded to `ndigits`. Rounding to 0 digits is what round
215
+ without digits does (except for objects, which are asked with the digits);
216
+ an integer has no digits below 10**0 to round. */
217
+ static VALUE
218
+ ca_round_copy (VALUE src, long ndigits)
219
+ {
220
+ volatile VALUE out;
221
+ CArray *ca, *co;
222
+ GetCArray(src, ca);
223
+ if ( ndigits == 0 && ca->data_type != CA_OBJECT ) {
224
+ return rb_ca_round(src);
225
+ }
226
+ out = rb_ca_copy(src);
227
+ GetCArray(out, co);
228
+ if ( ndigits > 0 && ca_is_integer_type(co) ) {
229
+ return out;
230
+ }
231
+ ca_round_entity(co, ndigits);
232
+ return out;
233
+ }
234
+
235
+ static VALUE
236
+ rb_ca_round_digits (int argc, VALUE *argv, VALUE self)
237
+ {
238
+ long ndigits;
239
+ rb_check_arity(argc, 0, 1);
240
+ if ( argc == 0 ) {
241
+ return rb_ca_round(self);
242
+ }
243
+ self = ca_round_source(self, argv[0], &ndigits);
244
+ return ca_round_copy(self, ndigits);
245
+ }
246
+
247
+ static VALUE
248
+ rb_ca_round_digits_bang (int argc, VALUE *argv, VALUE self)
249
+ {
250
+ long ndigits;
251
+ volatile VALUE src, out;
252
+ rb_check_arity(argc, 0, 1);
253
+ if ( argc == 0 ) {
254
+ return rb_ca_round_bang(self);
255
+ }
256
+ rb_ca_modify(self);
257
+ src = ca_round_source(self, argv[0], &ndigits);
258
+ if ( src != self ) {
259
+ rb_raise(rb_eCADataTypeError,
260
+ "round!: a boolean array can not hold the rounded int64 values");
261
+ }
262
+ out = ca_round_copy(self, ndigits);
263
+ rb_ca_store_all(self, out);
264
+ return self;
265
+ }
266
+
267
+ void
268
+ Init_carray_round (void)
269
+ {
270
+ id_round = rb_intern("round");
271
+ rb_define_method(rb_cCArray, "round", rb_ca_round_digits, -1);
272
+ rb_define_method(rb_cCArray, "round!", rb_ca_round_digits_bang, -1);
273
+ }