carray 3.0.2 → 3.0.4

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. data/lib/carray/table.rb +0 -108
@@ -7,13 +7,14 @@ class CArray
7
7
  # @!group MemoryView interop
8
8
 
9
9
  # @overload memory_view_available?(obj)
10
- # Returns `true` if `obj` exposes the Ruby `rb_memory_view`
11
- # protocol and a view can be acquired from it. Lightweight probe
12
- # used to gate {.from_memory_view} / {.wrap_memory_view} calls.
10
+ # Returns `true` if `obj` is a MemoryView producer (Ruby's
11
+ # `rb_memory_view_available_p`). Lightweight probe used to gate
12
+ # {.from_memory_view} / {.wrap_memory_view} calls; it does not
13
+ # acquire a view.
13
14
  #
14
- # Returning `true` does not guarantee acquisition will succeed —
15
- # a producer may still refuse a particular flag combination at
16
- # acquisition time.
15
+ # Returning `true` does not guarantee the import succeeds — the
16
+ # producer may still refuse the view, or offer a format CArray
17
+ # does not read.
17
18
  # @param obj [Object] any object (typically a foreign array such
18
19
  # as `Numo::NArray`, `Arrow::Array`, a `bytearray`, or a
19
20
  # CArray).
@@ -26,6 +27,7 @@ class CArray
26
27
  # @overload memory_view_reject_reason(obj)
27
28
  # Returns a String explaining why CArray's MemoryView producer
28
29
  # refuses to export `obj`, or `nil` if no problem is detected.
30
+ # For an object that is not a CArray it returns `nil`.
29
31
  #
30
32
  # Diagnostic only; useful when {.memory_view_available?} returns
31
33
  # `false` on a CArray and the generic "memory view not available"
@@ -34,8 +36,8 @@ class CArray
34
36
  # (mask propagation, non-contiguous strided view, etc.) call this
35
37
  # to print a human-readable reason.
36
38
  # @param obj [Object]
37
- # @return [String, nil] reason text, or `nil` when acquisition
38
- # would succeed.
39
+ # @return [String, nil] reason text, or `nil` when the export
40
+ # would succeed or `obj` is not a CArray.
39
41
  def memory_view_reject_reason(obj); end
40
42
 
41
43
  # @overload from_memory_view(src, data_type: nil, mask: nil)
@@ -46,15 +48,20 @@ class CArray
46
48
  #
47
49
  # For typeless producers (format `nil`, e.g. byte blobs from
48
50
  # `IO#read`), `data_type:` is required and the byte buffer is
49
- # reinterpreted as that data type with `ndim = 1`. For typed
51
+ # reinterpreted as that data type with `ndim = 1`; a typeless
52
+ # producer whose own layout is strided is refused. For typed
50
53
  # producers `data_type:` is optional; when given it must match
51
54
  # the producer's format.
52
55
  #
53
56
  # `mask:` accepts a paired buffer-protocol source whose shape
54
- # matches `src` and whose item size is 1 (PEP 3118 `?` / `B` /
55
- # `b`). The mask bytes are copied into the canonical
57
+ # matches `src` and whose item size is 1 (`?` / `B` / `C` /
58
+ # `b` / `c`). The mask bytes are copied into the canonical
56
59
  # `CA_BOOLEAN` mask slot with non-zero coerced to `1`. The copy
57
- # is independent of both buffers after the call.
60
+ # is independent of both buffers after the call. A boolean
61
+ # producer's bytes other than 0 and 1 are read as true.
62
+ #
63
+ # The result is a plain `CArray` whatever the receiver; a
64
+ # receiver other than `CArray` or a `CAWrap` raises `TypeError`.
58
65
  # @param src [Object] any MemoryView producer.
59
66
  # @param data_type [Symbol, Integer, Class, nil] target data
60
67
  # type. Required for typeless producers; optional (must match
@@ -63,7 +70,11 @@ class CArray
63
70
  # source. Must match `src.shape` and use a 1-byte/element
64
71
  # format.
65
72
  # @return [CArray] independent copy; not a `CAWrap`.
73
+ # @raise [TypeError] if the receiver is neither `CArray` nor a
74
+ # `CAWrap`.
66
75
  # @raise [ArgumentError] if `src` is not a MemoryView producer,
76
+ # if its shape is negative, too large, or does not fit in the
77
+ # bytes it reports,
67
78
  # if `data_type:` is missing for a typeless source, if
68
79
  # `data_type:` conflicts with the producer's format, or if
69
80
  # the supplied `mask:` fails shape / data type / contiguity
@@ -92,19 +103,23 @@ class CArray
92
103
  # when the wrap is garbage-collected.
