carray 3.0.1 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_obj_binop.c
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
#include "carray_internal.h" /* ca_lazy_arena_* */
|
|
35
35
|
#include "ca_binop_dispatch.h"
|
|
36
36
|
#include "ca_monop_dispatch.h" /* CA_MONOP_CAST_BASE */
|
|
37
|
+
#include "carray_math_kernel.h" /* ca_binop_not_implement */
|
|
37
38
|
|
|
38
39
|
/* carray_broadcast.c */
|
|
39
40
|
extern VALUE ca_broadcast_view (VALUE src, int8_t ndim,
|
|
@@ -48,7 +49,6 @@ extern int8_t CA_OBJ_LAZY_MARKER;
|
|
|
48
49
|
|
|
49
50
|
/* Defined in carray_lazy.c: wrap a non-CArray Ruby value as a
|
|
50
51
|
CScalar carrying the other operand's natural data_type. */
|
|
51
|
-
extern VALUE ca_lazy_wrap_scalar (VALUE other, CArray *self_ca);
|
|
52
52
|
|
|
53
53
|
/* ------------------------------------------------------------------- */
|
|
54
54
|
/* CABinOp struct */
|
|
@@ -239,58 +239,30 @@ ca_binop_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
|
239
239
|
ca_binop_func_xfer_stride(ca, starts, counts, strides, data, CA_XFER_GET);
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
CABinOp *ca = (CABinOp *) ap;
|
|
247
|
-
ca_size_t i;
|
|
248
|
-
char *out = (char *) data;
|
|
249
|
-
|
|
250
|
-
if ( dir != CA_XFER_GET ) {
|
|
251
|
-
rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_addrs PUT)");
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
for ( i = 0; i < n; i++ ) {
|
|
255
|
-
ca_size_t idx[CA_RANK_MAX];
|
|
256
|
-
ca_addr2index((CArray *)ca, addrs[i], idx);
|
|
257
|
-
ca_binop_func_xfer_index(ca, idx, out + i * ca->bytes, CA_XFER_GET);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/* Test / observability counters bumped from the xfer_stride hot
|
|
262
|
-
path so specs can assert scratch acquisition (one per node,
|
|
263
|
-
independent of left-chain depth) and materialise vs
|
|
264
|
-
non-materialise behaviour without attaching the view. */
|
|
242
|
+
/* Test / observability counters bumped from the evaluation hot path
|
|
243
|
+
so specs can assert scratch acquisition (one per node, independent
|
|
244
|
+
of left-chain depth) and materialise vs non-materialise behaviour
|
|
245
|
+
without attaching the view. */
|
|
265
246
|
ca_size_t ca_binop_scratch_acquire_count = 0;
|
|
266
247
|
ca_size_t ca_binop_materialise_call_count = 0;
|
|
267
248
|
|
|
249
|
+
/* Evaluate the cells a request names into `data` (packed, n cells). */
|
|
268
250
|
static void
|
|
269
|
-
|
|
270
|
-
ca_size_t *strides, void *data, int dir)
|
|
251
|
+
ca_binop_eval (CABinOp *bo, const ca_lazy_req_t *req, void *data)
|
|
271
252
|
{
|
|
272
|
-
|
|
273
|
-
ca_size_t slab_n;
|
|
253
|
+
ca_size_t slab_n = req->n;
|
|
274
254
|
int8_t k;
|
|
275
255
|
void *scratch;
|
|
276
256
|
volatile VALUE holder;
|
|
277
257
|
ca_size_t right_bytes;
|
|
278
258
|
ca_size_t right_step; /* element-stride for the kernel walk */
|
|
279
259
|
|
|
280
|
-
if ( dir != CA_XFER_GET ) {
|
|
281
|
-
rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_stride PUT)");
|
|
282
|
-
}
|
|
283
260
|
ca_binop_materialise_call_count++;
|
|
284
261
|
|
|
285
|
-
slab_n = 1;
|
|
286
|
-
for ( k = 0; k < bo->ndim; k++ ) slab_n *= counts[k];
|
|
287
|
-
|
|
288
262
|
/* === 1. Pull left into the output buffer ===
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
output row. */
|
|
293
|
-
ca_xfer_stride(bo->parent, starts, counts, strides, data, CA_XFER_GET);
|
|
263
|
+
left.data_type == output.data_type by the cast-before invariant,
|
|
264
|
+
so the output buffer holds left's cells as they are. */
|
|
265
|
+
ca_lazy_req_pull(bo->parent, req, data, CA_XFER_GET);
|
|
294
266
|
|
|
295
267
|
/* === 2. Pull right into an arena scratch === */
|
|
296
268
|
right_bytes = bo->right->bytes;
|
|
@@ -315,17 +287,12 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
315
287
|
right_step = 0;
|
|
316
288
|
}
|
|
317
289
|
else {
|
|
318
|
-
/* Same-shape right
|
|
319
|
-
same one the left was pulled with -- recomputing a packed one here
|
|
320
|
-
reads the right operand's cells 0, 1, 2 against the left's 0, 2, 4.
|
|
321
|
-
right.bytes matches output.bytes because right.data_type ==
|
|
322
|
-
out.data_type by cast-before, so the same steps serve both. */
|
|
290
|
+
/* Same-shape right, pulled over the same cells as the left. */
|
|
323
291
|
scratch = ( bo->data_type == CA_OBJECT )
|
|
324
292
|
? ca_lazy_arena_acquire_object(slab_n)
|
|
325
293
|
: ca_lazy_arena_acquire(slab_n * right_bytes);
|
|
326
294
|
ca_binop_scratch_acquire_count++;
|
|
327
|
-
|
|
328
|
-
CA_XFER_GET);
|
|
295
|
+
ca_lazy_req_pull(bo->right, req, scratch, CA_XFER_GET);
|
|
329
296
|
right_step = 1;
|
|
330
297
|
}
|
|
331
298
|
|
|
@@ -337,8 +304,9 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
337
304
|
* Mask handling:
|
|
338
305
|
* - non-trapping op → m = NULL (SIMD fast path; garbage compute
|
|
339
306
|
* on masked cells is allowed).
|
|
340
|
-
* - trapping op
|
|
341
|
-
* mask
|
|
307
|
+
* - trapping op (one that can raise on a cell, or an object cell)
|
|
308
|
+
* with any operand mask → the cells either operand masks
|
|
309
|
+
* (ca_lazy_req_mask), which the kernel skips.
|
|
342
310
|
*
|
|
343
311
|
* CAREFUL: the trapping-op mask is built from left.mask and
|
|
344
312
|
* right.mask directly, NOT from out->mask. The output's mask
|
|
@@ -353,67 +321,13 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
353
321
|
{
|
|
354
322
|
boolean8_t *slab_mask = NULL;
|
|
355
323
|
void *mscratch = NULL;
|
|
356
|
-
volatile VALUE mholder = Qnil;
|
|
357
|
-
int is_trapping = ca_binop_is_trapping(bo->op_id, bo->data_type);
|
|
358
|
-
|
|
359
|
-
if ( is_trapping && ( ca_has_mask(bo->parent) ||
|
|
360
|
-
ca_has_mask(bo->right) ) ) {
|
|
361
|
-
/* Build a slab-shaped mask = left.slab_mask | right.slab_mask.
|
|
362
|
-
Pull each operand's mask (or fill with 0 if absent) into the
|
|
363
|
-
output-shaped layout, then OR them in place. */
|
|
364
|
-
ca_size_t k_;
|
|
365
|
-
ca_size_t right_mask_strides[CA_RANK_MAX];
|
|
366
|
-
(void) mholder; /* Kept for stack-shape compatibility; arena
|
|
367
|
-
replaces the ALLOCV path here. */
|
|
368
|
-
|
|
369
|
-
mscratch = ca_lazy_arena_acquire(slab_n);
|
|
370
|
-
slab_mask = (boolean8_t *) mscratch;
|
|
371
|
-
|
|
372
|
-
if ( ca_has_mask(bo->parent) ) {
|
|
373
|
-
ca_size_t mstrides[CA_RANK_MAX];
|
|
374
|
-
ca_size_t s = 1;
|
|
375
|
-
for ( k_ = bo->ndim - 1; k_ >= 0; k_-- ) {
|
|
376
|
-
mstrides[k_] = s; s *= counts[k_];
|
|
377
|
-
}
|
|
378
|
-
ca_xfer_stride(bo->parent->mask, starts, counts, mstrides,
|
|
379
|
-
slab_mask, CA_XFER_GET);
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
memset(slab_mask, 0, slab_n);
|
|
383
|
-
}
|
|
384
324
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
ca_size_t one_counts[CA_RANK_MAX];
|
|
392
|
-
ca_size_t one_strides[CA_RANK_MAX];
|
|
393
|
-
boolean8_t one_bit = 0;
|
|
394
|
-
for ( k_ = 0; k_ < bo->right->ndim; k_++ ) {
|
|
395
|
-
one_counts[k_] = 1;
|
|
396
|
-
one_strides[k_] = 1;
|
|
397
|
-
}
|
|
398
|
-
ca_xfer_stride(bo->right->mask, one_starts, one_counts,
|
|
399
|
-
one_strides, &one_bit, CA_XFER_GET);
|
|
400
|
-
if ( one_bit ) {
|
|
401
|
-
for ( i_ = 0; i_ < slab_n; i_++ ) slab_mask[i_] = 1;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
else {
|
|
405
|
-
ca_size_t s = 1;
|
|
406
|
-
for ( k_ = bo->ndim - 1; k_ >= 0; k_-- ) {
|
|
407
|
-
right_mask_strides[k_] = s; s *= counts[k_];
|
|
408
|
-
}
|
|
409
|
-
/* Small mask-scratch for right; OR into slab_mask in
|
|
410
|
-
place to avoid a persistent second buffer. */
|
|
411
|
-
rm = (boolean8_t *) ALLOCA_N(boolean8_t, slab_n);
|
|
412
|
-
ca_xfer_stride(bo->right->mask, starts, counts,
|
|
413
|
-
right_mask_strides, rm, CA_XFER_GET);
|
|
414
|
-
for ( i_ = 0; i_ < slab_n; i_++ ) slab_mask[i_] |= rm[i_];
|
|
415
|
-
}
|
|
416
|
-
}
|
|
325
|
+
if ( ca_binop_is_trapping(bo->op_id, bo->data_type) ) {
|
|
326
|
+
CArray *ops[2];
|
|
327
|
+
ops[0] = bo->parent;
|
|
328
|
+
ops[1] = bo->right;
|
|
329
|
+
slab_mask = ca_lazy_req_mask(req, 2, ops);
|
|
330
|
+
mscratch = slab_mask;
|
|
417
331
|
}
|
|
418
332
|
|
|
419
333
|
ca_binop_func_t fn = ca_binop_kernel_lookup_vv(bo->op_id, bo->data_type);
|
|
@@ -435,6 +349,33 @@ ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
435
349
|
ca_lazy_arena_release(scratch);
|
|
436
350
|
}
|
|
437
351
|
|
|
352
|
+
static void
|
|
353
|
+
ca_binop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
354
|
+
ca_size_t *strides, void *data, int dir)
|
|
355
|
+
{
|
|
356
|
+
if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
|
|
357
|
+
ca_lazy_req_t req;
|
|
358
|
+
if ( dir != CA_XFER_GET ) {
|
|
359
|
+
rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_stride PUT)");
|
|
360
|
+
}
|
|
361
|
+
ca_lazy_req_region(&req, ap, starts, counts, strides);
|
|
362
|
+
ca_binop_eval((CABinOp *) ap, &req, data);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/* An address list is evaluated in one pass: each operand is gathered at
|
|
366
|
+
the same addresses and the kernel runs once over all of them. */
|
|
367
|
+
static void
|
|
368
|
+
ca_binop_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
369
|
+
void *data, int dir)
|
|
370
|
+
{
|
|
371
|
+
ca_lazy_req_t req;
|
|
372
|
+
if ( dir != CA_XFER_GET ) {
|
|
373
|
+
rb_raise(rb_eRuntimeError, "CABinOp is read-only (xfer_addrs PUT)");
|
|
374
|
+
}
|
|
375
|
+
ca_lazy_req_addrs(&req, n, addrs);
|
|
376
|
+
ca_binop_eval((CABinOp *) ap, &req, data);
|
|
377
|
+
}
|
|
378
|
+
|
|
438
379
|
static void
|
|
439
380
|
ca_binop_func_xfer_all (void *ap, void *data, int dir)
|
|
440
381
|
{
|
|
@@ -514,104 +455,25 @@ ca_binop_func_fill_data (void *ap, void *ptr)
|
|
|
514
455
|
rb_raise(rb_eRuntimeError, "CABinOp is read-only (fill_data)");
|
|
515
456
|
}
|
|
516
457
|
|
|
517
|
-
/* Build out.mask
|
|
518
|
-
|
|
519
|
-
OR `left.mask | right.mask`.
|
|
458
|
+
/* Build out.mask: the operands' masks ORed on each read (CAMaskOfOperands), so
|
|
459
|
+
that it follows them as the values do.
|
|
520
460
|
|
|
521
461
|
Boolean AND / OR are three-valued (Kleene): a masked cell is resolved by
|
|
522
462
|
the *known* side (`unknown | true = true`, `unknown & false = false`), so
|
|
523
|
-
it is NOT masked in the result.
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
element (true for OR, false for AND) dominates whatever garbage sits on
|
|
527
|
-
the masked side. Nested trees compose: an inner boolean `&`/`|` node's
|
|
528
|
-
mask is already Kleene-resolved by the time an outer node reads it.
|
|
529
|
-
|
|
530
|
-
Not memory-optimal (a CARepeat-like view would share pages), but correct
|
|
531
|
-
and decoupled from xfer_stride ordering. */
|
|
463
|
+
it is NOT masked in the result. The blind value the value kernel writes
|
|
464
|
+
is already correct on a resolved cell because the absorbing element (true
|
|
465
|
+
for OR, false for AND) dominates whatever sits on the masked side. */
|
|
532
466
|
static void
|
|
533
467
|
ca_binop_func_create_mask (void *ap)
|
|
534
468
|
{
|
|
535
469
|
CABinOp *bo = (CABinOp *) ap;
|
|
536
|
-
|
|
537
|
-
CArray *r = bo->right;
|
|
538
|
-
boolean8_t *dst;
|
|
539
|
-
ca_size_t i, n;
|
|
540
|
-
int has_l, has_r, kleene, need_l, need_r, is_or;
|
|
541
|
-
boolean8_t *lm, *rm, *lv, *rv;
|
|
542
|
-
|
|
543
|
-
has_l = ca_has_mask(l);
|
|
544
|
-
has_r = ca_has_mask(r);
|
|
545
|
-
if ( ! has_l && ! has_r ) return;
|
|
546
|
-
|
|
547
|
-
kleene = ( bo->data_type == CA_BOOLEAN &&
|
|
548
|
-
( bo->op_id == CA_BINOP_BIT_AND || bo->op_id == CA_BINOP_BIT_OR ) );
|
|
549
|
-
is_or = ( bo->op_id == CA_BINOP_BIT_OR );
|
|
550
|
-
|
|
551
|
-
/* One masked operand and no Kleene resolution: the answer is that
|
|
552
|
-
operand's mask, cell for cell. Share it the way CAMonOp shares its
|
|
553
|
-
parent's, rather than allocating a copy per node -- a chain of k
|
|
554
|
-
binops over one masked array then holds one boolean array, not k. */
|
|
555
|
-
if ( ! kleene && ( has_l != has_r ) ) {
|
|
556
|
-
CArray *src = has_l ? l : r;
|
|
557
|
-
if ( src->elements == bo->elements ) {
|
|
558
|
-
bo->mask = (CArray *) ca_refer_new(src->mask, CA_BOOLEAN,
|
|
559
|
-
bo->ndim, bo->dim, 0, 0);
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
470
|
+
int mode = CA_LAZY_MASK_OR;
|
|
563
471
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
/* Kleene needs operand values even where an operand is unmasked. */
|
|
569
|
-
need_l = has_l || kleene;
|
|
570
|
-
need_r = has_r || kleene;
|
|
571
|
-
/* Only Kleene reads operand values. Every other op reads the operand
|
|
572
|
-
masks alone, and attaching the operand to reach its mask materialises
|
|
573
|
-
the whole subexpression under it -- so a chain of k masked binops
|
|
574
|
-
evaluates its own subtree k times over. Attach what is read. */
|
|
575
|
-
if ( kleene ) {
|
|
576
|
-
if ( need_l ) ca_attach(l);
|
|
577
|
-
if ( need_r ) ca_attach(r);
|
|
578
|
-
}
|
|
579
|
-
else {
|
|
580
|
-
if ( has_l ) ca_attach(l->mask);
|
|
581
|
-
if ( has_r ) ca_attach(r->mask);
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
lm = has_l ? (boolean8_t *) l->mask->ptr : NULL;
|
|
585
|
-
rm = has_r ? (boolean8_t *) r->mask->ptr : NULL;
|
|
586
|
-
lv = kleene ? (boolean8_t *) l->ptr : NULL;
|
|
587
|
-
rv = kleene ? (boolean8_t *) r->ptr : NULL;
|
|
588
|
-
|
|
589
|
-
for ( i = 0; i < n; i++ ) {
|
|
590
|
-
/* right broadcast: repeat element 0 when right was a scalar. */
|
|
591
|
-
ca_size_t ri = bo->right_is_scalar ? 0 : i;
|
|
592
|
-
boolean8_t am = lm ? lm[i] : 0;
|
|
593
|
-
boolean8_t bm = rm ? rm[ri] : 0;
|
|
594
|
-
boolean8_t m = (boolean8_t)( am | bm );
|
|
595
|
-
if ( kleene && m ) {
|
|
596
|
-
boolean8_t av = lv[i], bv = rv[ri];
|
|
597
|
-
if ( is_or ) {
|
|
598
|
-
if ( ( ! am && av ) || ( ! bm && bv ) ) m = 0; /* known TRUE */
|
|
599
|
-
}
|
|
600
|
-
else {
|
|
601
|
-
if ( ( ! am && ! av ) || ( ! bm && ! bv ) ) m = 0; /* known FALSE */
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
dst[i] = m;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
if ( kleene ) {
|
|
608
|
-
if ( need_r ) ca_detach(r);
|
|
609
|
-
if ( need_l ) ca_detach(l);
|
|
610
|
-
}
|
|
611
|
-
else {
|
|
612
|
-
if ( has_r ) ca_detach(r->mask);
|
|
613
|
-
if ( has_l ) ca_detach(l->mask);
|
|
472
|
+
if ( bo->data_type == CA_BOOLEAN ) {
|
|
473
|
+
if ( bo->op_id == CA_BINOP_BIT_OR ) mode = CA_LAZY_MASK_KLEENE_OR;
|
|
474
|
+
if ( bo->op_id == CA_BINOP_BIT_AND ) mode = CA_LAZY_MASK_KLEENE_AND;
|
|
614
475
|
}
|
|
476
|
+
bo->mask = ca_lazy_operation_mask((CArray *) bo, mode);
|
|
615
477
|
}
|
|
616
478
|
|
|
617
479
|
ca_operation_function_t ca_binop_func = {
|
|
@@ -704,17 +566,22 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
|
|
|
704
566
|
l_resolved = collapse_marker(l_cary);
|
|
705
567
|
r_resolved = collapse_marker(r_cary);
|
|
706
568
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
569
|
+
ca_binop_read_boolean_as_truth(
|
|
570
|
+
ca_binop_kernel_lookup_vv(op_id, CA_BOOLEAN) != ca_binop_not_implement,
|
|
571
|
+
&l_resolved, &r_resolved);
|
|
572
|
+
|
|
573
|
+
/* A scalar beside the array (a Ruby value or a CScalar) takes the
|
|
574
|
+
data_type the eager binop gives it, and the pair is promoted as the
|
|
575
|
+
eager binop promotes it. An integer power keeps its int64 exponent
|
|
576
|
+
(ca_binop_kernel_input_data_types). */
|
|
577
|
+
if ( op_id != CA_BINOP_IPOWER &&
|
|
578
|
+
( ! rb_obj_is_carray(l_resolved) || ! rb_obj_is_carray(r_resolved) ||
|
|
579
|
+
rb_obj_is_cscalar(l_resolved) || rb_obj_is_cscalar(r_resolved) ) ) {
|
|
580
|
+
int l_scalar = ! rb_obj_is_carray(l_resolved) || rb_obj_is_cscalar(l_resolved);
|
|
581
|
+
int r_scalar = ! rb_obj_is_carray(r_resolved) || rb_obj_is_cscalar(r_resolved);
|
|
582
|
+
rb_ca_cast_self_or_other(&l_resolved, &r_resolved);
|
|
583
|
+
l_resolved = ca_lazy_settle_scalar(l_resolved, l_scalar);
|
|
584
|
+
r_resolved = ca_lazy_settle_scalar(r_resolved, r_scalar);
|
|
718
585
|
}
|
|
719
586
|
|
|
720
587
|
TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
|
|
@@ -725,6 +592,23 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
|
|
|
725
592
|
ca_binop_kernel_input_data_types(op_id, l->data_type, r->data_type,
|
|
726
593
|
&l_in_dt, &r_in_dt);
|
|
727
594
|
|
|
595
|
+
/* A boolean operand of an op with no boolean kernel (arithmetic) is
|
|
596
|
+
read as its 0/1 storage in int64, as rb_ca_call_binop does. */
|
|
597
|
+
if ( l_in_dt == CA_BOOLEAN &&
|
|
598
|
+
ca_binop_kernel_lookup_vv(op_id, CA_BOOLEAN) == ca_binop_not_implement ) {
|
|
599
|
+
l_in_dt = CA_INT64;
|
|
600
|
+
if ( r_in_dt == CA_BOOLEAN ) {
|
|
601
|
+
r_in_dt = CA_INT64;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/* No kernel for that data_type (fixlen arithmetic, ...): raise as the
|
|
606
|
+
eager binop does, before a view is built over it. */
|
|
607
|
+
if ( ca_binop_kernel_lookup_vv(op_id, l_in_dt) == ca_binop_not_implement ) {
|
|
608
|
+
rb_raise(rb_eCADataTypeError,
|
|
609
|
+
"invalid data_type for binop (not implemented)");
|
|
610
|
+
}
|
|
611
|
+
|
|
728
612
|
if ( l_in_dt != l->data_type ) {
|
|
729
613
|
VALUE cast_op = INT2NUM(CA_MONOP_CAST_BASE + l_in_dt);
|
|
730
614
|
l_resolved = rb_funcall(rb_const_get(rb_cObject, rb_intern("CAMonOp")),
|
|
@@ -757,11 +641,11 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
|
|
|
757
641
|
shape so the kernel sees matched shapes; cost is N
|
|
758
642
|
reads of the scalar cell with stride 0. */
|
|
759
643
|
if ( l->elements != r->elements ) {
|
|
760
|
-
if ( r->elements == 1
|
|
644
|
+
if ( r->elements == 1 ) {
|
|
761
645
|
/* CScalar-vs-array, right. xfer_stride handles this with
|
|
762
646
|
right_step = 0. */
|
|
763
647
|
}
|
|
764
|
-
else if ( l->elements == 1
|
|
648
|
+
else if ( l->elements == 1 ) {
|
|
765
649
|
int commutes = ( op_id == CA_BINOP_ADD ||
|
|
766
650
|
op_id == CA_BINOP_MUL ||
|
|
767
651
|
op_id == CA_BINOP_BIT_AND ||
|
|
@@ -816,6 +700,17 @@ rb_ca_binop_s_build (VALUE klass, VALUE l_cary, VALUE r_cary, VALUE op_id_val)
|
|
|
816
700
|
}
|
|
817
701
|
|
|
818
702
|
/* op_id accessor for inspect / dump_tree consumers in Ruby. */
|
|
703
|
+
/* Whether this node's kernel skips the cells its operands mask, rather
|
|
704
|
+
than computing them: a kernel that can raise on a cell or calls Ruby
|
|
705
|
+
for it. CArray::Fusion reads it so a plan carries the same rule. */
|
|
706
|
+
static VALUE
|
|
707
|
+
rb_ca_binop_trapping (VALUE self)
|
|
708
|
+
{
|
|
709
|
+
CABinOp *bo;
|
|
710
|
+
TypedData_Get_Struct(self, CABinOp, &cabinop_data_type, bo);
|
|
711
|
+
return ca_binop_is_trapping(bo->op_id, bo->data_type) ? Qtrue : Qfalse;
|
|
712
|
+
}
|
|
713
|
+
|
|
819
714
|
static VALUE
|
|
820
715
|
rb_ca_binop_op_id (VALUE self)
|
|
821
716
|
{
|
|
@@ -872,6 +767,7 @@ rb_ca_binop_initialize_copy (VALUE self, VALUE other)
|
|
|
872
767
|
{
|
|
873
768
|
CABinOp *ca, *cs;
|
|
874
769
|
TypedData_Get_Struct(self, CABinOp, &cabinop_data_type, ca);
|
|
770
|
+
ca_check_uninitialized(ca);
|
|
875
771
|
TypedData_Get_Struct(other, CABinOp, &cabinop_data_type, cs);
|
|
876
772
|
if ( ca_func[CA_OBJ_BINOP].pool_init ) {
|
|
877
773
|
ca_array_pool_alloc(ca, CA_OBJ_BINOP, cs->parent->ndim);
|
|
@@ -933,6 +829,7 @@ Init_ca_obj_binop (void)
|
|
|
933
829
|
|
|
934
830
|
rb_define_method(rb_cCABinOp, "__op_id__",
|
|
935
831
|
rb_ca_binop_op_id, 0);
|
|
832
|
+
rb_define_method(rb_cCABinOp, "__trapping__", rb_ca_binop_trapping, 0);
|
|
936
833
|
rb_define_method(rb_cCABinOp, "__binop_right__",
|
|
937
834
|
rb_ca_binop_right, 0);
|
|
938
835
|
|
data/ext/ca_obj_bitarray.c
CHANGED
|
@@ -96,6 +96,21 @@ ca_bitarray_setup (CABitarray *ca, CArray *parent)
|
|
|
96
96
|
rb_raise(rb_eCADataTypeError, "invalid data_type for bitarray");
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/* The bits of one byte would share that byte's one mask cell, so a bit
|
|
100
|
+
view takes no masked array and holds no mask of its own. */
|
|
101
|
+
if ( ca_has_mask(parent) ) {
|
|
102
|
+
rb_raise(rb_eArgError,
|
|
103
|
+
"bitarray: the array has a mask, which a bit view can not "
|
|
104
|
+
"carry (its bits would share one mask per byte); "
|
|
105
|
+
"use .value.bitarray to read the bits without it");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* ca == NULL asks for the checks above only, so that a constructor can
|
|
109
|
+
run them before it allocates. */
|
|
110
|
+
if ( ca == NULL ) {
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
99
114
|
ndim = parent->ndim + 1;
|
|
100
115
|
bitlen = 8 * parent->bytes;
|
|
101
116
|
elements = bitlen * parent->elements;
|
|
@@ -122,17 +137,15 @@ ca_bitarray_setup (CABitarray *ca, CArray *parent)
|
|
|
122
137
|
memcpy(ca->dim, parent->dim, (ndim-1) * sizeof(ca_size_t));
|
|
123
138
|
ca->dim[ndim-1] = bitlen;
|
|
124
139
|
|
|
125
|
-
if ( ca_has_mask(parent) ) {
|
|
126
|
-
ca_create_mask(ca);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
140
|
return 0;
|
|
130
141
|
}
|
|
131
142
|
|
|
132
143
|
CABitarray *
|
|
133
144
|
ca_bitarray_new (CArray *parent)
|
|
134
145
|
{
|
|
135
|
-
CABitarray *ca
|
|
146
|
+
CABitarray *ca;
|
|
147
|
+
ca_bitarray_setup(NULL, parent);
|
|
148
|
+
ca = (CABitarray *) ca_array_alloc(CA_OBJ_BITARRAY, parent->ndim + 1);
|
|
136
149
|
ca_bitarray_setup(ca, parent);
|
|
137
150
|
return ca;
|
|
138
151
|
}
|
|
@@ -178,7 +191,7 @@ ca_bitarray_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
|
178
191
|
ca_size_t bytes = ca->parent->bytes;
|
|
179
192
|
ca_size_t offset = idx[ca->ndim-1];
|
|
180
193
|
ca_size_t major, minor;
|
|
181
|
-
|
|
194
|
+
volatile VALUE holder;
|
|
182
195
|
uint8_t *v;
|
|
183
196
|
|
|
184
197
|
if ( ca_endian == CA_BIG_ENDIAN &&
|
|
@@ -191,7 +204,7 @@ ca_bitarray_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
|
191
204
|
}
|
|
192
205
|
minor = offset % 8;
|
|
193
206
|
|
|
194
|
-
v = (
|
|
207
|
+
v = ALLOCV_N(uint8_t, holder, ca->parent->bytes);
|
|
195
208
|
|
|
196
209
|
if ( dir == CA_XFER_GET ) {
|
|
197
210
|
ca_fetch_index(ca->parent, idx, v);
|
|
@@ -209,7 +222,7 @@ ca_bitarray_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
|
209
222
|
ca_store_index(ca->parent, idx, v);
|
|
210
223
|
}
|
|
211
224
|
|
|
212
|
-
|
|
225
|
+
ALLOCV_END(holder);
|
|
213
226
|
}
|
|
214
227
|
|
|
215
228
|
/* Batched gather / scatter.
|
|
@@ -315,6 +328,7 @@ static void
|
|
|
315
328
|
ca_bitarray_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
316
329
|
ca_size_t *strides, void *data, int dir)
|
|
317
330
|
{
|
|
331
|
+
if ( ca_region_is_empty(((CArray *) ap)->ndim, counts) ) return;
|
|
318
332
|
CABitarray *ca = (CABitarray *) ap;
|
|
319
333
|
int8_t ndim = ca->ndim;
|
|
320
334
|
ca_size_t native[CA_RANK_MAX], idx[CA_RANK_MAX];
|
|
@@ -478,29 +492,27 @@ ca_bitarray_func_fill_data (void *ap, void *ptr)
|
|
|
478
492
|
CABitarray *ca = (CABitarray *) ap;
|
|
479
493
|
ca_attach(ca->parent);
|
|
480
494
|
ca_bitarray_fill(ca, ptr);
|
|
481
|
-
|
|
482
|
-
ca_detach(ca->parent);
|
|
495
|
+
ca_sync_detach(ca->parent);
|
|
483
496
|
}
|
|
484
497
|
|
|
498
|
+
/* Reached when a mask is about to be put on the view (mask=, storing UNDEF
|
|
499
|
+
or a masked array), or when the array it views has gained a mask since
|
|
500
|
+
the view was made. */
|
|
501
|
+
NORETURN(static void ca_bitarray_func_create_mask (void *ap));
|
|
502
|
+
|
|
485
503
|
static void
|
|
486
504
|
ca_bitarray_func_create_mask (void *ap)
|
|
487
505
|
{
|
|
488
506
|
CABitarray *ca = (CABitarray *) ap;
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
495
|
-
count[ca->ndim-1] = ca->bitlen;
|
|
496
|
-
|
|
497
|
-
ca_update_mask(ca->parent);
|
|
498
|
-
if ( ! ca->parent->mask ) {
|
|
499
|
-
ca_create_mask(ca->parent);
|
|
507
|
+
if ( ca_has_mask(ca->parent) ) {
|
|
508
|
+
rb_raise(rb_eArgError,
|
|
509
|
+
"bitarray: the array this view reads has gained a mask, which "
|
|
510
|
+
"a bit view can not carry (its bits would share one mask per "
|
|
511
|
+
"byte); use .value.bitarray to read the bits without it");
|
|
500
512
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
513
|
+
rb_raise(rb_eArgError,
|
|
514
|
+
"a bitarray view can not hold a mask "
|
|
515
|
+
"(its bits would share one mask per byte)");
|
|
504
516
|
}
|
|
505
517
|
|
|
506
518
|
ca_operation_function_t ca_bitarray_func = {
|
|
@@ -703,6 +715,7 @@ rb_ca_bitarray_initialize_copy (VALUE self, VALUE other)
|
|
|
703
715
|
CABitarray *ca, *cs;
|
|
704
716
|
|
|
705
717
|
TypedData_Get_Struct(self, CABitarray, &cabitarray_data_type, ca);
|
|
718
|
+
ca_check_uninitialized(ca);
|
|
706
719
|
TypedData_Get_Struct(other, CABitarray, &cabitarray_data_type, cs);
|
|
707
720
|
|
|
708
721
|
if ( ca_func[CA_OBJ_BITARRAY].pool_init ) {
|