carray 3.0.2 → 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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. data/lib/carray/table.rb +0 -108
data/ext/ca_obj_bincmp.c CHANGED
@@ -10,7 +10,8 @@
10
10
 
11
11
  Dispatch by data_type:
12
12
  numeric (i8..f64, +complex) -> ca_bincmp_<op>_<type> kernel
13
- boolean / fixlen / object -> not implemented (raise)
13
+ fixlen -> ca_bincmp_<op>_fixlen (memcmp)
14
+ object -> ca_bincmp_<op>_VALUE
14
15
 
15
16
  CAREFUL: the binop in-place trick (= pull left into the output
16
17
  buffer) is structurally unavailable here — the output is
@@ -33,7 +34,6 @@
33
34
 
34
35
  extern VALUE ca_broadcast_view (VALUE src, int8_t ndim,
35
36
  ca_size_t *target_dim);
36
- extern VALUE ca_lazy_wrap_scalar (VALUE other, CArray *self_ca);
37
37
  extern void *ca_lazy_arena_acquire (ca_size_t bytes);
38
38
  extern void ca_lazy_arena_release (void *ptr);
39
39
 
@@ -74,10 +74,12 @@ typedef struct CABinCmp {
74
74
  target of both left & right, also the
75
75
  kernel lookup key) */
76
76
  double eps; /* Runtime tolerance slot for IS_CLOSE /
77
- IS_EQUIV; ignored for other ops. The
78
- `eps` name is retained to keep the
79
- `__eps__` Ruby accessor stable across
80
- the dual purpose. */
77
+ IS_EQUIV; ignored for other ops. */
78
+ int8_t sign_fix; /* 0, or the side (1 left, 2 right) of an
79
+ int64 operand compared with a uint64 one:
80
+ the kernel compares both as uint64 and
81
+ the cells where it is negative are
82
+ answered after */
81
83
  CArray *operands[2]; /* {left, right}; what parents points at */
82
84
  } CABinCmp;
83
85
 