93
104
  #
94
105
  # Contiguous typed producers return a `CAWrap`. Strided typed
95
- # producers return a `CAStride` layered on an inner `CAWrap` of
96
- # the producer's first byte, preserving the full stride pattern
106
+ # producers return a `CAStride` over a byte `CAWrap` of the
107
+ # bytes its elements reach, preserving the full stride pattern
97
108
  # (including negative strides where the producer offers them).
98
109
  # Typeless producers (format `nil`) require `data_type:` and are
99
- # reinterpreted with `ndim = 1`.
110
+ # reinterpreted with `ndim = 1`; a strided typeless producer is
111
+ # refused. A boolean producer must hold 0 or 1 in every byte.
100
112
  #
101
113
  # `mask:` accepts a paired buffer-protocol source whose shape
102
- # matches `src` and whose item size is 1 (PEP 3118 `?` / `B` /
103
- # `b`). The mask buffer is borrowed; writes to either side
104
- # propagate, and the mask MemoryView is released when the wrap
105
- # is collected. In this release, `mask:` requires a row-major
106
- # contiguous data source and a row-major contiguous mask
107
- # buffer.
114
+ # matches `src` and whose item size is 1 (`?` / `B` / `C` /
115
+ # `b` / `c`), holding 0 or 1 in every byte. The mask buffer is
116
+ # borrowed; writes to either side propagate, and the mask
117
+ # MemoryView is released when the wrap is collected. In this
118
+ # release, `mask:` requires a row-major contiguous data source
119
+ # and a row-major contiguous mask buffer that shares no bytes
120
+ # with the data. A read-only mask makes the whole array
121
+ # read-only, since a store writes the mask cell of each element
122
+ # it stores.
108
123
  #
109
124
  # The receiver picks the class of the result. Called on `CArray`
110
125
  # it builds a `CAWrap`; called on a subclass of `CAWrap` it
@@ -132,10 +147,12 @@ class CArray
132
147
  # @raise [TypeError] if the receiver is neither `CArray` nor a
133
148
  # subclass of `CAWrap`.
134
149
  # @raise [ArgumentError] if `src` is not a MemoryView producer,
135
- # if `data_type:` is missing for a typeless source, if
150
+ # if its shape is negative, too large, or does not fit in the
151
+ # bytes it reports, if a boolean buffer holds a byte other than
152
+ # 0 and 1, if `data_type:` is missing for a typeless source, if
136
153
  # `data_type:` conflicts with the producer's format, or if
137
154
  # the supplied `mask:` fails validation (shape / ndim /
138
- # data type / item_size / contiguity). Also raises when `mask:`
155
+ # data type / item_size / contiguity / overlap with the data). Also raises when `mask:`
139
156
  # is combined with a strided data source — that combination
140
157
  # is not supported in this release.
141
158
  # @example Zero-copy write propagation
@@ -12,16 +12,15 @@ class CArray
12
12
  #
13
13
  # Out-of-range positions are filled with `lval` (below-range) and
14
14
  # `uval` (above-range); when `lval` is given alone, it fills
15
- # both. Without either, out-of-range positions are masked.
15
+ # both. Without either, out-of-range positions are masked, and so
16
+ # they are with a fill of `UNDEF`.
16
17
  #
17
18
  # When `self` is a Face (CATime / CATimedelta / CACategorical),
18
- # the result is the same Face type, carrying the unit / labels; the
19
- # gather runs on the underlying storage and misses become UNDEF. Fill
20
- # (`lval` / `uval`) is not supported for a Face and raises ArgumentError
21
- # — omit the fill args to get UNDEF at misses.
19
+ # the result is the same Face type, carrying the unit / labels, and a
20
+ # fill is one of its values (a time for a CATime).
22
21
  # @param idx [CArray] flat addresses, of any shape.
23
- # @param lval [Object, nil] fill for indices `< 0` (non-Face only).
24
- # @param uval [Object, nil] fill for indices `>= self.elements` (non-Face only).
22
+ # @param lval [Object, nil] fill for indices `< 0`.
23
+ # @param uval [Object, nil] fill for indices `>= self.elements`.
25
24
  # @return [CArray] a fresh array shaped like `idx`; a Face of the same
26
25
  # type when `self` is a Face.
27
26
  # @raise [ArgumentError] if `lval` / `uval` is given and `self` is a Face.
@@ -30,13 +29,16 @@ class CArray
30
29
  # sort / sort_copy stubs live in yard-stubs/carray_sort.rb (same
31
30
  # file split as ext/carray_sort.c <-> ext/carray_order.c).
32
31
 
