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,481 @@
1
+ # Frequently-used CArray convenience methods kept eager-loaded.
2
+ #
3
+ # Rationale: a method lands here NOT because of its topic / domain (those
4
+ # have their own files such as compose.rb / math.rb / datetime.rb, many of
5
+ # them autoloaded) but because it is reached often enough that the
6
+ # lazy-autoload indirection is not worth it. These methods are NOT
7
+ # load-bearing -- the core works without them; that distinguishes this file
8
+ # from carray/runtime.rb (which holds the support the core depends on).
9
+ #
10
+ # Keep this file small and obvious. If a method is domain-specific or only
11
+ # occasionally used, it belongs in its topic file (autoloaded when possible),
12
+ # not here.
13
+
14
+ class CArray
15
+
16
+ # reshape / flatten / transpose! are defined in C
17
+ # (ext/ca_obj_refer.c and ext/ca_obj_transpose.c). The bare size-1
18
+ # insertion primitive is `__insert_axis_size1__` (C); `insert_axis` below
19
+ # is the user-facing method that owns the name and adds `repeat:`.
20
+
21
+ # @overload insert_axis(*positions, repeat: nil)
22
+ # Returns a view of `self` with one or more new axes inserted,
23
+ # optionally repeating along them.
24
+ #
25
+ # Each entry of `positions` names the source axis the new axis
26
+ # goes *before*. `ndim` (one past the last axis) appends at the
27
+ # end; negative positions count from the end. Repeating the same
28
+ # position inserts several axes before that axis, in argument
29
+ # order. Positions are in the *source* frame, so they do not
30
+ # shift as other axes are inserted (e.g. `insert_axis(0, 1, 2)`
31
+ # puts one axis before each of the first three source axes).
32
+ #
33
+ # Each inserted axis takes one of three forms, chosen by its
34
+ # `repeat` value: `1` (or `nil`) for a plain size-1 axis, an
35
+ # Integer `N > 1` for a read-only bound repeat view, or `:*` for
36
+ # an unbound repeat that binds on assignment. `repeat` is either
37
+ # a single value applied to every inserted axis, or an Array
38
+ # giving one value per position.
39
+ #
40
+ # The everyday way to add an axis is the `:_` / `:*` indexer
41
+ # when the shape is known at the call site; `insert_axis` is for
42
+ # library code that builds the axis list programmatically.
43
+ #
44
+ # @param positions [Array<Integer>] source-frame positions of the
45
+ # new axes.
46
+ # @param repeat [Integer, Symbol, Array, nil] repeat spec applied
47
+ # to each inserted axis.
48
+ # @return [CArray] view with the new axes inserted.
49
+ # @example
50
+ # a = CArray.int32(3, 4).seq
51
+ # a.insert_axis(0) # shape (1, 3, 4)
52
+ # a.insert_axis(1, repeat: 5) # shape (3, 5, 4)
53
+ # a.insert_axis(0, 1, repeat: [:*, 3]) # mixed unbound + bound
54
+ def insert_axis (*positions, repeat: nil)
55
+ flat = positions.flatten
56
+ if flat.empty?
57
+ raise ArgumentError, "insert_axis: at least one position is required"
58
+ end
59
+
60
+ # No repeat: -> plain size-1 insertion. The source-frame C primitive
61
+ # handles normalization, range check and multiplicity directly.
62
+ return __insert_axis_size1__(*flat) if repeat.nil?
63
+
64
+ # Source frame: each position names the source axis the new axis goes
65
+ # before. Gaps live in [0, ndim] (ndim = append at end); negatives count
66
+ # from the end gap. Duplicates are allowed (several axes before one
67
+ # source axis), kept in argument order.
68
+ gaps = flat.map { |p| CArray.normalize_axis(p, ndim + 1, "insert_axis") }
69
+
70
+ # One repeat value per position, in argument order.
71
+ reps =
72
+ case repeat
73
+ when Array
74
+ unless repeat.length == flat.length
75
+ raise ArgumentError,
76
+ "insert_axis: repeat array length (#{repeat.length}) " \
77
+ "must match number of positions (#{flat.length})"
78
+ end
79
+ repeat
80
+ else
81
+ Array.new(flat.length, repeat)
82
+ end
83
+
84
+ # Validate each value. A positive Integer or :* only; nil is not a
85
+ # valid per-axis repeat.
86
+ reps.each do |r|
87
+ case r
88
+ when Integer
89
+ raise ArgumentError, "insert_axis: repeat count must be >= 1" if r < 1
90
+ when :*
91
+ # ok
92
+ else
93
+ raise ArgumentError,
94
+ "insert_axis: repeat must be a positive Integer or :*, got #{r.inspect}"
95
+ end
96
+ end
97
+
98
+ # Final output layout: stable order by (gap, argument index) keeps
99
+ # same-gap axes in argument order; the k-th inserted axis lands at output
100
+ # position gap + k. This output position is only used to drive the
101
+ # output-shaped view constructors (broadcast_to / unbound_repeat); the
102
+ # actual insertion always goes through the source-frame primitive below.
103
+ order = (0...flat.length).sort_by { |i| [gaps[i], i] }
104
+ final = {}
105
+ order.each_with_index { |i, k| final[i] = gaps[i] + k }
106
+
107
+ unbound_args = order.select { |i| reps[i] == :* }
108
+ concrete_args = order.reject { |i| reps[i] == :* } # in output order
109
+
110
+ # Stage 1: insert the concrete (size-1 / bound) axes by their source
111
+ # gaps, then grow the bound ones with broadcast_to.
112
+ inter = self
113
+ unless concrete_args.empty?
114
+ inter = __insert_axis_size1__(*concrete_args.map { |i| gaps[i] })
115
+ if concrete_args.any? { |i| reps[i].is_a?(Integer) && reps[i] > 1 }
116
+ shp = inter.shape
117
+ concrete_args.each do |i|
118
+ r = reps[i]
119
+ next unless r.is_a?(Integer) && r > 1
120
+ # intermediate position = final position minus unbound axes before it
121
+ shp[final[i] - unbound_args.count { |u| final[u] < final[i] }] = r
122
+ end
123
+ inter = inter.broadcast_to(*shp)
124
+ end
125
+ end
126
+
127
+ return inter if unbound_args.empty?
128
+
129
+ # Stage 2: add the unbound axes over the final ndim (`:*` at unbound
130
+ # positions, nil consumes one stage-1 axis in order).
131
+ pattern = Array.new(ndim + flat.length, nil)
132
+ unbound_args.each { |i| pattern[final[i]] = :* }
133
+ inter.unbound_repeat(*pattern)
134
+ end
135
+
136
+ # @overload drop_axis
137
+ # Returns a view of `self` with every size-1 axis dropped.
138
+ # @return [CArray] view with reduced `ndim`.
139
+ def drop_axis
140
+ if ndim == 1
141
+ return self[]
142
+ else
143
+ newdim = shape.reject{|x| x == 1 }
144
+ return ( ndim != newdim.size ) ? reshape(*newdim) : self[]
145
+ end
146
+ end
147
+
148
+ # @overload address
149
+ # Returns an int32 CArray of the same shape as `self` where each
150
+ # cell holds its row-major flat address.
151
+ # @return [CArray]
152
+ def address
153
+ return CArray.int32(*shape).seq!
154
+ end
155
+
156
+ # @overload false
157
+ # Returns a boolean CArray of the same shape as `self` filled
158
+ # with `false`.
159
+ # @return [CArray]
160
+ def false ()
161
+ return template(:boolean)
162
+ end
163
+
164
+ # @overload true
165
+ # Returns a boolean CArray of the same shape as `self` filled
166
+ # with `true`.
167
+ # @return [CArray]
168
+ def true ()
169
+ return template(:boolean) { 1 }
170
+ end
171
+
172
+ # Sub-region copy (paste / crop), the old C `ca_paste` / `ca_clip` pair.
173
+ # `clip` is reserved for value clamping (clamp to a min/max range), so
174
+ # the read-out side is `crop`. Kept together as a pair (crop is rare, but paste is reached
175
+ # often -- concatenate / mosaic / resize / bit_string all use it). Both
176
+ # accept negative offsets.
177
+
178
+ # @overload paste(offset, src)
179
+ # Sets `self` at `offset` by copying `src`. Out-of-bounds cells
180
+ # (`src` extending past `self`'s edge or before its origin) are
181
+ # silently dropped via CAWindow's interior-only PUT scatter.
182
+ # @param offset [Array<Integer>] starting indices, length equal
183
+ # to `self.ndim`.
184
+ # @param src [CArray] source array.
185
+ # @return [self]
186
+ # @raise [ArgumentError] when `offset.length != self.ndim`.
187
+ def paste (offset, src)
188
+ raise ArgumentError, "offset length must equal ndim" if offset.length != ndim
189
+ ranges = offset.each_with_index.map { |o, i| o...(o + src.shape[i]) }
190
+ self.window(*ranges)[] = src
191
+ self
192
+ end
193
+
194
+ # @overload crop(offset, dst)
195
+ # Reads a `dst.shape`-sized region from `self` starting at
196
+ # `offset` into `dst`. Cells whose read position falls outside
197
+ # `self` leave the corresponding `dst` cells untouched.
198
+ # @param offset [Array<Integer>] source starting indices, length
199
+ # equal to `self.ndim`.
200
+ # @param dst [CArray] destination array; mutated in place.
201
+ # @return [CArray] `dst`.
202
+ # @raise [ArgumentError] when `offset.length != self.ndim`.
203
+ def crop (offset, dst)
204
+ raise ArgumentError, "offset length must equal ndim" if offset.length != ndim
205
+ src_ranges = []
206
+ dst_ranges = []
207
+ ndim.times do |i|
208
+ s_lo = [offset[i], 0].max
209
+ s_hi = [offset[i] + dst.shape[i], shape[i]].min
210
+ return dst if s_lo >= s_hi
211
+ src_ranges << (s_lo...s_hi)
212
+ dst_ranges << ((s_lo - offset[i])...(s_hi - offset[i]))
213
+ end
214
+ dst[*dst_ranges] = self[*src_ranges]
215
+ dst
216
+ end
217
+
218
+ # @overload lookup(table, fill_value = nil, lfill: nil, ufill: nil)
219
+ # Returns values gathered from `table` at the indices given by
220
+ # `self`. Equivalent to `table.project(self, lfill, ufill)` with
221
+ # the receiver / first argument swapped so the index reads as
222
+ # the subject. `fill_value` is sugar for symmetric dual-fill;
223
+ # `lfill` / `ufill` override per side (`UNDEF` or `nil` masks
224
+ # that end), following the `project` vocabulary.
225
+ # @param table [CArray] value table indexed by `self`.
226
+ # @param fill_value [Object, nil] symmetric fill for below- and
227
+ # above-range indices.
228
+ # @param lfill [Object, nil] override for below-range fill.
229
+ # @param ufill [Object, nil] override for above-range fill.
230
+ # @return [CArray] gathered values with the shape of `self`.
231
+ def lookup(table, fill_value=nil, lfill: nil, ufill: nil)
232
+ lfill = fill_value if lfill.nil?
233
+ ufill = fill_value if ufill.nil?
234
+ table.project(self, lfill, ufill)
235
+ end
236
+
237
+ # @overload <=>(other)
238
+ # Returns an element-wise 3-way comparison: `+1` where
239
+ # `self > other`, `-1` where `self < other`, `0` where equal.
240
+ # Output `data_type` is `CA_INT8`.
241
+ # @param other [CArray, Numeric] operand to compare against.
242
+ # @return [CArray]
243
+ def <=> (other)
244
+ (self > other).as_int8 - (self < other).as_int8
245
+ end
246
+
247
+ alias cmp <=>
248
+
249
+ # @overload clip(min, max = nil, fill_value = nil, lfill: nil, ufill: nil)
250
+ # Returns `self` with every element clamped to `[min, max]`.
251
+ #
252
+ # Either bound may be `nil` for a one-sided clip; that side
253
+ # dispatches to the `pmax` / `pmin` binop kernels. When
254
+ # `fill_value` (or `lfill` / `ufill`) is given, out-of-range
255
+ # cells are replaced by the fill instead of clamped -- pass
256
+ # `UNDEF` to mask that end. `fill_value` is sugar for symmetric
257
+ # dual-fill; `lfill` / `ufill` override per side.
258
+ #
259
+ # Boundary is strict `[min, max]`: values equal to a bound
260
+ # remain unchanged in both the clamped and filled variants.
261
+ #
262
+ # @param min [Numeric, nil] lower bound; `nil` for one-sided
263
+ # clip above.
264
+ # @param max [Numeric, nil] upper bound; `nil` for one-sided
265
+ # clip below.
266
+ # @param fill_value [Object, nil] symmetric fill for
267
+ # out-of-range cells.
268
+ # @param lfill [Object, nil] override below-range fill.
269
+ # @param ufill [Object, nil] override above-range fill.
270
+ # @return [CArray] new CArray with clamped or filled values.
271
+ # @raise [ArgumentError] when both `min` and `max` are `nil`.
272
+ # @example
273
+ # a.clip(0, 10) # strict clamp
274
+ # a.clip(0, 10, -1) # both ends -> -1
275
+ # a.clip(0, 10, lfill: UNDEF, ufill: 99) # below masks
276
+ def clip(min, max=nil, fill_value=nil, lfill: nil, ufill: nil)
277
+ if min.nil? && max.nil?
278
+ raise ArgumentError, "clip: at least one of (min, max) must be given"
279
+ end
280
+
281
+ # `fill_value` as a single argument is sugar applied to both ends; kwargs override.
282
+ lfill = fill_value if lfill.nil?
283
+ ufill = fill_value if ufill.nil?
284
+
285
+ if lfill.nil? && ufill.nil?
286
+ return __clip_ki__(min, max) if !min.nil? && !max.nil?
287
+ return pmax(min) if max.nil?
288
+ return pmin(max)
289
+ end
290
+
291
+ out = self.copy
292
+ out[:lt, min] = lfill unless min.nil? || lfill.nil?
293
+ out[:gt, max] = ufill unless max.nil? || ufill.nil?
294
+ out
295
+ end
296
+
297
+ # `contains` was retired in favour of {#is_in} (value-hash membership).
298
+ # `a.contains(v1, v2)` -> `a.is_in([v1, v2])`;
299
+ # `a.contains(v1, v2, axis: k)` -> `a.is_in([v1, v2]).any(axis: k)`.
300
+ # See carray/methods/is_in.rb. Note is_in collapses NaN (a NaN cell is in a
301
+ # set containing NaN), whereas contains (self.eq) never matched NaN.
302
+
303
+ # `windows` (the sliding-window iterator entry) lives in
304
+ # carray/window_iterator.rb, autoloaded on first use.
305
+
306
+ # ---------------------------------------------------------------------------
307
+ # Sequence fill over a range (span / span!) and a linear interval
308
+ # (scale / scale!).
309
+ # ---------------------------------------------------------------------------
310
+
311
+ # @overload span!(range)
312
+ # Sets `self` to a linear sequence over `range`, with the step
313
+ # chosen so that `range.end` (or `range.end` when the range is
314
+ # exclusive-end, treated as the limit not reached) determines the
315
+ # endpoint. Concretely:
316
+ #
317
+ # - inclusive range `a..b`: `self[0] == a`, `self[-1] == b`,
318
+ # intermediate values are evenly spaced.
319
+ # - exclusive range `a...b`: `self[0] == a`, `self[-1] == a + (N-1)
320
+ # * (b-a)/N` (endpoint `b` is not reached).
321
+ #
322
+ # Only **float** arrays are supported. Integer arrays raise —
323
+ # "N evenly-spaced integers" is not a well-defined concept; the
324
+ # error message shows the two idioms that cover the two distinct
325
+ # integer use cases:
326
+ #
327
+ # - (A) N points with both endpoints hitting `a` and `b` exactly
328
+ # (linspace-like): use the manual integer form
329
+ # `CArray.int32(N).seq * (b - a) / (N - 1) + a`, or sample as
330
+ # float then cast: `CArray.float64(N).span(a.to_f..b.to_f).int32`.
331
+ # - (B) N labels distributed uniformly over the value range so
332
+ # each of the `(b - a + 1)` values appears approximately the
333
+ # same number of times (bucket distribution): use
334
+ # `CArray.int32(N).seq * (b - a + 1) / N + a`.
335
+ #
336
+ # @param range [Range<Numeric>] value range to span.
337
+ # @return [self]
338
+ # @raise [ArgumentError] when `self` is not a float array.
339
+ def span! (range)
340
+ unless float?
341
+ raise ArgumentError,
342
+ "span!: integer arrays are ambiguous — 'N evenly-spaced " \
343
+ "integers' has two distinct meanings. Pick the one you want:\n" \
344
+ " (A) N points hitting both endpoints exactly (linspace-like):\n" \
345
+ " CArray.int32(N).seq * (b - a) / (N - 1) + a\n" \
346
+ " or CArray.float64(N).span(a.to_f..b.to_f).int32\n" \
347
+ " (B) N labels distributed uniformly over range values:\n" \
348
+ " CArray.int32(N).seq * (b - a + 1) / N + a"
349
+ end
350
+ first = range.begin.to_r
351
+ last = range.end.to_r
352
+ step = range.exclude_end? ? (last-first)/elements : (last-first)/(elements-1)
353
+ seq!(first, step)
354
+ return self
355
+ end
356
+
357
+ # @overload span(range)
358
+ # Returns a fresh CArray shaped like `self` filled with the
359
+ # linear sequence produced by {#span!}. Float arrays only.
360
+ # @param range [Range<Numeric>] value range to span.
361
+ # @return [CArray]
362
+ # @raise [ArgumentError] when `self` is not a float array.
363
+ def span (range)
364
+ return template.span!(range)
365
+ end
366
+
367
+ # @overload scale!(xa, xb)
368
+ # Sets `self` to `elements` evenly spaced float64 values from
369
+ # `xa` to `xb` inclusive.
370
+ # @param xa [Numeric] first value.
371
+ # @param xb [Numeric] last value.
372
+ # @return [self]
373
+ def scale! (xa, xb)
374
+ xa = xa.to_f
375
+ xb = xb.to_f
376
+ seq!(xa, (xb-xa)/(elements-1))
377
+ end
378
+
379
+ # @overload scale(xa, xb)
380
+ # Returns a fresh CArray shaped like `self` holding `elements`
381
+ # evenly spaced values from `xa` to `xb` inclusive.
382
+ # @param xa [Numeric] first value.
383
+ # @param xb [Numeric] last value.
384
+ # @return [CArray]
385
+ def scale (xa, xb)
386
+ template.scale!(xa, xb)
387
+ end
388
+
389
+ end
390
+
391
+ # ---------------------------------------------------------------------------
392
+ # Container -> CArray coercion (relocated from former basic.rb)
393
+ # ---------------------------------------------------------------------------
394
+
395
+ class Array
396
+
397
+ # @overload to_ca(writable: false)
398
+ # Returns `self` coerced into a `CA_OBJECT` CArray of matching
399
+ # shape.
400
+ #
401
+ # The result is a freshly built array that shares nothing with the
402
+ # receiver, so `writable: true` — a demand for a result whose writes
403
+ # reach the source — is refused.
404
+ # @return [CArray]
405
+ # @raise [RuntimeError] when `writable: true` is given.
406
+ def to_ca(writable: false)
407
+ if writable
408
+ raise "#{self.class}#to_ca builds a new array; " \
409
+ "it can't satisfy `writable: true'"
410
+ end
411
+ return CA_OBJECT(self)
412
+ end
413
+ end
414
+
415
+ # Reopened to add {#to_ca}, so a Range can be handed to any CArray entry
416
+ # point that coerces its operand (`CArray.cast`, `wrap_readonly`, `meshgrid`).
417
+ class Range
418
+
419
+ # @overload to_ca(writable: false)
420
+ # Returns the members of `self` as a 1-D `CA_OBJECT` CArray.
421
+ #
422
+ # Enumeration follows Ruby, so a Float range raises (`TypeError`,
423
+ # not iterable) and an endless range raises (`RangeError`); use
424
+ # {CArray.linspace} or `span!` for a float axis. A descending
425
+ # integer range is the one departure: it counts down
426
+ # (`(3..0).to_ca` gives `[3, 2, 1, 0]`, not the empty array
427
+ # `(3..0).to_a` gives), so that it agrees with the cast form
428
+ # `CA_INT32(3..0)`.
429
+ #
430
+ # As with {Array#to_ca} the result is newly built, so `writable: true`
431
+ # is refused.
432
+ #
433
+ # @return [CArray]
434
+ # @raise [RuntimeError] when `writable: true` is given.
435
+ def to_ca(writable: false)
436
+ if writable
437
+ raise "#{self.class}#to_ca builds a new array; " \
438
+ "it can't satisfy `writable: true'"
439
+ end
440
+ first, last = self.begin, self.end
441
+ if first.is_a?(Integer) and last.is_a?(Integer) and first > last
442
+ return CA_OBJECT(self, 1) # step 1: signed arange
443
+ end
444
+ return CA_OBJECT(self)
445
+ end
446
+ end
447
+
448
+ # Reopened to add {#to_ca}, so a stepped sequence can be handed to any CArray
449
+ # entry point that coerces its operand.
450
+ class Enumerator::ArithmeticSequence
451
+
452
+ # @overload to_ca(writable: false)
453
+ # Returns the members of `self` as a 1-D `CA_OBJECT` CArray, so that
454
+ # a strided axis can be written `(0..10).step(2)` or `(0.0..1.0).step(0.25)`.
455
+ #
456
+ # An endless sequence is rejected up front: unlike an endless Range,
457
+ # which `RangeError`s, enumerating one runs forever. As with
458
+ # {Range#to_ca}, descending integer bounds count down rather than
459
+ # coming back empty.
460
+ #
461
+ # As with {Array#to_ca} the result is newly built, so `writable: true`
462
+ # is refused.
463
+ #
464
+ # @return [CArray]
465
+ # @raise [RangeError] when the sequence has no end.
466
+ # @raise [RuntimeError] when `writable: true` is given.
467
+ def to_ca(writable: false)
468
+ if writable
469
+ raise "#{self.class}#to_ca builds a new array; " \
470
+ "it can't satisfy `writable: true'"
471
+ end
472
+ first, last, by = self.begin, self.end, self.step
473
+ if last.nil?
474
+ raise RangeError, "cannot convert endless arithmetic sequence to an array"
475
+ end
476
+ if first.is_a?(Integer) and last.is_a?(Integer) and by > 0 and first > last
477
+ return CA_OBJECT(Range.new(first, last, exclude_end?), by)
478
+ end
479
+ return CA_OBJECT(to_a)
480
+ end
481
+ end