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_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
 
@@ -78,6 +78,11 @@ typedef struct CABinCmp {
78
78
  `eps` name is retained to keep the
79
79
  `__eps__` Ruby accessor stable across
80
80
  the dual purpose. */
81
+ int8_t sign_fix; /* 0, or the side (1 left, 2 right) of an
82
+ int64 operand compared with a uint64 one:
83
+ the kernel compares both as uint64 and
84
+ the cells where it is negative are
85
+ answered after */
81
86
  CArray *operands[2]; /* {left, right}; what parents points at */
82
87
  } CABinCmp;
83
88
 
@@ -143,6 +148,15 @@ ca_bincmp_setup (CABinCmp *ca, CArray *left, CArray *right, uint16_t op_id,
143
148
  ca->right_is_scalar = ( right->elements == 1 && left->elements > 1 ) ? 1 : 0;
144
149
  /* Builder has already cast both operands to common data_type. */
145
150
  ca->common_dt = left->data_type;
151
+ ca->sign_fix = 0;
152
+ if ( left->data_type == CA_INT64 && right->data_type == CA_UINT64 ) {
153
+ ca->common_dt = CA_UINT64;
154
+ ca->sign_fix = 1;
155
+ }
156
+ else if ( left->data_type == CA_UINT64 && right->data_type == CA_INT64 ) {
157
+ ca->common_dt = CA_UINT64;
158
+ ca->sign_fix = 2;
159
+ }
146
160
  ca->eps = eps;
147
161
  ca->operands[0] = left;
148
162
  ca->operands[1] = right;
@@ -223,25 +237,6 @@ ca_bincmp_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
223
237
  ca_bincmp_func_xfer_stride(ca, starts, counts, strides, data, CA_XFER_GET);
224
238
  }
225
239
 
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
240
  /* Test / observability counters — bumped from the xfer_stride hot
246
241
  path so specs can assert scratch acquisition and leaf in-place
247
242
  hit rates without materialising the view. */
@@ -296,59 +291,37 @@ ca_bincmp_try_leaf_inplace (CArray *op, int8_t common_dt,
296
291
  return 1;
297
292
  }
298
293
 
294
+ /* Evaluate the cells a request names into `data` (packed, n cells). */
299
295
  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)
296
+ ca_bincmp_eval (CABinCmp *bc, const ca_lazy_req_t *req, void *data)
302
297
  {
303
- CABinCmp *bc = (CABinCmp *) ap;
304
- ca_size_t slab_n;
298
+ ca_size_t slab_n = req->n;
305
299
  int8_t k;
306
300
  void *left_scratch, *right_scratch;
307
- ca_size_t operand_bytes;
308
- ca_size_t operand_strides[CA_RANK_MAX];
301
+ ca_size_t left_bytes, right_bytes;
309
302
  ca_size_t right_step;
310
303
  int is_contig;
311
304
  int left_is_inplace = 0; /* skip release for leaf-opt path */
312
305
  int right_is_inplace = 0;
313
306
 
314
- if ( dir != CA_XFER_GET ) {
315
- rb_raise(rb_eRuntimeError, "CABinCmp is read-only (xfer_stride PUT)");
316
- }
317
307
  ca_bincmp_materialise_call_count++;
318
308
 
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];
323
-
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.
309
+ /* An operand's own bytes, not ca_sizeof[common_dt]: a fixlen cell has no
310
+ width in ca_sizeof, and the two fixlen operands may differ in width. */
311
+ left_bytes = bc->parent->bytes;
312
+ right_bytes = bc->right->bytes;
329
313
 
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
- }
314
+ /* The leaf in-place path reads an operand's own buffer, which holds the
315
+ wanted cells in the order the kernel reads them only for the row-major
316
+ slab that xfer_all and attach send. */
317
+ is_contig = ca_lazy_req_is_packed(req, bc);
345
318
 
346
319
  /* === 1. pull LEFT (leaf in-place read or arena scratch) === */