33
- # @overload partition(kth, axis: 0, masked_position: :last)
32
+ # @overload partition(kth, axis: nil, masked_position: :last)
34
33
  # Returns a `CARemap` view of `self` permuted along `axis` so that
35
34
  # the element at fiber-local position `kth` is in its final sorted
36
35
  # place, every element before it is `<=` it, and every element
37
36
  # after it is `>=` it. Order within the two regions is unspecified.
38
37
  # Average `O(n)` per fiber via quickselect.
39
38
  #
39
+ # Without `axis:` (or with `axis: nil`) `self` is flattened and
40
+ # treated as one fiber, as {#sort} does; the result is 1-D.
41
+ #
40
42
  # Negative `kth` counts from the end of the fiber
41
43
  # (`-self.shape[axis] <= kth < self.shape[axis]`).
42
44
  #
@@ -52,32 +54,39 @@ class CArray
52
54
  # among unmasked values.
53
55
  #
54
56
  # @param kth [Integer] target fiber-local position along `axis`.
55
- # @param axis [Integer]
57
+ # @param axis [Integer, nil] `nil` partitions the whole array.
56
58
  # @param masked_position [Symbol] `:last` (default) or `:first`.
57
59
  # @return [CArray] `CARemap` view of `self`.
58
60
  # @raise [ArgumentError] when `kth` is out of range.
59
- def partition(kth, axis: 0, masked_position: :last); end
61
+ def partition(kth, axis: nil, masked_position: :last); end
60
62
 
61
- # @overload partition_copy(kth, axis: 0, masked_position: :last)
62
- # Returns a fresh entity `CArray` with the same shape as `self`,
63
- # partitioned along `axis` by the same rule as {#partition}.
63
+ # @overload partition_copy(kth, axis: nil, masked_position: :last)
64
+ # Returns a fresh entity `CArray` partitioned along `axis` by the
65
+ # same rule as {#partition}: the shape of `self`, or 1-D when `axis`
66
+ # is omitted.
64
67
  # Bypasses the `CARemap` scatter layer for cases where an entity
65
68
  # is wanted directly. Same dispatch (numeric / boolean / `CA_FIXLEN` /
66
69
  # `CA_OBJECT`), same `kth` and `masked_position:` semantics.
67
70
  # Masked input delegates to {#partition} + copy.
68
71
  #
72
+ # A Face partitions in its surface order and comes back as the same
73
+ # Face: one whose storage order is its surface order is selected on its
74
+ # storage, a fixlen storage by byte order. A Face whose storage order is
75
+ # not its surface order (e.g. {CACategorical}) raises.
76
+ #
69
77
  # Float NaN policy: NaN cells are pre-partitioned to the tail. If
70
78
  # `kth` falls within the finite slice, quickselect runs over the
71
79
  # finite cells; otherwise the kth cell is already NaN.
72
80
  #
73
81
  # @param kth [Integer]
74
- # @param axis [Integer]
82
+ # @param axis [Integer, nil] `nil` partitions the whole array.
75
83
  # @param masked_position [Symbol] `:last` (default) or `:first`.
76
84
  # @return [CArray] fresh entity.
77
- # @raise [ArgumentError] same conditions as {#partition}.
78
- def partition_copy(kth, axis: 0, masked_position: :last); end
85
+ # @raise [ArgumentError] same conditions as {#partition}, or a Face that
86
+ # is not orderable by its storage.
87
+ def partition_copy(kth, axis: nil, masked_position: :last); end
79
88
 
80
- # @overload order(axis: nil, descending: false, method: :ordinal)
89
+ # @overload order(axis: nil, descending: false, method: :ordinal, kind: :quick)
81
90
  # Returns each cell's rank among the other cells along `axis`
82
91
  # (`0` = smallest). When `axis` is omitted, `self` is flattened
83
92
  # first (global rank). Sugar over `rank_index` (built on the
@@ -87,17 +96,19 @@ class CArray
87
96
  # `method:` selects how ties are ranked:
88
97
  #
89
98
  # - `:ordinal` (default) — every cell gets a distinct rank; ties
90
- # are broken by original position (stable). This is a total
91
- # order: no two cells ever compare equal.
92
- # - `:dense` — tied values share one rank (no gaps). Useful as a
93
- # `sort_addr` priority key: an `:ordinal` key never ties, so a
94
- # lower-priority key after it is never consulted; a `:dense` key
99
+ # are broken by original position (stable), the earlier cell first
100
+ # in both directions. This is a total order: no two cells ever
101
+ # compare equal.
102
+ # - `:dense` — tied values share one rank (no gaps). Every NaN is
103
+ # one value and shares one rank, placed after the numbers. Useful
104
+ # as a `sort_addr` priority key: an `:ordinal` key never ties, so
105
+ # a lower-priority key after it is never consulted; a `:dense` key
95
106
  # preserves the tie so it is.
