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.
Files changed (386) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -25
  3. data/CHANGELOG.md +338 -0
  4. data/{NEWS.md → CHANGELOG.v1.md} +3 -0
  5. data/LICENSE +1 -1
  6. data/README.md +120 -36
  7. data/carray.gemspec +32 -30
  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 +1244 -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 +124 -0
  15. data/ext/ca_binop_dispatch.h +152 -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 +239 -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 +4367 -0
  26. data/ext/ca_kernel_iterator.h +2596 -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 +839 -0
  33. data/ext/ca_obj_binop.c +948 -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 +967 -0
  39. data/ext/ca_obj_face.c +750 -0
  40. data/ext/ca_obj_face.h +279 -0
  41. data/ext/ca_obj_fake.c +239 -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 +308 -0
  45. data/ext/ca_obj_grid.c +866 -440
  46. data/ext/ca_obj_meld.c +1039 -0
  47. data/ext/ca_obj_moncmp.c +588 -0
  48. data/ext/ca_obj_monop.c +1123 -0
  49. data/ext/ca_obj_object.c +866 -296
  50. data/ext/ca_obj_record.c +470 -0
  51. data/ext/ca_obj_reduce.c +97 -82
  52. data/ext/ca_obj_refer.c +593 -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 +624 -0
  56. data/ext/ca_obj_select.c +344 -296
  57. data/ext/ca_obj_select_axis.c +1306 -0
  58. data/ext/ca_obj_shift.c +231 -793
  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 +2584 -0
  62. data/ext/ca_obj_string.c +270 -0
  63. data/ext/ca_obj_tile.c +622 -0
  64. data/ext/ca_obj_time.c +548 -0
  65. data/ext/ca_obj_timedelta.c +437 -0
  66. data/ext/ca_obj_transpose.c +62 -516
  67. data/ext/ca_obj_triop.c +785 -0
  68. data/ext/ca_obj_window.c +1202 -565
  69. data/ext/ca_op_byte_swap.c +175 -0
  70. data/ext/ca_op_cmplx64.h +123 -0
  71. data/ext/ca_op_ipower.c +316 -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 +473 -0
  75. data/ext/ca_sweep_engine.h +166 -0
  76. data/ext/ca_transform_common.c +235 -0
  77. data/ext/ca_triop_dispatch.c +55 -0
  78. data/ext/ca_triop_dispatch.h +62 -0
  79. data/ext/carray.h +810 -420
  80. data/ext/carray_access.c +873 -731
  81. data/ext/carray_attribute.c +98 -329
  82. data/ext/carray_bincount.c +255 -0
  83. data/ext/carray_broadcast.c +376 -0
  84. data/ext/carray_build_flags.h +3 -0
  85. data/ext/carray_call_cfunc.c +2897 -874
  86. data/ext/carray_call_cfunc.h +313 -0
  87. data/ext/carray_cast.c +1264 -315
  88. data/ext/carray_cast_func.rb +81 -40
  89. data/ext/carray_class.c +53 -63
  90. data/ext/carray_config.h +28 -0
  91. data/ext/carray_conversion.c +350 -346
  92. data/ext/carray_copy.c +168 -270
  93. data/ext/carray_core.c +1396 -206
  94. data/ext/carray_count.c +312 -0
  95. data/ext/carray_data_type.c +43 -19
  96. data/ext/carray_element.c +585 -213
  97. data/ext/carray_factorize.c +2542 -0
  98. data/ext/carray_generate.c +230 -559
  99. data/ext/carray_histogram.c +490 -0
  100. data/ext/carray_hold.c +228 -0
  101. data/ext/carray_index_classifier.c +1021 -0
  102. data/ext/carray_index_classifier.h +27 -0
  103. data/ext/carray_internal.h +136 -0
  104. data/ext/carray_kernels_bincmp.c +4446 -0
  105. data/ext/carray_kernels_binop.c +11001 -0
  106. data/ext/carray_kernels_init.c +1131 -0
  107. data/ext/carray_kernels_map.c +3467 -0
  108. data/ext/carray_kernels_moncmp.c +2097 -0
  109. data/ext/carray_kernels_monop.c +18313 -0
  110. data/ext/carray_kernels_reduce_aggregate.c +25837 -0
  111. data/ext/carray_kernels_reduce_boolean.c +330 -0
  112. data/ext/carray_kernels_reduce_cumulative.c +14593 -0
  113. data/ext/carray_kernels_reduce_extreme.c +16948 -0
  114. data/ext/carray_kernels_reduce_variance.c +3910 -0
  115. data/ext/carray_kernels_scan.c +3693 -0
  116. data/ext/carray_kernels_search.c +32138 -0
  117. data/ext/carray_kernels_sort.c +10626 -0
  118. data/ext/carray_kernels_triop.c +1392 -0
  119. data/ext/carray_lazy.c +737 -0
  120. data/ext/carray_loop.c +88 -200
  121. data/ext/carray_mask.c +853 -158
  122. data/ext/carray_math_kernel.h +120 -0
  123. data/ext/carray_mathfunc.c +10 -241
  124. data/ext/carray_median_percentile.c +1257 -0
  125. data/ext/carray_memory_view.c +1650 -0
  126. data/ext/carray_operator.c +1525 -320
  127. data/ext/carray_order.c +664 -1394
  128. data/ext/carray_partition.c +416 -0
  129. data/ext/carray_random.c +518 -0
  130. data/ext/carray_scatter.c +357 -0
  131. data/ext/carray_slab.c +1219 -0
  132. data/ext/carray_slab.h +84 -0
  133. data/ext/carray_sort.c +829 -0
  134. data/ext/carray_sort_kernel.c +620 -0
  135. data/ext/carray_struct.c +695 -0
  136. data/ext/carray_test.c +343 -229
  137. data/ext/carray_undef.c +34 -17
  138. data/ext/carray_utils.c +175 -74
  139. data/ext/extconf.rb +234 -55
  140. data/ext/mk_call_cfunc.rb +671 -0
  141. data/ext/mkkernel.rb +9096 -0
  142. data/ext/ruby_carray.c +211 -108
  143. data/ext/version.h +4 -14
  144. data/ext/version.rb +5 -13
  145. data/lib/carray/arrow_tensor.rb +401 -0
  146. data/lib/carray/attribute.rb +166 -0
  147. data/lib/carray/autoload_carray.rb +239 -0
  148. data/lib/carray/autoload_method_extension.rb +45 -0
  149. data/lib/carray/axis_group.rb +711 -0
  150. data/lib/carray/basics.rb +481 -0
  151. data/lib/carray/bincount_nd.rb +358 -0
  152. data/lib/carray/block_iterator.rb +614 -0
  153. data/lib/carray/boolean_reduce.rb +109 -0
  154. data/lib/carray/categorical.rb +561 -0
  155. data/lib/carray/categorical_iterator.rb +1084 -0
  156. data/lib/carray/complex.rb +150 -0
  157. data/lib/carray/conditional.rb +216 -0
  158. data/lib/carray/const_string.rb +228 -0
  159. data/lib/carray/construct.rb +160 -328
  160. data/lib/carray/core_extensions.rb +297 -0
  161. data/lib/carray/data_type_extension.rb +250 -0
  162. data/lib/carray/fixlen_string.rb +95 -0
  163. data/lib/carray/frame/concat.rb +132 -0
  164. data/lib/carray/frame/convert.rb +95 -0
  165. data/lib/carray/frame/csv_parser.rb +211 -0
  166. data/lib/carray/frame/frame.rb +642 -0
  167. data/lib/carray/frame/group.rb +186 -0
  168. data/lib/carray/frame/io.rb +321 -0
  169. data/lib/carray/frame/join.rb +248 -0
  170. data/lib/carray/frame/records.rb +99 -0
  171. data/lib/carray/frame/sort.rb +113 -0
  172. data/lib/carray/frame/verbs.rb +316 -0
  173. data/lib/carray/frame.rb +16 -0
  174. data/lib/carray/fuse_source.rb +123 -0
  175. data/lib/carray/fusion.rb +218 -0
  176. data/lib/carray/histogram.rb +512 -0
  177. data/lib/carray/inspect.rb +37 -26
  178. data/lib/carray/iterator.rb +58 -349
  179. data/lib/carray/lazy.rb +941 -0
  180. data/lib/carray/mask_gap_fill.rb +200 -0
  181. data/lib/carray/math.rb +78 -342
  182. data/lib/carray/meld_reduce.rb +289 -0
  183. data/lib/carray/methods/align_addr.rb +116 -0
  184. data/lib/carray/methods/bin.rb +128 -0
  185. data/lib/carray/methods/bincount.rb +87 -0
  186. data/lib/carray/methods/bit_string.rb +92 -0
  187. data/lib/carray/methods/broadcast.rb +63 -0
  188. data/lib/carray/methods/choose.rb +39 -0
  189. data/lib/carray/methods/composition.rb +280 -0
  190. data/lib/carray/methods/gather_nd.rb +206 -0
  191. data/lib/carray/methods/index.rb +39 -0
  192. data/lib/carray/methods/insert_block.rb +99 -0
  193. data/lib/carray/methods/is_in.rb +141 -0
  194. data/lib/carray/methods/join.rb +90 -0
  195. data/lib/carray/methods/locate_addr.rb +52 -0
  196. data/lib/carray/methods/mask_duplicates.rb +41 -0
  197. data/lib/carray/methods/meshgrid.rb +90 -0
  198. data/lib/carray/methods/mode.rb +126 -0
  199. data/lib/carray/methods/nunique.rb +46 -0
  200. data/lib/carray/methods/resize.rb +56 -0
  201. data/lib/carray/methods/snap.rb +161 -0
  202. data/lib/carray/methods/string_format.rb +57 -0
  203. data/lib/carray/methods/unique.rb +47 -0
  204. data/lib/carray/methods/value_counts.rb +71 -0
  205. data/lib/carray/mkmf.rb +124 -101
  206. data/lib/carray/runtime.rb +89 -0
  207. data/lib/carray/serialize.rb +478 -167
  208. data/lib/carray/slab_iterator.rb +305 -0
  209. data/lib/carray/stack.rb +291 -0
  210. data/lib/carray/string.rb +56 -180
  211. data/lib/carray/string_operation_extension.rb +289 -0
  212. data/lib/carray/struct.rb +335 -323
  213. data/lib/carray/struct_builder.rb +697 -0
  214. data/lib/carray/table.rb +41 -2
  215. data/lib/carray/time.rb +2654 -38
  216. data/lib/carray/window_iterator.rb +927 -0
  217. data/lib/carray.rb +55 -57
  218. data/yard-stubs/ca_obj_array.rb +385 -0
  219. data/yard-stubs/ca_obj_bitarray.rb +38 -0
  220. data/yard-stubs/ca_obj_bitfield.rb +43 -0
  221. data/yard-stubs/ca_obj_block.rb +73 -0
  222. data/yard-stubs/ca_obj_byte_swap.rb +56 -0
  223. data/yard-stubs/ca_obj_fake.rb +31 -0
  224. data/yard-stubs/ca_obj_farray.rb +32 -0
  225. data/yard-stubs/ca_obj_field.rb +45 -0
  226. data/yard-stubs/ca_obj_grid.rb +35 -0
  227. data/yard-stubs/ca_obj_refer.rb +72 -0
  228. data/yard-stubs/ca_obj_roll.rb +45 -0
  229. data/yard-stubs/ca_obj_shift.rb +43 -0
  230. data/yard-stubs/ca_obj_stride.rb +181 -0
  231. data/yard-stubs/ca_obj_tile.rb +29 -0
  232. data/yard-stubs/ca_obj_transpose.rb +40 -0
  233. data/yard-stubs/ca_obj_window.rb +49 -0
  234. data/yard-stubs/carray_access.rb +131 -0
  235. data/yard-stubs/carray_attribute.rb +246 -0
  236. data/yard-stubs/carray_broadcast.rb +37 -0
  237. data/yard-stubs/carray_cast.rb +489 -0
  238. data/yard-stubs/carray_class.rb +65 -0
  239. data/yard-stubs/carray_conversion.rb +76 -0
  240. data/yard-stubs/carray_copy.rb +79 -0
  241. data/yard-stubs/carray_core.rb +114 -0
  242. data/yard-stubs/carray_count.rb +79 -0
  243. data/yard-stubs/carray_element.rb +108 -0
  244. data/yard-stubs/carray_generate.rb +66 -0
  245. data/yard-stubs/carray_lazy.rb +23 -0
  246. data/yard-stubs/carray_loop.rb +140 -0
  247. data/yard-stubs/carray_mask.rb +259 -0
  248. data/yard-stubs/carray_math.rb +132 -0
  249. data/yard-stubs/carray_mathfunc.rb +45 -0
  250. data/yard-stubs/carray_median_percentile.rb +89 -0
  251. data/yard-stubs/carray_memory_view.rb +163 -0
  252. data/yard-stubs/carray_order.rb +312 -0
  253. data/yard-stubs/carray_random.rb +89 -0
  254. data/yard-stubs/carray_scatter.rb +106 -0
  255. data/yard-stubs/carray_slab.rb +57 -0
  256. data/yard-stubs/carray_sort.rb +163 -0
  257. data/yard-stubs/carray_test.rb +85 -0
  258. data/yard-stubs/carray_undef.rb +64 -0
  259. data/yard-stubs/carray_utils.rb +97 -0
  260. data/yard-stubs/ruby_carray.rb +193 -0
  261. metadata +220 -138
  262. data/Rakefile +0 -51
  263. data/TODO.md +0 -18
  264. data/ext/ca_iter_block.c +0 -257
  265. data/ext/ca_iter_dimension.c +0 -299
  266. data/ext/ca_iter_window.c +0 -214
  267. data/ext/ca_obj_mapping.c +0 -644
  268. data/ext/ca_obj_unbound_repeat.c +0 -529
  269. data/ext/carray_iterator.c +0 -641
  270. data/ext/carray_math.rb +0 -850
  271. data/ext/carray_numeric.c +0 -259
  272. data/ext/carray_sort_addr.c +0 -254
  273. data/ext/carray_stat.c +0 -2100
  274. data/ext/carray_stat_proc.rb +0 -1999
  275. data/ext/mkmath.rb +0 -741
  276. data/ext/ruby_ccomplex.c +0 -509
  277. data/ext/ruby_float_func.c +0 -86
  278. data/lib/carray/array.rb +0 -8
  279. data/lib/carray/autoload/autoload_base.rb +0 -19
  280. data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
  281. data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
  282. data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
  283. data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
  284. data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
  285. data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
  286. data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
  287. data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
  288. data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
  289. data/lib/carray/autoload/autoload_gem_random.rb +0 -8
  290. data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
  291. data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
  292. data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
  293. data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
  294. data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
  295. data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
  296. data/lib/carray/autoload/autoload_object_link.rb +0 -1
  297. data/lib/carray/autoload/autoload_object_pack.rb +0 -2
  298. data/lib/carray/autoload.rb +0 -141
  299. data/lib/carray/basic.rb +0 -191
  300. data/lib/carray/broadcast.rb +0 -101
  301. data/lib/carray/compose.rb +0 -315
  302. data/lib/carray/convert.rb +0 -115
  303. data/lib/carray/info.rb +0 -110
  304. data/lib/carray/io/imagemagick.rb +0 -235
  305. data/lib/carray/mask.rb +0 -102
  306. data/lib/carray/math/histogram.rb +0 -177
  307. data/lib/carray/math/recurrence.rb +0 -93
  308. data/lib/carray/object/ca_obj_iterator.rb +0 -50
  309. data/lib/carray/object/ca_obj_link.rb +0 -50
  310. data/lib/carray/object/ca_obj_pack.rb +0 -99
  311. data/lib/carray/obsolete.rb +0 -256
  312. data/lib/carray/ordering.rb +0 -181
  313. data/lib/carray/testing.rb +0 -51
  314. data/lib/carray/transform.rb +0 -109
  315. data/mailmap +0 -1
  316. data/misc/Methods.ja.md +0 -182
  317. data/misc/NOTE +0 -51
  318. data/spec/Classes/CABitfield_spec.rb +0 -58
  319. data/spec/Classes/CABlockIterator_spec.rb +0 -114
  320. data/spec/Classes/CABlock_spec.rb +0 -205
  321. data/spec/Classes/CAField_spec.rb +0 -39
  322. data/spec/Classes/CAGrid_spec.rb +0 -75
  323. data/spec/Classes/CAMap_spec.rb +0 -0
  324. data/spec/Classes/CAMapping_spec.rb +0 -105
  325. data/spec/Classes/CAObject_attribute_spec.rb +0 -33
  326. data/spec/Classes/CAObject_spec.rb +0 -33
  327. data/spec/Classes/CARefer_spec.rb +0 -93
  328. data/spec/Classes/CARepeat_spec.rb +0 -65
  329. data/spec/Classes/CASelect_spec.rb +0 -22
  330. data/spec/Classes/CAShift_spec.rb +0 -16
  331. data/spec/Classes/CAStruct_spec.rb +0 -71
  332. data/spec/Classes/CATranspose_spec.rb +0 -60
  333. data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
  334. data/spec/Classes/CAWindow_spec.rb +0 -54
  335. data/spec/Classes/CAWrap_spec.rb +0 -8
  336. data/spec/Classes/CArray_spec.rb +0 -184
  337. data/spec/Classes/CScalar_spec.rb +0 -55
  338. data/spec/Features/feature_130_spec.rb +0 -19
  339. data/spec/Features/feature_attributes_spec.rb +0 -280
  340. data/spec/Features/feature_boolean_spec.rb +0 -98
  341. data/spec/Features/feature_broadcast.rb +0 -116
  342. data/spec/Features/feature_cast_function.rb +0 -19
  343. data/spec/Features/feature_cast_spec.rb +0 -33
  344. data/spec/Features/feature_class_spec.rb +0 -84
  345. data/spec/Features/feature_complex_spec.rb +0 -42
  346. data/spec/Features/feature_composite_spec.rb +0 -124
  347. data/spec/Features/feature_convert_spec.rb +0 -46
  348. data/spec/Features/feature_copy_spec.rb +0 -123
  349. data/spec/Features/feature_creation_spec.rb +0 -84
  350. data/spec/Features/feature_element_spec.rb +0 -144
  351. data/spec/Features/feature_extream_spec.rb +0 -54
  352. data/spec/Features/feature_generate_spec.rb +0 -74
  353. data/spec/Features/feature_index_spec.rb +0 -69
  354. data/spec/Features/feature_mask_spec.rb +0 -580
  355. data/spec/Features/feature_math_spec.rb +0 -97
  356. data/spec/Features/feature_order_spec.rb +0 -146
  357. data/spec/Features/feature_ref_store_spec.rb +0 -209
  358. data/spec/Features/feature_serialization_spec.rb +0 -125
  359. data/spec/Features/feature_stat_spec.rb +0 -397
  360. data/spec/Features/feature_virtual_spec.rb +0 -48
  361. data/spec/Features/method_eq_spec.rb +0 -81
  362. data/spec/Features/method_is_nan_spec.rb +0 -12
  363. data/spec/Features/method_map_spec.rb +0 -54
  364. data/spec/Features/method_max_with.rb +0 -20
  365. data/spec/Features/method_min_with.rb +0 -19
  366. data/spec/Features/method_ne_spec.rb +0 -18
  367. data/spec/Features/method_project_spec.rb +0 -188
  368. data/spec/Features/method_ref_spec.rb +0 -27
  369. data/spec/Features/method_round_spec.rb +0 -11
  370. data/spec/Features/method_s_linspace_spec.rb +0 -48
  371. data/spec/Features/method_s_span_spec.rb +0 -14
  372. data/spec/Features/method_seq_spec.rb +0 -47
  373. data/spec/Features/method_sort_with.rb +0 -43
  374. data/spec/Features/method_sorted_with.rb +0 -29
  375. data/spec/Features/method_span_spec.rb +0 -42
  376. data/spec/Features/method_wrap_readonly_spec.rb +0 -43
  377. data/spec/UnitTest/test_CAVirtual.rb +0 -214
  378. data/spec/spec_all.rb +0 -10
  379. data/utils/ca_ase.rb +0 -21
  380. data/utils/ca_methods.rb +0 -15
  381. data/utils/cast_checker.rb +0 -30
  382. data/utils/convert_test.rb +0 -73
  383. data/utils/extract_yard.rb +0 -22
  384. data/utils/guess_shape.rb +0 -76
  385. data/utils/monkey_patch_methods.rb +0 -62
  386. 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
+ }
@@ -0,0 +1,3 @@
1
+ /* GENERATED by extconf.rb: the flags this build's arithmetic
2
+ was compiled with. See CArray::BUILD_FLAGS. */
3
+ #define CA_BUILD_FLAGS "-O3 -fno-fast-math -fopenmp-simd -march=native"