347
320
  {
348
321
  char *left_inplace = NULL;
349
322
  if ( is_contig &&
350
323
  ca_bincmp_try_leaf_inplace(bc->parent, bc->common_dt,
351
- starts, counts, operand_bytes,
324
+ req->starts, req->counts, left_bytes,
352
325
  &left_inplace) ) {
353
326
  /* Leaf-opt path: use parent->ptr + byte_offset directly. */
354
327
  left_scratch = left_inplace;
@@ -358,10 +331,9 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
358
331
  else {
359
332
  left_scratch = ( bc->common_dt == CA_OBJECT )
360
333
  ? ca_lazy_arena_acquire_object(slab_n)
361
- : ca_lazy_arena_acquire(slab_n * operand_bytes);
334
+ : ca_lazy_arena_acquire(slab_n * left_bytes);
362
335
  ca_bincmp_scratch_acquire_count++;
363
- ca_xfer_stride(bc->parent, starts, counts, operand_strides, left_scratch,
364
- CA_XFER_GET);
336
+ ca_lazy_req_pull(bc->parent, req, left_scratch, CA_XFER_GET);
365
337
  }
366
338
  }
367
339
 
@@ -378,7 +350,7 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
378
350
  for ( k = 0; k < bc->right->ndim; k++ ) one_counts[k] = 1;
379
351
 
380
352
  if ( ca_bincmp_try_leaf_inplace(bc->right, bc->common_dt,
381
- one_starts, one_counts, operand_bytes,
353
+ one_starts, one_counts, right_bytes,
382
354
  &right_inplace) ) {
383
355
  right_scratch = right_inplace;
384
356
  right_is_inplace = 1;
@@ -386,10 +358,10 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
386
358
  }
387
359
  else {
388
360
  ca_size_t one_strides[CA_RANK_MAX];
389
- for ( k = 0; k < bc->right->ndim; k++ ) one_strides[k] = operand_bytes;
361
+ for ( k = 0; k < bc->right->ndim; k++ ) one_strides[k] = right_bytes;
390
362
  right_scratch = ( bc->common_dt == CA_OBJECT )
391
363
  ? ca_lazy_arena_acquire_object(1)
392
- : ca_lazy_arena_acquire(operand_bytes);
364
+ : ca_lazy_arena_acquire(right_bytes);
393
365
  ca_bincmp_scratch_acquire_count++;
394
366
  ca_xfer_stride(bc->right, one_starts, one_counts, one_strides,
395
367
  right_scratch, CA_XFER_GET);
@@ -401,7 +373,7 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
401
373
  char *right_inplace = NULL;
402
374
  if ( is_contig &&
403
375
  ca_bincmp_try_leaf_inplace(bc->right, bc->common_dt,
404
- starts, counts, operand_bytes,
376
+ req->starts, req->counts, right_bytes,
405
377
  &right_inplace) ) {
406
378
  right_scratch = right_inplace;
407
379
  right_is_inplace = 1;
@@ -410,10 +382,9 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
410
382
  else {
411
383
  right_scratch = ( bc->common_dt == CA_OBJECT )
412
384
  ? ca_lazy_arena_acquire_object(slab_n)
413
- : ca_lazy_arena_acquire(slab_n * operand_bytes);
385
+ : ca_lazy_arena_acquire(slab_n * right_bytes);
414
386
  ca_bincmp_scratch_acquire_count++;
415
- ca_xfer_stride(bc->right, starts, counts, operand_strides, right_scratch,
416
- CA_XFER_GET);
387
+ ca_lazy_req_pull(bc->right, req, right_scratch, CA_XFER_GET);
417
388
  }
418
389
  right_step = 1;
419
390
  }
@@ -423,14 +394,16 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
423
394
  * Kernel signature (ext/carray.h):
424
395
  * fn(n, m, ptr1, b1, i1, ptr2, b2, i2, ptr3, b3, i3)
425
396
  *
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.
397
+ * The `b*` args are the cell widths. The typed kernels step by
398
+ * sizeof(T) and ignore them; the fixlen kernels step and compare by
399
+ * them.
429
400
  *
430
- * Non-trapping: m=NULL (= SIMD fast path). Mask propagation handled
431
- * by create_mask at view construction time.
401
+ * m=NULL (= SIMD fast path) except for object operands, whose cells
402
+ * call Ruby: those skip the masked cells, as the eager comparison
403
+ * does. The output mask comes from create_mask.
432
404
  */
433
405
  {
406
+ boolean8_t *slab_mask = NULL;
434
407
  ca_bincmp_func_t fn = ca_bincmp_kernel_lookup(bc->op_id, bc->common_dt);
435
408
  if ( fn == NULL ) {
436
409
  if ( ! right_is_inplace ) ca_lazy_arena_release(right_scratch);
@@ -439,17 +412,59 @@ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
439
412
  "CABinCmp: kernel not implemented (op_id=%u data_type=%d)",
440
413
  (unsigned) bc->op_id, (int) bc->common_dt);
441
414
  }
442
- fn(slab_n, NULL,
443
- (char *) left_scratch, 0, 1,
444
- (char *) right_scratch, 0, right_step,
445
- (char *) data, 0, 1,
415
+ if ( bc->common_dt == CA_OBJECT ) {
416
+ slab_mask = ca_lazy_req_mask(req, 2, bc->operands);
417
+ }
418
+ fn(slab_n, slab_mask,
419
+ (char *) left_scratch, left_bytes, 1,
420
+ (char *) right_scratch, right_bytes, right_step,
421
+ (char *) data, 1, 1,
446
422
  bc->eps); /* Runtime tolerance for IS_CLOSE / IS_EQUIV. */
423
+ if ( slab_mask ) ca_lazy_arena_release(slab_mask);
424
+ }
425
+
426
+ if ( bc->sign_fix ) {
427
+ const int64_t *sp = (const int64_t *)
428
+ ( bc->sign_fix == 1 ? left_scratch : right_scratch );
429
+ ca_size_t step = ( bc->sign_fix == 1 ) ? 1 : right_step;
430
+ boolean8_t answer =
431
+ (boolean8_t) ca_bincmp_answer_when_negative(bc->op_id, bc->sign_fix);
432
+ ca_size_t i;
433
+ for ( i = 0; i < slab_n; i++ ) {
434
+ if ( sp[i * step] < 0 ) ((boolean8_t *) data)[i] = answer;
435
+ }
447
436
  }
448
437
 
449
438
  if ( ! right_is_inplace ) ca_lazy_arena_release(right_scratch);
450
439
  if ( ! left_is_inplace ) ca_lazy_arena_release(left_scratch);
451
440
  }
452
441
 
442
+ static void
443
+ ca_bincmp_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
444
+ ca_size_t *strides, void *data, int dir)
445
+ {
446
+ if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
447
+ ca_lazy_req_t req;
448
+ if ( dir != CA_XFER_GET ) {
449
+ rb_raise(rb_eRuntimeError, "CABinCmp is read-only (xfer_stride PUT)");
450
+ }
451
+ ca_lazy_req_region(&req, ap, starts, counts, strides);
452
+ ca_bincmp_eval((CABinCmp *) ap, &req, data);
453
+ }
454
+
455
+ /* An address list is evaluated in one pass, as a region is. */
456
+ static void
457
+ ca_bincmp_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
458
+ void *data, int dir)
459
+ {
460
+ ca_lazy_req_t req;
461
+ if ( dir != CA_XFER_GET ) {
462
+ rb_raise(rb_eRuntimeError, "CABinCmp is read-only (xfer_addrs PUT)");
463
+ }
464
+ ca_lazy_req_addrs(&req, n, addrs);
465
+ ca_bincmp_eval((CABinCmp *) ap, &req, data);
466
+ }
467
+
453
468
  static void