96
107
  #
97
- # `descending:` negates the rank order (`(n-1) - rank`, `n` =
98
- # fiber element count minus masked cells). This composes correctly
99
- # with `method: :dense`: ties stay tied after the transform, and
100
- # group-to-group order still reverses.
108
+ # `descending:` ranks the largest value `0`; NaN comes after the
109
+ # numbers in both directions. Tied cells keep their
110
+ # original order under `:ordinal` and share a rank under `:dense`, so
111
+ # dense ranks stay without gaps.
101
112
  #
102
113
  # Masked cells are excluded from ranking (own cell becomes UNDEF,
103
114
  # like `rank_index`); `descending:`/`method:` apply to the
@@ -105,9 +116,11 @@ class CArray
105
116
  # @param axis [Integer, nil]
106
117
  # @param descending [Boolean]
107
118
  # @param method [Symbol] `:ordinal` (default) or `:dense`.
119
+ # @param kind [Symbol] `:quick` (default) or `:stable`, as for
120
+ # {#sort_index}; a performance choice only.
108
121
  # @return [CArray] `:int64` ranks, shape == `self.shape`.
109
122
  # @raise [ArgumentError] when `method:` is neither `:ordinal` nor `:dense`.
110
- def order(axis: nil, descending: false, method: :ordinal); end
123
+ def order(axis: nil, descending: false, method: :ordinal, kind: :quick); end
111
124
 
112
125
  # @!endgroup
113
126
 
@@ -121,7 +134,7 @@ class CArray
121
134
  # with `UNDEF` at positions where the value is not present.
122
135
  # @param val [Numeric, CArray]
123
136
  # @return [Integer, CArray, nil]
124
- # @raise [RuntimeError] if `self` has any masked element.
137
+ # @raise [ArgumentError] if `self` has any masked element.
125
138
  # @overload bsearch(val, axis:)
126
139
  # Per-fiber binary search along `axis`. Returns a CArray of
127
140
  # axis-local positions, one per fiber.
@@ -148,6 +161,24 @@ class CArray
148
161
  # to `val`. For float types, `eps` (default machine epsilon)
149
162
  # sets the tolerance. Returns `nil` if no match.
150
163
  #
164
+ # `val` is compared in the type both share, as `self.eq(val)`
165
+ # compares: an integer array searched with a Float is compared in
166
+ # float64 (so `3.9` does not match `3`, and `eps` applies), a pair of
167
+ # mixed sign is compared by value (`-1` does not find `255`), and an
168
+ # Integer an integer array cannot hold matches nothing.
169
+ # The same holds for {#bsearch} and {#search_nearest}. On an
170
+ # `:object` array a cell matches when it is `==` to `val`, as {#eq}
171
+ # compares (so `1` matches `1.0`, which {#is_in} does not).
172
+ #
173
+ # An `UNDEF` `val`, or a masked cell of a CArray `val`, finds
174
+ # nothing: `nil`, or `UNDEF` in that cell of the result. The same
175
+ # holds for {#bsearch} and {#search_nearest}.
176
+ #
177
+ # A time array (`CATime`, `CATimedelta`) takes a value of another
178
+ # unit, a `Time` or a String: when it is off the array's grid the
179
+ # two are compared in the finer unit, so it matches nothing (and
180
+ # {#search_nearest} finds the nearest cell).
181
+ #
151
182
  # `self` need not be sorted; this is a linear scan. For sorted
152
183
  # data prefer {#bsearch}.
153
184
  # @param val [Object]
@@ -206,7 +237,8 @@ class CArray
206
237
  # bracketing samples. The integer part of the returned address is
207
238
  # the index of the lower bracket, the fractional part is the
208
239
  # interpolation weight toward the next sample. Out-of-range `val`
209
- # returns NaN.
240
+ # returns NaN. A one-point axis has no segment: `val` equal to the
241
+ # point is at 0, any other value is out of range.
210
242
  #
211
243
  # `self` is coerced to `:float64` if it is not already. When
212
244
  # `axis: nil`, `self` is flattened to 1-D first.
@@ -24,7 +24,10 @@ class CArray
24
24
  # Fills `self` with uniform random numbers in-place and returns
25
25
  # `self`. Boolean arrays fill 0/1 at 50% probability, ignoring
26
26
  # any range argument. Complex arrays sample real and imaginary
