carray 3.0.2 → 3.0.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 (218) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +304 -0
  3. data/README.md +3 -4
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +225 -0
  6. data/ext/ca_axis_group.c +177 -99
  7. data/ext/ca_binop_dispatch.c +54 -32
  8. data/ext/ca_binop_dispatch.h +1 -0
  9. data/ext/ca_categorical_iterator.c +66 -71
  10. data/ext/ca_compare.c +8 -2
  11. data/ext/ca_for_buffer.h +21 -68
  12. data/ext/ca_group_iter.c +27 -11
  13. data/ext/ca_kernel_iterator.c +663 -214
  14. data/ext/ca_kernel_iterator.h +231 -167
  15. data/ext/ca_monop_dispatch.c +4 -4
  16. data/ext/ca_monop_dispatch.h +4 -0
  17. data/ext/ca_obj_array.c +132 -22
  18. data/ext/ca_obj_bincmp.c +152 -121
  19. data/ext/ca_obj_binop.c +107 -210
  20. data/ext/ca_obj_bitarray.c +37 -24
  21. data/ext/ca_obj_bitfield.c +95 -62
  22. data/ext/ca_obj_block.c +1 -0
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +96 -25
  25. data/ext/ca_obj_face.c +406 -64
  26. data/ext/ca_obj_face.h +92 -47
  27. data/ext/ca_obj_fake.c +21 -50
  28. data/ext/ca_obj_farray.c +1 -0
  29. data/ext/ca_obj_field.c +16 -3
  30. data/ext/ca_obj_fixlen_string.c +21 -21
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +189 -107
  33. data/ext/ca_obj_moncmp.c +61 -61
  34. data/ext/ca_obj_monop.c +125 -107
  35. data/ext/ca_obj_object.c +543 -233
  36. data/ext/ca_obj_record.c +51 -16
  37. data/ext/ca_obj_reduce.c +5 -8
  38. data/ext/ca_obj_refer.c +117 -33
  39. data/ext/ca_obj_remap.c +57 -17
  40. data/ext/ca_obj_repeat.c +21 -5
  41. data/ext/ca_obj_roll.c +115 -11
  42. data/ext/ca_obj_select.c +47 -49
  43. data/ext/ca_obj_select_axis.c +58 -60
  44. data/ext/ca_obj_shift.c +22 -102
  45. data/ext/ca_obj_stack.c +223 -118
  46. data/ext/ca_obj_stride.c +195 -34
  47. data/ext/ca_obj_string.c +17 -18
  48. data/ext/ca_obj_tile.c +32 -16
  49. data/ext/ca_obj_time.c +23 -25
  50. data/ext/ca_obj_timedelta.c +21 -23
  51. data/ext/ca_obj_transpose.c +12 -3
  52. data/ext/ca_obj_triop.c +110 -117
  53. data/ext/ca_obj_window.c +149 -27
  54. data/ext/ca_op_ipower.c +24 -11
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_sort_kernels.h +70 -0
  58. data/ext/ca_sweep_engine.c +102 -79
  59. data/ext/ca_sweep_engine.h +7 -20
  60. data/ext/ca_triop_dispatch.c +4 -1
  61. data/ext/ca_triop_dispatch.h +5 -2
  62. data/ext/caframe_csv_reader.c +463 -0
  63. data/ext/carray.h +70 -27
  64. data/ext/carray_access.c +455 -211
  65. data/ext/carray_address_basis.c +177 -36
  66. data/ext/carray_attribute.c +45 -3
  67. data/ext/carray_bincount.c +32 -2
  68. data/ext/carray_broadcast.c +46 -14
  69. data/ext/carray_call_cfunc.c +0 -28
  70. data/ext/carray_cast.c +1444 -209
  71. data/ext/carray_cast_func.rb +34 -21
  72. data/ext/carray_conversion.c +197 -73
  73. data/ext/carray_copy.c +32 -11
  74. data/ext/carray_core.c +514 -122
  75. data/ext/carray_count.c +140 -87
  76. data/ext/carray_element.c +18 -27
  77. data/ext/carray_factorize.c +569 -277
  78. data/ext/carray_generate.c +76 -40
  79. data/ext/carray_histogram.c +152 -94
  80. data/ext/carray_hold.c +2 -1
  81. data/ext/carray_index_classifier.c +63 -96
  82. data/ext/carray_internal.h +385 -3
  83. data/ext/carray_lazy.c +834 -79
  84. data/ext/carray_loop.c +81 -65
  85. data/ext/carray_mask.c +682 -316
  86. data/ext/carray_math_kernel.h +1 -0
  87. data/ext/carray_median_percentile.c +221 -76
  88. data/ext/carray_memory_view.c +254 -248
  89. data/ext/carray_operator.c +1089 -359
  90. data/ext/carray_order.c +133 -69
  91. data/ext/carray_partition.c +102 -56
  92. data/ext/carray_random.c +273 -239
  93. data/ext/carray_scatter.c +308 -65
  94. data/ext/carray_segment.c +257 -0
  95. data/ext/carray_slab.c +170 -70
  96. data/ext/carray_sort.c +215 -218
  97. data/ext/carray_sort_kernel.c +8 -1
  98. data/ext/carray_struct.c +99 -21
  99. data/ext/carray_test.c +167 -64
  100. data/ext/carray_time_text.c +1182 -0
  101. data/ext/carray_utils.c +363 -98
  102. data/ext/extconf.rb +27 -2
  103. data/ext/mk_call_cfunc.rb +0 -2
  104. data/ext/mk_pow5_table.rb +35 -0
  105. data/ext/mkkernel.rb +1076 -846
  106. data/ext/ruby_carray.c +7 -1
  107. data/ext/version.h +4 -4
  108. data/ext/version.rb +4 -2
  109. data/lib/carray/attribute.rb +39 -0
  110. data/lib/carray/autoload_carray.rb +19 -0
  111. data/lib/carray/autoload_method_extension.rb +6 -0
  112. data/lib/carray/axis_group.rb +174 -26
  113. data/lib/carray/basics.rb +91 -25
  114. data/lib/carray/bincount_nd.rb +6 -0
  115. data/lib/carray/block_iterator.rb +118 -48
  116. data/lib/carray/boolean_reduce.rb +21 -29
  117. data/lib/carray/categorical.rb +94 -26
  118. data/lib/carray/categorical_iterator.rb +333 -826
  119. data/lib/carray/complex.rb +36 -29
  120. data/lib/carray/conditional.rb +94 -7
  121. data/lib/carray/const_string.rb +46 -0
  122. data/lib/carray/frame/concat.rb +157 -6
  123. data/lib/carray/frame/convert.rb +13 -7
  124. data/lib/carray/frame/csv_parser.rb +589 -82
  125. data/lib/carray/frame/describe.rb +79 -0
  126. data/lib/carray/frame/frame.rb +124 -25
  127. data/lib/carray/frame/group.rb +189 -63
  128. data/lib/carray/frame/io.rb +412 -72
  129. data/lib/carray/frame/join.rb +134 -46
  130. data/lib/carray/frame/records.rb +37 -16
  131. data/lib/carray/frame/reshape.rb +448 -0
  132. data/lib/carray/frame/sort.rb +26 -2
  133. data/lib/carray/frame/verbs.rb +715 -48
  134. data/lib/carray/frame.rb +2 -0
  135. data/lib/carray/fuse_source.rb +111 -2
  136. data/lib/carray/fusion.rb +229 -38
  137. data/lib/carray/inspect.rb +29 -11
  138. data/lib/carray/iterator.rb +14 -2
  139. data/lib/carray/lazy.rb +54 -30
  140. data/lib/carray/mask_gap_fill.rb +66 -52
  141. data/lib/carray/math.rb +32 -19
  142. data/lib/carray/meld_reduce.rb +40 -7
  143. data/lib/carray/methods/align_addr.rb +8 -4
  144. data/lib/carray/methods/bincount.rb +2 -2
  145. data/lib/carray/methods/bit_string.rb +14 -3
  146. data/lib/carray/methods/composition.rb +16 -10
  147. data/lib/carray/methods/factorize.rb +2 -2
  148. data/lib/carray/methods/gather_nd.rb +13 -2
  149. data/lib/carray/methods/insert_block.rb +9 -14
  150. data/lib/carray/methods/is_in.rb +117 -4
  151. data/lib/carray/methods/join.rb +1 -1
  152. data/lib/carray/methods/locate_addr.rb +177 -36
  153. data/lib/carray/methods/mode.rb +18 -1
  154. data/lib/carray/methods/repeat.rb +1 -20
  155. data/lib/carray/methods/resize.rb +21 -23
  156. data/lib/carray/methods/snap.rb +34 -12
  157. data/lib/carray/methods/unique.rb +11 -2
  158. data/lib/carray/record_order.rb +208 -0
  159. data/lib/carray/runtime.rb +14 -11
  160. data/lib/carray/segment_iterator.rb +990 -0
  161. data/lib/carray/serialize.rb +197 -27
  162. data/lib/carray/slab_iterator.rb +51 -27
  163. data/lib/carray/stack.rb +10 -4
  164. data/lib/carray/string_operation_extension.rb +4 -3
  165. data/lib/carray/struct.rb +142 -51
  166. data/lib/carray/struct_builder.rb +110 -14
  167. data/lib/carray/table.rb +2 -2
  168. data/lib/carray/time.rb +517 -103
  169. data/lib/carray/window_iterator.rb +127 -72
  170. data/lib/carray.rb +2 -2
  171. data/yard-stubs/ca_obj_array.rb +4 -4
  172. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  173. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  174. data/yard-stubs/ca_obj_fake.rb +1 -1
  175. data/yard-stubs/ca_obj_field.rb +1 -1
  176. data/yard-stubs/ca_obj_refer.rb +3 -3
  177. data/yard-stubs/ca_obj_roll.rb +0 -1
  178. data/yard-stubs/ca_obj_stride.rb +10 -7
  179. data/yard-stubs/ca_obj_transpose.rb +1 -1
  180. data/yard-stubs/ca_obj_window.rb +1 -2
  181. data/yard-stubs/carray_access.rb +5 -4
  182. data/yard-stubs/carray_broadcast.rb +1 -1
  183. data/yard-stubs/carray_cast.rb +78 -43
  184. data/yard-stubs/carray_conversion.rb +13 -1
  185. data/yard-stubs/carray_copy.rb +8 -3
  186. data/yard-stubs/carray_core.rb +3 -3
  187. data/yard-stubs/carray_count.rb +9 -0
  188. data/yard-stubs/carray_lazy.rb +5 -1
  189. data/yard-stubs/carray_loop.rb +4 -1
  190. data/yard-stubs/carray_mask.rb +34 -10
  191. data/yard-stubs/carray_math.rb +25 -13
  192. data/yard-stubs/carray_median_percentile.rb +10 -6
  193. data/yard-stubs/carray_order.rb +34 -13
  194. data/yard-stubs/carray_scatter.rb +10 -3
  195. data/yard-stubs/carray_segment.rb +72 -0
  196. data/yard-stubs/carray_slab.rb +2 -1
  197. data/yard-stubs/carray_sort.rb +43 -3
  198. data/yard-stubs/carray_test.rb +10 -0
  199. data/yard-stubs/carray_utils.rb +0 -26
  200. metadata +11 -19
  201. data/ext/ca_for_each_element.h +0 -239
  202. data/ext/carray_build_flags.h +0 -3
  203. data/ext/carray_config.h +0 -28
  204. data/ext/carray_kernels_bincmp.c +0 -4446
  205. data/ext/carray_kernels_binop.c +0 -11001
  206. data/ext/carray_kernels_init.c +0 -1131
  207. data/ext/carray_kernels_map.c +0 -3467
  208. data/ext/carray_kernels_moncmp.c +0 -2097
  209. data/ext/carray_kernels_monop.c +0 -18313
  210. data/ext/carray_kernels_reduce_aggregate.c +0 -26005
  211. data/ext/carray_kernels_reduce_boolean.c +0 -330
  212. data/ext/carray_kernels_reduce_cumulative.c +0 -14862
  213. data/ext/carray_kernels_reduce_extreme.c +0 -17494
  214. data/ext/carray_kernels_reduce_variance.c +0 -3910
  215. data/ext/carray_kernels_scan.c +0 -3693
  216. data/ext/carray_kernels_search.c +0 -32218
  217. data/ext/carray_kernels_sort.c +0 -10626
  218. data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_axis_group.c CHANGED