454
469
  ca_bincmp_func_xfer_all (void *ap, void *data, int dir)
455
470
  {
@@ -513,45 +528,12 @@ ca_bincmp_func_fill_data (void *ap, void *ptr)
513
528
  rb_raise(rb_eRuntimeError, "CABinCmp is read-only (fill_data)");
514
529
  }
515
530
 
516
- /* mask = left.mask | right.mask, materialised as boolean8_t.
517
- Mirrors CABinOp's create_mask policy. */
531
+ /* mask = left.mask | right.mask, computed on each read (CAMaskOfOperands). */
518
532
  static void
519
533
  ca_bincmp_func_create_mask (void *ap)
520
534
  {
521
535
  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);
536
+ bc->mask = ca_lazy_operation_mask((CArray *) bc, CA_LAZY_MASK_OR);
555
537
  }
556
538
 
557
539
  ca_operation_function_t ca_bincmp_func = {
@@ -605,26 +587,58 @@ rb_ca_bincmp_new (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
605
587
  return obj;
606
588
  }
607
589
 
590
+ /* An operand taken to data type dt: a scalar by value, an array through a
591
+ cast view so the expression stays lazy. */
592
+ static VALUE
593
+ ca_bincmp_cast_operand (VALUE v, int8_t dt)
594
+ {
595
+ CArray *ca;
596
+ TypedData_Get_Struct(v, CArray, &carray_data_type, ca);
597
+ if ( ca->data_type == dt ) return v;
598
+ if ( rb_obj_is_cscalar(v) ) {
599
+ return rb_funcall(v, rb_intern("to_type"), 1, INT2NUM(dt));
600
+ }
601
+ return rb_funcall(rb_const_get(rb_cObject, rb_intern("CAMonOp")),
602
+ rb_intern("__build__"), 2,
603
+ v, INT2NUM(CA_MONOP_CAST_BASE + dt));
604
+ }
605
+
608
606
  VALUE
609
607
  rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
610
608
  {
611
609
  CArray *l, *r;
612
610
  int8_t l_in_dt, r_in_dt;
611
+ int signed_side = 0;
613
612
  volatile VALUE l_resolved, r_resolved;
614
613
 
615
614
  l_resolved = collapse_marker(l_cary);
616
615
  r_resolved = collapse_marker(r_cary);
617
616
 
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);
617
+ switch ( ca_bincmp_integer_prepare(&l_resolved, &r_resolved, op_id,
618
+ &signed_side) ) {
619
+ case 1: return rb_ca_bincmp_build(l_resolved, l_resolved, CA_BINCMP_EQ, eps);
620
+ case 2: return rb_ca_bincmp_build(l_resolved, l_resolved, CA_BINCMP_NE, eps);
621
+ case 3:
622
+ /* The unsigned operand goes to uint64 and the signed one to int64;
623
+ ca_bincmp_setup reads that pair as a comparison to correct. */
624
+ l_resolved = ca_bincmp_cast_operand(l_resolved,
625
+ ( signed_side == 1 ) ? CA_INT64 : CA_UINT64);
626
+ r_resolved = ca_bincmp_cast_operand(r_resolved,
627
+ ( signed_side == 2 ) ? CA_INT64 : CA_UINT64);
628
+ break;
623
629
  }
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);
630
+
631
+ /* A scalar beside the array (a Ruby value or a CScalar) is wrapped and
632
+ promoted as the eager comparison does it. */
633
+ if ( ! rb_obj_is_carray(l_resolved) || ! rb_obj_is_carray(r_resolved) ||
634
+ rb_obj_is_cscalar(l_resolved) || rb_obj_is_cscalar(r_resolved) ) {
635
+ int l_scalar = ! rb_obj_is_carray(l_resolved) || rb_obj_is_cscalar(l_resolved);
636
+ int r_scalar = ! rb_obj_is_carray(r_resolved) || rb_obj_is_cscalar(r_resolved);
637
+ if ( ! signed_side ) {
638
+ rb_ca_cast_self_or_other(&l_resolved, &r_resolved);
639
+ }
640
+ l_resolved = ca_lazy_settle_scalar(l_resolved, l_scalar);
641
+ r_resolved = ca_lazy_settle_scalar(r_resolved, r_scalar);
628
642
  }