27
- # parts independently from the same range.
27
+ # parts independently from the same range. An integer array takes
28
+ # Integer bounds whose every value fits its type (the whole range
29
+ # of the type included); a float array takes finite bounds. Every
30
+ # cell gets a value, so the mask is cleared, as by `seq!` or `fill`.
28
31
  #
29
32
  # @param low [Numeric] lower bound (inclusive).
30
33
  # @param high [Numeric] upper bound (exclusive).
@@ -35,7 +38,11 @@ class CArray
35
38
  # @raise [CArray::DataTypeError] for `:object` / `:fixlen` arrays.
36
39
  # @raise [ArgumentError] when an integer array is called with no
37
40
  # range, when `low >= high`, when a Range is combined with a
38
- # second positional argument, or when a Range endpoint is nil.
41
+ # second positional argument, when a Range endpoint is nil, or
42
+ # when a float bound is NaN or infinite.
43
+ # @raise [TypeError] when an integer array is given a non-Integer
44
+ # bound.
45
+ # @raise [RangeError] when the integer range does not fit the type.
39
46
  def random!(*args, rng: nil); end
40
47
 
41
48
  # @overload random(rng: nil)
@@ -51,7 +58,7 @@ class CArray
51
58
  # Fills `self` with standard normal `N(0, 1)` samples via
52
59
  # Box-Muller and returns `self`. Restricted to float / complex
53
60
  # data types; complex fills real and imaginary parts as two
54
- # independent normals per cell.
61
+ # independent normals per cell. The mask is cleared.
55
62
  # @param rng [Random, nil] RNG instance; nil uses the per-ractor
56
63
  # default RNG.
57
64
  # @return [self]
@@ -72,7 +79,9 @@ class CArray
72
79
  # Fisher-Yates permutes `self` in-place and returns `self`.
73
80
  # Without `axis:`, shuffles all cells as if flattened. With
74
81
  # `axis:`, permutes slices along that axis (the trailing
75
- # sub-slab is treated as a byte chunk and swapped whole).
82
+ # sub-slab is treated as a byte chunk and swapped whole). The mask
83
+ # moves with the values: a masked cell stays masked wherever it
84
+ # lands.
76
85
  # @param axis [Integer, nil] axis to permute along; nil = flat.
77
86
  # @param rng [Random, nil] RNG instance; nil uses the per-ractor
78
87
  # default RNG.
@@ -16,13 +16,20 @@ class CArray
16
16
  # Shared contract:
17
17
  #
18
18
  # - `addrs` is a CArray of any integer type (coerced to
19
- # `CA_SIZE`) or a Ruby Array.
19
+ # `CA_SIZE`) or a Ruby Array. A float or complex CArray is
20
+ # refused with `IndexError`, as `self[addrs]` refuses it.
20
21
  # - `vals` is a CArray of length matching `addrs` (coerced to
21
- # `self.data_type`), or a Numeric scalar broadcast to all
22
- # addresses.
23
- # - Out-of-range `addrs[i]` (`< 0` or `>= self.elements`) raises
24
- # `IndexError`.
25
- # - `self.data_type` must be numeric.
22
+ # `self.data_type`), or a scalar broadcast to all addresses: any
23
+ # Numeric, `true` / `false`, or `UNDEF`. The scalar is converted as
24
+ # `self[i] = v` converts it, so a value that does not fit the type
25
+ # raises (`RangeError`, `FloatDomainError` for NaN into an integer
26
+ # type). A scalar `UNDEF` is a masked value.
27
+ # - A negative `addrs[i]` counts from the end. One out of range
28
+ # raises `IndexError`; the pairs before it stay applied, through a
29
+ # view as well.
30
+ # - `self.data_type` must be numeric. Complex is accepted by
31
+ # every variant except {#scatter_min!} and {#scatter_max!},
32
+ # since complex values have no order.
26
33
  #
27
34
  # Mask policy differs between the accumulate family and
28
35
  # {#scatter_replace!}: the accumulate variants skip the pair when
@@ -73,6 +80,8 @@ class CArray
73
80
  # @param addrs [CArray, Array<Integer>]
74
81
  # @param vals [CArray, Numeric]
75
82
  # @return [self]
83
+ # @raise [CArray::DataTypeError] for a non-numeric or complex
84
+ # `data_type`.
76
85
  def scatter_min!(addrs, vals); end
77
86
 
78
87
  # @overload scatter_max!(addrs, vals)
@@ -82,6 +91,8 @@ class CArray
82
91
  # @param addrs [CArray, Array<Integer>]
83
92
  # @param vals [CArray, Numeric]
84
93
  # @return [self]
94
+ # @raise [CArray::DataTypeError] for a non-numeric or complex
95
+ # `data_type`.
85
96
  def scatter_max!(addrs, vals); end