@@ -33,6 +33,7 @@
33
33
  --------------------------------------------------------------------------- */
34
34
 
35
35
  #include "carray.h"
36
+ #include "carray_internal.h" /* CA_EXTREMUM_REPLACES, ca_obj_extremum_replaces */
36
37
  #include "ca_kernel_iterator.h"
37
38
  #include <math.h>
38
39
 
@@ -64,8 +65,8 @@ group_op_code (VALUE vop)
64
65
  else if ( id == rb_intern("max_addr") ) return GR_MAXADDR;
65
66
  else if ( id == rb_intern("all") ) return GR_ALL;
66
67
  else if ( id == rb_intern("any") ) return GR_ANY;
67
- rb_raise(rb_eArgError, "axis_group_reduce: unsupported op :%s",
68
- rb_id2name(id));
68
+ rb_raise(rb_eArgError, "axis_group_reduce: unsupported op :%"PRIsVALUE,
69
+ rb_id2str(id));
69
70
  }
70
71
 
71
72
  /* ---- per-slab-element composite-code walk, templated on the load type ----
@@ -206,16 +207,16 @@ group_op_code (VALUE vop)
206
207
  only while nothing else has landed, the first number displaces it, and a
207
208
  group of nothing but NaN answers NaN (for a position, UNDEF). `v` is the
208
209
  widened load, so testing it for NaN is the same question for every source
209
- type and costs an integer body nothing. seen_num[] says whether a number
210
- has landed; cnt[] still says whether anything has. */
210
+ type and costs an integer body nothing. The replacement test is the
211
+ shared CA_EXTREMUM_REPLACES; the first member is taken whatever it is.
212
+ seen_num[] says whether a number has landed (the positions read it);
213
+ cnt[] says whether anything has. */
211
214
  #define GMINMAX(T, A, CMP) \