@@ -143,6 +145,15 @@ ca_bincmp_setup (CABinCmp *ca, CArray *left, CArray *right, uint16_t op_id,
143
145
  ca->right_is_scalar = ( right->elements == 1 && left->elements > 1 ) ? 1 : 0;
144
146
  /* Builder has already cast both operands to common data_type. */
145
147
  ca->common_dt = left->data_type;
148
+ ca->sign_fix = 0;
149
+ if ( left->data_type == CA_INT64 && right->data_type == CA_UINT64 ) {
150
+ ca->common_dt = CA_UINT64;
151
+ ca->sign_fix = 1;
152
+ }
153
+ else if ( left->data_type == CA_UINT64 && right->data_type == CA_INT64 ) {
154
+ ca->common_dt = CA_UINT64;
155
+ ca->sign_fix = 2;
156
+ }
146
157
  ca->eps = eps;
147
158
  ca->operands[0] = left;
148
159
  ca->operands[1] = right;
@@ -165,6 +176,7 @@ ca_bincmp_setup (CABinCmp *ca, CArray *left, CArray *right, uint16_t op_id,
165
176
  CABinCmp *
166
177
  ca_bincmp_new (CArray *left, CArray *right, uint16_t op_id, double eps)
167
178
  {
179
+ /* check: the setup checks nothing */
168
180
  CABinCmp *ca = (CABinCmp *) ca_array_alloc(CA_OBJ_BINCMP, left->ndim);
169
181
  ca_bincmp_setup(ca, left, right, op_id, eps);
170
182
  return ca;
@@ -212,7 +224,7 @@ ca_bincmp_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
212
224
  int8_t k;
213
225
 
214
226
  if ( dir != CA_XFER_GET ) {
215
- rb_raise(rb_eRuntimeError, "CABinCmp is read-only (xfer_index PUT)");
227
+ ca_refuse_read_only();
216
228
  }
217
229
 
218
230
  for ( k = ca->ndim - 1; k >= 0; k-- ) {
@@ -223,25 +235,6 @@ ca_bincmp_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
223
235
  ca_bincmp_func_xfer_stride(ca, starts, counts, strides, data, CA_XFER_GET);
224
236
  }
225
237
 
226
- static void
227
- ca_bincmp_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
228
- void *data, int dir)
229
- {
230
- CABinCmp *ca = (CABinCmp *) ap;
231
- ca_size_t i;
232
- char *out = (char *) data;
233
-
234
- if ( dir != CA_XFER_GET ) {
235
- rb_raise(rb_eRuntimeError, "CABinCmp is read-only (xfer_addrs PUT)");
236
- }
237
-
238
- for ( i = 0; i < n; i++ ) {
239
- ca_size_t idx[CA_RANK_MAX];
240
- ca_addr2index((CArray *)ca, addrs[i], idx);
241
- ca_bincmp_func_xfer_index(ca, idx, out + i, CA_XFER_GET);
242
- }
243
- }
244
-
245
238
  /* Test / observability counters — bumped from the xfer_stride hot
246
239
  path so specs can assert scratch acquisition and leaf in-place
247
240
  hit rates without materialising the view. */
@@ -296,59 +289,37 @@ ca_bincmp_try_leaf_inplace (CArray *op, int8_t common_dt,
296
289
  return 1;
297
290
  }
298
291
 
292
+ /* Evaluate the cells a request names into `data` (packed, n cells). */
299
293
  static void
300
- ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
301
- ca_size_t *strides, void *data, int dir)
294
+ ca_bincmp_eval (CABinCmp *bc, const ca_lazy_req_t *req, void *data)
302
295
  {
303
- CABinCmp *bc = (CABinCmp *) ap;
304
- ca_size_t slab_n;
296
+ ca_size_t slab_n = req->n;
305
297
  int8_t k;
306
298
  void *left_scratch, *right_scratch;
307
- ca_size_t operand_bytes;
308
- ca_size_t operand_strides[CA_RANK_MAX];
299
+ ca_size_t left_bytes, right_bytes;
309
300
  ca_size_t right_step;
310
301
  int is_contig;
311
302
  int left_is_inplace = 0; /* skip release for leaf-opt path */
312
303
  int right_is_inplace = 0;
313
304
 
314
- if ( dir != CA_XFER_GET ) {
315
- rb_raise(rb_eRuntimeError, "CABinCmp is read-only (xfer_stride PUT)");
316
- }
317
305
  ca_bincmp_materialise_call_count++;
318
306
 
319
- slab_n = 1;
320
- for ( k = 0; k < bc->ndim; k++ ) slab_n *= counts[k];
321
-
322
- operand_bytes = ca_sizeof[bc->common_dt];
307
+ /* An operand's own bytes, not ca_sizeof[common_dt]: a fixlen cell has no
308
+ width in ca_sizeof, and the two fixlen operands may differ in width. */
309
+ left_bytes = bc->parent->bytes;
310
+ right_bytes = bc->right->bytes;
323
311
 
324
- /* An operand cell is operand_bytes wide where this view's is one byte
325
- (CA_BOOLEAN), so the caller's strides cannot be handed to the operand
326
- pull the way a binop hands them on -- they have to be restated at the
327
- operand's cell size. strides[k] / bytes is the index step, which is
328
- what the two spaces share.
329
-
330
- is_contig says the caller asked for the row-major slab that xfer_all
331
- and attach send. Only then does an operand's own buffer hold the
332
- wanted cells in the packed order the kernel reads them in, so it is
333
- also the only case the leaf in-place path is good for. */
334
- {
335
- ca_size_t native = bc->bytes;
336
- is_contig = 1;
337
- for ( k = bc->ndim - 1; k >= 0; k-- ) {
338
- operand_strides[k] = strides[k] / bc->bytes * operand_bytes;
339
- if ( strides[k] != native ) {
340
- is_contig = 0;
341
- }
342
- native *= bc->dim[k];
343
- }
344
- }
312
+ /* The leaf in-place path reads an operand's own buffer, which holds the
313
+ wanted cells in the order the kernel reads them only for the row-major
314
+ slab that xfer_all and attach send. */
315
+ is_contig = ca_lazy_req_is_packed(req, bc);
345
316
 
346
317
  /* === 1. pull LEFT (leaf in-place read or arena scratch) === */
347
318
  {
348
319
  char *left_inplace = NULL;
349
320
  if ( is_contig &&
350
321
  ca_bincmp_try_leaf_inplace(bc->parent, bc->common_dt,
351
- starts, counts, operand_bytes,
322
+ req->starts, req->counts, left_bytes,
352
323
  &left_inplace) ) {
353
324
  /* Leaf-opt path: use parent->ptr + byte_offset directly. */
354
325
  left_scratch = left_inplace;
@@ -358,10 +329,9 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
358
329
  else {
359
330
  left_scratch = ( bc->common_dt == CA_OBJECT )
360
331
  ? ca_lazy_arena_acquire_object(slab_n)
361
- : ca_lazy_arena_acquire(slab_n * operand_bytes);
332
+ : ca_lazy_arena_acquire(slab_n * left_bytes);
362
333
  ca_bincmp_scratch_acquire_count++;
363
- ca_xfer_stride(bc->parent, starts, counts, operand_strides, left_scratch,
364
- CA_XFER_GET);
334
+ ca_lazy_req_pull(bc->parent, req, left_scratch, CA_XFER_GET);
365
335
  }
366
336
  }
367
337
 
@@ -378,7 +348,7 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
378
348
  for ( k = 0; k < bc->right->ndim; k++ ) one_counts[k] = 1;
379
349
 
380
350
  if ( ca_bincmp_try_leaf_inplace(bc->right, bc->common_dt,
381
- one_starts, one_counts, operand_bytes,
351
+ one_starts, one_counts, right_bytes,
382
352
  &right_inplace) ) {
383
353
  right_scratch = right_inplace;
384
354
  right_is_inplace = 1;
@@ -386,10 +356,10 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
386
356
  }
387
357
  else {
388
358
  ca_size_t one_strides[CA_RANK_MAX];
389
- for ( k = 0; k < bc->right->ndim; k++ ) one_strides[k] = operand_bytes;
359
+ for ( k = 0; k < bc->right->ndim; k++ ) one_strides[k] = right_bytes;
390
360
  right_scratch = ( bc->common_dt == CA_OBJECT )
391
361
  ? ca_lazy_arena_acquire_object(1)
392
- : ca_lazy_arena_acquire(operand_bytes);
362
+ : ca_lazy_arena_acquire(right_bytes);
393
363
  ca_bincmp_scratch_acquire_count++;
394
364
  ca_xfer_stride(bc->right, one_starts, one_counts, one_strides,
395
365
  right_scratch, CA_XFER_GET);
@@ -401,7 +371,7 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
401
371
  char *right_inplace = NULL;
402
372
  if ( is_contig &&
403
373
  ca_bincmp_try_leaf_inplace(bc->right, bc->common_dt,
404
- starts, counts, operand_bytes,
374
+ req->starts, req->counts, right_bytes,
405
375
  &right_inplace) ) {
406
376
  right_scratch = right_inplace;
407
377
  right_is_inplace = 1;
@@ -410,10 +380,9 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
410
380
  else {
411
381
  right_scratch = ( bc->common_dt == CA_OBJECT )
412
382
  ? ca_lazy_arena_acquire_object(slab_n)
413
- : ca_lazy_arena_acquire(slab_n * operand_bytes);
383
+ : ca_lazy_arena_acquire(slab_n * right_bytes);
414
384
  ca_bincmp_scratch_acquire_count++;
415
- ca_xfer_stride(bc->right, starts, counts, operand_strides, right_scratch,
416
- CA_XFER_GET);
385
+ ca_lazy_req_pull(bc->right, req, right_scratch, CA_XFER_GET);
417
386
  }
418
387
  right_step = 1;
419
388
  }
@@ -423,14 +392,16 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
423
392
  * Kernel signature (ext/carray.h):
424
393
  * fn(n, m, ptr1, b1, i1, ptr2, b2, i2, ptr3, b3, i3)
425
394
  *
426
- * Per inspection of generated ca_bincmp_<op>_<data_type>, the `b*` args
427
- * are declared but unused (kernel computes ptr + k*i*sizeof(T)). We
428
- * pass 0 for the base arguments.
395
+ * The `b*` args are the cell widths. The typed kernels step by
396
+ * sizeof(T) and ignore them; the fixlen kernels step and compare by
397
+ * them.
429
398
  *
430
- * Non-trapping: m=NULL (= SIMD fast path). Mask propagation handled
431
- * by create_mask at view construction time.
399
+ * m=NULL (= SIMD fast path) except for object operands, whose cells
400
+ * call Ruby: those skip the masked cells, as the eager comparison
401
+ * does. The output mask comes from create_mask.
432
402
  */
433
403
  {
404
+ boolean8_t *slab_mask = NULL;
434
405
  ca_bincmp_func_t fn = ca_bincmp_kernel_lookup(bc->op_id, bc->common_dt);
435
406
  if ( fn == NULL ) {
436
407
  if ( ! right_is_inplace ) ca_lazy_arena_release(right_scratch);
@@ -439,17 +410,59 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
439
410
  "CABinCmp: kernel not implemented (op_id=%u data_type=%d)",
440
411
  (unsigned) bc->op_id, (int) bc->common_dt);
441
412
  }
442
- fn(slab_n, NULL,
443
- (char *) left_scratch, 0, 1,
444
- (char *) right_scratch, 0, right_step,
445
- (char *) data, 0, 1,
413
+ if ( ca_op_raises_on_cell(CA_OP_KIND_BINCMP, bc->op_id, bc->common_dt) ) {
414
+ slab_mask = ca_lazy_req_mask(req, 2, bc->operands);
415
+ }
416
+ fn(slab_n, slab_mask,
417
+ (char *) left_scratch, left_bytes, 1,
418
+ (char *) right_scratch, right_bytes, right_step,
419
+ (char *) data, 1, 1,
446
420
  bc->eps); /* Runtime tolerance for IS_CLOSE / IS_EQUIV. */
421
+ if ( slab_mask ) ca_lazy_arena_release(slab_mask);
422
+ }
423
+
424
+ if ( bc->sign_fix ) {
425
+ const int64_t *sp = (const int64_t *)
426
+ ( bc->sign_fix == 1 ? left_scratch : right_scratch );
427
+ ca_size_t step = ( bc->sign_fix == 1 ) ? 1 : right_step;
428
+ boolean8_t answer =
429
+ (boolean8_t) ca_bincmp_answer_when_negative(bc->op_id, bc->sign_fix);
430
+ ca_size_t i;
431
+ for ( i = 0; i < slab_n; i++ ) {
432
+ if ( sp[i * step] < 0 ) ((boolean8_t *) data)[i] = answer;
433
+ }
447
434
  }
448
435
 
449
436
  if ( ! right_is_inplace ) ca_lazy_arena_release(right_scratch);
450
437
  if ( ! left_is_inplace ) ca_lazy_arena_release(left_scratch);
451
438
  }
452
439
 
440
+ static void
441
+ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
442
+ ca_size_t *strides, void *data, int dir)
443
+ {
444
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
445
+ ca_lazy_req_t req;
446
+ if ( dir != CA_XFER_GET ) {
447
+ ca_refuse_read_only();
448
+ }
449
+ ca_lazy_req_region(&req, ap, starts, counts, strides);
450
+ ca_bincmp_eval((CABinCmp *) ap, &req, data);
451
+ }
452
+
453
+ /* An address list is evaluated in one pass, as a region is. */
454
+ static void
455
+ ca_bincmp_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
456
+ void *data, int dir)
457
+ {
458
+ ca_lazy_req_t req;
459
+ if ( dir != CA_XFER_GET ) {
460
+ ca_refuse_read_only();
461
+ }
462
+ ca_lazy_req_addrs(&req, n, addrs);
463
+ ca_bincmp_eval((CABinCmp *) ap, &req, data);
464
+ }
465
+
453
466
  static void
454
467
  ca_bincmp_func_xfer_all (void *ap, void *data, int dir)
455
468
  {
@@ -467,7 +480,7 @@ static void
467
480
  ca_bincmp_func_allocate (void *ap)
468
481
  {
469
482
  CABinCmp *ca = (CABinCmp *) ap;
470
- ca->ptr = xmalloc(ca_length(ca));
483
+ ca->ptr = ca_alloc_cells((CArray *) ca);
471
484
  }
472
485
 
473
486
  static void
@@ -484,7 +497,7 @@ ca_bincmp_func_attach (void *ap)
484
497
  int8_t k;
485
498
  ca_size_t s;
486
499
 
487
- ca->ptr = xmalloc(ca_length(ca));
500
+ ca->ptr = ca_alloc_cells((CArray *) ca);
488
501
 
489
502
  s = ca->bytes;
490
503
  for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
@@ -510,48 +523,15 @@ NORETURN(static void ca_bincmp_func_fill_data (void *ap, void *ptr));
510
523
  static void
511
524
  ca_bincmp_func_fill_data (void *ap, void *ptr)
512
525
  {
513
- rb_raise(rb_eRuntimeError, "CABinCmp is read-only (fill_data)");
526
+ ca_refuse_read_only();
514
527
  }
515
528
 
516
- /* mask = left.mask | right.mask, materialised as boolean8_t.
517
- Mirrors CABinOp's create_mask policy. */
529
+ /* mask = left.mask | right.mask, computed on each read (CAMaskOfOperands). */
518
530
  static void
519
531
  ca_bincmp_func_create_mask (void *ap)
520
532
  {
521
533
  CABinCmp *bc = (CABinCmp *) ap;
522
- CArray *l = bc->parent;
523
- CArray *r = bc->right;
524
- CArray *lm = NULL, *rm = NULL;
525
- boolean8_t *dst;
526
- ca_size_t i, n;
527
- int has_l, has_r;
528
-
529
- has_l = ca_has_mask(l);
530
- has_r = ca_has_mask(r);
531
- if ( ! has_l && ! has_r ) return;
532
-
533
- if ( has_l ) lm = l->mask;
534
- if ( has_r ) rm = r->mask;
535
-
536
- bc->mask = (CArray *) carray_new(CA_BOOLEAN, bc->ndim, bc->dim, 0, NULL);
537
- dst = (boolean8_t *) bc->mask->ptr;
538
- n = bc->elements;
539
-
540
- if ( has_l ) ca_attach(lm);
541
- if ( has_r ) ca_attach(rm);
542
-
543
- for ( i = 0; i < n; i++ ) {
544
- boolean8_t a = has_l ? ((boolean8_t *) lm->ptr)[i] : 0;
545
- boolean8_t b = 0;
546
- if ( has_r ) {
547
- ca_size_t ri = bc->right_is_scalar ? 0 : i;
548
- b = ((boolean8_t *) rm->ptr)[ri];
549
- }
550
- dst[i] = (boolean8_t)( a | b );
551
- }
552
-
553
- if ( has_l ) ca_detach(lm);
554
- if ( has_r ) ca_detach(rm);
534
+ bc->mask = ca_lazy_operation_mask((CArray *) bc, CA_LAZY_MASK_OR);
555
535
  }
556
536
 
557
537
  ca_operation_function_t ca_bincmp_func = {
@@ -598,6 +578,14 @@ rb_ca_bincmp_new (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
598
578
  rb_check_carray_object(r_cary);
599
579
  TypedData_Get_Struct(l_cary, CArray, &carray_data_type, l);
600
580
  TypedData_Get_Struct(r_cary, CArray, &carray_data_type, r);
581
+ /* No kernel for the type the builder cast to: refuse as the eager
582
+ comparison does, before anything is allocated. */
583
+ {
584
+ ca_bincmp_func_t fn = ca_bincmp_kernel_lookup(op_id, l->data_type);
585
+ if ( fn == NULL || fn == ca_bincmp_not_implement ) {
586
+ ca_op_refuse_unimplemented(l_cary, l->data_type, rb_eTypeError);
587
+ }
588
+ }
601
589
  ca = ca_bincmp_new(l, r, op_id, eps);
602
590
  obj = ca_wrap_struct(ca);
603
591
  rb_ca_set_parent(obj, l_cary);
@@ -605,26 +593,58 @@ rb_ca_bincmp_new (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
605
593
  return obj;
606
594
  }
607
595
 
596
+ /* An operand taken to data type dt: a scalar by value, an array through a
597
+ cast view so the expression stays lazy. */
598
+ static VALUE
599
+ ca_bincmp_cast_operand (VALUE v, int8_t dt)
600
+ {
601
+ CArray *ca;
602
+ TypedData_Get_Struct(v, CArray, &carray_data_type, ca);
603
+ if ( ca->data_type == dt ) return v;
604
+ if ( rb_obj_is_cscalar(v) ) {
605
+ return rb_funcall(v, rb_intern("to_type"), 1, INT2NUM(dt));
606
+ }
607
+ return rb_funcall(rb_const_get(rb_cObject, rb_intern("CAMonOp")),
608
+ rb_intern("__build__"), 2,
609
+ v, INT2NUM(CA_MONOP_CAST_BASE + dt));
610
+ }
611
+
608
612
  VALUE
609
613
  rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
610
614
  {
611
615
  CArray *l, *r;
612
616
  int8_t l_in_dt, r_in_dt;
617
+ int signed_side = 0;
613
618
  volatile VALUE l_resolved, r_resolved;
614
619
 
615
620
  l_resolved = collapse_marker(l_cary);
616
621
  r_resolved = collapse_marker(r_cary);
617
622
 
618
- /* Scalar wrap — same policy as CABinOp. */
619
- if ( ! rb_obj_is_carray(l_resolved) ) {
620
- rb_check_carray_object(r_resolved);
621
- TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
622
- l_resolved = ca_lazy_wrap_scalar(l_resolved, r);
623
+ switch ( ca_bincmp_integer_prepare(&l_resolved, &r_resolved, op_id,
624
+ &signed_side) ) {
625
+ case 1: return rb_ca_bincmp_build(l_resolved, l_resolved, CA_BINCMP_EQ, eps);
626
+ case 2: return rb_ca_bincmp_build(l_resolved, l_resolved, CA_BINCMP_NE, eps);
627
+ case 3:
628
+ /* The unsigned operand goes to uint64 and the signed one to int64;
629
+ ca_bincmp_setup reads that pair as a comparison to correct. */
630
+ l_resolved = ca_bincmp_cast_operand(l_resolved,
631
+ ( signed_side == 1 ) ? CA_INT64 : CA_UINT64);
632
+ r_resolved = ca_bincmp_cast_operand(r_resolved,
633
+ ( signed_side == 2 ) ? CA_INT64 : CA_UINT64);
634
+ break;
623
635
  }
624
- if ( ! rb_obj_is_carray(r_resolved) ) {
625
- rb_check_carray_object(l_resolved);
626
- TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
627
- r_resolved = ca_lazy_wrap_scalar(r_resolved, l);
636
+
637
+ /* A scalar beside the array (a Ruby value or a CScalar) is wrapped and
638
+ promoted as the eager comparison does it. */
639
+ if ( ! rb_obj_is_carray(l_resolved) || ! rb_obj_is_carray(r_resolved) ||
640
+ rb_obj_is_cscalar(l_resolved) || rb_obj_is_cscalar(r_resolved) ) {
641
+ int l_scalar = ! rb_obj_is_carray(l_resolved) || rb_obj_is_cscalar(l_resolved);
642
+ int r_scalar = ! rb_obj_is_carray(r_resolved) || rb_obj_is_cscalar(r_resolved);
643
+ if ( ! signed_side ) {
644
+ rb_ca_cast_self_or_other(&l_resolved, &r_resolved);
645
+ }
646
+ l_resolved = ca_lazy_settle_scalar(l_resolved, l_scalar);
647
+ r_resolved = ca_lazy_settle_scalar(r_resolved, r_scalar);
628
648
  }
629
649
 
630
650
  TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
@@ -633,6 +653,10 @@ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
633
653
  /* Cast both operands to the common data_type. */
634
654
  ca_bincmp_kernel_input_data_types(op_id, l->data_type, r->data_type,
635
655
  &l_in_dt, &r_in_dt);
656
+ if ( signed_side ) {
657
+ l_in_dt = l->data_type;
658
+ r_in_dt = r->data_type;
659
+ }
636
660
 
637
661
  if ( l_in_dt != l->data_type ) {
638
662
  VALUE cast_op = INT2NUM(CA_MONOP_CAST_BASE + l_in_dt);
@@ -655,10 +679,10 @@ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
655
679
  TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
656
680
 
657
681
  if ( l->elements != r->elements ) {
658
- if ( r->elements == 1 && l->elements > 1 ) {
682
+ if ( r->elements == 1 ) {
659
683
  /* CScalar right: handled via right_is_scalar */
660
684
  }
661
- else if ( l->elements == 1 && r->elements > 1 ) {
685
+ else if ( l->elements == 1 ) {
662
686
  /* Comparison ops commute under negation (LT/GT/LE/GE flip to
663
687
  their counterpart, EQ/NE are commutative), but here we
664
688
  broadcast the left scalar up instead of swapping, so op_id
@@ -693,33 +717,39 @@ rb_ca_bincmp_s_build (int argc, VALUE *argv, VALUE klass)
693
717
  double eps = 0.0;
694
718
  (void) klass;
695
719
  rb_scan_args(argc, argv, "31", &l_cary, &r_cary, &op_id_val, &eps_val);
720
+ /* fits: an operation number from the library's own table */
696
721
  op_id = (uint16_t) NUM2UINT(op_id_val);
697
722
  if ( argc >= 4 ) eps = NUM2DBL(eps_val);
698
723
  return rb_ca_bincmp_build(l_cary, r_cary, op_id, eps);
699
724
  }
700
725
 
726
+ /* Whether this node's kernel skips the cells its operands mask, rather
727
+ than computing them: object cells, which call Ruby. CArray::Fusion
728
+ reads it so a plan carries the same rule. */
701
729
  static VALUE
702
- rb_ca_bincmp_op_id (VALUE self)
730
+ rb_ca_bincmp_trapping (VALUE self)
703
731
  {
704
732
  CABinCmp *bc;
705
733
  TypedData_Get_Struct(self, CABinCmp, &cabincmp_data_type, bc);
706
- return UINT2NUM(bc->op_id);
734
+ return ca_op_raises_on_cell(CA_OP_KIND_BINCMP, bc->op_id, bc->common_dt)
735
+ ? Qtrue : Qfalse;
707
736
  }
708
737
 
709
738
  static VALUE
710
- rb_ca_bincmp_right (VALUE self)
739
+ rb_ca_bincmp_op_id (VALUE self)
711
740
  {
712
- return rb_ivar_get(self, rb_intern("__bincmp_right__"));
741
+ CABinCmp *bc;
742
+ TypedData_Get_Struct(self, CABinCmp, &cabincmp_data_type, bc);
743
+ return UINT2NUM(bc->op_id);
713
744
  }
714
745
 
715
746
  static VALUE
716
- rb_ca_bincmp_eps (VALUE self)
747
+ rb_ca_bincmp_right (VALUE self)
717
748
  {
718
- CABinCmp *bc;
719
- TypedData_Get_Struct(self, CABinCmp, &cabincmp_data_type, bc);
720
- return rb_float_new(bc->eps);
749
+ return rb_ivar_get(self, rb_intern("__bincmp_right__"));
721
750
  }
722
751
 
752
+ #ifdef CARRAY_DEV_BUILD
723
753
  static VALUE
724
754
  rb_ca_bincmp_s_reset_scratch_counter (VALUE klass)
725
755
  {
@@ -764,6 +794,7 @@ rb_ca_bincmp_s_leaf_inplace_count (VALUE klass)
764
794
  (void) klass;
765
795
  return SIZE2NUM(ca_bincmp_leaf_inplace_count);
766
796
  }
797
+ #endif /* CARRAY_DEV_BUILD */
767
798
 
768
799
  static VALUE
769
800
  rb_ca_bincmp_s_allocate (VALUE klass)
@@ -777,6 +808,7 @@ rb_ca_bincmp_initialize_copy (VALUE self, VALUE other)
777
808
  {
778
809
  CABinCmp *ca, *cs;
779
810
  TypedData_Get_Struct(self, CABinCmp, &cabincmp_data_type, ca);
811
+ ca_check_uninitialized(ca);
780
812
  TypedData_Get_Struct(other, CABinCmp, &cabincmp_data_type, cs);
781
813
  if ( ca_func[CA_OBJ_BINCMP].pool_init ) {
782
814
  ca_array_pool_alloc(ca, CA_OBJ_BINCMP, cs->parent->ndim);
@@ -820,10 +852,11 @@ Init_ca_obj_bincmp (void)
820
852
  rb_ca_bincmp_s_build, -1);
821
853
 
822
854
  rb_define_method(rb_cCABinCmp, "__op_id__", rb_ca_bincmp_op_id, 0);
855
+ rb_define_method(rb_cCABinCmp, "__trapping__", rb_ca_bincmp_trapping, 0);
823
856
  rb_define_method(rb_cCABinCmp, "__bincmp_right__",
824
857
  rb_ca_bincmp_right, 0);
825
- rb_define_method(rb_cCABinCmp, "__eps__", rb_ca_bincmp_eps, 0);
826
858
 
859
+ #ifdef CARRAY_DEV_BUILD
827
860
  rb_define_singleton_method(rb_cCABinCmp, "__reset_scratch_counter__",
828
861
  rb_ca_bincmp_s_reset_scratch_counter, 0);
829
862
  rb_define_singleton_method(rb_cCABinCmp, "__scratch_count__",
@@ -836,4 +869,5 @@ Init_ca_obj_bincmp (void)
836
869
  rb_ca_bincmp_s_reset_leaf_inplace_counter, 0);
837
870
  rb_define_singleton_method(rb_cCABinCmp, "__leaf_inplace_count__",
838
871
  rb_ca_bincmp_s_leaf_inplace_count, 0);
872
+ #endif
839
873
  }