629
643
 
630
644
  TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
@@ -633,6 +647,10 @@ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
633
647
  /* Cast both operands to the common data_type. */
634
648
  ca_bincmp_kernel_input_data_types(op_id, l->data_type, r->data_type,
635
649
  &l_in_dt, &r_in_dt);
650
+ if ( signed_side ) {
651
+ l_in_dt = l->data_type;
652
+ r_in_dt = r->data_type;
653
+ }
636
654
 
637
655
  if ( l_in_dt != l->data_type ) {
638
656
  VALUE cast_op = INT2NUM(CA_MONOP_CAST_BASE + l_in_dt);
@@ -655,10 +673,10 @@ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
655
673
  TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
656
674
 
657
675
  if ( l->elements != r->elements ) {
658
- if ( r->elements == 1 && l->elements > 1 ) {
676
+ if ( r->elements == 1 ) {
659
677
  /* CScalar right: handled via right_is_scalar */
660
678
  }
661
- else if ( l->elements == 1 && r->elements > 1 ) {
679
+ else if ( l->elements == 1 ) {
662
680
  /* Comparison ops commute under negation (LT/GT/LE/GE flip to
663
681
  their counterpart, EQ/NE are commutative), but here we
664
682
  broadcast the left scalar up instead of swapping, so op_id
@@ -698,6 +716,17 @@ rb_ca_bincmp_s_build (int argc, VALUE *argv, VALUE klass)
698
716
  return rb_ca_bincmp_build(l_cary, r_cary, op_id, eps);
699
717
  }
700
718
 
719
+ /* Whether this node's kernel skips the cells its operands mask, rather
720
+ than computing them: object cells, which call Ruby. CArray::Fusion
721
+ reads it so a plan carries the same rule. */
722
+ static VALUE
723
+ rb_ca_bincmp_trapping (VALUE self)
724
+ {
725
+ CABinCmp *bc;
726
+ TypedData_Get_Struct(self, CABinCmp, &cabincmp_data_type, bc);
727
+ return ( bc->common_dt == CA_OBJECT ) ? Qtrue : Qfalse;
728
+ }
729
+
701
730
  static VALUE
702
731
  rb_ca_bincmp_op_id (VALUE self)
703
732
  {
@@ -777,6 +806,7 @@ rb_ca_bincmp_initialize_copy (VALUE self, VALUE other)
777
806
  {
778
807
  CABinCmp *ca, *cs;
779
808
  TypedData_Get_Struct(self, CABinCmp, &cabincmp_data_type, ca);
809
+ ca_check_uninitialized(ca);
780
810
  TypedData_Get_Struct(other, CABinCmp, &cabincmp_data_type, cs);
781
811
  if ( ca_func[CA_OBJ_BINCMP].pool_init ) {
782
812
  ca_array_pool_alloc(ca, CA_OBJ_BINCMP, cs->parent->ndim);
@@ -820,6 +850,7 @@ Init_ca_obj_bincmp (void)
820
850
  rb_ca_bincmp_s_build, -1);
821
851
 
822
852
  rb_define_method(rb_cCABinCmp, "__op_id__", rb_ca_bincmp_op_id, 0);
853
+ rb_define_method(rb_cCABinCmp, "__trapping__", rb_ca_bincmp_trapping, 0);
823
854
  rb_define_method(rb_cCABinCmp, "__bincmp_right__",
824
855
  rb_ca_bincmp_right, 0);
825
856
  rb_define_method(rb_cCABinCmp, "__eps__", rb_ca_bincmp_eps, 0);