86
97
 
87
98
  # @overload scatter_replace!(addrs, vals)
@@ -94,11 +105,12 @@ class CArray
94
105
  # result is written back many times.
95
106
  #
96
107
  # Unlike the arithmetic `scatter_*!` family, `self` may be
97
- # **boolean** (assignment does not widen), and `true` / `false`
98
- # are accepted as scalar `vals` alongside numeric scalars.
108
+ # **boolean** (assignment does not widen); `true` / `false` (or
109
+ # `1` / `0`) are its scalar values. A scalar `UNDEF` masks every
110
+ # addressed cell.
99
111
  #
100
112
  # @param addrs [CArray, Array<Integer>]
101
- # @param vals [CArray, Numeric, true, false]
113
+ # @param vals [CArray, Numeric, true, false, UNDEF]
102
114
  # @return [self]
103
115
  def scatter_replace!(addrs, vals); end
104
116
 
@@ -0,0 +1,72 @@
1
+ # DOCUMENTATION ONLY — DO NOT REQUIRE.
2
+ # Stubs for methods defined in ext/carray_segment.c.
3
+ # See yard-stubs/README.md and yard-stubs/STYLE.md.
4
+
5
+ class CArray
6
+ # @!group Index and address conversion
7
+ #
8
+ # A flat sequence cut into consecutive segments has three
9
+ # representations, and these methods convert between them:
10
+ #
11
+ # lengths [2, 0, 3] one count per segment
12
+ # offsets [0, 2, 2, 5] every boundary, both ends included
13
+ # segment index [0, 0, 2, 2, 2] the segment each element is in
14
+ #
15
+ # Segment `c` spans `offsets[c]...offsets[c + 1]`, so there is no
16
+ # special case for the last segment and none for an empty one.
17
+ #
18
+ # Both methods compute in int64 and return int64, so a total beyond
19
+ # 2**53 stays exact. They accept a CArray of any integer or boolean
20
+ # data type (views included, read in flatten order) or an Array of
21
+ # Integers, and refuse masked cells: a masked length is not a count,
22
+ # and a masked offset is not a position.
23
+
24
+ # @overload segment_offsets(lengths:)
25
+ # Returns the boundaries of segments with the given lengths: `0`
26
+ # first, then the running total. `k` lengths give `k + 1` offsets,
27
+ # so no lengths give `[0]`.
28
+ #
29
+ # CArray.segment_offsets(lengths: [2, 0, 3]) # => [0, 2, 2, 5]
30
+ #
31
+ # @param lengths [CArray, Array<Integer>] one count per segment.
32
+ # @return [CArray] int64, one element more than `lengths`.
33
+ # @raise [ArgumentError] for a negative length, a masked length,
34
+ # or a non-Integer in an Array.
35
+ # @raise [CArray::DataTypeError] for a non-integer data type.
36
+ # @raise [RangeError] when the total overflows int64.
37
+ def self.segment_offsets(lengths:); end
38
+
39
+ # @overload segment_index(lengths:)
40
+ # Returns, for each element of the cut sequence, the segment it
41
+ # belongs to. A segment of length 0 contributes no elements, so
42
+ # its number does not appear.
43
+ #
44
+ # CArray.segment_index(lengths: [2, 0, 3]) # => [0, 0, 2, 2, 2]
45
+ #
46
+ # The same as `CArray.int64(k).seq.repeat(lengths)`, as an owned
47
+ # array rather than a view.
48
+ # @param lengths [CArray, Array<Integer>] one count per segment.
49
+ # @return [CArray] int64, `lengths.sum` elements.
50
+ #
51
+ # @overload segment_index(offsets:)
52
+ # The same from boundaries. The offsets need not start at 0: the
53
+ # offsets of a range cut out of a longer table start where that
54
+ # range starts, and the result then covers
55
+ # `offsets[0]...offsets[-1]` with the segments numbered from 0.
56
+ #
57
+ # CArray.segment_index(offsets: [0, 2, 2, 5]) # => [0, 0, 2, 2, 2]
58
+ # CArray.segment_index(offsets: [4, 6, 6, 9]) # => [0, 0, 2, 2, 2]
59
+ #
60
+ # @param offsets [CArray, Array<Integer>] `k + 1` non-decreasing
61
+ # boundaries.
62
+ # @return [CArray] int64, `offsets[-1] - offsets[0]` elements.
63
+ #
64
+ # @raise [ArgumentError] for a negative length, decreasing or empty
65
+ # offsets, a masked cell, a non-Integer in an Array, or unless
66
+ # exactly one of `lengths:` and `offsets:` is given.
67
+ # @raise [CArray::DataTypeError] for a non-integer data type.
68
+ # @raise [RangeError] when the total length overflows int64.
69
+ def self.segment_index(lengths: nil, offsets: nil); end
70
+
71
+ # @!endgroup
72
+ end
@@ -14,7 +14,8 @@ class CArray
14
14
  # duration of the block — capturing it across iterations sees the last
