carray 2.0.0 → 3.0.0
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/.yardopts +5 -25
- data/CHANGELOG.md +16 -0
- data/LICENSE +1 -1
- data/NEWS.md +3 -0
- data/README.md +128 -44
- data/carray.gemspec +22 -24
- data/ext/ca_array_pool.c +91 -0
- data/ext/ca_axis_descriptor.h +186 -0
- data/ext/ca_axis_dispatch.c +924 -0
- data/ext/ca_axis_group.c +1208 -0
- data/ext/ca_bincmp_dispatch.c +76 -0
- data/ext/ca_bincmp_dispatch.h +85 -0
- data/ext/ca_binop_dispatch.c +125 -0
- data/ext/ca_binop_dispatch.h +159 -0
- data/ext/ca_categorical_iterator.c +1375 -0
- data/ext/ca_compare.c +94 -0
- data/ext/ca_compare.h +26 -0
- data/ext/ca_composite_dispatch.c +414 -0
- data/ext/ca_composite_dispatch.h +116 -0
- data/ext/ca_for_buffer.h +96 -0
- data/ext/ca_for_each_element.h +241 -0
- data/ext/ca_group_iter.c +304 -0
- data/ext/ca_iter_substrate.h +325 -0
- data/ext/ca_kernel_iterator.c +4321 -0
- data/ext/ca_kernel_iterator.h +2603 -0
- data/ext/ca_moncmp_dispatch.c +37 -0
- data/ext/ca_moncmp_dispatch.h +62 -0
- data/ext/ca_monop_dispatch.c +200 -0
- data/ext/ca_monop_dispatch.h +235 -0
- data/ext/ca_obj_array.c +355 -359
- data/ext/ca_obj_bincmp.c +809 -0
- data/ext/ca_obj_binop.c +892 -0
- data/ext/ca_obj_bitarray.c +369 -164
- data/ext/ca_obj_bitfield.c +294 -234
- data/ext/ca_obj_block.c +189 -711
- data/ext/ca_obj_byte_swap.c +766 -0
- data/ext/ca_obj_const_string.c +965 -0
- data/ext/ca_obj_face.c +670 -0
- data/ext/ca_obj_face.h +247 -0
- data/ext/ca_obj_fake.c +228 -100
- data/ext/ca_obj_farray.c +54 -441
- data/ext/ca_obj_field.c +82 -529
- data/ext/ca_obj_fixlen_string.c +306 -0
- data/ext/ca_obj_grid.c +858 -440
- data/ext/ca_obj_meld.c +1034 -0
- data/ext/ca_obj_moncmp.c +569 -0
- data/ext/ca_obj_monop.c +1111 -0
- data/ext/ca_obj_object.c +774 -298
- data/ext/ca_obj_record.c +468 -0
- data/ext/ca_obj_reduce.c +97 -82
- data/ext/ca_obj_refer.c +569 -459
- data/ext/ca_obj_remap.c +475 -0
- data/ext/ca_obj_repeat.c +92 -477
- data/ext/ca_obj_roll.c +616 -0
- data/ext/ca_obj_select.c +344 -296
- data/ext/ca_obj_select_axis.c +1296 -0
- data/ext/ca_obj_shift.c +230 -792
- data/ext/ca_obj_source.c +78 -0
- data/ext/ca_obj_stack.c +1173 -0
- data/ext/ca_obj_stride.c +2501 -0
- data/ext/ca_obj_string.c +268 -0
- data/ext/ca_obj_tile.c +614 -0
- data/ext/ca_obj_time.c +546 -0
- data/ext/ca_obj_timedelta.c +435 -0
- data/ext/ca_obj_transpose.c +62 -516
- data/ext/ca_obj_triop.c +746 -0
- data/ext/ca_obj_unbound_repeat.c +208 -241
- data/ext/ca_obj_window.c +1131 -563
- data/ext/ca_op_byte_swap.c +175 -0
- data/ext/ca_op_ipower.c +319 -0
- data/ext/ca_op_powi.h +88 -0
- data/ext/ca_sort_kernels.h +132 -0
- data/ext/ca_sweep_engine.c +430 -0
- data/ext/ca_sweep_engine.h +157 -0
- data/ext/ca_transform_common.c +228 -0
- data/ext/ca_triop_dispatch.c +55 -0
- data/ext/ca_triop_dispatch.h +62 -0
- data/ext/carray.h +795 -402
- data/ext/carray_access.c +831 -711
- data/ext/carray_attribute.c +98 -330
- data/ext/carray_bincount.c +255 -0
- data/ext/carray_broadcast.c +283 -0
- data/ext/carray_call_cfunc.c +1360 -828
- data/ext/carray_call_cfunc.h +160 -0
- data/ext/carray_cast.c +1212 -301
- data/ext/carray_cast_func.rb +81 -40
- data/ext/carray_class.c +53 -63
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +350 -346
- data/ext/carray_copy.c +156 -268
- data/ext/carray_core.c +1342 -199
- data/ext/carray_count.c +312 -0
- data/ext/carray_data_type.c +43 -19
- data/ext/carray_element.c +585 -213
- data/ext/carray_factorize.c +2542 -0
- data/ext/carray_generate.c +230 -559
- data/ext/carray_histogram.c +490 -0
- data/ext/carray_hold.c +228 -0
- data/ext/carray_index_classifier.c +1035 -0
- data/ext/carray_index_classifier.h +27 -0
- data/ext/carray_internal.h +120 -0
- data/ext/carray_kernels_bincmp.c +4445 -0
- data/ext/carray_kernels_binop.c +10979 -0
- data/ext/carray_kernels_init.c +36 -0
- data/ext/carray_kernels_map.c +3466 -0
- data/ext/carray_kernels_moncmp.c +2096 -0
- data/ext/carray_kernels_monop.c +18312 -0
- data/ext/carray_kernels_reduce_aggregate.c +25836 -0
- data/ext/carray_kernels_reduce_boolean.c +329 -0
- data/ext/carray_kernels_reduce_cumulative.c +14592 -0
- data/ext/carray_kernels_reduce_extreme.c +16947 -0
- data/ext/carray_kernels_reduce_variance.c +3909 -0
- data/ext/carray_kernels_scan.c +3692 -0
- data/ext/carray_kernels_search.c +32137 -0
- data/ext/carray_kernels_sort.c +10625 -0
- data/ext/carray_kernels_triop.c +1391 -0
- data/ext/carray_lazy.c +567 -0
- data/ext/carray_loop.c +88 -200
- data/ext/carray_mask.c +848 -154
- data/ext/carray_math_kernel.h +120 -0
- data/ext/carray_mathfunc.c +10 -241
- data/ext/carray_median_percentile.c +1257 -0
- data/ext/carray_memory_view.c +1625 -0
- data/ext/carray_operator.c +1526 -318
- data/ext/carray_order.c +664 -1394
- data/ext/carray_partition.c +416 -0
- data/ext/carray_random.c +518 -0
- data/ext/carray_scatter.c +357 -0
- data/ext/carray_slab.c +1219 -0
- data/ext/carray_slab.h +84 -0
- data/ext/carray_sort.c +829 -0
- data/ext/carray_sort_kernel.c +620 -0
- data/ext/carray_struct.c +695 -0
- data/ext/carray_test.c +343 -229
- data/ext/carray_undef.c +34 -17
- data/ext/carray_utils.c +175 -74
- data/ext/extconf.rb +216 -55
- data/ext/mk_call_cfunc.rb +480 -0
- data/ext/mkkernel.rb +8842 -0
- data/ext/ruby_carray.c +202 -101
- data/ext/version.h +4 -14
- data/ext/version.rb +5 -13
- data/lib/carray/arrow_tensor.rb +401 -0
- data/lib/carray/attribute.rb +166 -0
- data/lib/carray/autoload_carray.rb +220 -0
- data/lib/carray/autoload_method_extension.rb +44 -0
- data/lib/carray/axis_group.rb +711 -0
- data/lib/carray/basics.rb +481 -0
- data/lib/carray/bincount_nd.rb +358 -0
- data/lib/carray/block_iterator.rb +604 -0
- data/lib/carray/boolean_reduce.rb +109 -0
- data/lib/carray/categorical.rb +561 -0
- data/lib/carray/categorical_iterator.rb +1062 -0
- data/lib/carray/complex.rb +150 -0
- data/lib/carray/conditional.rb +216 -0
- data/lib/carray/const_string.rb +228 -0
- data/lib/carray/construct.rb +139 -328
- data/lib/carray/core_extensions.rb +240 -0
- data/lib/carray/data_type_extension.rb +233 -0
- data/lib/carray/fixlen_string.rb +95 -0
- data/lib/carray/frame/concat.rb +132 -0
- data/lib/carray/frame/convert.rb +95 -0
- data/lib/carray/frame/csv_parser.rb +211 -0
- data/lib/carray/frame/frame.rb +649 -0
- data/lib/carray/frame/group.rb +186 -0
- data/lib/carray/frame/io.rb +164 -0
- data/lib/carray/frame/join.rb +248 -0
- data/lib/carray/frame/records.rb +99 -0
- data/lib/carray/frame/sort.rb +113 -0
- data/lib/carray/frame/verbs.rb +299 -0
- data/lib/carray/frame.rb +16 -0
- data/lib/carray/histogram.rb +512 -0
- data/lib/carray/inspect.rb +37 -20
- data/lib/carray/iterator.rb +57 -349
- data/lib/carray/lazy.rb +889 -0
- data/lib/carray/mask_gap_fill.rb +200 -0
- data/lib/carray/math.rb +78 -342
- data/lib/carray/meld_reduce.rb +289 -0
- data/lib/carray/methods/align_addr.rb +116 -0
- data/lib/carray/methods/bin.rb +128 -0
- data/lib/carray/methods/bincount.rb +87 -0
- data/lib/carray/methods/bit_string.rb +92 -0
- data/lib/carray/methods/broadcast.rb +63 -0
- data/lib/carray/methods/choose.rb +39 -0
- data/lib/carray/methods/composition.rb +280 -0
- data/lib/carray/methods/gather_nd.rb +206 -0
- data/lib/carray/methods/index.rb +39 -0
- data/lib/carray/methods/insert_block.rb +99 -0
- data/lib/carray/methods/is_in.rb +141 -0
- data/lib/carray/methods/join.rb +90 -0
- data/lib/carray/methods/locate_addr.rb +47 -0
- data/lib/carray/methods/mask_duplicates.rb +41 -0
- data/lib/carray/methods/meshgrid.rb +91 -0
- data/lib/carray/methods/mode.rb +126 -0
- data/lib/carray/methods/nunique.rb +46 -0
- data/lib/carray/methods/resize.rb +56 -0
- data/lib/carray/methods/snap.rb +156 -0
- data/lib/carray/methods/string_format.rb +57 -0
- data/lib/carray/methods/unique.rb +47 -0
- data/lib/carray/methods/value_counts.rb +71 -0
- data/lib/carray/mkmf.rb +124 -101
- data/lib/carray/runtime.rb +108 -0
- data/lib/carray/serialize.rb +478 -167
- data/lib/carray/slab_iterator.rb +292 -0
- data/lib/carray/stack.rb +291 -0
- data/lib/carray/string.rb +56 -180
- data/lib/carray/string_operation_extension.rb +289 -0
- data/lib/carray/struct.rb +335 -323
- data/lib/carray/struct_builder.rb +697 -0
- data/lib/carray/table.rb +41 -2
- data/lib/carray/time.rb +2255 -38
- data/lib/carray/window_iterator.rb +655 -0
- data/lib/carray.rb +55 -57
- metadata +163 -130
- data/Rakefile +0 -51
- data/TODO.md +0 -18
- data/ext/ca_iter_block.c +0 -257
- data/ext/ca_iter_dimension.c +0 -299
- data/ext/ca_iter_window.c +0 -214
- data/ext/ca_obj_mapping.c +0 -644
- data/ext/carray_iterator.c +0 -641
- data/ext/carray_math.rb +0 -850
- data/ext/carray_numeric.c +0 -259
- data/ext/carray_sort_addr.c +0 -254
- data/ext/carray_stat.c +0 -2100
- data/ext/carray_stat_proc.rb +0 -1999
- data/ext/mkmath.rb +0 -741
- data/ext/ruby_ccomplex.c +0 -509
- data/ext/ruby_float_func.c +0 -86
- data/lib/carray/array.rb +0 -8
- data/lib/carray/autoload/autoload_base.rb +0 -19
- data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
- data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
- data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
- data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
- data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
- data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
- data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
- data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
- data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
- data/lib/carray/autoload/autoload_gem_random.rb +0 -8
- data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
- data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
- data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
- data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
- data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
- data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
- data/lib/carray/autoload/autoload_object_link.rb +0 -1
- data/lib/carray/autoload/autoload_object_pack.rb +0 -2
- data/lib/carray/autoload.rb +0 -141
- data/lib/carray/basic.rb +0 -191
- data/lib/carray/broadcast.rb +0 -101
- data/lib/carray/compose.rb +0 -315
- data/lib/carray/convert.rb +0 -115
- data/lib/carray/info.rb +0 -110
- data/lib/carray/io/imagemagick.rb +0 -235
- data/lib/carray/mask.rb +0 -102
- data/lib/carray/math/histogram.rb +0 -177
- data/lib/carray/math/recurrence.rb +0 -93
- data/lib/carray/object/ca_obj_iterator.rb +0 -50
- data/lib/carray/object/ca_obj_link.rb +0 -50
- data/lib/carray/object/ca_obj_pack.rb +0 -99
- data/lib/carray/obsolete.rb +0 -256
- data/lib/carray/ordering.rb +0 -181
- data/lib/carray/testing.rb +0 -51
- data/lib/carray/transform.rb +0 -109
- data/misc/Methods.ja.md +0 -182
- data/misc/NOTE +0 -51
- data/spec/Classes/CABitfield_spec.rb +0 -58
- data/spec/Classes/CABlockIterator_spec.rb +0 -114
- data/spec/Classes/CABlock_spec.rb +0 -205
- data/spec/Classes/CAField_spec.rb +0 -39
- data/spec/Classes/CAGrid_spec.rb +0 -75
- data/spec/Classes/CAMap_spec.rb +0 -0
- data/spec/Classes/CAMapping_spec.rb +0 -105
- data/spec/Classes/CAObject_attribute_spec.rb +0 -33
- data/spec/Classes/CAObject_spec.rb +0 -33
- data/spec/Classes/CARefer_spec.rb +0 -93
- data/spec/Classes/CARepeat_spec.rb +0 -65
- data/spec/Classes/CASelect_spec.rb +0 -22
- data/spec/Classes/CAShift_spec.rb +0 -16
- data/spec/Classes/CAStruct_spec.rb +0 -71
- data/spec/Classes/CATranspose_spec.rb +0 -60
- data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
- data/spec/Classes/CAWindow_spec.rb +0 -54
- data/spec/Classes/CAWrap_spec.rb +0 -8
- data/spec/Classes/CArray_spec.rb +0 -184
- data/spec/Classes/CScalar_spec.rb +0 -55
- data/spec/Classes/ex1.rb +0 -46
- data/spec/Features/feature_130_spec.rb +0 -19
- data/spec/Features/feature_attributes_spec.rb +0 -280
- data/spec/Features/feature_boolean_spec.rb +0 -98
- data/spec/Features/feature_broadcast.rb +0 -116
- data/spec/Features/feature_cast_function.rb +0 -19
- data/spec/Features/feature_cast_spec.rb +0 -33
- data/spec/Features/feature_class_spec.rb +0 -84
- data/spec/Features/feature_complex_spec.rb +0 -42
- data/spec/Features/feature_composite_spec.rb +0 -124
- data/spec/Features/feature_convert_spec.rb +0 -46
- data/spec/Features/feature_copy_spec.rb +0 -123
- data/spec/Features/feature_creation_spec.rb +0 -84
- data/spec/Features/feature_element_spec.rb +0 -144
- data/spec/Features/feature_extream_spec.rb +0 -54
- data/spec/Features/feature_generate_spec.rb +0 -74
- data/spec/Features/feature_index_spec.rb +0 -69
- data/spec/Features/feature_mask_spec.rb +0 -580
- data/spec/Features/feature_math_spec.rb +0 -97
- data/spec/Features/feature_order_spec.rb +0 -146
- data/spec/Features/feature_ref_store_spec.rb +0 -209
- data/spec/Features/feature_serialization_spec.rb +0 -125
- data/spec/Features/feature_stat_spec.rb +0 -397
- data/spec/Features/feature_virtual_spec.rb +0 -48
- data/spec/Features/method_eq_spec.rb +0 -81
- data/spec/Features/method_is_nan_spec.rb +0 -12
- data/spec/Features/method_map_spec.rb +0 -54
- data/spec/Features/method_max_with.rb +0 -20
- data/spec/Features/method_min_with.rb +0 -19
- data/spec/Features/method_ne_spec.rb +0 -18
- data/spec/Features/method_project_spec.rb +0 -188
- data/spec/Features/method_ref_spec.rb +0 -27
- data/spec/Features/method_round_spec.rb +0 -11
- data/spec/Features/method_s_linspace_spec.rb +0 -48
- data/spec/Features/method_s_span_spec.rb +0 -14
- data/spec/Features/method_seq_spec.rb +0 -47
- data/spec/Features/method_sort_with.rb +0 -43
- data/spec/Features/method_sorted_with.rb +0 -29
- data/spec/Features/method_span_spec.rb +0 -42
- data/spec/Features/method_wrap_readonly_spec.rb +0 -43
- data/spec/UnitTest/test_CAVirtual.rb +0 -214
- data/spec/spec_all.rb +0 -10
- data/utils/ca_ase.rb +0 -21
- data/utils/ca_methods.rb +0 -15
- data/utils/cast_checker.rb +0 -30
- data/utils/convert_test.rb +0 -73
- data/utils/extract_yard.rb +0 -22
- data/utils/guess_shape.rb +0 -76
- data/utils/monkey_patch_methods.rb +0 -62
- data/utils/remove_resource_fork.sh +0 -5
data/ext/ca_obj_triop.c
ADDED
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
Lazy triadic element-wise arithmetic view: holds (op1, op2, op3,
|
|
4
|
+
op_id) and materialises the promoted result on attach. Carries
|
|
5
|
+
CA_FLAG_READ_ONLY; there is no bang path and `[]=` raises.
|
|
6
|
+
|
|
7
|
+
Sibling of ca_obj_binop.c (binary arithmetic) — same 3.0 lazy
|
|
8
|
+
substrate. Dispatched by ca_triop_kernel_lookup_vvv from
|
|
9
|
+
ca_triop_dispatch.h. Casts to the common data_type are inserted
|
|
10
|
+
as CAMonOp nodes on all 3 operands by the public builder before the
|
|
11
|
+
CATriOp is constructed.
|
|
12
|
+
|
|
13
|
+
xfer_stride model (mirrors CABinOp):
|
|
14
|
+
1. Pull op1 into `data` (the output buffer). op1 and output share
|
|
15
|
+
data_type (cast-before invariant), so this is safe as an
|
|
16
|
+
in-place gather.
|
|
17
|
+
2. Pull op2 into an arena scratch (per-node).
|
|
18
|
+
3. Pull op3 into another arena scratch (per-node).
|
|
19
|
+
4. Call the eager 1-D kernel with src1 == dst == data (in-place
|
|
20
|
+
op1), src2 == scratch2, src3 == scratch3.
|
|
21
|
+
|
|
22
|
+
Mask handling: none of the currently-defined triops (fma / fms /
|
|
23
|
+
clip) trap on integer zero divisor, so m=NULL always at the
|
|
24
|
+
kernel walk (SIMD fast path). Output mask is a blind OR of
|
|
25
|
+
operand masks (create_mask time).
|
|
26
|
+
|
|
27
|
+
Cross-ndim promotion: intentional design rejection, mirroring
|
|
28
|
+
CABinOp. Callers must reshape explicitly.
|
|
29
|
+
|
|
30
|
+
---------------------------------------------------------------------------- */
|
|
31
|
+
|
|
32
|
+
#include "carray.h"
|
|
33
|
+
#include "carray_internal.h" /* ca_lazy_arena_* */
|
|
34
|
+
#include "ca_triop_dispatch.h"
|
|
35
|
+
#include "ca_monop_dispatch.h" /* CA_MONOP_CAST_BASE */
|
|
36
|
+
|
|
37
|
+
extern VALUE ca_broadcast_view (VALUE src, int8_t ndim,
|
|
38
|
+
ca_size_t *target_dim);
|
|
39
|
+
|
|
40
|
+
int8_t CA_OBJ_TRIOP;
|
|
41
|
+
VALUE rb_cCATriOp;
|
|
42
|
+
|
|
43
|
+
extern int8_t CA_OBJ_LAZY_MARKER;
|
|
44
|
+
extern VALUE ca_lazy_wrap_scalar (VALUE other, CArray *self_ca);
|
|
45
|
+
|
|
46
|
+
/* ------------------------------------------------------------------- */
|
|
47
|
+
/* CATriOp struct */
|
|
48
|
+
/* ------------------------------------------------------------------- */
|
|
49
|
+
|
|
50
|
+
typedef struct CATriOp {
|
|
51
|
+
int16_t obj_type;
|
|
52
|
+
int8_t data_type;
|
|
53
|
+
int8_t ndim;
|
|
54
|
+
int32_t flags;
|
|
55
|
+
ca_size_t bytes;
|
|
56
|
+
ca_size_t elements;
|
|
57
|
+
ca_size_t *dim;
|
|
58
|
+
char *ptr;
|
|
59
|
+
CArray *mask;
|
|
60
|
+
char *_pool;
|
|
61
|
+
CArray *parent; /* = op1 */
|
|
62
|
+
uint32_t attach;
|
|
63
|
+
uint8_t nosync;
|
|
64
|
+
/* CATriOp-specific tail */
|
|
65
|
+
CArray *op2;
|
|
66
|
+
CArray *op3;
|
|
67
|
+
uint16_t op_id;
|
|
68
|
+
uint8_t op2_is_scalar;
|
|
69
|
+
uint8_t op3_is_scalar;
|
|
70
|
+
} CATriOp;
|
|
71
|
+
|
|
72
|
+
static size_t
|
|
73
|
+
ca_triop_dsize (const void *ap)
|
|
74
|
+
{
|
|
75
|
+
const CATriOp *ca = (const CATriOp *) ap;
|
|
76
|
+
return sizeof(CATriOp) + ca->ndim * sizeof(ca_size_t);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static size_t
|
|
80
|
+
ca_triop_pool_bytes (int8_t ndim)
|
|
81
|
+
{
|
|
82
|
+
ca_size_t n = (ndim > 0) ? ndim : 1;
|
|
83
|
+
return (size_t) n * sizeof(ca_size_t);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static void
|
|
87
|
+
ca_triop_pool_init (void *ap, int8_t ndim)
|
|
88
|
+
{
|
|
89
|
+
CATriOp *ca = (CATriOp *) ap;
|
|
90
|
+
ca->dim = (ca_size_t *) ca->_pool;
|
|
91
|
+
(void) ndim;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const rb_data_type_t catriop_data_type = {
|
|
95
|
+
.parent = &caview_data_type,
|
|
96
|
+
.wrap_struct_name = "CATriOp",
|
|
97
|
+
.function = {
|
|
98
|
+
.dmark = ca_mark,
|
|
99
|
+
.dfree = ca_free,
|
|
100
|
+
.dsize = ca_triop_dsize,
|
|
101
|
+
.dcompact = NULL
|
|
102
|
+
},
|
|
103
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/* ------------------------------------------------------------------- */
|
|
107
|
+
/* setup / new / free */
|
|
108
|
+
/* ------------------------------------------------------------------- */
|
|
109
|
+
|
|
110
|
+
static int
|
|
111
|
+
ca_triop_setup (CATriOp *ca, CArray *op1, CArray *op2, CArray *op3,
|
|
112
|
+
uint16_t op_id)
|
|
113
|
+
{
|
|
114
|
+
int8_t out_dt = ca_lazy_promote_triop(op_id, op1->data_type,
|
|
115
|
+
op2->data_type, op3->data_type);
|
|
116
|
+
ca_size_t out_bytes = ca_sizeof[out_dt];
|
|
117
|
+
|
|
118
|
+
ca->obj_type = CA_OBJ_TRIOP;
|
|
119
|
+
ca->data_type = out_dt;
|
|
120
|
+
ca->flags = CA_FLAG_READ_ONLY;
|
|
121
|
+
ca->ndim = op1->ndim;
|
|
122
|
+
ca->bytes = out_bytes;
|
|
123
|
+
ca->elements = op1->elements;
|
|
124
|
+
ca->ptr = NULL;
|
|
125
|
+
ca->mask = NULL;
|
|
126
|
+
if ( ! ca->_pool ) {
|
|
127
|
+
ca->dim = ALLOC_N(ca_size_t, op1->ndim);
|
|
128
|
+
}
|
|
129
|
+
ca->parent = op1;
|
|
130
|
+
ca->attach = 0;
|
|
131
|
+
ca->nosync = 0;
|
|
132
|
+
ca->op2 = op2;
|
|
133
|
+
ca->op3 = op3;
|
|
134
|
+
ca->op_id = op_id;
|
|
135
|
+
ca->op2_is_scalar = ( op2->elements == 1 && op1->elements > 1 ) ? 1 : 0;
|
|
136
|
+
ca->op3_is_scalar = ( op3->elements == 1 && op1->elements > 1 ) ? 1 : 0;
|
|
137
|
+
|
|
138
|
+
memcpy(ca->dim, op1->dim, op1->ndim * sizeof(ca_size_t));
|
|
139
|
+
|
|
140
|
+
if ( ca_has_mask(op1) || ca_has_mask(op2) || ca_has_mask(op3) ) {
|
|
141
|
+
ca_create_mask(ca);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if ( ca_is_scalar(op1) && ca_is_scalar(op2) && ca_is_scalar(op3) ) {
|
|
145
|
+
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
CATriOp *
|
|
152
|
+
ca_triop_new (CArray *op1, CArray *op2, CArray *op3, uint16_t op_id)
|
|
153
|
+
{
|
|
154
|
+
CATriOp *ca = (CATriOp *) ca_array_alloc(CA_OBJ_TRIOP, op1->ndim);
|
|
155
|
+
ca_triop_setup(ca, op1, op2, op3, op_id);
|
|
156
|
+
return ca;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static void
|
|
160
|
+
free_ca_triop (void *ap)
|
|
161
|
+
{
|
|
162
|
+
CATriOp *ca = (CATriOp *) ap;
|
|
163
|
+
if ( ca != NULL ) {
|
|
164
|
+
ca_free(ca->mask);
|
|
165
|
+
if ( ca->_pool ) {
|
|
166
|
+
ca_array_free(ca);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
xfree(ca->dim);
|
|
170
|
+
xfree(ca);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* ------------------------------------------------------------------- */
|
|
176
|
+
/* operation function table */
|
|
177
|
+
/* ------------------------------------------------------------------- */
|
|
178
|
+
|
|
179
|
+
static void ca_triop_func_xfer_stride (void *ap, ca_size_t *starts,
|
|
180
|
+
ca_size_t *counts, ca_size_t *strides,
|
|
181
|
+
void *data, int dir);
|
|
182
|
+
|
|
183
|
+
static void *
|
|
184
|
+
ca_triop_func_clone (void *ap)
|
|
185
|
+
{
|
|
186
|
+
CATriOp *ca = (CATriOp *) ap;
|
|
187
|
+
return ca_triop_new(ca->parent, ca->op2, ca->op3, ca->op_id);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
static void
|
|
191
|
+
ca_triop_func_xfer_index (void *ap, ca_size_t *idx, void *data, int dir)
|
|
192
|
+
{
|
|
193
|
+
CATriOp *ca = (CATriOp *) ap;
|
|
194
|
+
ca_size_t starts[CA_RANK_MAX];
|
|
195
|
+
ca_size_t counts[CA_RANK_MAX];
|
|
196
|
+
ca_size_t strides[CA_RANK_MAX];
|
|
197
|
+
int8_t k;
|
|
198
|
+
ca_size_t s;
|
|
199
|
+
|
|
200
|
+
if ( dir != CA_XFER_GET ) {
|
|
201
|
+
rb_raise(rb_eRuntimeError, "CATriOp is read-only (xfer_index PUT)");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
s = ca->bytes;
|
|
205
|
+
for ( k = ca->ndim - 1; k >= 0; k-- ) {
|
|
206
|
+
starts[k] = idx[k];
|
|
207
|
+
counts[k] = 1;
|
|
208
|
+
strides[k] = s;
|
|
209
|
+
}
|
|
210
|
+
ca_triop_func_xfer_stride(ca, starts, counts, strides, data, CA_XFER_GET);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
static void
|
|
214
|
+
ca_triop_func_xfer_addrs (void *ap, ca_size_t n, ca_size_t *addrs,
|
|
215
|
+
void *data, int dir)
|
|
216
|
+
{
|
|
217
|
+
CATriOp *ca = (CATriOp *) ap;
|
|
218
|
+
ca_size_t i;
|
|
219
|
+
char *out = (char *) data;
|
|
220
|
+
|
|
221
|
+
if ( dir != CA_XFER_GET ) {
|
|
222
|
+
rb_raise(rb_eRuntimeError, "CATriOp is read-only (xfer_addrs PUT)");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
for ( i = 0; i < n; i++ ) {
|
|
226
|
+
ca_size_t idx[CA_RANK_MAX];
|
|
227
|
+
ca_addr2index((CArray *)ca, addrs[i], idx);
|
|
228
|
+
ca_triop_func_xfer_index(ca, idx, out + i * ca->bytes, CA_XFER_GET);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* Test / observability counters (mirror CABinOp's counters). */
|
|
233
|
+
ca_size_t ca_triop_scratch_acquire_count = 0;
|
|
234
|
+
ca_size_t ca_triop_materialise_call_count = 0;
|
|
235
|
+
|
|
236
|
+
/* Pull one operand into a scratch (or one cell if it is a scalar to
|
|
237
|
+
be broadcast at step=0). Returns the scratch pointer; updates
|
|
238
|
+
*step_out to 0 (scalar) or 1 (same-shape). */
|
|
239
|
+
static void *
|
|
240
|
+
pull_operand (CArray *op, int is_scalar, ca_size_t *starts,
|
|
241
|
+
ca_size_t *counts, ca_size_t slab_n, int8_t ndim,
|
|
242
|
+
ca_size_t *step_out)
|
|
243
|
+
{
|
|
244
|
+
void *scratch;
|
|
245
|
+
ca_size_t bytes = op->bytes;
|
|
246
|
+
int8_t k;
|
|
247
|
+
|
|
248
|
+
if ( is_scalar ) {
|
|
249
|
+
ca_size_t one_starts[CA_RANK_MAX] = {0};
|
|
250
|
+
ca_size_t one_counts[CA_RANK_MAX];
|
|
251
|
+
ca_size_t one_strides[CA_RANK_MAX];
|
|
252
|
+
for ( k = 0; k < op->ndim; k++ ) {
|
|
253
|
+
one_counts[k] = 1;
|
|
254
|
+
one_strides[k] = bytes;
|
|
255
|
+
}
|
|
256
|
+
scratch = ca_lazy_arena_acquire(bytes);
|
|
257
|
+
ca_triop_scratch_acquire_count++;
|
|
258
|
+
ca_xfer_stride(op, one_starts, one_counts, one_strides, scratch,
|
|
259
|
+
CA_XFER_GET);
|
|
260
|
+
*step_out = 0;
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
ca_size_t op_strides[CA_RANK_MAX];
|
|
264
|
+
ca_size_t s = bytes;
|
|
265
|
+
for ( k = ndim - 1; k >= 0; k-- ) {
|
|
266
|
+
op_strides[k] = s;
|
|
267
|
+
s *= counts[k];
|
|
268
|
+
}
|
|
269
|
+
scratch = ca_lazy_arena_acquire(slab_n * bytes);
|
|
270
|
+
ca_triop_scratch_acquire_count++;
|
|
271
|
+
ca_xfer_stride(op, starts, counts, op_strides, scratch, CA_XFER_GET);
|
|
272
|
+
*step_out = 1;
|
|
273
|
+
}
|
|
274
|
+
return scratch;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
static void
|
|
278
|
+
ca_triop_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
279
|
+
ca_size_t *strides, void *data, int dir)
|
|
280
|
+
{
|
|
281
|
+
CATriOp *to = (CATriOp *) ap;
|
|
282
|
+
ca_size_t slab_n;
|
|
283
|
+
int8_t k;
|
|
284
|
+
void *scratch2, *scratch3;
|
|
285
|
+
ca_size_t op2_step, op3_step;
|
|
286
|
+
|
|
287
|
+
if ( dir != CA_XFER_GET ) {
|
|
288
|
+
rb_raise(rb_eRuntimeError, "CATriOp is read-only (xfer_stride PUT)");
|
|
289
|
+
}
|
|
290
|
+
ca_triop_materialise_call_count++;
|
|
291
|
+
|
|
292
|
+
slab_n = 1;
|
|
293
|
+
for ( k = 0; k < to->ndim; k++ ) slab_n *= counts[k];
|
|
294
|
+
|
|
295
|
+
/* Step 1: pull op1 into the output buffer. */
|
|
296
|
+
ca_xfer_stride(to->parent, starts, counts, strides, data, CA_XFER_GET);
|
|
297
|
+
|
|
298
|
+
/* Step 2: pull op2 into an arena scratch. */
|
|
299
|
+
scratch2 = pull_operand(to->op2, to->op2_is_scalar, starts, counts,
|
|
300
|
+
slab_n, to->ndim, &op2_step);
|
|
301
|
+
|
|
302
|
+
/* Step 3: pull op3 into another arena scratch. */
|
|
303
|
+
scratch3 = pull_operand(to->op3, to->op3_is_scalar, starts, counts,
|
|
304
|
+
slab_n, to->ndim, &op3_step);
|
|
305
|
+
|
|
306
|
+
/* Step 4: apply the kernel. ptr1 == ptr4 (in-place op1); no
|
|
307
|
+
currently-defined triop traps, so m=NULL. */
|
|
308
|
+
{
|
|
309
|
+
ca_triop_func_t fn = ca_triop_kernel_lookup_vvv(to->op_id, to->data_type);
|
|
310
|
+
if ( fn == NULL ) {
|
|
311
|
+
ca_lazy_arena_release(scratch3);
|
|
312
|
+
ca_lazy_arena_release(scratch2);
|
|
313
|
+
rb_raise(rb_eNotImpError,
|
|
314
|
+
"CATriOp: kernel not implemented (op_id=%u data_type=%d)",
|
|
315
|
+
(unsigned) to->op_id, (int) to->data_type);
|
|
316
|
+
}
|
|
317
|
+
fn(slab_n, NULL,
|
|
318
|
+
(char *)data, 1, /* src1 == dst (op1, in-place) */
|
|
319
|
+
(char *)scratch2, op2_step, /* src2 (op2) */
|
|
320
|
+
(char *)scratch3, op3_step, /* src3 (op3) */
|
|
321
|
+
(char *)data, 1); /* dst */
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
ca_lazy_arena_release(scratch3);
|
|
325
|
+
ca_lazy_arena_release(scratch2);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
static void
|
|
329
|
+
ca_triop_func_xfer_all (void *ap, void *data, int dir)
|
|
330
|
+
{
|
|
331
|
+
CATriOp *ca = (CATriOp *) ap;
|
|
332
|
+
ca_size_t starts[CA_RANK_MAX];
|
|
333
|
+
ca_size_t native[CA_RANK_MAX];
|
|
334
|
+
int8_t k;
|
|
335
|
+
ca_size_t s = ca->bytes;
|
|
336
|
+
for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
|
|
337
|
+
for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
|
|
338
|
+
ca_xfer_stride(ca, starts, ca->dim, native, data, dir);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
static void
|
|
342
|
+
ca_triop_func_allocate (void *ap)
|
|
343
|
+
{
|
|
344
|
+
CATriOp *ca = (CATriOp *) ap;
|
|
345
|
+
ca->ptr = xmalloc(ca_length(ca));
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
static void
|
|
349
|
+
ca_triop_func_attach (void *ap)
|
|
350
|
+
{
|
|
351
|
+
/* CAREFUL: call the view-specific xfer_stride directly (same as
|
|
352
|
+
CABinOp). The public dispatcher's self-memcpy fast path would
|
|
353
|
+
leave the freshly-allocated buffer holding garbage. */
|
|
354
|
+
CATriOp *ca = (CATriOp *) ap;
|
|
355
|
+
ca_size_t starts[CA_RANK_MAX];
|
|
356
|
+
ca_size_t native[CA_RANK_MAX];
|
|
357
|
+
int8_t k;
|
|
358
|
+
ca_size_t s;
|
|
359
|
+
|
|
360
|
+
ca->ptr = xmalloc(ca_length(ca));
|
|
361
|
+
|
|
362
|
+
s = ca->bytes;
|
|
363
|
+
for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
|
|
364
|
+
for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
|
|
365
|
+
ca_triop_func_xfer_stride(ca, starts, ca->dim, native, ca->ptr, CA_XFER_GET);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
static void
|
|
369
|
+
ca_triop_func_sync (void *ap)
|
|
370
|
+
{
|
|
371
|
+
(void) ap; /* read-only */
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
static void
|
|
375
|
+
ca_triop_func_detach (void *ap)
|
|
376
|
+
{
|
|
377
|
+
CATriOp *ca = (CATriOp *) ap;
|
|
378
|
+
xfree(ca->ptr);
|
|
379
|
+
ca->ptr = NULL;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
NORETURN(static void ca_triop_func_fill_data (void *ap, void *ptr));
|
|
383
|
+
static void
|
|
384
|
+
ca_triop_func_fill_data (void *ap, void *ptr)
|
|
385
|
+
{
|
|
386
|
+
(void) ap; (void) ptr;
|
|
387
|
+
rb_raise(rb_eRuntimeError, "CATriOp is read-only (fill_data)");
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/* Build out.mask. Blind OR of the three operand masks — none of the
|
|
391
|
+
currently-defined triops carry a Kleene 3-valued fixup. */
|
|
392
|
+
static void
|
|
393
|
+
ca_triop_func_create_mask (void *ap)
|
|
394
|
+
{
|
|
395
|
+
CATriOp *to = (CATriOp *) ap;
|
|
396
|
+
CArray *op1 = to->parent;
|
|
397
|
+
CArray *op2 = to->op2;
|
|
398
|
+
CArray *op3 = to->op3;
|
|
399
|
+
boolean8_t *dst, *m1, *m2, *m3;
|
|
400
|
+
ca_size_t i, n;
|
|
401
|
+
int has1, has2, has3;
|
|
402
|
+
|
|
403
|
+
has1 = ca_has_mask(op1);
|
|
404
|
+
has2 = ca_has_mask(op2);
|
|
405
|
+
has3 = ca_has_mask(op3);
|
|
406
|
+
if ( ! has1 && ! has2 && ! has3 ) return;
|
|
407
|
+
|
|
408
|
+
to->mask = (CArray *) carray_new(CA_BOOLEAN, to->ndim, to->dim, 0, NULL);
|
|
409
|
+
dst = (boolean8_t *) to->mask->ptr;
|
|
410
|
+
n = to->elements;
|
|
411
|
+
|
|
412
|
+
if ( has1 ) ca_attach(op1);
|
|
413
|
+
if ( has2 ) ca_attach(op2);
|
|
414
|
+
if ( has3 ) ca_attach(op3);
|
|
415
|
+
|
|
416
|
+
m1 = has1 ? (boolean8_t *) op1->mask->ptr : NULL;
|
|
417
|
+
m2 = has2 ? (boolean8_t *) op2->mask->ptr : NULL;
|
|
418
|
+
m3 = has3 ? (boolean8_t *) op3->mask->ptr : NULL;
|
|
419
|
+
|
|
420
|
+
for ( i = 0; i < n; i++ ) {
|
|
421
|
+
ca_size_t i2 = to->op2_is_scalar ? 0 : i;
|
|
422
|
+
ca_size_t i3 = to->op3_is_scalar ? 0 : i;
|
|
423
|
+
boolean8_t a = m1 ? m1[i] : 0;
|
|
424
|
+
boolean8_t b = m2 ? m2[i2] : 0;
|
|
425
|
+
boolean8_t c = m3 ? m3[i3] : 0;
|
|
426
|
+
dst[i] = (boolean8_t) ( a | b | c );
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if ( has3 ) ca_detach(op3);
|
|
430
|
+
if ( has2 ) ca_detach(op2);
|
|
431
|
+
if ( has1 ) ca_detach(op1);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
ca_operation_function_t ca_triop_func = {
|
|
435
|
+
-1, /* CA_OBJ_TRIOP, set at install time */
|
|
436
|
+
CA_VIEW_ARRAY,
|
|
437
|
+
free_ca_triop,
|
|
438
|
+
ca_triop_func_clone,
|
|
439
|
+
ca_triop_func_allocate,
|
|
440
|
+
ca_triop_func_attach,
|
|
441
|
+
ca_triop_func_sync,
|
|
442
|
+
ca_triop_func_detach,
|
|
443
|
+
ca_triop_func_fill_data,
|
|
444
|
+
ca_triop_func_create_mask,
|
|
445
|
+
ca_triop_func_xfer_index,
|
|
446
|
+
ca_triop_func_xfer_addrs,
|
|
447
|
+
NULL, /* fold_stride: never fold — op boundary */
|
|
448
|
+
ca_triop_func_xfer_stride,
|
|
449
|
+
ca_triop_func_xfer_all,
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
/* ------------------------------------------------------------------- */
|
|
453
|
+
/* Public builder */
|
|
454
|
+
/* ------------------------------------------------------------------- */
|
|
455
|
+
|
|
456
|
+
static VALUE
|
|
457
|
+
collapse_marker (VALUE cary)
|
|
458
|
+
{
|
|
459
|
+
CArray *ca;
|
|
460
|
+
if ( ! rb_obj_is_carray(cary) ) return cary;
|
|
461
|
+
TypedData_Get_Struct(cary, CArray, &carray_data_type, ca);
|
|
462
|
+
if ( ca->obj_type == CA_OBJ_LAZY_MARKER ) {
|
|
463
|
+
return rb_ca_parent(cary);
|
|
464
|
+
}
|
|
465
|
+
return cary;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/* Low-level constructor. Does NOT insert cast nodes; the caller must
|
|
469
|
+
have promoted all three operands to the common data_type. */
|
|
470
|
+
static VALUE
|
|
471
|
+
rb_ca_triop_new (VALUE cary1, VALUE cary2, VALUE cary3, uint16_t op_id)
|
|
472
|
+
{
|
|
473
|
+
volatile VALUE obj;
|
|
474
|
+
CArray *op1, *op2, *op3;
|
|
475
|
+
CATriOp *ca;
|
|
476
|
+
rb_check_carray_object(cary1);
|
|
477
|
+
rb_check_carray_object(cary2);
|
|
478
|
+
rb_check_carray_object(cary3);
|
|
479
|
+
TypedData_Get_Struct(cary1, CArray, &carray_data_type, op1);
|
|
480
|
+
TypedData_Get_Struct(cary2, CArray, &carray_data_type, op2);
|
|
481
|
+
TypedData_Get_Struct(cary3, CArray, &carray_data_type, op3);
|
|
482
|
+
ca = ca_triop_new(op1, op2, op3, op_id);
|
|
483
|
+
obj = ca_wrap_struct(ca);
|
|
484
|
+
rb_ca_set_parent(obj, cary1);
|
|
485
|
+
/* Pin op2 / op3 via ivars so GC keeps them alive. parent slot
|
|
486
|
+
already pins op1. */
|
|
487
|
+
rb_ivar_set(obj, rb_intern("__triop_op2__"), cary2);
|
|
488
|
+
rb_ivar_set(obj, rb_intern("__triop_op3__"), cary3);
|
|
489
|
+
return obj;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/* Insert a cast node if operand's data_type differs from target. */
|
|
493
|
+
static VALUE
|
|
494
|
+
insert_cast (VALUE cary, int8_t target_dt, CArray **ca_out)
|
|
495
|
+
{
|
|
496
|
+
CArray *ca;
|
|
497
|
+
TypedData_Get_Struct(cary, CArray, &carray_data_type, ca);
|
|
498
|
+
if ( ca->data_type != target_dt ) {
|
|
499
|
+
VALUE cast_op = INT2NUM(CA_MONOP_CAST_BASE + target_dt);
|
|
500
|
+
cary = rb_funcall(rb_const_get(rb_cObject, rb_intern("CAMonOp")),
|
|
501
|
+
rb_intern("__build__"), 2, cary, cast_op);
|
|
502
|
+
TypedData_Get_Struct(cary, CArray, &carray_data_type, ca);
|
|
503
|
+
}
|
|
504
|
+
*ca_out = ca;
|
|
505
|
+
return cary;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/* Public builder: build a CATriOp tree node for op_id over
|
|
509
|
+
(cary1, cary2, cary3). Inserts cast nodes when any operand's
|
|
510
|
+
data_type differs from the common data_type, then resolves
|
|
511
|
+
same-ndim size-1 broadcast pairwise against op1 (the walk anchor).
|
|
512
|
+
|
|
513
|
+
Broadcast: each of op2 / op3 is aligned against op1 via
|
|
514
|
+
ca_broadcast_pair. After alignment, each must have either the
|
|
515
|
+
same elements as op1 or be a 1-element CScalar (walked with
|
|
516
|
+
element_step = 0 by the kernel). If op1 itself is a 1-element
|
|
517
|
+
CScalar and any of op2 / op3 is an array, op1 is lifted via
|
|
518
|
+
ca_repeat_new + ca_broadcast_view (same trick as CABinOp).
|
|
519
|
+
|
|
520
|
+
Cross-ndim promotion is rejected, mirroring CABinOp. */
|
|
521
|
+
VALUE
|
|
522
|
+
rb_ca_triop_build (VALUE cary1, VALUE cary2, VALUE cary3, uint16_t op_id)
|
|
523
|
+
{
|
|
524
|
+
CArray *op1, *op2, *op3;
|
|
525
|
+
int8_t dt1, dt2, dt3;
|
|
526
|
+
volatile VALUE r1, r2, r3;
|
|
527
|
+
|
|
528
|
+
r1 = collapse_marker(cary1);
|
|
529
|
+
r2 = collapse_marker(cary2);
|
|
530
|
+
r3 = collapse_marker(cary3);
|
|
531
|
+
|
|
532
|
+
/* Promote non-CArray Ruby values (e.g. clip's Numeric bounds) to
|
|
533
|
+
CScalars carrying an existing operand's data_type. */
|
|
534
|
+
if ( ! rb_obj_is_carray(r1) || ! rb_obj_is_carray(r2) || ! rb_obj_is_carray(r3) ) {
|
|
535
|
+
/* Find an anchor CArray for scalar promotion. */
|
|
536
|
+
CArray *anchor = NULL;
|
|
537
|
+
if ( rb_obj_is_carray(r1) ) TypedData_Get_Struct(r1, CArray, &carray_data_type, anchor);
|
|
538
|
+
else if ( rb_obj_is_carray(r2) ) TypedData_Get_Struct(r2, CArray, &carray_data_type, anchor);
|
|
539
|
+
else if ( rb_obj_is_carray(r3) ) TypedData_Get_Struct(r3, CArray, &carray_data_type, anchor);
|
|
540
|
+
if ( anchor == NULL ) {
|
|
541
|
+
rb_raise(rb_eArgError,
|
|
542
|
+
"CATriOp: at least one operand must be a CArray");
|
|
543
|
+
}
|
|
544
|
+
if ( ! rb_obj_is_carray(r1) ) r1 = ca_lazy_wrap_scalar(r1, anchor);
|
|
545
|
+
if ( ! rb_obj_is_carray(r2) ) r2 = ca_lazy_wrap_scalar(r2, anchor);
|
|
546
|
+
if ( ! rb_obj_is_carray(r3) ) r3 = ca_lazy_wrap_scalar(r3, anchor);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
TypedData_Get_Struct(r1, CArray, &carray_data_type, op1);
|
|
550
|
+
TypedData_Get_Struct(r2, CArray, &carray_data_type, op2);
|
|
551
|
+
TypedData_Get_Struct(r3, CArray, &carray_data_type, op3);
|
|
552
|
+
|
|
553
|
+
/* Step 1: cast to common data_type. */
|
|
554
|
+
ca_triop_kernel_input_data_types(op_id,
|
|
555
|
+
op1->data_type, op2->data_type, op3->data_type,
|
|
556
|
+
&dt1, &dt2, &dt3);
|
|
557
|
+
r1 = insert_cast(r1, dt1, &op1);
|
|
558
|
+
r2 = insert_cast(r2, dt2, &op2);
|
|
559
|
+
r3 = insert_cast(r3, dt3, &op3);
|
|
560
|
+
|
|
561
|
+
/* Step 2: pairwise broadcast against op1 (the walk anchor). If op1
|
|
562
|
+
is a scalar and any of op2 / op3 is an array, lift op1 up to the
|
|
563
|
+
array shape first. */
|
|
564
|
+
{
|
|
565
|
+
CArray *anchor = NULL;
|
|
566
|
+
volatile VALUE r_anchor = Qnil;
|
|
567
|
+
int8_t anchor_ndim;
|
|
568
|
+
/* Pick the largest-ndim non-scalar operand as anchor. */
|
|
569
|
+
if ( op1->elements > 1 ) { anchor = op1; r_anchor = r1; }
|
|
570
|
+
else if ( op2->elements > 1 ) { anchor = op2; r_anchor = r2; }
|
|
571
|
+
else if ( op3->elements > 1 ) { anchor = op3; r_anchor = r3; }
|
|
572
|
+
if ( anchor && anchor != op1 ) {
|
|
573
|
+
/* op1 is a CScalar but the walk shape is determined by another
|
|
574
|
+
operand. Lift op1 up to anchor's shape via
|
|
575
|
+
ca_repeat_new + ca_broadcast_view (same trick as CABinOp's
|
|
576
|
+
non-commutative left-scalar path). */
|
|
577
|
+
anchor_ndim = anchor->ndim;
|
|
578
|
+
if ( anchor_ndim > op1->ndim ) {
|
|
579
|
+
ca_size_t count[CA_RANK_MAX];
|
|
580
|
+
int8_t k;
|
|
581
|
+
for ( k = 0; k < anchor_ndim - 1; k++ ) count[k] = 1;
|
|
582
|
+
count[anchor_ndim - 1] = 0;
|
|
583
|
+
r1 = rb_ca_repeat_new(r1, anchor_ndim, count);
|
|
584
|
+
TypedData_Get_Struct(r1, CArray, &carray_data_type, op1);
|
|
585
|
+
}
|
|
586
|
+
r1 = ca_broadcast_view(r1, anchor_ndim, anchor->dim);
|
|
587
|
+
TypedData_Get_Struct(r1, CArray, &carray_data_type, op1);
|
|
588
|
+
(void) r_anchor;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/* Now align op2 / op3 against op1 for size-1 broadcast. */
|
|
593
|
+
ca_broadcast_pair(&r1, &r2);
|
|
594
|
+
TypedData_Get_Struct(r1, CArray, &carray_data_type, op1);
|
|
595
|
+
TypedData_Get_Struct(r2, CArray, &carray_data_type, op2);
|
|
596
|
+
ca_broadcast_pair(&r1, &r3);
|
|
597
|
+
TypedData_Get_Struct(r1, CArray, &carray_data_type, op1);
|
|
598
|
+
TypedData_Get_Struct(r3, CArray, &carray_data_type, op3);
|
|
599
|
+
|
|
600
|
+
/* Step 3: shape sanity — each of op2 / op3 must match op1's element
|
|
601
|
+
count OR be a 1-element CScalar (kernel walks with element_step
|
|
602
|
+
= 0 in that case). */
|
|
603
|
+
if ( op2->elements != op1->elements && op2->elements != 1 ) {
|
|
604
|
+
rb_raise(rb_eArgError,
|
|
605
|
+
"CATriOp: shape mismatch on op2 (%lld vs %lld) — only "
|
|
606
|
+
"same-ndim size-1 broadcast is supported; cross-ndim "
|
|
607
|
+
"promotion is not adopted in CArray "
|
|
608
|
+
"(reshape explicitly)",
|
|
609
|
+
(long long) op2->elements, (long long) op1->elements);
|
|
610
|
+
}
|
|
611
|
+
if ( op3->elements != op1->elements && op3->elements != 1 ) {
|
|
612
|
+
rb_raise(rb_eArgError,
|
|
613
|
+
"CATriOp: shape mismatch on op3 (%lld vs %lld) — only "
|
|
614
|
+
"same-ndim size-1 broadcast is supported; cross-ndim "
|
|
615
|
+
"promotion is not adopted in CArray "
|
|
616
|
+
"(reshape explicitly)",
|
|
617
|
+
(long long) op3->elements, (long long) op1->elements);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
return rb_ca_triop_new(r1, r2, r3, op_id);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
static VALUE
|
|
624
|
+
rb_ca_triop_s_build (VALUE klass, VALUE cary1, VALUE cary2, VALUE cary3,
|
|
625
|
+
VALUE op_id_val)
|
|
626
|
+
{
|
|
627
|
+
uint16_t op_id = (uint16_t) NUM2UINT(op_id_val);
|
|
628
|
+
(void) klass;
|
|
629
|
+
return rb_ca_triop_build(cary1, cary2, cary3, op_id);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
static VALUE
|
|
633
|
+
rb_ca_triop_op_id (VALUE self)
|
|
634
|
+
{
|
|
635
|
+
CATriOp *to;
|
|
636
|
+
TypedData_Get_Struct(self, CATriOp, &catriop_data_type, to);
|
|
637
|
+
return UINT2NUM(to->op_id);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
static VALUE
|
|
641
|
+
rb_ca_triop_op2 (VALUE self)
|
|
642
|
+
{
|
|
643
|
+
return rb_ivar_get(self, rb_intern("__triop_op2__"));
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
static VALUE
|
|
647
|
+
rb_ca_triop_op3 (VALUE self)
|
|
648
|
+
{
|
|
649
|
+
return rb_ivar_get(self, rb_intern("__triop_op3__"));
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/* Test instrumentation. */
|
|
653
|
+
static VALUE
|
|
654
|
+
rb_ca_triop_s_reset_scratch_counter (VALUE klass)
|
|
655
|
+
{
|
|
656
|
+
(void) klass;
|
|
657
|
+
ca_triop_scratch_acquire_count = 0;
|
|
658
|
+
return Qnil;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
static VALUE
|
|
662
|
+
rb_ca_triop_s_scratch_count (VALUE klass)
|
|
663
|
+
{
|
|
664
|
+
(void) klass;
|
|
665
|
+
return SIZE2NUM(ca_triop_scratch_acquire_count);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
static VALUE
|
|
669
|
+
rb_ca_triop_s_reset_materialise_counter (VALUE klass)
|
|
670
|
+
{
|
|
671
|
+
(void) klass;
|
|
672
|
+
ca_triop_materialise_call_count = 0;
|
|
673
|
+
return Qnil;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
static VALUE
|
|
677
|
+
rb_ca_triop_s_materialise_count (VALUE klass)
|
|
678
|
+
{
|
|
679
|
+
(void) klass;
|
|
680
|
+
return SIZE2NUM(ca_triop_materialise_call_count);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
static VALUE
|
|
684
|
+
rb_ca_triop_s_allocate (VALUE klass)
|
|
685
|
+
{
|
|
686
|
+
CATriOp *ca;
|
|
687
|
+
return TypedData_Make_Struct(klass, CATriOp, &catriop_data_type, ca);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
static VALUE
|
|
691
|
+
rb_ca_triop_initialize_copy (VALUE self, VALUE other)
|
|
692
|
+
{
|
|
693
|
+
CATriOp *ca, *cs;
|
|
694
|
+
TypedData_Get_Struct(self, CATriOp, &catriop_data_type, ca);
|
|
695
|
+
TypedData_Get_Struct(other, CATriOp, &catriop_data_type, cs);
|
|
696
|
+
if ( ca_func[CA_OBJ_TRIOP].pool_init ) {
|
|
697
|
+
ca_array_pool_alloc(ca, CA_OBJ_TRIOP, cs->parent->ndim);
|
|
698
|
+
}
|
|
699
|
+
ca_triop_setup(ca, cs->parent, cs->op2, cs->op3, cs->op_id);
|
|
700
|
+
return self;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
void
|
|
704
|
+
Init_ca_obj_triop (void)
|
|
705
|
+
{
|
|
706
|
+
rb_cCATriOp = rb_define_class("CATriOp", rb_cCAView);
|
|
707
|
+
|
|
708
|
+
ca_triop_func.struct_size = sizeof(CATriOp);
|
|
709
|
+
ca_triop_func.pool_bytes = ca_triop_pool_bytes;
|
|
710
|
+
ca_triop_func.pool_init = ca_triop_pool_init;
|
|
711
|
+
|
|
712
|
+
CA_OBJ_TRIOP = ca_install_obj_type(rb_cCATriOp,
|
|
713
|
+
&catriop_data_type,
|
|
714
|
+
rb_cCArrayMask,
|
|
715
|
+
&carray_mask_data_type, &ca_triop_func, sizeof(ca_triop_func));
|
|
716
|
+
rb_define_const(rb_cObject, "CA_OBJ_TRIOP", INT2NUM(CA_OBJ_TRIOP));
|
|
717
|
+
|
|
718
|
+
/* op_id constants shared with lib/carray/lazy.rb. */
|
|
719
|
+
rb_define_const(rb_cCATriOp, "OP_FMA", INT2NUM(CA_TRIOP_FMA));
|
|
720
|
+
rb_define_const(rb_cCATriOp, "OP_FMS", INT2NUM(CA_TRIOP_FMS));
|
|
721
|
+
rb_define_const(rb_cCATriOp, "OP_CLIP", INT2NUM(CA_TRIOP_CLIP));
|
|
722
|
+
|
|
723
|
+
rb_define_alloc_func(rb_cCATriOp, rb_ca_triop_s_allocate);
|
|
724
|
+
rb_define_method(rb_cCATriOp, "initialize_copy",
|
|
725
|
+
rb_ca_triop_initialize_copy, 1);
|
|
726
|
+
|
|
727
|
+
rb_define_singleton_method(rb_cCATriOp, "__build__",
|
|
728
|
+
rb_ca_triop_s_build, 4);
|
|
729
|
+
|
|
730
|
+
rb_define_method(rb_cCATriOp, "__op_id__",
|
|
731
|
+
rb_ca_triop_op_id, 0);
|
|
732
|
+
rb_define_method(rb_cCATriOp, "__triop_op2__",
|
|
733
|
+
rb_ca_triop_op2, 0);
|
|
734
|
+
rb_define_method(rb_cCATriOp, "__triop_op3__",
|
|
735
|
+
rb_ca_triop_op3, 0);
|
|
736
|
+
|
|
737
|
+
/* Test instrumentation. */
|
|
738
|
+
rb_define_singleton_method(rb_cCATriOp, "__reset_scratch_counter__",
|
|
739
|
+
rb_ca_triop_s_reset_scratch_counter, 0);
|
|
740
|
+
rb_define_singleton_method(rb_cCATriOp, "__scratch_count__",
|
|
741
|
+
rb_ca_triop_s_scratch_count, 0);
|
|
742
|
+
rb_define_singleton_method(rb_cCATriOp, "__reset_materialise_counter__",
|
|
743
|
+
rb_ca_triop_s_reset_materialise_counter, 0);
|
|
744
|
+
rb_define_singleton_method(rb_cCATriOp, "__materialise_count__",
|
|
745
|
+
rb_ca_triop_s_materialise_count, 0);
|
|
746
|
+
}
|