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.
Files changed (339) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +5 -25
  3. data/CHANGELOG.md +16 -0
  4. data/LICENSE +1 -1
  5. data/NEWS.md +3 -0
  6. data/README.md +128 -44
  7. data/carray.gemspec +22 -24
  8. data/ext/ca_array_pool.c +91 -0
  9. data/ext/ca_axis_descriptor.h +186 -0
  10. data/ext/ca_axis_dispatch.c +924 -0
  11. data/ext/ca_axis_group.c +1208 -0
  12. data/ext/ca_bincmp_dispatch.c +76 -0
  13. data/ext/ca_bincmp_dispatch.h +85 -0
  14. data/ext/ca_binop_dispatch.c +125 -0
  15. data/ext/ca_binop_dispatch.h +159 -0
  16. data/ext/ca_categorical_iterator.c +1375 -0
  17. data/ext/ca_compare.c +94 -0
  18. data/ext/ca_compare.h +26 -0
  19. data/ext/ca_composite_dispatch.c +414 -0
  20. data/ext/ca_composite_dispatch.h +116 -0
  21. data/ext/ca_for_buffer.h +96 -0
  22. data/ext/ca_for_each_element.h +241 -0
  23. data/ext/ca_group_iter.c +304 -0
  24. data/ext/ca_iter_substrate.h +325 -0
  25. data/ext/ca_kernel_iterator.c +4321 -0
  26. data/ext/ca_kernel_iterator.h +2603 -0
  27. data/ext/ca_moncmp_dispatch.c +37 -0
  28. data/ext/ca_moncmp_dispatch.h +62 -0
  29. data/ext/ca_monop_dispatch.c +200 -0
  30. data/ext/ca_monop_dispatch.h +235 -0
  31. data/ext/ca_obj_array.c +355 -359
  32. data/ext/ca_obj_bincmp.c +809 -0
  33. data/ext/ca_obj_binop.c +892 -0
  34. data/ext/ca_obj_bitarray.c +369 -164
  35. data/ext/ca_obj_bitfield.c +294 -234
  36. data/ext/ca_obj_block.c +189 -711
  37. data/ext/ca_obj_byte_swap.c +766 -0
  38. data/ext/ca_obj_const_string.c +965 -0
  39. data/ext/ca_obj_face.c +670 -0
  40. data/ext/ca_obj_face.h +247 -0
  41. data/ext/ca_obj_fake.c +228 -100
  42. data/ext/ca_obj_farray.c +54 -441
  43. data/ext/ca_obj_field.c +82 -529
  44. data/ext/ca_obj_fixlen_string.c +306 -0
  45. data/ext/ca_obj_grid.c +858 -440
  46. data/ext/ca_obj_meld.c +1034 -0
  47. data/ext/ca_obj_moncmp.c +569 -0
  48. data/ext/ca_obj_monop.c +1111 -0
  49. data/ext/ca_obj_object.c +774 -298
  50. data/ext/ca_obj_record.c +468 -0
  51. data/ext/ca_obj_reduce.c +97 -82
  52. data/ext/ca_obj_refer.c +569 -459
  53. data/ext/ca_obj_remap.c +475 -0
  54. data/ext/ca_obj_repeat.c +92 -477
  55. data/ext/ca_obj_roll.c +616 -0
  56. data/ext/ca_obj_select.c +344 -296
  57. data/ext/ca_obj_select_axis.c +1296 -0
  58. data/ext/ca_obj_shift.c +230 -792
  59. data/ext/ca_obj_source.c +78 -0
  60. data/ext/ca_obj_stack.c +1173 -0
  61. data/ext/ca_obj_stride.c +2501 -0
  62. data/ext/ca_obj_string.c +268 -0
  63. data/ext/ca_obj_tile.c +614 -0
  64. data/ext/ca_obj_time.c +546 -0
  65. data/ext/ca_obj_timedelta.c +435 -0
  66. data/ext/ca_obj_transpose.c +62 -516
  67. data/ext/ca_obj_triop.c +746 -0
  68. data/ext/ca_obj_unbound_repeat.c +208 -241
  69. data/ext/ca_obj_window.c +1131 -563
  70. data/ext/ca_op_byte_swap.c +175 -0
  71. data/ext/ca_op_ipower.c +319 -0
  72. data/ext/ca_op_powi.h +88 -0
  73. data/ext/ca_sort_kernels.h +132 -0
  74. data/ext/ca_sweep_engine.c +430 -0
  75. data/ext/ca_sweep_engine.h +157 -0
  76. data/ext/ca_transform_common.c +228 -0
  77. data/ext/ca_triop_dispatch.c +55 -0
  78. data/ext/ca_triop_dispatch.h +62 -0
  79. data/ext/carray.h +795 -402
  80. data/ext/carray_access.c +831 -711
  81. data/ext/carray_attribute.c +98 -330
  82. data/ext/carray_bincount.c +255 -0
  83. data/ext/carray_broadcast.c +283 -0
  84. data/ext/carray_call_cfunc.c +1360 -828
  85. data/ext/carray_call_cfunc.h +160 -0
  86. data/ext/carray_cast.c +1212 -301
  87. data/ext/carray_cast_func.rb +81 -40
  88. data/ext/carray_class.c +53 -63
  89. data/ext/carray_config.h +28 -0
  90. data/ext/carray_conversion.c +350 -346
  91. data/ext/carray_copy.c +156 -268
  92. data/ext/carray_core.c +1342 -199
  93. data/ext/carray_count.c +312 -0
  94. data/ext/carray_data_type.c +43 -19
  95. data/ext/carray_element.c +585 -213
  96. data/ext/carray_factorize.c +2542 -0
  97. data/ext/carray_generate.c +230 -559
  98. data/ext/carray_histogram.c +490 -0
  99. data/ext/carray_hold.c +228 -0
  100. data/ext/carray_index_classifier.c +1035 -0
  101. data/ext/carray_index_classifier.h +27 -0
  102. data/ext/carray_internal.h +120 -0
  103. data/ext/carray_kernels_bincmp.c +4445 -0
  104. data/ext/carray_kernels_binop.c +10979 -0
  105. data/ext/carray_kernels_init.c +36 -0
  106. data/ext/carray_kernels_map.c +3466 -0
  107. data/ext/carray_kernels_moncmp.c +2096 -0
  108. data/ext/carray_kernels_monop.c +18312 -0
  109. data/ext/carray_kernels_reduce_aggregate.c +25836 -0
  110. data/ext/carray_kernels_reduce_boolean.c +329 -0
  111. data/ext/carray_kernels_reduce_cumulative.c +14592 -0
  112. data/ext/carray_kernels_reduce_extreme.c +16947 -0
  113. data/ext/carray_kernels_reduce_variance.c +3909 -0
  114. data/ext/carray_kernels_scan.c +3692 -0
  115. data/ext/carray_kernels_search.c +32137 -0
  116. data/ext/carray_kernels_sort.c +10625 -0
  117. data/ext/carray_kernels_triop.c +1391 -0
  118. data/ext/carray_lazy.c +567 -0
  119. data/ext/carray_loop.c +88 -200
  120. data/ext/carray_mask.c +848 -154
  121. data/ext/carray_math_kernel.h +120 -0
  122. data/ext/carray_mathfunc.c +10 -241
  123. data/ext/carray_median_percentile.c +1257 -0
  124. data/ext/carray_memory_view.c +1625 -0
  125. data/ext/carray_operator.c +1526 -318
  126. data/ext/carray_order.c +664 -1394
  127. data/ext/carray_partition.c +416 -0
  128. data/ext/carray_random.c +518 -0
  129. data/ext/carray_scatter.c +357 -0
  130. data/ext/carray_slab.c +1219 -0
  131. data/ext/carray_slab.h +84 -0
  132. data/ext/carray_sort.c +829 -0
  133. data/ext/carray_sort_kernel.c +620 -0
  134. data/ext/carray_struct.c +695 -0
  135. data/ext/carray_test.c +343 -229
  136. data/ext/carray_undef.c +34 -17
  137. data/ext/carray_utils.c +175 -74
  138. data/ext/extconf.rb +216 -55
  139. data/ext/mk_call_cfunc.rb +480 -0
  140. data/ext/mkkernel.rb +8842 -0
  141. data/ext/ruby_carray.c +202 -101
  142. data/ext/version.h +4 -14
  143. data/ext/version.rb +5 -13
  144. data/lib/carray/arrow_tensor.rb +401 -0
  145. data/lib/carray/attribute.rb +166 -0
  146. data/lib/carray/autoload_carray.rb +220 -0
  147. data/lib/carray/autoload_method_extension.rb +44 -0
  148. data/lib/carray/axis_group.rb +711 -0
  149. data/lib/carray/basics.rb +481 -0
  150. data/lib/carray/bincount_nd.rb +358 -0
  151. data/lib/carray/block_iterator.rb +604 -0
  152. data/lib/carray/boolean_reduce.rb +109 -0
  153. data/lib/carray/categorical.rb +561 -0
  154. data/lib/carray/categorical_iterator.rb +1062 -0
  155. data/lib/carray/complex.rb +150 -0
  156. data/lib/carray/conditional.rb +216 -0
  157. data/lib/carray/const_string.rb +228 -0
  158. data/lib/carray/construct.rb +139 -328
  159. data/lib/carray/core_extensions.rb +240 -0
  160. data/lib/carray/data_type_extension.rb +233 -0
  161. data/lib/carray/fixlen_string.rb +95 -0
  162. data/lib/carray/frame/concat.rb +132 -0
  163. data/lib/carray/frame/convert.rb +95 -0
  164. data/lib/carray/frame/csv_parser.rb +211 -0
  165. data/lib/carray/frame/frame.rb +649 -0
  166. data/lib/carray/frame/group.rb +186 -0
  167. data/lib/carray/frame/io.rb +164 -0
  168. data/lib/carray/frame/join.rb +248 -0
  169. data/lib/carray/frame/records.rb +99 -0
  170. data/lib/carray/frame/sort.rb +113 -0
  171. data/lib/carray/frame/verbs.rb +299 -0
  172. data/lib/carray/frame.rb +16 -0
  173. data/lib/carray/histogram.rb +512 -0
  174. data/lib/carray/inspect.rb +37 -20
  175. data/lib/carray/iterator.rb +57 -349
  176. data/lib/carray/lazy.rb +889 -0
  177. data/lib/carray/mask_gap_fill.rb +200 -0
  178. data/lib/carray/math.rb +78 -342
  179. data/lib/carray/meld_reduce.rb +289 -0
  180. data/lib/carray/methods/align_addr.rb +116 -0
  181. data/lib/carray/methods/bin.rb +128 -0
  182. data/lib/carray/methods/bincount.rb +87 -0
  183. data/lib/carray/methods/bit_string.rb +92 -0
  184. data/lib/carray/methods/broadcast.rb +63 -0
  185. data/lib/carray/methods/choose.rb +39 -0
  186. data/lib/carray/methods/composition.rb +280 -0
  187. data/lib/carray/methods/gather_nd.rb +206 -0
  188. data/lib/carray/methods/index.rb +39 -0
  189. data/lib/carray/methods/insert_block.rb +99 -0
  190. data/lib/carray/methods/is_in.rb +141 -0
  191. data/lib/carray/methods/join.rb +90 -0
  192. data/lib/carray/methods/locate_addr.rb +47 -0
  193. data/lib/carray/methods/mask_duplicates.rb +41 -0
  194. data/lib/carray/methods/meshgrid.rb +91 -0
  195. data/lib/carray/methods/mode.rb +126 -0
  196. data/lib/carray/methods/nunique.rb +46 -0
  197. data/lib/carray/methods/resize.rb +56 -0
  198. data/lib/carray/methods/snap.rb +156 -0
  199. data/lib/carray/methods/string_format.rb +57 -0
  200. data/lib/carray/methods/unique.rb +47 -0
  201. data/lib/carray/methods/value_counts.rb +71 -0
  202. data/lib/carray/mkmf.rb +124 -101
  203. data/lib/carray/runtime.rb +108 -0
  204. data/lib/carray/serialize.rb +478 -167
  205. data/lib/carray/slab_iterator.rb +292 -0
  206. data/lib/carray/stack.rb +291 -0
  207. data/lib/carray/string.rb +56 -180
  208. data/lib/carray/string_operation_extension.rb +289 -0
  209. data/lib/carray/struct.rb +335 -323
  210. data/lib/carray/struct_builder.rb +697 -0
  211. data/lib/carray/table.rb +41 -2
  212. data/lib/carray/time.rb +2255 -38
  213. data/lib/carray/window_iterator.rb +655 -0
  214. data/lib/carray.rb +55 -57
  215. metadata +163 -130
  216. data/Rakefile +0 -51
  217. data/TODO.md +0 -18
  218. data/ext/ca_iter_block.c +0 -257
  219. data/ext/ca_iter_dimension.c +0 -299
  220. data/ext/ca_iter_window.c +0 -214
  221. data/ext/ca_obj_mapping.c +0 -644
  222. data/ext/carray_iterator.c +0 -641
  223. data/ext/carray_math.rb +0 -850
  224. data/ext/carray_numeric.c +0 -259
  225. data/ext/carray_sort_addr.c +0 -254
  226. data/ext/carray_stat.c +0 -2100
  227. data/ext/carray_stat_proc.rb +0 -1999
  228. data/ext/mkmath.rb +0 -741
  229. data/ext/ruby_ccomplex.c +0 -509
  230. data/ext/ruby_float_func.c +0 -86
  231. data/lib/carray/array.rb +0 -8
  232. data/lib/carray/autoload/autoload_base.rb +0 -19
  233. data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
  234. data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
  235. data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
  236. data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
  237. data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
  238. data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
  239. data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
  240. data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
  241. data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
  242. data/lib/carray/autoload/autoload_gem_random.rb +0 -8
  243. data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
  244. data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
  245. data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
  246. data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
  247. data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
  248. data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
  249. data/lib/carray/autoload/autoload_object_link.rb +0 -1
  250. data/lib/carray/autoload/autoload_object_pack.rb +0 -2
  251. data/lib/carray/autoload.rb +0 -141
  252. data/lib/carray/basic.rb +0 -191
  253. data/lib/carray/broadcast.rb +0 -101
  254. data/lib/carray/compose.rb +0 -315
  255. data/lib/carray/convert.rb +0 -115
  256. data/lib/carray/info.rb +0 -110
  257. data/lib/carray/io/imagemagick.rb +0 -235
  258. data/lib/carray/mask.rb +0 -102
  259. data/lib/carray/math/histogram.rb +0 -177
  260. data/lib/carray/math/recurrence.rb +0 -93
  261. data/lib/carray/object/ca_obj_iterator.rb +0 -50
  262. data/lib/carray/object/ca_obj_link.rb +0 -50
  263. data/lib/carray/object/ca_obj_pack.rb +0 -99
  264. data/lib/carray/obsolete.rb +0 -256
  265. data/lib/carray/ordering.rb +0 -181
  266. data/lib/carray/testing.rb +0 -51
  267. data/lib/carray/transform.rb +0 -109
  268. data/misc/Methods.ja.md +0 -182
  269. data/misc/NOTE +0 -51
  270. data/spec/Classes/CABitfield_spec.rb +0 -58
  271. data/spec/Classes/CABlockIterator_spec.rb +0 -114
  272. data/spec/Classes/CABlock_spec.rb +0 -205
  273. data/spec/Classes/CAField_spec.rb +0 -39
  274. data/spec/Classes/CAGrid_spec.rb +0 -75
  275. data/spec/Classes/CAMap_spec.rb +0 -0
  276. data/spec/Classes/CAMapping_spec.rb +0 -105
  277. data/spec/Classes/CAObject_attribute_spec.rb +0 -33
  278. data/spec/Classes/CAObject_spec.rb +0 -33
  279. data/spec/Classes/CARefer_spec.rb +0 -93
  280. data/spec/Classes/CARepeat_spec.rb +0 -65
  281. data/spec/Classes/CASelect_spec.rb +0 -22
  282. data/spec/Classes/CAShift_spec.rb +0 -16
  283. data/spec/Classes/CAStruct_spec.rb +0 -71
  284. data/spec/Classes/CATranspose_spec.rb +0 -60
  285. data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
  286. data/spec/Classes/CAWindow_spec.rb +0 -54
  287. data/spec/Classes/CAWrap_spec.rb +0 -8
  288. data/spec/Classes/CArray_spec.rb +0 -184
  289. data/spec/Classes/CScalar_spec.rb +0 -55
  290. data/spec/Classes/ex1.rb +0 -46
  291. data/spec/Features/feature_130_spec.rb +0 -19
  292. data/spec/Features/feature_attributes_spec.rb +0 -280
  293. data/spec/Features/feature_boolean_spec.rb +0 -98
  294. data/spec/Features/feature_broadcast.rb +0 -116
  295. data/spec/Features/feature_cast_function.rb +0 -19
  296. data/spec/Features/feature_cast_spec.rb +0 -33
  297. data/spec/Features/feature_class_spec.rb +0 -84
  298. data/spec/Features/feature_complex_spec.rb +0 -42
  299. data/spec/Features/feature_composite_spec.rb +0 -124
  300. data/spec/Features/feature_convert_spec.rb +0 -46
  301. data/spec/Features/feature_copy_spec.rb +0 -123
  302. data/spec/Features/feature_creation_spec.rb +0 -84
  303. data/spec/Features/feature_element_spec.rb +0 -144
  304. data/spec/Features/feature_extream_spec.rb +0 -54
  305. data/spec/Features/feature_generate_spec.rb +0 -74
  306. data/spec/Features/feature_index_spec.rb +0 -69
  307. data/spec/Features/feature_mask_spec.rb +0 -580
  308. data/spec/Features/feature_math_spec.rb +0 -97
  309. data/spec/Features/feature_order_spec.rb +0 -146
  310. data/spec/Features/feature_ref_store_spec.rb +0 -209
  311. data/spec/Features/feature_serialization_spec.rb +0 -125
  312. data/spec/Features/feature_stat_spec.rb +0 -397
  313. data/spec/Features/feature_virtual_spec.rb +0 -48
  314. data/spec/Features/method_eq_spec.rb +0 -81
  315. data/spec/Features/method_is_nan_spec.rb +0 -12
  316. data/spec/Features/method_map_spec.rb +0 -54
  317. data/spec/Features/method_max_with.rb +0 -20
  318. data/spec/Features/method_min_with.rb +0 -19
  319. data/spec/Features/method_ne_spec.rb +0 -18
  320. data/spec/Features/method_project_spec.rb +0 -188
  321. data/spec/Features/method_ref_spec.rb +0 -27
  322. data/spec/Features/method_round_spec.rb +0 -11
  323. data/spec/Features/method_s_linspace_spec.rb +0 -48
  324. data/spec/Features/method_s_span_spec.rb +0 -14
  325. data/spec/Features/method_seq_spec.rb +0 -47
  326. data/spec/Features/method_sort_with.rb +0 -43
  327. data/spec/Features/method_sorted_with.rb +0 -29
  328. data/spec/Features/method_span_spec.rb +0 -42
  329. data/spec/Features/method_wrap_readonly_spec.rb +0 -43
  330. data/spec/UnitTest/test_CAVirtual.rb +0 -214
  331. data/spec/spec_all.rb +0 -10
  332. data/utils/ca_ase.rb +0 -21
  333. data/utils/ca_methods.rb +0 -15
  334. data/utils/cast_checker.rb +0 -30
  335. data/utils/convert_test.rb +0 -73
  336. data/utils/extract_yard.rb +0 -22
  337. data/utils/guess_shape.rb +0 -76
  338. data/utils/monkey_patch_methods.rb +0 -62
  339. 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 dtype (no cast to
7
+ int64), skips per-iteration bounds checking (caller validates label
8
+ range), and emits the output dtype directly.
9
+
10
+ Output dtype:
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 dtype.
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 dtypes × 2 output
34
+ dtypes = 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 dtype: 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 dtype = weights dtype.
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,283 @@
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 or when they are
16
+ incompatible (the caller's existing elements-mismatch raise
17
+ path then handles the error). Called by carray_cast.c's
18
+ coercion path and by the binop dispatcher.
19
+
20
+ rb_ca_broadcast_to -- backs the public CArray#broadcast_to method
21
+ (right-to-left axis pairing; see the docstring at the function).
22
+
23
+ Case B (cross-ndim dim-prepending) is not handled by the implicit
24
+ helpers; users with cross-ndim operands keep using the explicit :*
25
+ form or #broadcast_to (which does accept cross-ndim with target axes
26
+ pinned to size 1). See PROPOSAL_BROADCASTING_AND_UNBOUND.md.
27
+
28
+ ---------------------------------------------------------------------------- */
29
+
30
+ #include "carray.h"
31
+
32
+ /* Build a CAStride view of `src` with shape `target_dim`. For each
33
+ axis where src.dim[i] == target_dim[i], inherit the row-major byte
34
+ stride; for src.dim[i] == 1 and target_dim[i] > 1, use stride 0.
35
+ Otherwise, raise. If no axis needs expansion, return src as-is. */
36
+ VALUE
37
+ ca_broadcast_view (VALUE src, int8_t ndim, ca_size_t *target_dim)
38
+ {
39
+ CArray *cs;
40
+ ca_size_t src_strides[CA_RANK_MAX];
41
+ ca_size_t new_strides[CA_RANK_MAX];
42
+ ca_size_t s;
43
+ int needs_broadcast = 0;
44
+ int i;
45
+ CAStride *view;
46
+ volatile VALUE obj;
47
+
48
+ TypedData_Get_Struct(src, CArray, &carray_data_type, cs);
49
+
50
+ if (cs->ndim != ndim) {
51
+ rb_raise(rb_eRuntimeError,
52
+ "broadcast: ndim mismatch (%d vs %d)",
53
+ (int) cs->ndim, (int) ndim);
54
+ }
55
+
56
+ /* Row-major byte strides for src treated as contiguous. When src is
57
+ itself a CAStride, the compose-fold path at attach time collapses
58
+ the chain to root, so passing parent-relative row-major strides
59
+ is correct. */
60
+ s = cs->bytes;
61
+ for (i = ndim - 1; i >= 0; i--) {
62
+ src_strides[i] = s;
63
+ s *= cs->dim[i];
64
+ }
65
+
66
+ for (i = 0; i < ndim; i++) {
67
+ if (cs->dim[i] == target_dim[i]) {
68
+ new_strides[i] = src_strides[i];
69
+ }
70
+ else if (cs->dim[i] == 1) {
71
+ new_strides[i] = 0;
72
+ needs_broadcast = 1;
73
+ }
74
+ else {
75
+ rb_raise(rb_eRuntimeError,
76
+ "broadcast: cannot broadcast axis %d (%lld vs %lld)",
77
+ i, (long long) cs->dim[i], (long long) target_dim[i]);
78
+ }
79
+ }
80
+
81
+ if (!needs_broadcast) return src;
82
+
83
+ view = ca_stride_new(CA_OBJ_STRIDE, cs,
84
+ cs->data_type, cs->bytes,
85
+ ndim, target_dim, new_strides, 0);
86
+ ca_set_flag(view, CA_FLAG_READ_ONLY);
87
+ if (view->mask) {
88
+ ca_set_flag(view->mask, CA_FLAG_READ_ONLY);
89
+ }
90
+ obj = ca_wrap_struct(view);
91
+ rb_ca_set_parent(obj, src);
92
+ return obj;
93
+ }
94
+
95
+ /* Two-sided broadcast for binary ops (case A only). When both
96
+ operands are non-scalar with equal ndim and at least one axis pair
97
+ is (1, N) / (N, 1) / (1, 1), wrap each in a CAStride with stride-0
98
+ axes so the downstream iterator sees matched shapes. If shapes are
99
+ pairwise equal, no-op. If any axis pair is incompatible (neither
100
+ side is 1 nor equal), no-op (caller's existing element-count check
101
+ raises). */
102
+ void
103
+ ca_broadcast_pair (volatile VALUE *self, volatile VALUE *other)
104
+ {
105
+ CArray *ca, *cb;
106
+ ca_size_t target_dim[CA_RANK_MAX];
107
+ int can_broadcast = 1;
108
+ int needs_broadcast = 0;
109
+ int i;
110
+
111
+ TypedData_Get_Struct(*self, CArray, &carray_data_type, ca);
112
+ TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
113
+
114
+ if (ca_is_scalar(ca) || ca_is_scalar(cb)) return;
115
+ if (ca->ndim != cb->ndim) return;
116
+ if (ca->ndim == 0) return;
117
+
118
+ for (i = 0; i < ca->ndim; i++) {
119
+ if (ca->dim[i] == cb->dim[i]) {
120
+ target_dim[i] = ca->dim[i];
121
+ }
122
+ else if (ca->dim[i] == 1) {
123
+ target_dim[i] = cb->dim[i];
124
+ needs_broadcast = 1;
125
+ }
126
+ else if (cb->dim[i] == 1) {
127
+ target_dim[i] = ca->dim[i];
128
+ needs_broadcast = 1;
129
+ }
130
+ else {
131
+ can_broadcast = 0;
132
+ break;
133
+ }
134
+ }
135
+
136
+ if (!can_broadcast || !needs_broadcast) return;
137
+
138
+ *self = ca_broadcast_view(*self, ca->ndim, target_dim);
139
+ *other = ca_broadcast_view(*other, ca->ndim, target_dim);
140
+ }
141
+
142
+ /* CArray#broadcast_to(*newdim) -- pairs axes right-to-left:
143
+ - source axis == target axis -> data axis (inherit stride)
144
+ - target axis == 1 -> size-1 collapse, source consumed
145
+ only when it is also 1
146
+ - source axis == 1 -> broadcast (stride 0, source
147
+ consumed)
148
+ - source exhausted, target 1 -> insert size-1 axis
149
+ - otherwise -> RuntimeError
150
+
151
+ Intentionally conservative on cross-ndim: prepended axes are only
152
+ inserted as size-1. Target > 1 on a prepended axis raises, in
153
+ keeping with PROPOSAL_BROADCASTING_AND_UNBOUND.md's strict-ndim
154
+ policy.
155
+
156
+ Result is tagged CA_OBJ_REPEAT (CARepeat) rather than plain CAStride
157
+ so introspection (`view.class`) surfaces the broadcast intent. */
158
+
159
+ static VALUE
160
+ rb_ca_broadcast_to (int argc, VALUE *argv, VALUE self)
161
+ {
162
+ CArray *cs;
163
+ ca_size_t target_dim[CA_RANK_MAX];
164
+ ca_size_t new_strides[CA_RANK_MAX];
165
+ ca_size_t src_strides[CA_RANK_MAX];
166
+ ca_size_t s;
167
+ int8_t target_ndim;
168
+ int needs_view = 0;
169
+ int t_idx, s_idx;
170
+ int i;
171
+ CAStride *view;
172
+ volatile VALUE obj;
173
+
174
+ TypedData_Get_Struct(self, CArray, &carray_data_type, cs);
175
+
176
+ if (argc < 0 || argc > CA_RANK_MAX) {
177
+ rb_raise(rb_eArgError, "broadcast_to: invalid number of dims (%d)", argc);
178
+ }
179
+ target_ndim = (int8_t) argc;
180
+
181
+ if (target_ndim < cs->ndim) {
182
+ rb_raise(rb_eRuntimeError,
183
+ "broadcast_to: target ndim %d smaller than source ndim %d",
184
+ (int) target_ndim, (int) cs->ndim);
185
+ }
186
+
187
+ for (i = 0; i < target_ndim; i++) {
188
+ target_dim[i] = NUM2SIZE(argv[i]);
189
+ if (target_dim[i] < 0) {
190
+ rb_raise(rb_eArgError,
191
+ "broadcast_to: negative dim at axis %d", i);
192
+ }
193
+ }
194
+
195
+ /* CScalar source: build an all-stride-0 CARepeat view of any
196
+ target shape. Generalises the cross-ndim rule, which is strict
197
+ for non-scalar sources (each source axis must pair with a target
198
+ axis); for a scalar the natural extension is "any target shape,
199
+ stride 0 everywhere". */
200
+ if (ca_is_scalar(cs)) {
201
+ for (i = 0; i < target_ndim; i++) {
202
+ new_strides[i] = 0;
203
+ }
204
+ view = ca_stride_new(CA_OBJ_REPEAT, cs,
205
+ cs->data_type, cs->bytes,
206
+ target_ndim, target_dim, new_strides, 0);
207
+ ca_set_flag(view, CA_FLAG_READ_ONLY);
208
+ if (view->mask) {
209
+ ca_set_flag(view->mask, CA_FLAG_READ_ONLY);
210
+ }
211
+ obj = ca_wrap_struct(view);
212
+ rb_ca_set_parent(obj, self);
213
+ return obj;
214
+ }
215
+
216
+ /* Row-major byte strides for source (interpreted as contiguous;
217
+ compose-fold at attach time handles non-contiguous parents). */
218
+ s = cs->bytes;
219
+ for (i = cs->ndim - 1; i >= 0; i--) {
220
+ src_strides[i] = s;
221
+ s *= cs->dim[i];
222
+ }
223
+
224
+ /* Pair right-to-left. s_idx tracks the next source axis to be
225
+ consumed; -1 means source is exhausted. */
226
+ t_idx = target_ndim - 1;
227
+ s_idx = cs->ndim - 1;
228
+
229
+ while (t_idx >= 0) {
230
+ ca_size_t dd = target_dim[t_idx];
231
+ ca_size_t sd = (s_idx >= 0) ? cs->dim[s_idx] : -1;
232
+
233
+ if (sd == dd) {
234
+ new_strides[t_idx] = src_strides[s_idx];
235
+ s_idx--;
236
+ }
237
+ else if (dd == 1) {
238
+ new_strides[t_idx] = 0;
239
+ if (sd == 1) s_idx--;
240
+ needs_view = 1;
241
+ }
242
+ else if (sd == 1) {
243
+ new_strides[t_idx] = 0;
244
+ s_idx--;
245
+ needs_view = 1;
246
+ }
247
+ else {
248
+ /* sd == -1 (source exhausted) with dd > 1, or sd > 1 with
249
+ dd > 1 and not equal: cannot broadcast. */
250
+ rb_raise(rb_eRuntimeError,
251
+ "broadcast_to: cannot broadcast axis %d "
252
+ "(source %s, target %lld)",
253
+ t_idx,
254
+ (sd < 0 ? "(exhausted)" : "non-1"),
255
+ (long long) dd);
256
+ }
257
+ t_idx--;
258
+ }
259
+
260
+ if (s_idx >= 0) {
261
+ rb_raise(rb_eRuntimeError,
262
+ "broadcast_to: %d source axes left unmatched", s_idx + 1);
263
+ }
264
+
265
+ if (!needs_view) return self;
266
+
267
+ view = ca_stride_new(CA_OBJ_REPEAT, cs,
268
+ cs->data_type, cs->bytes,
269
+ target_ndim, target_dim, new_strides, 0);
270
+ ca_set_flag(view, CA_FLAG_READ_ONLY);
271
+ if (view->mask) {
272
+ ca_set_flag(view->mask, CA_FLAG_READ_ONLY);
273
+ }
274
+ obj = ca_wrap_struct(view);
275
+ rb_ca_set_parent(obj, self);
276
+ return obj;
277
+ }
278
+
279
+ void
280
+ Init_carray_broadcast (void)
281
+ {
282
+ rb_define_method(rb_cCArray, "broadcast_to", rb_ca_broadcast_to, -1);
283
+ }