212
215
  do { \
213
216
  A *acc = (A *) co->ptr; \
214
217
  A av = (A) rv; \
215
- if ( v == v ) { \
216
- if ( ! seen_num[o] ) { acc[o] = av; seen_num[o] = 1; } \
217
- else if ( av CMP acc[o] ) acc[o] = av; \
218
- } else if ( cnt[o] == 0 ) acc[o] = av; \
218
+ if ( cnt[o] == 0 || CA_EXTREMUM_REPLACES(av, acc[o], CMP) ) acc[o] = av; \
219
+ if ( v == v ) seen_num[o] = 1; \
219
220
  cnt[o] += 1; \
220
221
  } while (0)
221
222
 
@@ -310,7 +311,7 @@ group_op_code (VALUE vop)
310
311
  Empty / all-masked groups follow the CArray zero-contribution contract: an
311
312
  identity-bearing op returns its identity (sum 0, prod 1, count 0, all true,
312
313
  any false), a ratio / extremum returns UNDEF. Sample variance / stddev:
313
- n == 0 UNDEF, n == 1 -> 0.0, n >= 2 the formula.
314
+ n < 2 UNDEF, n >= 2 the formula.
314
315
  */
315
316
  static VALUE
316
317
  rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
@@ -321,7 +322,7 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
321
322
  GetCArray(self, src);
322
323
 
323
324
  if ( src->ndim <= 0 ) {
324
- rb_raise(rb_eRuntimeError, "axis_group_reduce: scalar source");
325
+ rb_raise(rb_eArgError, "axis_group_reduce: scalar source");
325
326
  }
326
327
 
327
328
  /* --- group (slab) axes --- */
@@ -393,9 +394,7 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
393
394
  size_t nbytes = (size_t) bundle_ca[bi]->elements * sizeof(int32_t);
394
395
  VALUE vbuf = rb_str_tmp_new((long) nbytes);
395
396
  rb_ary_push((VALUE) keep, vbuf);
396
- ca_attach(bundle_ca[bi]);
397
- memcpy(RSTRING_PTR(vbuf), bundle_ca[bi]->ptr, nbytes);
398
- ca_detach(bundle_ca[bi]);
397
+ ca_copy_data(bundle_ca[bi], RSTRING_PTR(vbuf));
399
398
  bundle_codes[bi] = (int32_t *) RSTRING_PTR(vbuf);
400
399
  }
401
400
 
@@ -477,9 +476,9 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
477
476
  case CA_INT32: case CA_UINT32: case CA_INT64: case CA_UINT64:
478
477
  case CA_FLOAT32: case CA_FLOAT64: break;
479
478
  default:
