carray 2.0.1 → 3.0.1
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 +6 -25
- data/CHANGELOG.md +338 -0
- data/{NEWS.md → CHANGELOG.v1.md} +3 -0
- data/LICENSE +1 -1
- data/README.md +120 -36
- data/carray.gemspec +32 -30
- 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 +1244 -0
- data/ext/ca_bincmp_dispatch.c +76 -0
- data/ext/ca_bincmp_dispatch.h +85 -0
- data/ext/ca_binop_dispatch.c +124 -0
- data/ext/ca_binop_dispatch.h +152 -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 +239 -0
- data/ext/ca_group_iter.c +304 -0
- data/ext/ca_iter_substrate.h +325 -0
- data/ext/ca_kernel_iterator.c +4367 -0
- data/ext/ca_kernel_iterator.h +2596 -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 +839 -0
- data/ext/ca_obj_binop.c +948 -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 +967 -0
- data/ext/ca_obj_face.c +750 -0
- data/ext/ca_obj_face.h +279 -0
- data/ext/ca_obj_fake.c +239 -100
- data/ext/ca_obj_farray.c +54 -441
- data/ext/ca_obj_field.c +82 -529
- data/ext/ca_obj_fixlen_string.c +308 -0
- data/ext/ca_obj_grid.c +866 -440
- data/ext/ca_obj_meld.c +1039 -0
- data/ext/ca_obj_moncmp.c +588 -0
- data/ext/ca_obj_monop.c +1123 -0
- data/ext/ca_obj_object.c +866 -296
- data/ext/ca_obj_record.c +470 -0
- data/ext/ca_obj_reduce.c +97 -82
- data/ext/ca_obj_refer.c +593 -459
- data/ext/ca_obj_remap.c +475 -0
- data/ext/ca_obj_repeat.c +92 -477
- data/ext/ca_obj_roll.c +624 -0
- data/ext/ca_obj_select.c +344 -296
- data/ext/ca_obj_select_axis.c +1306 -0
- data/ext/ca_obj_shift.c +231 -793
- data/ext/ca_obj_source.c +78 -0
- data/ext/ca_obj_stack.c +1173 -0
- data/ext/ca_obj_stride.c +2584 -0
- data/ext/ca_obj_string.c +270 -0
- data/ext/ca_obj_tile.c +622 -0
- data/ext/ca_obj_time.c +548 -0
- data/ext/ca_obj_timedelta.c +437 -0
- data/ext/ca_obj_transpose.c +62 -516
- data/ext/ca_obj_triop.c +785 -0
- data/ext/ca_obj_window.c +1202 -565
- data/ext/ca_op_byte_swap.c +175 -0
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +316 -0
- data/ext/ca_op_powi.h +88 -0
- data/ext/ca_sort_kernels.h +132 -0
- data/ext/ca_sweep_engine.c +473 -0
- data/ext/ca_sweep_engine.h +166 -0
- data/ext/ca_transform_common.c +235 -0
- data/ext/ca_triop_dispatch.c +55 -0
- data/ext/ca_triop_dispatch.h +62 -0
- data/ext/carray.h +810 -420
- data/ext/carray_access.c +873 -731
- data/ext/carray_attribute.c +98 -329
- data/ext/carray_bincount.c +255 -0
- data/ext/carray_broadcast.c +376 -0
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +2897 -874
- data/ext/carray_call_cfunc.h +313 -0
- data/ext/carray_cast.c +1264 -315
- 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 +168 -270
- data/ext/carray_core.c +1396 -206
- 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 +1021 -0
- data/ext/carray_index_classifier.h +27 -0
- data/ext/carray_internal.h +136 -0
- data/ext/carray_kernels_bincmp.c +4446 -0
- data/ext/carray_kernels_binop.c +11001 -0
- data/ext/carray_kernels_init.c +1131 -0
- data/ext/carray_kernels_map.c +3467 -0
- data/ext/carray_kernels_moncmp.c +2097 -0
- data/ext/carray_kernels_monop.c +18313 -0
- data/ext/carray_kernels_reduce_aggregate.c +25837 -0
- data/ext/carray_kernels_reduce_boolean.c +330 -0
- data/ext/carray_kernels_reduce_cumulative.c +14593 -0
- data/ext/carray_kernels_reduce_extreme.c +16948 -0
- data/ext/carray_kernels_reduce_variance.c +3910 -0
- data/ext/carray_kernels_scan.c +3693 -0
- data/ext/carray_kernels_search.c +32138 -0
- data/ext/carray_kernels_sort.c +10626 -0
- data/ext/carray_kernels_triop.c +1392 -0
- data/ext/carray_lazy.c +737 -0
- data/ext/carray_loop.c +88 -200
- data/ext/carray_mask.c +853 -158
- 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 +1650 -0
- data/ext/carray_operator.c +1525 -320
- 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 +234 -55
- data/ext/mk_call_cfunc.rb +671 -0
- data/ext/mkkernel.rb +9096 -0
- data/ext/ruby_carray.c +211 -108
- 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 +239 -0
- data/lib/carray/autoload_method_extension.rb +45 -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 +614 -0
- data/lib/carray/boolean_reduce.rb +109 -0
- data/lib/carray/categorical.rb +561 -0
- data/lib/carray/categorical_iterator.rb +1084 -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 +160 -328
- data/lib/carray/core_extensions.rb +297 -0
- data/lib/carray/data_type_extension.rb +250 -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 +642 -0
- data/lib/carray/frame/group.rb +186 -0
- data/lib/carray/frame/io.rb +321 -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 +316 -0
- data/lib/carray/frame.rb +16 -0
- data/lib/carray/fuse_source.rb +123 -0
- data/lib/carray/fusion.rb +218 -0
- data/lib/carray/histogram.rb +512 -0
- data/lib/carray/inspect.rb +37 -26
- data/lib/carray/iterator.rb +58 -349
- data/lib/carray/lazy.rb +941 -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 +52 -0
- data/lib/carray/methods/mask_duplicates.rb +41 -0
- data/lib/carray/methods/meshgrid.rb +90 -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 +161 -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 +89 -0
- data/lib/carray/serialize.rb +478 -167
- data/lib/carray/slab_iterator.rb +305 -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 +2654 -38
- data/lib/carray/window_iterator.rb +927 -0
- data/lib/carray.rb +55 -57
- data/yard-stubs/ca_obj_array.rb +385 -0
- data/yard-stubs/ca_obj_bitarray.rb +38 -0
- data/yard-stubs/ca_obj_bitfield.rb +43 -0
- data/yard-stubs/ca_obj_block.rb +73 -0
- data/yard-stubs/ca_obj_byte_swap.rb +56 -0
- data/yard-stubs/ca_obj_fake.rb +31 -0
- data/yard-stubs/ca_obj_farray.rb +32 -0
- data/yard-stubs/ca_obj_field.rb +45 -0
- data/yard-stubs/ca_obj_grid.rb +35 -0
- data/yard-stubs/ca_obj_refer.rb +72 -0
- data/yard-stubs/ca_obj_roll.rb +45 -0
- data/yard-stubs/ca_obj_shift.rb +43 -0
- data/yard-stubs/ca_obj_stride.rb +181 -0
- data/yard-stubs/ca_obj_tile.rb +29 -0
- data/yard-stubs/ca_obj_transpose.rb +40 -0
- data/yard-stubs/ca_obj_window.rb +49 -0
- data/yard-stubs/carray_access.rb +131 -0
- data/yard-stubs/carray_attribute.rb +246 -0
- data/yard-stubs/carray_broadcast.rb +37 -0
- data/yard-stubs/carray_cast.rb +489 -0
- data/yard-stubs/carray_class.rb +65 -0
- data/yard-stubs/carray_conversion.rb +76 -0
- data/yard-stubs/carray_copy.rb +79 -0
- data/yard-stubs/carray_core.rb +114 -0
- data/yard-stubs/carray_count.rb +79 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +23 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +132 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +89 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +312 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +57 -0
- data/yard-stubs/carray_sort.rb +163 -0
- data/yard-stubs/carray_test.rb +85 -0
- data/yard-stubs/carray_undef.rb +64 -0
- data/yard-stubs/carray_utils.rb +97 -0
- data/yard-stubs/ruby_carray.rb +193 -0
- metadata +220 -138
- 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/ca_obj_unbound_repeat.c +0 -529
- 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/mailmap +0 -1
- 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/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
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
carray_bincount.c — dedicated bincount kernels (count-only + weighted)
|
|
4
|
+
|
|
5
|
+
Tight per-element scatter into a pre-sized 1-D output buffer. The
|
|
6
|
+
inner loop reads labels in their native integer data type (no cast to
|
|
7
|
+
int64), skips per-iteration bounds checking (caller validates label
|
|
8
|
+
range), and emits the output data type directly.
|
|
9
|
+
|
|
10
|
+
Output data type:
|
|
11
|
+
- count-only: UInt32 if length < 2^32, else UInt64.
|
|
12
|
+
- weighted: weights.data_type.
|
|
13
|
+
|
|
14
|
+
Mask: a masked label is skipped; for the weighted kernel a masked
|
|
15
|
+
weight is also skipped (its label contributes 0).
|
|
16
|
+
|
|
17
|
+
Caller contract (= lib/carray/methods/bincount.rb's CArray#bincount):
|
|
18
|
+
- self is integer data type.
|
|
19
|
+
- length is the output size, pre-sized to max(length, label_max+1)
|
|
20
|
+
with label_min >= 0 already verified.
|
|
21
|
+
|
|
22
|
+
Public Ruby surface is CArray#bincount(weights:, length:) in
|
|
23
|
+
lib/carray/methods/bincount.rb; this file provides the private
|
|
24
|
+
kernels __bincount_count__(length) and
|
|
25
|
+
__bincount_weighted__(weights, length).
|
|
26
|
+
|
|
27
|
+
Design: devel/PROPOSAL_BINCOUNT_DEDICATED_KERNEL.md.
|
|
28
|
+
|
|
29
|
+
--------------------------------------------------------------------------- */
|
|
30
|
+
|
|
31
|
+
#include "carray.h"
|
|
32
|
+
|
|
33
|
+
/* Tight inner loop: 2 mask-aware variants × 8 label data types × 2 output
|
|
34
|
+
data types = 32 specializations. Generated via macro expansion.
|
|
35
|
+
|
|
36
|
+
Layout:
|
|
37
|
+
COUNT_KERNEL(LABEL_T, OUT_T)
|
|
38
|
+
no-mask path: for i; out[label[i]]++
|
|
39
|
+
label-mask path: for i; if (mlabel[i]) continue; out[label[i]]++
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
#define COUNT_KERNEL(LABEL_T, OUT_T) do { \
|
|
43
|
+
const LABEL_T *lp = (const LABEL_T *) cl->ptr; \
|
|
44
|
+
OUT_T *op = (OUT_T *) co->ptr; \
|
|
45
|
+
if ( mlabel ) { \
|
|
46
|
+
for (i = 0; i < n; i++) { \
|
|
47
|
+
if ( mlabel[i] ) continue; \
|
|
48
|
+
op[(size_t) lp[i]]++; \
|
|
49
|
+
} \
|
|
50
|
+
} \
|
|
51
|
+
else { \
|
|
52
|
+
for (i = 0; i < n; i++) { \
|
|
53
|
+
op[(size_t) lp[i]]++; \
|
|
54
|
+
} \
|
|
55
|
+
} \
|
|
56
|
+
} while (0)
|
|
57
|
+
|
|
58
|
+
#define COUNT_DISPATCH_LABEL(OUT_T) do { \
|
|
59
|
+
switch ( cl->data_type ) { \
|
|
60
|
+
case CA_INT8: COUNT_KERNEL(int8_t, OUT_T); break; \
|
|
61
|
+
case CA_INT16: COUNT_KERNEL(int16_t, OUT_T); break; \
|
|
62
|
+
case CA_INT32: COUNT_KERNEL(int32_t, OUT_T); break; \
|
|
63
|
+
case CA_INT64: COUNT_KERNEL(int64_t, OUT_T); break; \
|
|
64
|
+
case CA_UINT8: COUNT_KERNEL(uint8_t, OUT_T); break; \
|
|
65
|
+
case CA_UINT16: COUNT_KERNEL(uint16_t, OUT_T); break; \
|
|
66
|
+
case CA_UINT32: COUNT_KERNEL(uint32_t, OUT_T); break; \
|
|
67
|
+
case CA_UINT64: COUNT_KERNEL(uint64_t, OUT_T); break; \
|
|
68
|
+
default: \
|
|
69
|
+
rb_raise(rb_eCADataTypeError, \
|
|
70
|
+
"bincount: integer label array required (got %d)", \
|
|
71
|
+
cl->data_type); \
|
|
72
|
+
} \
|
|
73
|
+
} while (0)
|
|
74
|
+
|
|
75
|
+
/* __bincount_count__(length) -- count occurrences of each label in
|
|
76
|
+
self. Allocates a zero-filled UInt32 (or UInt64 if length >= 2^32)
|
|
77
|
+
output of size `length`, then runs the 8-way label dispatch. */
|
|
78
|
+
static VALUE
|
|
79
|
+
rb_ca_bincount_count_kernel (VALUE self, VALUE rlength)
|
|
80
|
+
{
|
|
81
|
+
CArray *cl, *co;
|
|
82
|
+
VALUE vout;
|
|
83
|
+
ca_size_t i, n, length;
|
|
84
|
+
ca_size_t shape_out[1];
|
|
85
|
+
boolean8_t *mlabel;
|
|
86
|
+
int out_type;
|
|
87
|
+
|
|
88
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, cl);
|
|
89
|
+
length = (ca_size_t) NUM2SIZET(rlength);
|
|
90
|
+
if ( length < 0 ) {
|
|
91
|
+
rb_raise(rb_eArgError, "bincount: length must be non-negative");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Output data type: UInt32 default; UInt64 if length doesn't fit. */
|
|
95
|
+
out_type = (length > 0xFFFFFFFFLL) ? CA_UINT64 : CA_UINT32;
|
|
96
|
+
shape_out[0] = length;
|
|
97
|
+
vout = rb_carray_new(out_type, 1, shape_out, 0, NULL);
|
|
98
|
+
TypedData_Get_Struct(vout, CArray, &carray_data_type, co);
|
|
99
|
+
|
|
100
|
+
/* Zero-fill output (we own it, just allocated). */
|
|
101
|
+
memset(co->ptr, 0, (size_t) co->bytes * (size_t) co->elements);
|
|
102
|
+
|
|
103
|
+
if ( cl->elements == 0 ) {
|
|
104
|
+
return vout;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
ca_attach(cl);
|
|
108
|
+
n = cl->elements;
|
|
109
|
+
mlabel = cl->mask ? (boolean8_t *) cl->mask->ptr : NULL;
|
|
110
|
+
|
|
111
|
+
if ( out_type == CA_UINT32 ) {
|
|
112
|
+
COUNT_DISPATCH_LABEL(uint32_t);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
COUNT_DISPATCH_LABEL(uint64_t);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
ca_detach(cl);
|
|
119
|
+
|
|
120
|
+
return vout;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
#undef COUNT_KERNEL
|
|
124
|
+
#undef COUNT_DISPATCH_LABEL
|
|
125
|
+
|
|
126
|
+
/* --------------------------------------------------------------- */
|
|
127
|
+
|
|
128
|
+
/* Weighted variant: output data type = weights data type.
|
|
129
|
+
Inner: out[label[i]] += weight[i].
|
|
130
|
+
Mask: skip if label[i] masked OR weight[i] masked. */
|
|
131
|
+
|
|
132
|
+
#define WEIGHTED_KERNEL(LABEL_T, W_T) do { \
|
|
133
|
+
const LABEL_T *lp = (const LABEL_T *) cl->ptr; \
|
|
134
|
+
const W_T *wp = (const W_T *) cw->ptr; \
|
|
135
|
+
W_T *op = (W_T *) co->ptr; \
|
|
136
|
+
if ( mlabel && mweight ) { \
|
|
137
|
+
for (i = 0; i < n; i++) { \
|
|
138
|
+
if ( mlabel[i] || mweight[i] ) continue; \
|
|
139
|
+
op[(size_t) lp[i]] += wp[i]; \
|
|
140
|
+
} \
|
|
141
|
+
} \
|
|
142
|
+
else if ( mlabel ) { \
|
|
143
|
+
for (i = 0; i < n; i++) { \
|
|
144
|
+
if ( mlabel[i] ) continue; \
|
|
145
|
+
op[(size_t) lp[i]] += wp[i]; \
|
|
146
|
+
} \
|
|
147
|
+
} \
|
|
148
|
+
else if ( mweight ) { \
|
|
149
|
+
for (i = 0; i < n; i++) { \
|
|
150
|
+
if ( mweight[i] ) continue; \
|
|
151
|
+
op[(size_t) lp[i]] += wp[i]; \
|
|
152
|
+
} \
|
|
153
|
+
} \
|
|
154
|
+
else { \
|
|
155
|
+
for (i = 0; i < n; i++) { \
|
|
156
|
+
op[(size_t) lp[i]] += wp[i]; \
|
|
157
|
+
} \
|
|
158
|
+
} \
|
|
159
|
+
} while (0)
|
|
160
|
+
|
|
161
|
+
#define WEIGHTED_DISPATCH_LABEL(W_T) do { \
|
|
162
|
+
switch ( cl->data_type ) { \
|
|
163
|
+
case CA_INT8: WEIGHTED_KERNEL(int8_t, W_T); break; \
|
|
164
|
+
case CA_INT16: WEIGHTED_KERNEL(int16_t, W_T); break; \
|
|
165
|
+
case CA_INT32: WEIGHTED_KERNEL(int32_t, W_T); break; \
|
|
166
|
+
case CA_INT64: WEIGHTED_KERNEL(int64_t, W_T); break; \
|
|
167
|
+
case CA_UINT8: WEIGHTED_KERNEL(uint8_t, W_T); break; \
|
|
168
|
+
case CA_UINT16: WEIGHTED_KERNEL(uint16_t, W_T); break; \
|
|
169
|
+
case CA_UINT32: WEIGHTED_KERNEL(uint32_t, W_T); break; \
|
|
170
|
+
case CA_UINT64: WEIGHTED_KERNEL(uint64_t, W_T); break; \
|
|
171
|
+
default: \
|
|
172
|
+
rb_raise(rb_eCADataTypeError, \
|
|
173
|
+
"bincount: integer label array required (got %d)", \
|
|
174
|
+
cl->data_type); \
|
|
175
|
+
} \
|
|
176
|
+
} while (0)
|
|
177
|
+
|
|
178
|
+
/* __bincount_weighted__(weights, length) -- sum `weights[i]` into
|
|
179
|
+
`out[label[i]]`. Allocates a zero-filled output of weights.data_type
|
|
180
|
+
and size `length`, then runs the 8 label × 10 weight dispatch
|
|
181
|
+
(integer + float; the inner WEIGHTED_KERNEL macro branches over the
|
|
182
|
+
four mask combinations). */
|
|
183
|
+
static VALUE
|
|
184
|
+
rb_ca_bincount_weighted_kernel (VALUE self, VALUE rweights, VALUE rlength)
|
|
185
|
+
{
|
|
186
|
+
CArray *cl, *cw, *co;
|
|
187
|
+
VALUE vout;
|
|
188
|
+
ca_size_t i, n, length;
|
|
189
|
+
ca_size_t shape_out[1];
|
|
190
|
+
boolean8_t *mlabel, *mweight;
|
|
191
|
+
int w_type;
|
|
192
|
+
|
|
193
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, cl);
|
|
194
|
+
TypedData_Get_Struct(rweights, CArray, &carray_data_type, cw);
|
|
195
|
+
length = (ca_size_t) NUM2SIZET(rlength);
|
|
196
|
+
if ( length < 0 ) {
|
|
197
|
+
rb_raise(rb_eArgError, "bincount: length must be non-negative");
|
|
198
|
+
}
|
|
199
|
+
if ( cw->elements != cl->elements ) {
|
|
200
|
+
rb_raise(rb_eArgError,
|
|
201
|
+
"bincount: weights length (%lld) doesn't match labels length (%lld)",
|
|
202
|
+
(long long) cw->elements, (long long) cl->elements);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
w_type = cw->data_type;
|
|
206
|
+
shape_out[0] = length;
|
|
207
|
+
vout = rb_carray_new(w_type, 1, shape_out, 0, NULL);
|
|
208
|
+
TypedData_Get_Struct(vout, CArray, &carray_data_type, co);
|
|
209
|
+
|
|
210
|
+
memset(co->ptr, 0, (size_t) co->bytes * (size_t) co->elements);
|
|
211
|
+
|
|
212
|
+
if ( cl->elements == 0 ) {
|
|
213
|
+
return vout;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
ca_attach_n(2, cl, cw);
|
|
217
|
+
n = cl->elements;
|
|
218
|
+
mlabel = cl->mask ? (boolean8_t *) cl->mask->ptr : NULL;
|
|
219
|
+
mweight = cw->mask ? (boolean8_t *) cw->mask->ptr : NULL;
|
|
220
|
+
|
|
221
|
+
switch ( w_type ) {
|
|
222
|
+
case CA_FLOAT64: WEIGHTED_DISPATCH_LABEL(double); break;
|
|
223
|
+
case CA_FLOAT32: WEIGHTED_DISPATCH_LABEL(float); break;
|
|
224
|
+
case CA_INT64: WEIGHTED_DISPATCH_LABEL(int64_t); break;
|
|
225
|
+
case CA_INT32: WEIGHTED_DISPATCH_LABEL(int32_t); break;
|
|
226
|
+
case CA_INT16: WEIGHTED_DISPATCH_LABEL(int16_t); break;
|
|
227
|
+
case CA_INT8: WEIGHTED_DISPATCH_LABEL(int8_t); break;
|
|
228
|
+
case CA_UINT64: WEIGHTED_DISPATCH_LABEL(uint64_t); break;
|
|
229
|
+
case CA_UINT32: WEIGHTED_DISPATCH_LABEL(uint32_t); break;
|
|
230
|
+
case CA_UINT16: WEIGHTED_DISPATCH_LABEL(uint16_t); break;
|
|
231
|
+
case CA_UINT8: WEIGHTED_DISPATCH_LABEL(uint8_t); break;
|
|
232
|
+
default:
|
|
233
|
+
ca_detach_n(2, cl, cw);
|
|
234
|
+
rb_raise(rb_eCADataTypeError,
|
|
235
|
+
"bincount: weights must be numeric (got %d)", w_type);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
ca_detach_n(2, cl, cw);
|
|
239
|
+
|
|
240
|
+
return vout;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
#undef WEIGHTED_KERNEL
|
|
244
|
+
#undef WEIGHTED_DISPATCH_LABEL
|
|
245
|
+
|
|
246
|
+
/* --------------------------------------------------------------- */
|
|
247
|
+
|
|
248
|
+
void
|
|
249
|
+
Init_carray_bincount (void)
|
|
250
|
+
{
|
|
251
|
+
rb_define_private_method(rb_cCArray, "__bincount_count__",
|
|
252
|
+
rb_ca_bincount_count_kernel, 1);
|
|
253
|
+
rb_define_private_method(rb_cCArray, "__bincount_weighted__",
|
|
254
|
+
rb_ca_bincount_weighted_kernel, 2);
|
|
255
|
+
}
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
Implicit broadcasting helpers and CArray#broadcast_to.
|
|
4
|
+
|
|
5
|
+
ca_broadcast_view (src, ndim, target_dim)
|
|
6
|
+
Wrap `src` in a CAStride view whose shape is `target_dim`,
|
|
7
|
+
treating size-1 axes of `src` as broadcast (stride 0).
|
|
8
|
+
Returns `src` unchanged when no expansion is needed.
|
|
9
|
+
Called by ca_broadcast_pair below and by the binop dispatcher
|
|
10
|
+
in ext/ca_obj_binop.c.
|
|
11
|
+
|
|
12
|
+
ca_broadcast_pair (&self, &other)
|
|
13
|
+
Two-sided expansion for binary ops (case A only: same ndim,
|
|
14
|
+
size-1 axes broadcast pairwise). Leaves both operands
|
|
15
|
+
unchanged when shapes are already equal, and raises when they
|
|
16
|
+
cannot be paired: both operands of a binary operation are
|
|
17
|
+
equally authoritative, so a shape conflict has no resolution.
|
|
18
|
+
Called by carray_cast.c's coercion path and by the binop,
|
|
19
|
+
bincmp and triop builders, which is every place two operands
|
|
20
|
+
are brought together.
|
|
21
|
+
|
|
22
|
+
rb_ca_broadcast_to -- backs the public CArray#broadcast_to method
|
|
23
|
+
(right-to-left axis pairing; see the docstring at the function).
|
|
24
|
+
|
|
25
|
+
Case B (cross-ndim dim-prepending) is not handled by the implicit
|
|
26
|
+
helpers; users with cross-ndim operands keep using the explicit :*
|
|
27
|
+
form or #broadcast_to (which does accept cross-ndim with target axes
|
|
28
|
+
pinned to size 1). See PROPOSAL_BROADCASTING_AND_UNBOUND.md.
|
|
29
|
+
|
|
30
|
+
---------------------------------------------------------------------------- */
|
|
31
|
+
|
|
32
|
+
#include "carray.h"
|
|
33
|
+
|
|
34
|
+
NORETURN(static void ca_broadcast_refuse_write (VALUE dst, VALUE src));
|
|
35
|
+
|
|
36
|
+
/* Report a source that cannot be brought to the destination's shape. */
|
|
37
|
+
static void
|
|
38
|
+
ca_broadcast_refuse_write (VALUE dst, VALUE src)
|
|
39
|
+
{
|
|
40
|
+
volatile VALUE dst_s = rb_inspect(rb_funcall(dst, rb_intern("shape"), 0));
|
|
41
|
+
volatile VALUE src_s = rb_inspect(rb_funcall(src, rb_intern("shape"), 0));
|
|
42
|
+
rb_raise(rb_eRuntimeError,
|
|
43
|
+
"shape mismatch writing to carray (%s <- %s); shapes must agree "
|
|
44
|
+
"once size-1 axes are dropped, or one side must be 1-D, or the "
|
|
45
|
+
"source must be smaller and broadcastable -- use .flatten to "
|
|
46
|
+
"write the values in the order they lie",
|
|
47
|
+
StringValueCStr(dst_s), StringValueCStr(src_s));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Bring `*src` to `dst`'s shape for a write into `dst` (assignment, and
|
|
51
|
+
the in-place operators, whose result shape is the destination's by
|
|
52
|
+
definition). The destination owns the shape and the source only
|
|
53
|
+
supplies values, so what is allowed here is wider than what two
|
|
54
|
+
operands of a binary operation may do -- but only where nothing is
|
|
55
|
+
duplicated. When the counts already agree the values land in the
|
|
56
|
+
order they lie and the shape is merely a reading of them: shapes that
|
|
57
|
+
both sides claim must agree once size-1 axes are dropped, since such
|
|
58
|
+
an axis moves no element, and a 1-D side claims no shape at all,
|
|
59
|
+
whether it is the flat source or the flat container. When the source
|
|
60
|
+
is smaller it is repeated instead, and that is held to same-ndim
|
|
61
|
+
size-1 and is one-sided: the destination never grows. Raises when
|
|
62
|
+
neither reading applies. */
|
|
63
|
+
void
|
|
64
|
+
ca_broadcast_to_destination (VALUE dst, volatile VALUE *src)
|
|
65
|
+
{
|
|
66
|
+
CArray *cd, *cs;
|
|
67
|
+
|
|
68
|
+
TypedData_Get_Struct(dst, CArray, &carray_data_type, cd);
|
|
69
|
+
TypedData_Get_Struct(*src, CArray, &carray_data_type, cs);
|
|
70
|
+
|
|
71
|
+
if ( cs->elements == cd->elements ) {
|
|
72
|
+
ca_size_t dst_dim[CA_RANK_MAX], src_dim[CA_RANK_MAX];
|
|
73
|
+
int dst_ndim = 0, src_ndim = 0, i, agree;
|
|
74
|
+
if ( cd->ndim <= 1 || cs->ndim <= 1 ) return;
|
|
75
|
+
for ( i = 0; i < cd->ndim; i++ ) {
|
|
76
|
+
if ( cd->dim[i] != 1 ) dst_dim[dst_ndim++] = cd->dim[i];
|
|
77
|
+
}
|
|
78
|
+
for ( i = 0; i < cs->ndim; i++ ) {
|
|
79
|
+
if ( cs->dim[i] != 1 ) src_dim[src_ndim++] = cs->dim[i];
|
|
80
|
+
}
|
|
81
|
+
agree = ( dst_ndim == src_ndim );
|
|
82
|
+
for ( i = 0; agree && i < dst_ndim; i++ ) {
|
|
83
|
+
if ( dst_dim[i] != src_dim[i] ) agree = 0;
|
|
84
|
+
}
|
|
85
|
+
if ( ! agree ) ca_broadcast_refuse_write(dst, *src);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if ( cs->elements < cd->elements && cs->ndim == cd->ndim ) {
|
|
90
|
+
int i;
|
|
91
|
+
for ( i = 0; i < cd->ndim; i++ ) {
|
|
92
|
+
if ( cs->dim[i] != cd->dim[i] && cs->dim[i] != 1 ) break;
|
|
93
|
+
}
|
|
94
|
+
if ( i == cd->ndim ) {
|
|
95
|
+
*src = ca_broadcast_view(*src, cd->ndim, cd->dim);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
ca_broadcast_refuse_write(dst, *src);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* Build a CAStride view of `src` with shape `target_dim`. For each
|
|
104
|
+
axis where src.dim[i] == target_dim[i], inherit the row-major byte
|
|
105
|
+
stride; for src.dim[i] == 1 and target_dim[i] > 1, use stride 0.
|
|
106
|
+
Otherwise, raise. If no axis needs expansion, return src as-is. */
|
|
107
|
+
VALUE
|
|
108
|
+
ca_broadcast_view (VALUE src, int8_t ndim, ca_size_t *target_dim)
|
|
109
|
+
{
|
|
110
|
+
CArray *cs;
|
|
111
|
+
ca_size_t src_strides[CA_RANK_MAX];
|
|
112
|
+
ca_size_t new_strides[CA_RANK_MAX];
|
|
113
|
+
ca_size_t s;
|
|
114
|
+
int needs_broadcast = 0;
|
|
115
|
+
int i;
|
|
116
|
+
CAStride *view;
|
|
117
|
+
volatile VALUE obj;
|
|
118
|
+
|
|
119
|
+
TypedData_Get_Struct(src, CArray, &carray_data_type, cs);
|
|
120
|
+
|
|
121
|
+
if (cs->ndim != ndim) {
|
|
122
|
+
rb_raise(rb_eRuntimeError,
|
|
123
|
+
"broadcast: ndim mismatch (%d vs %d)",
|
|
124
|
+
(int) cs->ndim, (int) ndim);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Row-major byte strides for src treated as contiguous. When src is
|
|
128
|
+
itself a CAStride, the compose-fold path at attach time collapses
|
|
129
|
+
the chain to root, so passing parent-relative row-major strides
|
|
130
|
+
is correct. */
|
|
131
|
+
s = cs->bytes;
|
|
132
|
+
for (i = ndim - 1; i >= 0; i--) {
|
|
133
|
+
src_strides[i] = s;
|
|
134
|
+
s *= cs->dim[i];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
for (i = 0; i < ndim; i++) {
|
|
138
|
+
if (cs->dim[i] == target_dim[i]) {
|
|
139
|
+
new_strides[i] = src_strides[i];
|
|
140
|
+
}
|
|
141
|
+
else if (cs->dim[i] == 1) {
|
|
142
|
+
new_strides[i] = 0;
|
|
143
|
+
needs_broadcast = 1;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
rb_raise(rb_eRuntimeError,
|
|
147
|
+
"broadcast: cannot broadcast axis %d (%lld vs %lld)",
|
|
148
|
+
i, (long long) cs->dim[i], (long long) target_dim[i]);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!needs_broadcast) return src;
|
|
153
|
+
|
|
154
|
+
view = ca_stride_new(CA_OBJ_STRIDE, cs,
|
|
155
|
+
cs->data_type, cs->bytes,
|
|
156
|
+
ndim, target_dim, new_strides, 0);
|
|
157
|
+
ca_set_flag(view, CA_FLAG_READ_ONLY);
|
|
158
|
+
if (view->mask) {
|
|
159
|
+
ca_set_flag(view->mask, CA_FLAG_READ_ONLY);
|
|
160
|
+
}
|
|
161
|
+
obj = ca_wrap_struct(view);
|
|
162
|
+
rb_ca_set_parent(obj, src);
|
|
163
|
+
return obj;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* Two-sided broadcast for binary ops (case A only). When both
|
|
167
|
+
operands are non-scalar with equal ndim and at least one axis pair
|
|
168
|
+
is (1, N) / (N, 1) / (1, 1), wrap each in a CAStride with stride-0
|
|
169
|
+
axes so the downstream iterator sees matched shapes. If shapes are
|
|
170
|
+
pairwise equal, no-op. If any axis pair is incompatible (neither
|
|
171
|
+
side is 1 nor equal), no-op (caller's existing element-count check
|
|
172
|
+
raises). */
|
|
173
|
+
NORETURN(static void ca_broadcast_refuse (VALUE self, VALUE other));
|
|
174
|
+
|
|
175
|
+
/* Report a pair that cannot be brought to a common shape. Naming both
|
|
176
|
+
shapes is the point of the message: the caller wrote two arrays that
|
|
177
|
+
cannot be combined, and the only remedy is to say which two. */
|
|
178
|
+
static void
|
|
179
|
+
ca_broadcast_refuse (VALUE self, VALUE other)
|
|
180
|
+
{
|
|
181
|
+
volatile VALUE self_s = rb_inspect(rb_funcall(self, rb_intern("shape"), 0));
|
|
182
|
+
volatile VALUE other_s = rb_inspect(rb_funcall(other, rb_intern("shape"), 0));
|
|
183
|
+
rb_raise(rb_eArgError,
|
|
184
|
+
"shape mismatch between operands (%s and %s); shapes must "
|
|
185
|
+
"agree, or differ only in size-1 axes with equal ndim -- use "
|
|
186
|
+
".flatten on both sides to operate on the values in the order "
|
|
187
|
+
"they lie",
|
|
188
|
+
StringValueCStr(self_s), StringValueCStr(other_s));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
void
|
|
192
|
+
ca_broadcast_pair (volatile VALUE *self, volatile VALUE *other)
|
|
193
|
+
{
|
|
194
|
+
CArray *ca, *cb;
|
|
195
|
+
ca_size_t target_dim[CA_RANK_MAX];
|
|
196
|
+
int can_broadcast = 1;
|
|
197
|
+
int needs_broadcast = 0;
|
|
198
|
+
int i;
|
|
199
|
+
|
|
200
|
+
TypedData_Get_Struct(*self, CArray, &carray_data_type, ca);
|
|
201
|
+
TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
|
|
202
|
+
|
|
203
|
+
/* A scalar carries no shape and reaches every cell; leave the pair to
|
|
204
|
+
the caller's own scalar handling. A one-element array is not a
|
|
205
|
+
scalar: it states a shape, and is held to it. */
|
|
206
|
+
if (ca_is_scalar(ca) || ca_is_scalar(cb)) return;
|
|
207
|
+
if (ca->ndim != cb->ndim) ca_broadcast_refuse(*self, *other);
|
|
208
|
+
if (ca->ndim == 0) return;
|
|
209
|
+
|
|
210
|
+
for (i = 0; i < ca->ndim; i++) {
|
|
211
|
+
if (ca->dim[i] == cb->dim[i]) {
|
|
212
|
+
target_dim[i] = ca->dim[i];
|
|
213
|
+
}
|
|
214
|
+
else if (ca->dim[i] == 1) {
|
|
215
|
+
target_dim[i] = cb->dim[i];
|
|
216
|
+
needs_broadcast = 1;
|
|
217
|
+
}
|
|
218
|
+
else if (cb->dim[i] == 1) {
|
|
219
|
+
target_dim[i] = ca->dim[i];
|
|
220
|
+
needs_broadcast = 1;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
can_broadcast = 0;
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (!can_broadcast) ca_broadcast_refuse(*self, *other);
|
|
229
|
+
if (!needs_broadcast) return;
|
|
230
|
+
|
|
231
|
+
*self = ca_broadcast_view(*self, ca->ndim, target_dim);
|
|
232
|
+
*other = ca_broadcast_view(*other, ca->ndim, target_dim);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* CArray#broadcast_to(*newdim) -- pairs axes right-to-left:
|
|
236
|
+
- source axis == target axis -> data axis (inherit stride)
|
|
237
|
+
- target axis == 1 -> size-1 collapse, source consumed
|
|
238
|
+
only when it is also 1
|
|
239
|
+
- source axis == 1 -> broadcast (stride 0, source
|
|
240
|
+
consumed)
|
|
241
|
+
- source exhausted, target 1 -> insert size-1 axis
|
|
242
|
+
- otherwise -> RuntimeError
|
|
243
|
+
|
|
244
|
+
Intentionally conservative on cross-ndim: prepended axes are only
|
|
245
|
+
inserted as size-1. Target > 1 on a prepended axis raises, in
|
|
246
|
+
keeping with PROPOSAL_BROADCASTING_AND_UNBOUND.md's strict-ndim
|
|
247
|
+
policy.
|
|
248
|
+
|
|
249
|
+
Result is tagged CA_OBJ_REPEAT (CARepeat) rather than plain CAStride
|
|
250
|
+
so introspection (`view.class`) surfaces the broadcast intent. */
|
|
251
|
+
|
|
252
|
+
static VALUE
|
|
253
|
+
rb_ca_broadcast_to (int argc, VALUE *argv, VALUE self)
|
|
254
|
+
{
|
|
255
|
+
CArray *cs;
|
|
256
|
+
ca_size_t target_dim[CA_RANK_MAX];
|
|
257
|
+
ca_size_t new_strides[CA_RANK_MAX];
|
|
258
|
+
ca_size_t src_strides[CA_RANK_MAX];
|
|
259
|
+
ca_size_t s;
|
|
260
|
+
int8_t target_ndim;
|
|
261
|
+
int needs_view = 0;
|
|
262
|
+
int t_idx, s_idx;
|
|
263
|
+
int i;
|
|
264
|
+
CAStride *view;
|
|
265
|
+
volatile VALUE obj;
|
|
266
|
+
|
|
267
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, cs);
|
|
268
|
+
|
|
269
|
+
if (argc < 0 || argc > CA_RANK_MAX) {
|
|
270
|
+
rb_raise(rb_eArgError, "broadcast_to: invalid number of dims (%d)", argc);
|
|
271
|
+
}
|
|
272
|
+
target_ndim = (int8_t) argc;
|
|
273
|
+
|
|
274
|
+
if (target_ndim < cs->ndim) {
|
|
275
|
+
rb_raise(rb_eRuntimeError,
|
|
276
|
+
"broadcast_to: target ndim %d smaller than source ndim %d",
|
|
277
|
+
(int) target_ndim, (int) cs->ndim);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
for (i = 0; i < target_ndim; i++) {
|
|
281
|
+
target_dim[i] = NUM2SIZE(argv[i]);
|
|
282
|
+
if (target_dim[i] < 0) {
|
|
283
|
+
rb_raise(rb_eArgError,
|
|
284
|
+
"broadcast_to: negative dim at axis %d", i);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/* CScalar source: build an all-stride-0 CARepeat view of any
|
|
289
|
+
target shape. Generalises the cross-ndim rule, which is strict
|
|
290
|
+
for non-scalar sources (each source axis must pair with a target
|
|
291
|
+
axis); for a scalar the natural extension is "any target shape,
|
|
292
|
+
stride 0 everywhere". */
|
|
293
|
+
if (ca_is_scalar(cs)) {
|
|
294
|
+
for (i = 0; i < target_ndim; i++) {
|
|
295
|
+
new_strides[i] = 0;
|
|
296
|
+
}
|
|
297
|
+
view = ca_stride_new(CA_OBJ_REPEAT, cs,
|
|
298
|
+
cs->data_type, cs->bytes,
|
|
299
|
+
target_ndim, target_dim, new_strides, 0);
|
|
300
|
+
ca_set_flag(view, CA_FLAG_READ_ONLY);
|
|
301
|
+
if (view->mask) {
|
|
302
|
+
ca_set_flag(view->mask, CA_FLAG_READ_ONLY);
|
|
303
|
+
}
|
|
304
|
+
obj = ca_wrap_struct(view);
|
|
305
|
+
rb_ca_set_parent(obj, self);
|
|
306
|
+
return obj;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* Row-major byte strides for source (interpreted as contiguous;
|
|
310
|
+
compose-fold at attach time handles non-contiguous parents). */
|
|
311
|
+
s = cs->bytes;
|
|
312
|
+
for (i = cs->ndim - 1; i >= 0; i--) {
|
|
313
|
+
src_strides[i] = s;
|
|
314
|
+
s *= cs->dim[i];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/* Pair right-to-left. s_idx tracks the next source axis to be
|
|
318
|
+
consumed; -1 means source is exhausted. */
|
|
319
|
+
t_idx = target_ndim - 1;
|
|
320
|
+
s_idx = cs->ndim - 1;
|
|
321
|
+
|
|
322
|
+
while (t_idx >= 0) {
|
|
323
|
+
ca_size_t dd = target_dim[t_idx];
|
|
324
|
+
ca_size_t sd = (s_idx >= 0) ? cs->dim[s_idx] : -1;
|
|
325
|
+
|
|
326
|
+
if (sd == dd) {
|
|
327
|
+
new_strides[t_idx] = src_strides[s_idx];
|
|
328
|
+
s_idx--;
|
|
329
|
+
}
|
|
330
|
+
else if (dd == 1) {
|
|
331
|
+
new_strides[t_idx] = 0;
|
|
332
|
+
if (sd == 1) s_idx--;
|
|
333
|
+
needs_view = 1;
|
|
334
|
+
}
|
|
335
|
+
else if (sd == 1) {
|
|
336
|
+
new_strides[t_idx] = 0;
|
|
337
|
+
s_idx--;
|
|
338
|
+
needs_view = 1;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
/* sd == -1 (source exhausted) with dd > 1, or sd > 1 with
|
|
342
|
+
dd > 1 and not equal: cannot broadcast. */
|
|
343
|
+
rb_raise(rb_eRuntimeError,
|
|
344
|
+
"broadcast_to: cannot broadcast axis %d "
|
|
345
|
+
"(source %s, target %lld)",
|
|
346
|
+
t_idx,
|
|
347
|
+
(sd < 0 ? "(exhausted)" : "non-1"),
|
|
348
|
+
(long long) dd);
|
|
349
|
+
}
|
|
350
|
+
t_idx--;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (s_idx >= 0) {
|
|
354
|
+
rb_raise(rb_eRuntimeError,
|
|
355
|
+
"broadcast_to: %d source axes left unmatched", s_idx + 1);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (!needs_view) return self;
|
|
359
|
+
|
|
360
|
+
view = ca_stride_new(CA_OBJ_REPEAT, cs,
|
|
361
|
+
cs->data_type, cs->bytes,
|
|
362
|
+
target_ndim, target_dim, new_strides, 0);
|
|
363
|
+
ca_set_flag(view, CA_FLAG_READ_ONLY);
|
|
364
|
+
if (view->mask) {
|
|
365
|
+
ca_set_flag(view->mask, CA_FLAG_READ_ONLY);
|
|
366
|
+
}
|
|
367
|
+
obj = ca_wrap_struct(view);
|
|
368
|
+
rb_ca_set_parent(obj, self);
|
|
369
|
+
return obj;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
void
|
|
373
|
+
Init_carray_broadcast (void)
|
|
374
|
+
{
|
|
375
|
+
rb_define_method(rb_cCArray, "broadcast_to", rb_ca_broadcast_to, -1);
|
|
376
|
+
}
|