15
15
  # slab's data — and it is read-only: writing through it raises. To
16
16
  # produce values per slab use `map_slab` or `reduce_slab`; to write in
17
- # place, assign through the array itself.
17
+ # place, assign through the array itself. Over a Face (`CATime`, a
18
+ # record type) the slab is that Face.
18
19
  # @overload each_slab(axis:)
19
20
  # Returns an Enumerator when no block is given.
20
21
  # @param axis [Integer, Array<Integer>, nil] the slab axis or axes
@@ -28,7 +29,10 @@ class CArray
28
29
  # Returns a new CArray built by replacing each slab of `self` with the
29
30
  # block's result. The block receives the slab view and must return a
30
31
  # value of the same shape as the slab (a CArray or scalar); the results
31
- # are written into the output at the same positions.
32
+ # are written into the output at the same positions, and a masked
33
+ # cell of the block's result is masked in the output. Over a Face the
34
+ # slab is that Face, and the output is too unless `data_type:` is
35
+ # given; a read-only Face answers in `:object` cells.
32
36
  # @param axis [Integer, Array<Integer>, nil] the slab axis or axes.
33
37
  # @param data_type [Symbol, Integer, Class, nil] output data type
34
38
  # (defaults to `self`'s data type).
@@ -47,6 +51,10 @@ class CArray
47
51
  # Per-element form (`init:` given): the block receives `(acc, x)` for
48
52
  # each element of the slab and returns the new accumulator; the final
49
53
  # accumulator per slab fills the output.
54
+ #
55
+ # `UNDEF` from the block masks that output cell. Over a Face the slab
56
+ # (and each element) is that Face's, and the output is that Face unless
57
+ # `data_type:` is given; a read-only Face answers in `:object` cells.
50
58
  # @param axis [Integer, Array<Integer>, nil] the slab axis or axes.
51
59
  # @param init [Object] the initial accumulator (selects the
52
60
  # per-element form).
@@ -115,6 +115,43 @@ class CArray
115
115
  # `:stable`.
116
116
  def sort_addr(axis: nil, kind: :quick, masked_position: :last); end
117
117
 
118
+ # @overload sort_index(axis: nil, kind: :quick, masked_position: :last)
119
+ # Returns, for each fiber along `axis`, the positions within the
120
+ # fiber that put it in ascending order: `:int64`, shaped like
121
+ # `self`. For a 1-D array, `a[a.sort_index]` is `a` sorted.
122
+ #
123
+ # Without `axis:` (or with `axis: nil`) `self` is flattened and
124
+ # treated as one fiber, as {#sort} does: the result is 1-D with
125
+ # `self.elements` entries, and `a.flatten[a.sort_index]` is
126
+ # `a.sort`.
127
+ #
128
+ # The sort is **stable**: cells that compare equal keep their
129
+ # input order, whichever `kind:` is chosen, so sorting by one key
130
+ # and then stably by another orders by the second key first and
131
+ # the first within it. `kind:` is a performance characteristic
132
+ # only:
133
+ #
134
+ # - `:quick` (default) — introsort with mergesort escape.
135
+ # - `:stable` — bottom-up mergesort.
136
+ #
137
+ # NaN and masked cells cannot be compared with the rest and are
138
+ # placed at one end of each fiber: NaN after the numbers, masked
139
+ # cells at the end `masked_position:` names (`:last`, default, or
140
+ # `:first`). Relative order within the masked cells is unspecified.
141
+ #
142
+ # Takes numeric data types, boolean, `CA_FIXLEN` (byte order),
143
+ # `CA_OBJECT` (`<=>` per pair), and an ordered Face such as
144
+ # `CATime`. Complex values have no order.
145
+ # @param axis [Integer, nil] axis along which fibers run; negative
146
+ # counts from the end. `nil` sorts the whole array.
147
+ # @param kind [Symbol] `:quick` or `:stable`.
148
+ # @param masked_position [Symbol] `:last` (default) or `:first`.
149
+ # @return [CArray] `:int64` positions within each fiber.
150
+ # @raise [ArgumentError] when `kind:` is neither `:quick` nor
151
+ # `:stable`, or `axis` is out of range.
152
+ # @raise [CArray::DataTypeError] for a complex `data_type`.
153
+ def sort_index(axis: nil, kind: :quick, masked_position: :last); end
154
+
118
155
  # @!group Index and address conversion