480
- rb_raise(rb_eRuntimeError,
481
- "axis_group_reduce: unsupported source data_type %d",
482
- src->data_type);
479
+ rb_raise(rb_eCADataTypeError,
480
+ "axis_group: %"PRIsVALUE" over a group is not supported for data type %s",
481
+ rb_sym2str(vop), ca_type_name[src->data_type]);
483
482
  }
484
483
 
485
484
  /* output data type per op */
@@ -618,8 +617,8 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
618
617
  /* Empty / all-masked groups follow the same zero-contribution contract as
619
618
  CArray reductions (ERI, matching the categorical sibling): an identity-
620
619
  bearing op returns its identity (sum 0, prod 1, count 0, all true, any
621
- false), a ratio / extremum returns UNDEF. Sample variance/stddev: n==0
622
- UNDEF, n==1 -> 0.0 (the n=1 contract), n>=2 the formula. */
620
+ false), a ratio / extremum returns UNDEF. Sample variance/stddev: n<2
621
+ UNDEF (n-1 is zero), n>=2 the formula. */
623
622
  if ( op == GR_COUNT ) {
624
623
  int64_t *out = (int64_t *) co->ptr;
625
624
  for ( ca_size_t o = 0; o < nout; o++ ) out[o] = (int64_t) cnt[o];
@@ -664,8 +663,7 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
664
663
  break;
665
664
  case GR_VARIANCE:
666
665
  case GR_STDDEV:
667
- if ( cnt[o] == 0 ) { out[o] = 0.0; MARK_UNDEF(o); }
668
- else if ( cnt[o] == 1 ) { out[o] = 0.0; } /* n=1 contract */
666
+ if ( cnt[o] < 2 ) { out[o] = 0.0; MARK_UNDEF(o); }
669
667
  else { double var = sumsq[o] / ( (double) cnt[o] - 1.0 );
670
668
  out[o] = ( op == GR_STDDEV ) ? sqrt(var) : var; }
671
669
  break;
@@ -854,7 +852,9 @@ group_scan_build_plan (ca_iter_state *st, boolean8_t *m,
854
852
  emits its own value: a per-group `seen` byte initialises the accumulator
855
853
  lazily on first hit — no sentinel like HUGE_VAL, which an integer data type could
856
854
  not represent. CMP is > for max, < for min: a later member replaces the
857
- running extremum when `rv CMP acc`. A cell masked within its group holds the
855
+ running extremum when CA_EXTREMUM_REPLACES (a NaN never does, and a
856
+ number displaces a leading NaN, as the core cummax / cummin and the
857
+ reduce twins above do). A cell masked within its group holds the
858
858
  current extremum once a member has been seen (output NOT masked, like sum);
859
859
  before any member the extremum is undefined so the cell stays UNDEF (the
860
860
  CArray reduction contract: empty max/min has no value — deliberately NOT the
@@ -895,7 +895,9 @@ group_scan_build_plan (ca_iter_state *st, boolean8_t *m,
895
895
  } \
896
896
  T rv = *(T *)(p + sw_doff[e]); \
897
897
  if ( ! seen[code] ) { acce[code] = rv; seen[code] = 1; } \
898
- else if ( rv CMP acce[code] ) { acce[code] = rv; } \
898
+ else if ( CA_EXTREMUM_REPLACES(rv, acce[code], CMP) ) { \
899
+ acce[code] = rv; \
900
+ } \
899
901
  outp[addr] = acce[code]; \
900
902
  } \
901
903
  } \
@@ -933,19 +935,19 @@ group_scan_build_plan (ca_iter_state *st, boolean8_t *m,
933
935
  both unmasked (matching core object cumsum / cumprod); cummax / cummin hold
934
936
  the running VALUE only once a member has been seen and stay UNDEF before that
935
937
  (no identity for arbitrary objects). GW_SKIP (excluded) stays UNDEF. accn /
936
- seen are reset at each band; acco carries the running VALUE. */
938
+ seen are reset at each band; acco carries the running VALUE.
939
+ Expanded only in group_scan_object_body, whose walk state is c->st. */
937
940
  #define GROUP_SCAN_OBJECT_WALK(EMIT, HOLD) \
938
941
  do { \
939
- ca_iter_state st; \
940
942
  char *p; \
941
943
  boolean8_t *m; \
942
944
  ca_size_t b = 0; \
943
945
  int ready = 0; \
944
- CA_FOR_EACH_SLAB(st, ca, axes, (int8_t) ngroup, CA_KERNEL_READ, p, m) { \
945
- ca_size_t SE = st.slab_elements; \
946
+ CA_FOR_EACH_SLAB(c->st, ca, axes, (int8_t) ngroup, CA_KERNEL_READ, p, m) {\
947
+ ca_size_t SE = c->st.slab_elements; \
946
948
  if ( SE > 0 ) { \
947
949
  if ( ! ready ) { \
948
- group_scan_build_plan(&st, m, n_bundles, bundle_codes, bundle_k, \
950
+ group_scan_build_plan(&c->st, m, n_bundles, bundle_codes, bundle_k,\
949
951
  bundle_placeval, bundle_nconsumed, \
950
952
  bundle_slot, bundle_cstride, ngroup, \
951
953
  grstride, sw_code, sw_doff, sw_moff, sw_addr);\
@@ -970,6 +972,137 @@ group_scan_build_plan (ca_iter_state *st, boolean8_t *m,
970
972
  } \
971
973
  } while (0)
972
974
 
975
+ /* Marks output cell o UNDEF, creating the output mask on first use. Used
976
+ by the scan walks, in functions that hold the output as `co` and the mask
977
+ pointer as `omask`. */
978
+ #define MARK_OUT_UNDEF(o) do { \
979
+ if ( ! omask ) { \
980
+ ca_create_mask(co); \
981
+ omask = (boolean8_t *) co->mask->ptr; \
982
+ } \
983
+ omask[o] = 1; \
984
+ } while (0)
985
+
986
+ /* The CA_OBJECT lane of __axis_group_scan__. Every cell calls into Ruby,
987
+ so the walk can raise part way; its state lives in the caller's frame, in
988
+ c->st, and ca_iter_ensure finishes it however this body leaves. The
989
+ buffers are ALLOCV-backed, so the unwind collects them. */
990
+ typedef struct {
991
+ ca_iter_state st;
992
+ CArray *ca;
993
+ CArray *co;
994
+ int op;
995
+ int8_t *axes;
996
+ long ngroup;
997
+ int n_bundles;
998
+ int32_t **bundle_codes;
999
+ ca_size_t *bundle_k;
1000
+ ca_size_t *bundle_placeval;
1001
+ int *bundle_nconsumed;
1002
+ int (*bundle_slot)[CA_RANK_MAX];
1003
+ ca_size_t (*bundle_cstride)[CA_RANK_MAX];
1004
+ ca_size_t *grstride;
1005
+ ca_size_t *band_addr;
1006
+ ca_size_t K_total;
1007
+ ca_size_t *sw_code;
1008
+ ca_size_t *sw_doff;
1009
+ ca_size_t *sw_moff;
1010
+ ca_size_t *sw_addr;
1011
+ ca_size_t *accn;
1012
+ char *seen;
1013
+ VALUE *acco;
1014
+ } group_scan_object_t;
1015
+
1016
+ static VALUE
1017
+ group_scan_object_body (VALUE arg)
1018
+ {
1019
+ group_scan_object_t *c = (group_scan_object_t *) arg;
1020
+ CArray *ca = c->ca;
1021
+ CArray *co = c->co;
1022
+ int op = c->op;
1023
+ int8_t *axes = c->axes;
1024
+ long ngroup = c->ngroup;
1025
+ int n_bundles = c->n_bundles;
1026
+ int32_t **bundle_codes = c->bundle_codes;
1027
+ ca_size_t *bundle_k = c->bundle_k;
1028
+ ca_size_t *bundle_placeval = c->bundle_placeval;
1029
+ int *bundle_nconsumed = c->bundle_nconsumed;
1030
+ int (*bundle_slot)[CA_RANK_MAX] = c->bundle_slot;
1031
+ ca_size_t (*bundle_cstride)[CA_RANK_MAX] = c->bundle_cstride;
1032
+ ca_size_t *grstride = c->grstride;
1033
+ ca_size_t *band_addr = c->band_addr;
1034
+ ca_size_t K_total = c->K_total;
1035
+ ca_size_t *sw_code = c->sw_code;
1036
+ ca_size_t *sw_doff = c->sw_doff;
1037
+ ca_size_t *sw_moff = c->sw_moff;
1038
+ ca_size_t *sw_addr = c->sw_addr;
1039
+ ca_size_t *accn = c->accn;
1040
+ char *seen = c->seen;
1041
+ VALUE *acco = c->acco;
1042
+ boolean8_t *omask = NULL;
1043
+
1044
+ if ( op == GS_CUMCOUNT ) { /* int64 1-based running count */
1045
+ int64_t *outi = (int64_t *) co->ptr;
1046
+ GROUP_SCAN_OBJECT_WALK(
1047
+ accn[code] += 1; outi[addr] = (int64_t) accn[code];,
1048
+ outi[addr] = (int64_t) accn[code];
1049
+ );
1050
+ }
1051
+ else { /* object running VALUE */
1052
+ VALUE *outo = (VALUE *) co->ptr;
1053
+ switch ( op ) {
1054
+ case GS_CUMSUM:
1055
+ /* Identity 0 (matching the core object cumsum): a group's acc is lazily
1056
+ seeded to 0 (Fixnum, so 0 + ev promotes to ev's class), so a cell
1057
+ masked before any present member holds 0 unmasked and an all-masked
1058
+ group yields 0 everywhere. seen doubles as the per-band init flag. */
1059
+ GROUP_SCAN_OBJECT_WALK(
1060
+ if ( ! seen[code] ) { acco[code] = INT2FIX(0); seen[code] = 1; }
1061
+ acco[code] = rb_funcall(acco[code], rb_intern("+"), 1, ev);
1062
+ outo[addr] = acco[code];,
1063
+ if ( ! seen[code] ) { acco[code] = INT2FIX(0); seen[code] = 1; }
1064
+ outo[addr] = acco[code];
1065
+ );
1066
+ break;
1067
+ case GS_CUMPROD:
1068
+ /* Identity 1, same lazy-init as cumsum. */
1069
+ GROUP_SCAN_OBJECT_WALK(
1070
+ if ( ! seen[code] ) { acco[code] = INT2FIX(1); seen[code] = 1; }
1071
+ acco[code] = rb_funcall(acco[code], rb_intern("*"), 1, ev);
1072
+ outo[addr] = acco[code];,
1073
+ if ( ! seen[code] ) { acco[code] = INT2FIX(1); seen[code] = 1; }
1074
+ outo[addr] = acco[code];
1075
+ );
1076
+ break;
1077
+ case GS_CUMMAX:
1078
+ /* No identity: seed from the first member, hold only once seen; a cell
1079
+ masked before any member stays UNDEF (empty-max contract). */
1080
+ GROUP_SCAN_OBJECT_WALK(
1081
+ if ( ! seen[code] ) { acco[code] = ev; seen[code] = 1; }
1082
+ else if ( ca_obj_extremum_replaces(ev, acco[code], rb_intern(">")) ) {
1083
+ acco[code] = ev;
1084
+ }
1085
+ outo[addr] = acco[code];,
1086
+ if ( seen[code] ) { outo[addr] = acco[code]; }
1087
+ else { MARK_OUT_UNDEF(addr); }
1088
+ );
1089
+ break;
1090
+ case GS_CUMMIN:
1091
+ GROUP_SCAN_OBJECT_WALK(
1092
+ if ( ! seen[code] ) { acco[code] = ev; seen[code] = 1; }
1093
+ else if ( ca_obj_extremum_replaces(ev, acco[code], rb_intern("<")) ) {
1094
+ acco[code] = ev;
1095
+ }
1096
+ outo[addr] = acco[code];,
1097
+ if ( seen[code] ) { outo[addr] = acco[code]; }
1098
+ else { MARK_OUT_UNDEF(addr); }
1099
+ );
1100
+ break;
1101
+ }
1102
+ }
1103
+ return Qnil;
1104
+ }
1105
+
973
1106
  static int
974
1107
  group_scan_op_code (VALUE vop)
975
1108
  {
@@ -979,7 +1112,7 @@ group_scan_op_code (VALUE vop)
979
1112
  else if ( id == rb_intern("cummax") ) return GS_CUMMAX;
980
1113
  else if ( id == rb_intern("cummin") ) return GS_CUMMIN;
981
1114
  else if ( id == rb_intern("cumprod") ) return GS_CUMPROD;
982
- rb_raise(rb_eArgError, "axis_group_scan: unsupported op :%s", rb_id2name(id));
1115
+ rb_raise(rb_eArgError, "axis_group_scan: unsupported op :%"PRIsVALUE, rb_id2str(id));
983
1116
  }
984
1117
 
985
1118
  /* __axis_group_scan__(group_axes, bundles, op) — group-keyed segment scan of
@@ -1022,7 +1155,7 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1022
1155
  GetCArray(self, src);
1023
1156
 
1024
1157
  if ( src->ndim <= 0 ) {
1025
- rb_raise(rb_eRuntimeError, "axis_group_scan: scalar source");
1158
+ rb_raise(rb_eArgError, "axis_group_scan: scalar source");
1026
1159
  }
1027
1160
 
1028
1161
  /* --- group (slab) axes (same validation as reduce) --- */
@@ -1096,9 +1229,7 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1096
1229
  size_t nbytes = (size_t) bundle_ca[bi]->elements * sizeof(int32_t);
1097
1230
  VALUE vbuf = rb_str_tmp_new((long) nbytes);
1098
1231
  rb_ary_push((VALUE) keep, vbuf);
1099
- ca_attach(bundle_ca[bi]);
1100
- memcpy(RSTRING_PTR(vbuf), bundle_ca[bi]->ptr, nbytes);
1101
- ca_detach(bundle_ca[bi]);
1232
+ ca_copy_data(bundle_ca[bi], RSTRING_PTR(vbuf));
1102
1233
  bundle_codes[bi] = (int32_t *) RSTRING_PTR(vbuf);
1103
1234
  }
1104
1235
 
@@ -1160,7 +1291,7 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1160
1291
  case CA_INT32: case CA_UINT32: case CA_INT64: case CA_UINT64:
1161
1292
  case CA_FLOAT32: case CA_FLOAT64: case CA_OBJECT: break;
1162
1293
  default:
1163
- rb_raise(rb_eRuntimeError,
1294
+ rb_raise(rb_eCADataTypeError,
1164
1295
  "axis_group_scan: unsupported source data_type %d",
1165
1296
  src->data_type);
1166
1297
  }
@@ -1232,75 +1363,23 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1232
1363
  double acc_init = ( op == GS_CUMPROD ) ? 1.0 : 0.0;
1233
1364
 
1234
1365
  boolean8_t *omask = NULL;
1235
- #define MARK_OUT_UNDEF(o) do { \
1236
- if ( ! omask ) { \
1237
- ca_create_mask(co); \
1238
- omask = (boolean8_t *) co->mask->ptr; \
1239
- } \
1240
- omask[o] = 1; \
1241
- } while (0)
1242
1366
 
1243
1367
  if ( src->data_type == CA_OBJECT ) {
1244
- if ( op == GS_CUMCOUNT ) { /* int64 1-based running count */
1245
- int64_t *outi = (int64_t *) co->ptr;
1246
- GROUP_SCAN_OBJECT_WALK(
1247
- accn[code] += 1; outi[addr] = (int64_t) accn[code];,
1248
- outi[addr] = (int64_t) accn[code];
1249
- );
1250
- }
1251
- else { /* object running VALUE */
1252
- VALUE *outo = (VALUE *) co->ptr;
1368
+ group_scan_object_t c;
1369
+ if ( op != GS_CUMCOUNT ) {
1253
1370
  acco = ALLOCV_N(VALUE, h_acco, K_total);
1254
- switch ( op ) {
1255
- case GS_CUMSUM:
1256
- /* Identity 0 (matching the core object cumsum): a group's acc is lazily
1257
- seeded to 0 (Fixnum, so 0 + ev promotes to ev's class), so a cell
1258
- masked before any present member holds 0 unmasked and an all-masked
1259
- group yields 0 everywhere. seen doubles as the per-band init flag. */
1260
- GROUP_SCAN_OBJECT_WALK(
1261
- if ( ! seen[code] ) { acco[code] = INT2FIX(0); seen[code] = 1; }
1262
- acco[code] = rb_funcall(acco[code], rb_intern("+"), 1, ev);
1263
- outo[addr] = acco[code];,
1264
- if ( ! seen[code] ) { acco[code] = INT2FIX(0); seen[code] = 1; }
1265
- outo[addr] = acco[code];
1266
- );
1267
- break;
1268
- case GS_CUMPROD:
1269
- /* Identity 1, same lazy-init as cumsum. */
1270
- GROUP_SCAN_OBJECT_WALK(
1271
- if ( ! seen[code] ) { acco[code] = INT2FIX(1); seen[code] = 1; }
1272
- acco[code] = rb_funcall(acco[code], rb_intern("*"), 1, ev);
1273
- outo[addr] = acco[code];,
1274
- if ( ! seen[code] ) { acco[code] = INT2FIX(1); seen[code] = 1; }
1275
- outo[addr] = acco[code];
1276
- );
1277
- break;
1278
- case GS_CUMMAX:
1279
- /* No identity: seed from the first member, hold only once seen; a cell
1280
- masked before any member stays UNDEF (empty-max contract). */
1281
- GROUP_SCAN_OBJECT_WALK(
1282
- if ( ! seen[code] ) { acco[code] = ev; seen[code] = 1; }
1283
- else if ( NUM2INT(rb_funcall(ev, rb_intern("<=>"), 1, acco[code])) > 0 ) {
1284
- acco[code] = ev;
1285
- }
1286
- outo[addr] = acco[code];,
1287
- if ( seen[code] ) { outo[addr] = acco[code]; }
1288
- else { MARK_OUT_UNDEF(addr); }
1289
- );
1290
- break;
1291
- case GS_CUMMIN:
1292
- GROUP_SCAN_OBJECT_WALK(
1293
- if ( ! seen[code] ) { acco[code] = ev; seen[code] = 1; }
1294
- else if ( NUM2INT(rb_funcall(ev, rb_intern("<=>"), 1, acco[code])) < 0 ) {
1295
- acco[code] = ev;
1296
- }
1297
- outo[addr] = acco[code];,
1298
- if ( seen[code] ) { outo[addr] = acco[code]; }
1299
- else { MARK_OUT_UNDEF(addr); }
1300
- );
1301
- break;
1302
- }
1303
1371
  }
1372
+ c.ca = ca; c.co = co; c.op = op;
1373
+ c.axes = axes; c.ngroup = ngroup;
1374
+ c.n_bundles = n_bundles; c.bundle_codes = bundle_codes;
1375
+ c.bundle_k = bundle_k; c.bundle_placeval = bundle_placeval;
1376
+ c.bundle_nconsumed = bundle_nconsumed;
1377
+ c.bundle_slot = bundle_slot; c.bundle_cstride = bundle_cstride;
1378
+ c.grstride = grstride; c.band_addr = band_addr; c.K_total = K_total;
1379
+ c.sw_code = sw_code; c.sw_doff = sw_doff;
1380
+ c.sw_moff = sw_moff; c.sw_addr = sw_addr;
1381
+ c.accn = accn; c.seen = seen; c.acco = acco;
1382
+ ca_iter_ensure(1, &c.st, group_scan_object_body, (VALUE) &c);
1304
1383
  }
1305
1384
  else { /* native data type dispatch */
1306
1385
  switch ( op ) {
@@ -1330,7 +1409,6 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1330
1409
  break;
1331
1410
  }
1332
1411
  }
1333
- #undef MARK_OUT_UNDEF
1334
1412
 
1335
1413
  ALLOCV_END(h_band2); ALLOCV_END(h_code); ALLOCV_END(h_doff);
1336
1414
  ALLOCV_END(h_moff); ALLOCV_END(h_addr); ALLOCV_END(h_accd);
@@ -27,39 +27,56 @@
27
27
  /* vv kernel lookup */
28
28
  /* ------------------------------------------------------------------- */
29
29
 
30
+ /* The kernel table of each op id. The eager operators hold the tables
31
+ themselves; ca_binop_op_id_of_table maps one back to its op id, so that
32
+ both ask ca_binop_is_trapping the same question. */
33
+ static ca_binop_func_t * const ca_binop_tables[CA_BINOP_COUNT] = {
34
+ [CA_BINOP_ADD] = ca_binop_add,
35
+ [CA_BINOP_SUB] = ca_binop_sub,
36
+ [CA_BINOP_MUL] = ca_binop_mul,
37
+ [CA_BINOP_DIV] = ca_binop_div,
38
+ [CA_BINOP_POW] = ca_binop_power,
39
+ [CA_BINOP_BIT_AND] = ca_binop_bit_and_i,
40
+ [CA_BINOP_BIT_OR] = ca_binop_bit_or_i,
41
+ [CA_BINOP_BIT_XOR] = ca_binop_bit_xor_i,
42
+ [CA_BINOP_BIT_LSHIFT]= ca_binop_bit_lshift,
43
+ [CA_BINOP_BIT_RSHIFT]= ca_binop_bit_rshift,
44
+ [CA_BINOP_MOD] = ca_binop_mod,
45
+ [CA_BINOP_QUO] = ca_binop_quo_i,
46
+ [CA_BINOP_RCP_MUL] = ca_binop_rcp_mul,
47
+ [CA_BINOP_IPOWER] = ca_binop_ipower,
48
+ [CA_BINOP_COPYSIGN] = ca_binop_copysign,
49
+ [CA_BINOP_LOGADDEXP] = ca_binop_logaddexp,
50
+ [CA_BINOP_NEXTAFTER] = ca_binop_nextafter,
51
+ [CA_BINOP_FMOD] = ca_binop_fmod,
52
+ [CA_BINOP_ATAN2] = ca_binop_atan2,
53
+ [CA_BINOP_HYPOT] = ca_binop_hypot,
54
+ [CA_BINOP_PMAX] = ca_binop_pmax,
55
+ [CA_BINOP_PMIN] = ca_binop_pmin,
56
+ [CA_BINOP_MAXIMUM] = ca_binop_maximum,
57
+ [CA_BINOP_MINIMUM] = ca_binop_minimum,
58
+ [CA_BINOP_AND] = ca_binop_and,
59
+ [CA_BINOP_OR] = ca_binop_or,
60
+ [CA_BINOP_XOR] = ca_binop_xor,
61
+ };
62
+
30
63
  ca_binop_func_t
31
64
  ca_binop_kernel_lookup_vv (uint16_t op_id, int8_t common_dt)
32
65
  {
33
- switch (op_id) {
34
- case CA_BINOP_ADD: return ca_binop_add [common_dt];
35
- case CA_BINOP_SUB: return ca_binop_sub [common_dt];
36
- case CA_BINOP_MUL: return ca_binop_mul [common_dt];
37
- case CA_BINOP_DIV: return ca_binop_div [common_dt];
38
- case CA_BINOP_POW: return ca_binop_power [common_dt];
39
- case CA_BINOP_BIT_AND: return ca_binop_bit_and_i [common_dt];
40
- case CA_BINOP_BIT_OR: return ca_binop_bit_or_i [common_dt];
41
- case CA_BINOP_BIT_XOR: return ca_binop_bit_xor_i [common_dt];
42
- case CA_BINOP_BIT_LSHIFT: return ca_binop_bit_lshift [common_dt];
43
- case CA_BINOP_BIT_RSHIFT: return ca_binop_bit_rshift [common_dt];
44
- case CA_BINOP_MOD: return ca_binop_mod [common_dt];
45
- case CA_BINOP_QUO: return ca_binop_quo_i [common_dt];
46
- case CA_BINOP_RCP_MUL: return ca_binop_rcp_mul [common_dt];
47
- case CA_BINOP_IPOWER: return ca_binop_ipower [common_dt];
48
- case CA_BINOP_COPYSIGN: return ca_binop_copysign [common_dt];
49
- case CA_BINOP_LOGADDEXP: return ca_binop_logaddexp [common_dt];
50
- case CA_BINOP_NEXTAFTER: return ca_binop_nextafter [common_dt];
51
- case CA_BINOP_FMOD: return ca_binop_fmod [common_dt];
52
- case CA_BINOP_ATAN2: return ca_binop_atan2 [common_dt];
53
- case CA_BINOP_HYPOT: return ca_binop_hypot [common_dt];
54
- case CA_BINOP_PMAX: return ca_binop_pmax [common_dt];
55
- case CA_BINOP_PMIN: return ca_binop_pmin [common_dt];
56
- case CA_BINOP_MAXIMUM: return ca_binop_maximum [common_dt];
57
- case CA_BINOP_MINIMUM: return ca_binop_minimum [common_dt];
58
- case CA_BINOP_AND: return ca_binop_and [common_dt];
59
- case CA_BINOP_OR: return ca_binop_or [common_dt];
60
- case CA_BINOP_XOR: return ca_binop_xor [common_dt];
61
- default: return NULL;
66
+ if ( op_id >= CA_BINOP_COUNT || ! ca_binop_tables[op_id] ) return NULL;
67
+ return ca_binop_tables[op_id][common_dt];
68
+ }
69
+
70
+ /* The op id whose kernel table is `table`, or -1 for a table no op id
71
+ names. */
72
+ int
73
+ ca_binop_op_id_of_table (ca_binop_func_t table[])
74
+ {
75
+ int op_id;
76
+ for ( op_id = 0; op_id < CA_BINOP_COUNT; op_id++ ) {
77
+ if ( ca_binop_tables[op_id] == table ) return op_id;
62
78
  }
79
+ return -1;
63
80
  }
64
81
 
65
82
  /* ------------------------------------------------------------------- */
@@ -106,10 +123,12 @@ ca_binop_kernel_input_data_types (uint16_t op_id, int8_t l_dt, int8_t r_dt,
106
123
  int
107
124
  ca_binop_is_trapping (uint16_t op_id, int8_t common_dt)
108
125
  {
109
- /* Integer DIV / MOD / QUO / FMOD can SIGFPE on a zero divisor. Float
110
- DIV returns NaN/Inf and does NOT trap, so it is not classified
111
- trapping. */
126
+ /* An object cell calls Ruby, which can raise for any op. Integer
127
+ DIV / MOD / QUO / FMOD / RCP_MUL raise on a zero divisor, and POW /
128
+ IPOWER on zero to a negative power. Float division returns NaN/Inf
129
+ and does not trap. */
112
130
  int is_integer = ( common_dt >= CA_INT8 && common_dt <= CA_UINT64 );
131
+ if ( common_dt == CA_OBJECT ) return 1;
113
132
  if ( ! is_integer ) return 0;
114
133
 
115
134
  switch (op_id) {
@@ -117,6 +136,9 @@ ca_binop_is_trapping (uint16_t op_id, int8_t common_dt)
117
136
  case CA_BINOP_MOD:
118
137
  case CA_BINOP_QUO:
119
138
  case CA_BINOP_FMOD:
139
+ case CA_BINOP_RCP_MUL:
140
+ case CA_BINOP_POW:
141
+ case CA_BINOP_IPOWER:
120
142
  return 1;
121
143
  default:
122
144
  return 0;
@@ -148,5 +148,6 @@ void ca_binop_kernel_input_data_types (uint16_t op_id, int8_t l_dt, int8_t r_dt,
148
148
  a slab mask to the kernel so masked cells are skipped (otherwise
149
149
  masked-zero divisors crash with SIGFPE). See §3.4 rev3. */
150
150
  int ca_binop_is_trapping (uint16_t op_id, int8_t common_dt);
151
+ int ca_binop_op_id_of_table (ca_binop_func_t table[]);
151
152
 
152
153
  #endif /* CA_BINOP_DISPATCH_H */