119
156
 
120
157
  # @overload axis2addr(indices, axis: 0)
@@ -142,23 +179,27 @@ class CArray
142
179
  # is a one-liner on top of `flatten[axis2addr(...)]`.
143
180
  #
144
181
  # Shape rule: `indices.ndim == self.ndim`, and
145
- # `indices.dim[j] == self.dim[j]` for all `j != axis`;
146
- # `indices.dim[axis]` is free.
182
+ # `indices.shape[j] == self.shape[j]` for all `j != axis`;
183
+ # `indices.shape[axis]` is free.
147
184
  #
148
185
  # `indices` data_type: any integer kind (zero-copy when
149
186
  # already `:int64`). Negative indices: Python-style
150
- # (`-1` == last). Out-of-range indices raise `RangeError`.
151
- # Negative `axis:` is Python-style.
187
+ # (`-1` == last). Out-of-range indices raise `IndexError`.
188
+ # Negative `axis:` is Python-style. A masked index gives a
189
+ # masked address (its stored value is not read), so
190
+ # `take_along_axis` answers `UNDEF` there and `put_along_axis`
191
+ # writes nothing there.
152
192
  #
153
193
  # @param indices [CArray] integer-typed axis-local positions.
154
194
  # @param axis [Integer] axis along which `indices` are
155
195
  # interpreted.
156
196
  # @return [CArray] `:int64` view-flat addresses, same shape as
157
197
  # `indices`.
158
- # @raise [RangeError] when an index is out of range after
159
- # negative normalization.
160
- # @raise [ArgumentError] for shape / ndim / data_type
161
- # violations.
198
+ # @raise [IndexError] when an index is out of range after
199
+ # negative normalization, or `indices` is a float or complex
200
+ # array.
201
+ # @raise [ArgumentError] for shape / ndim violations, or a
202
+ # boolean / object `indices`.
162
203
  def axis2addr(indices, axis: 0); end
163
204
 
164
205
  # @!endgroup
@@ -6,8 +6,9 @@ class CArray
6
6
  # @!group Index and address conversion
7
7
 
8
8
  # @overload valid_index?(*idx)
9
- # Returns `true` if the given index tuple is in range for `self`.
10
- # The number of indices must equal `ndim`.
9
+ # Returns `true` if the given index tuple names a cell of `self`,
10
+ # that is, if `self[*idx]` would not raise. A negative index counts
11
+ # from the end of its axis. The number of indices must equal `ndim`.
11
12
  # @param idx [Array<Integer>] one index per axis.
12
13
  # @return [Boolean]
13
14
  # @raise [ArgumentError] if the number of indices does not match
@@ -15,7 +16,8 @@ class CArray
15
16
  def valid_index?(*idx); end
16
17
 
17
18
  # @overload valid_addr?(addr)
18
- # Returns `true` if `addr` is in range `0...elements` for `self`.
19
+ # Returns `true` if `addr` names a cell of `self`: `0...elements`, or
20
+ # a negative address counting from the end (`-elements..-1`).
19
21
  # @param addr [Integer] flat address into the contiguous element
20
22
  # sequence.
21
23
  # @return [Boolean]
@@ -36,6 +38,13 @@ class CArray
36
38
  # `data_class`, `data_type`, mask state, and elementwise values as
37
39
  # `self`. NaN values compare unequal (IEEE semantics), so two
38
40
  # arrays with NaN at the same position are not `==`.
41
+ #
42
+ # A Face (a time, string or categorical array) equals only a Face of
43
+ # its own class, and is compared by its values: two time arrays of
44
+ # different units holding the same instants are `==`, as are two
45
+ # categoricals with the same labels at each cell whatever the order
46
+ # of their vocabularies. A Face is never `==` to an array that is not
47
+ # one, even when the bytes match.
39
48
  # @param other [Object]
40
49
  # @return [Boolean]
41
50
  def ==(other); end
@@ -46,6 +55,9 @@ class CArray
46
55
  # are compared bitwise (for numeric types) or via `Object#eql?`
47
56
  # (for `:object` arrays). Unlike `==`, `NaN.eql?(NaN)` holds, so
48
57
  # two mask-free arrays with NaN at the same positions are `eql?`.
58
+ # Two Faces are `eql?` only when they are of the same class, share
59
+ # their state (a time array's unit, a categorical's labels) and hold
60
+ # the same storage.
49
61
  #
50
62
  # Guarantees `a.eql?(b)` ⇒ `a.hash == b.hash`.
51
63
  # @param other [Object]