carray 3.0.3 → 3.0.5

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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +469 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_descriptor.h +27 -24
  7. data/ext/ca_axis_dispatch.c +14 -26
  8. data/ext/ca_axis_group.c +27 -27
  9. data/ext/ca_binop_dispatch.c +1 -29
  10. data/ext/ca_binop_dispatch.h +0 -1
  11. data/ext/ca_categorical_iterator.c +231 -153
  12. data/ext/ca_compare.c +9 -20
  13. data/ext/ca_composite_dispatch.c +9 -9
  14. data/ext/ca_group_iter.c +16 -17
  15. data/ext/ca_kernel_iterator.c +1240 -2000
  16. data/ext/ca_kernel_iterator.h +502 -519
  17. data/ext/ca_monop_dispatch.c +82 -59
  18. data/ext/ca_monop_dispatch.h +1 -0
  19. data/ext/ca_obj_array.c +152 -45
  20. data/ext/ca_obj_bincmp.c +25 -21
  21. data/ext/ca_obj_binop.c +16 -26
  22. data/ext/ca_obj_bitarray.c +8 -3
  23. data/ext/ca_obj_bitfield.c +63 -49
  24. data/ext/ca_obj_block.c +18 -9
  25. data/ext/ca_obj_byte_swap.c +7 -7
  26. data/ext/ca_obj_const_string.c +188 -22
  27. data/ext/ca_obj_face.c +280 -58
  28. data/ext/ca_obj_face.h +19 -0
  29. data/ext/ca_obj_fake.c +15 -29
  30. data/ext/ca_obj_farray.c +6 -3
  31. data/ext/ca_obj_field.c +30 -8
  32. data/ext/ca_obj_fixlen_string.c +2 -3
  33. data/ext/ca_obj_grid.c +455 -134
  34. data/ext/ca_obj_meld.c +172 -34
  35. data/ext/ca_obj_moncmp.c +23 -8
  36. data/ext/ca_obj_monop.c +113 -67
  37. data/ext/ca_obj_object.c +210 -52
  38. data/ext/ca_obj_record.c +15 -7
  39. data/ext/ca_obj_reduce.c +17 -8
  40. data/ext/ca_obj_refer.c +42 -35
  41. data/ext/ca_obj_remap.c +30 -9
  42. data/ext/ca_obj_repeat.c +9 -10
  43. data/ext/ca_obj_roll.c +31 -10
  44. data/ext/ca_obj_select.c +48 -14
  45. data/ext/ca_obj_select_axis.c +15 -47
  46. data/ext/ca_obj_shift.c +41 -7
  47. data/ext/ca_obj_stack.c +180 -34
  48. data/ext/ca_obj_stride.c +190 -134
  49. data/ext/ca_obj_string.c +80 -4
  50. data/ext/ca_obj_tile.c +32 -11
  51. data/ext/ca_obj_time.c +22 -6
  52. data/ext/ca_obj_timedelta.c +22 -6
  53. data/ext/ca_obj_transpose.c +13 -7
  54. data/ext/ca_obj_triop.c +26 -32
  55. data/ext/ca_obj_window.c +267 -74
  56. data/ext/ca_op_ipower.c +4 -4
  57. data/ext/ca_sort_kernels.h +6 -3
  58. data/ext/ca_sweep_engine.c +2 -2
  59. data/ext/caframe_csv_reader.c +80 -1
  60. data/ext/carray.h +214 -75
  61. data/ext/carray_access.c +200 -99
  62. data/ext/carray_address_basis.c +343 -87
  63. data/ext/carray_attribute.c +113 -6
  64. data/ext/carray_bincount.c +10 -8
  65. data/ext/carray_broadcast.c +13 -8
  66. data/ext/carray_build_flags.h +3 -0
  67. data/ext/carray_call_cfunc.c +108 -0
  68. data/ext/carray_cast.c +375 -96
  69. data/ext/carray_cast_func.rb +90 -20
  70. data/ext/carray_class.c +4 -3
  71. data/ext/carray_config.h +28 -0
  72. data/ext/carray_conversion.c +18 -9
  73. data/ext/carray_copy.c +51 -14
  74. data/ext/carray_core.c +150 -55
  75. data/ext/carray_count.c +56 -20
  76. data/ext/carray_element.c +81 -33
  77. data/ext/carray_factorize.c +138 -84
  78. data/ext/carray_generate.c +199 -52
  79. data/ext/carray_histogram.c +63 -18
  80. data/ext/carray_hold.c +12 -15
  81. data/ext/carray_index_classifier.c +388 -176
  82. data/ext/carray_internal.h +348 -29
  83. data/ext/carray_kernels_bincmp.c +4453 -0
  84. data/ext/carray_kernels_binop.c +11368 -0
  85. data/ext/carray_kernels_init.c +1734 -0
  86. data/ext/carray_kernels_moncmp.c +2104 -0
  87. data/ext/carray_kernels_monop.c +18369 -0
  88. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  89. data/ext/carray_kernels_reduce_boolean.c +406 -0
  90. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  91. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  92. data/ext/carray_kernels_reduce_variance.c +3849 -0
  93. data/ext/carray_kernels_scan.c +4302 -0
  94. data/ext/carray_kernels_search.c +33829 -0
  95. data/ext/carray_kernels_sort.c +10897 -0
  96. data/ext/carray_kernels_triop.c +1864 -0
  97. data/ext/carray_key_windows.c +220 -0
  98. data/ext/carray_lazy.c +170 -111
  99. data/ext/carray_mask.c +337 -94
  100. data/ext/carray_median_percentile.c +82 -28
  101. data/ext/carray_memory_view.c +669 -561
  102. data/ext/carray_operator.c +129 -52
  103. data/ext/carray_order.c +604 -77
  104. data/ext/carray_partition.c +28 -27
  105. data/ext/carray_random.c +85 -31
  106. data/ext/carray_round.c +273 -0
  107. data/ext/carray_scatter.c +87 -45
  108. data/ext/carray_segment.c +3 -3
  109. data/ext/carray_slab.c +123 -37
  110. data/ext/carray_sort.c +259 -51
  111. data/ext/carray_sort_kernel.c +5 -7
  112. data/ext/carray_struct.c +54 -61
  113. data/ext/carray_test.c +26 -5
  114. data/ext/carray_time_text.c +4 -2
  115. data/ext/carray_undef.c +4 -0
  116. data/ext/carray_utils.c +309 -66
  117. data/ext/mk_call_cfunc.rb +19 -2
  118. data/ext/mkkernel.rb +403 -350
  119. data/ext/ruby_carray.c +10 -4
  120. data/ext/version.h +4 -4
  121. data/lib/carray/attribute.rb +139 -22
  122. data/lib/carray/autoload_carray.rb +8 -31
  123. data/lib/carray/autoload_method_extension.rb +14 -5
  124. data/lib/carray/axis_group.rb +255 -106
  125. data/lib/carray/basics.rb +105 -17
  126. data/lib/carray/bincount_nd.rb +12 -2
  127. data/lib/carray/block_iterator.rb +126 -23
  128. data/lib/carray/boolean_reduce.rb +17 -17
  129. data/lib/carray/categorical.rb +195 -59
  130. data/lib/carray/categorical_iterator.rb +132 -29
  131. data/lib/carray/complex.rb +5 -5
  132. data/lib/carray/conditional.rb +67 -18
  133. data/lib/carray/const_string.rb +24 -5
  134. data/lib/carray/construct.rb +15 -11
  135. data/lib/carray/data_type_extension.rb +9 -1
  136. data/lib/carray/distance_limit.rb +77 -0
  137. data/lib/carray/fixlen_string.rb +48 -3
  138. data/lib/carray/frame/column_verbs.rb +71 -0
  139. data/lib/carray/frame/concat.rb +17 -3
  140. data/lib/carray/frame/convert.rb +69 -0
  141. data/lib/carray/frame/csv_parser.rb +111 -17
  142. data/lib/carray/frame/describe.rb +3 -2
  143. data/lib/carray/frame/frame.rb +252 -28
  144. data/lib/carray/frame/group.rb +603 -101
  145. data/lib/carray/frame/io.rb +117 -28
  146. data/lib/carray/frame/join.rb +312 -51
  147. data/lib/carray/frame/records.rb +83 -7
  148. data/lib/carray/frame/reshape.rb +42 -35
  149. data/lib/carray/frame/sort.rb +7 -19
  150. data/lib/carray/frame/verbs.rb +188 -48
  151. data/lib/carray/frame/windows.rb +117 -0
  152. data/lib/carray/frame.rb +2 -0
  153. data/lib/carray/fuse_source.rb +42 -6
  154. data/lib/carray/fusion.rb +40 -16
  155. data/lib/carray/histogram.rb +6 -1
  156. data/lib/carray/inspect.rb +31 -8
  157. data/lib/carray/iterator.rb +85 -7
  158. data/lib/carray/key_windows.rb +620 -0
  159. data/lib/carray/lazy.rb +217 -183
  160. data/lib/carray/mask_gap_fill.rb +63 -57
  161. data/lib/carray/meld_reduce.rb +12 -14
  162. data/lib/carray/methods/bin.rb +26 -18
  163. data/lib/carray/methods/bincount.rb +16 -0
  164. data/lib/carray/methods/bit_string.rb +1 -1
  165. data/lib/carray/methods/choose.rb +16 -3
  166. data/lib/carray/methods/composition.rb +3 -1
  167. data/lib/carray/methods/gather_nd.rb +14 -5
  168. data/lib/carray/methods/insert_block.rb +2 -2
  169. data/lib/carray/methods/is_between.rb +59 -0
  170. data/lib/carray/methods/is_in.rb +61 -37
  171. data/lib/carray/methods/join.rb +1 -6
  172. data/lib/carray/methods/lag.rb +49 -0
  173. data/lib/carray/methods/locate_addr.rb +47 -51
  174. data/lib/carray/methods/mode.rb +1 -1
  175. data/lib/carray/methods/nunique.rb +11 -6
  176. data/lib/carray/methods/resize.rb +3 -3
  177. data/lib/carray/methods/value_counts.rb +4 -11
  178. data/lib/carray/record_order.rb +3 -3
  179. data/lib/carray/rng.rb +3 -0
  180. data/lib/carray/runtime.rb +53 -8
  181. data/lib/carray/segment_iterator.rb +323 -88
  182. data/lib/carray/serialize.rb +45 -14
  183. data/lib/carray/slab_iterator.rb +50 -0
  184. data/lib/carray/stack.rb +15 -12
  185. data/lib/carray/string.rb +113 -5
  186. data/lib/carray/string_operation_extension.rb +21 -6
  187. data/lib/carray/struct.rb +9 -21
  188. data/lib/carray/struct_builder.rb +24 -11
  189. data/lib/carray/time.rb +819 -158
  190. data/lib/carray/window_iterator.rb +122 -16
  191. data/lib/carray.rb +7 -0
  192. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  193. data/yard-stubs/ca_obj_field.rb +4 -0
  194. data/yard-stubs/ca_obj_grid.rb +21 -10
  195. data/yard-stubs/ca_obj_refer.rb +2 -1
  196. data/yard-stubs/ca_obj_roll.rb +2 -2
  197. data/yard-stubs/ca_obj_shift.rb +5 -1
  198. data/yard-stubs/ca_obj_tile.rb +1 -1
  199. data/yard-stubs/ca_obj_transpose.rb +5 -4
  200. data/yard-stubs/ca_obj_window.rb +8 -3
  201. data/yard-stubs/carray_access.rb +6 -1
  202. data/yard-stubs/carray_attribute.rb +3 -6
  203. data/yard-stubs/carray_cast.rb +12 -0
  204. data/yard-stubs/carray_conversion.rb +7 -2
  205. data/yard-stubs/carray_copy.rb +4 -2
  206. data/yard-stubs/carray_count.rb +4 -4
  207. data/yard-stubs/carray_element.rb +17 -10
  208. data/yard-stubs/carray_generate.rb +21 -1
  209. data/yard-stubs/carray_mask.rb +32 -3
  210. data/yard-stubs/carray_math.rb +41 -5
  211. data/yard-stubs/carray_median_percentile.rb +5 -2
  212. data/yard-stubs/carray_memory_view.rb +40 -23
  213. data/yard-stubs/carray_order.rb +129 -22
  214. data/yard-stubs/carray_random.rb +13 -4
  215. data/yard-stubs/carray_scatter.rb +17 -10
  216. data/yard-stubs/carray_slab.rb +9 -2
  217. data/yard-stubs/carray_sort.rb +6 -5
  218. data/yard-stubs/carray_test.rb +5 -3
  219. metadata +25 -3
  220. data/lib/carray/arrow_tensor.rb +0 -401
  221. data/lib/carray/table.rb +0 -108
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 76ca6c2983cbd1e07acc64daeedc7328bee9239369f56f3af661ed1cc41e0bfb
4
- data.tar.gz: 1506fa95c68148469451631fb375826e2599a979b4593db8c7508cf16d3c7545
3
+ metadata.gz: ccd30e8ea5b53c3a2654a86a0ab7473b3073f7feffa7db7be0e5c9aef5bc17c8
4
+ data.tar.gz: ffcd91fe93ca10b4b12dbff035ffc25533699472b364482a59bf2aa635296032
5
5
  SHA512:
6
- metadata.gz: 66a3078a1bdd6459ab0c7526a588cc81191a4e043a17028b769b87b5d32874a9fd20c2b4828217dfa573457871f476155d005db518da600bbef38baca5551eb8
7
- data.tar.gz: 23479b0a9b229489ff5ed1afa7fdc0a30150b9d3ba32803b089f1f9e5d7a955cd556c478c7cb5346e516830632a4ba35cb54d186f54a783b589d7cabec9498d5
6
+ metadata.gz: 53c08f4ccf6a4c25219cef4e8f27e7de9740dc8c69ee493ff8e3631c87499cd15ed121d5f7707bd1017f77e0309dc1be2628fa3611b9b3c979e0e075008842d6
7
+ data.tar.gz: 2200b047a456603d6274d9dfaf8f93c011ce1cc1eb457c454fa7f9cdc9c75ea4b96c9bbe1dab0b37710f8b872ac5e8b630db5c0dacae12a9012b1b34d4c7f1ec
data/CHANGELOG.md CHANGED
@@ -34,6 +34,475 @@ and a newer one. The 1.x history, up to the 2.0.0 release, is in
34
34
  neighbour ("as well", "the producer above") or leave unnamed the
35
35
  method, class or keyword it is about. -->
36
36
 
37
+ ## 3.0.5
38
+
39
+ - New: `GroupedFrame#aggregate` takes a block instead of a spec. The block
40
+ is given the grouping once and returns a Hash of output name => a
41
+ CArray with one value per group, built from `g["col"]` iterators and
42
+ CArray arithmetic (`g["temp"].max - g["temp"].min`). `grp[array]`
43
+ groups any CArray with one entry per row, such as a value computed
44
+ from columns or a column with cells masked.
45
+
46
+ - New: a `CAFrame` grouped reduction takes a Hash of column name => value
47
+ as `fill_value:`, filling only the named columns. A single
48
+ `fill_value:` still goes to every column and has to suit each.
49
+
50
+ - New: `CArray.meld` brings pieces of different data types to a common
51
+ one, as `CArray.stack` does, and takes `data_type:`. `CAFrame.meld` and
52
+ a frame splice still refuse a column whose pieces differ in data type;
53
+ cast the column first, or use `concatenate`.
54
+
55
+ - New: `scatter_replace!` takes an object or fixed-length array, as
56
+ `put_nd` and `put_along_axis` do. The accumulating members
57
+ (`scatter_add!` and the others) still take numeric arrays only.
58
+
59
+ - New: `CAConstString#count` and `CACategorical#count` with no argument
60
+ count the cells that are not masked, as `CArray#count` does.
61
+
62
+ - New: `CAFixlenString` answers `minmax`, `cummax` and `cummin`, as
63
+ `CAString` does.
64
+
65
+ - New (C extensions): `carray.h` defines `ca_u_<type>` cell types and
66
+ `CA_U(type)`, of the same size and value as the plain types but with no
67
+ alignment requirement, for reading cells that need not be aligned (a
68
+ refer with a byte offset, a struct member, a wrapped buffer). The slab
69
+ macros in `ca_kernel_iterator.h` use them for their pointers.
70
+
71
+ - Change: `CACategorical#sort_addr` is renamed `group_addr`, the order of
72
+ the cells by category. `sort_addr` on a categorical now raises, as
73
+ `sort_index` does, since a categorical has no order of values.
74
+
75
+ - Change: a Face's `parent` (of a `CATime`, `CARecord`, ...) is a
76
+ read-only view of its storage. Write the storage of a time through
77
+ `CATime#ticks`.
78
+
79
+ - Change: an operator that cannot bring two data types together raises
80
+ `CArray::DataTypeError` instead of `TypeError`. `DataTypeError` is a
81
+ `TypeError`, so `rescue TypeError` still catches it.
82
+
83
+ - Change: a float cell with no integer of the target type -- an infinity,
84
+ or a value out of the type's range -- is now treated the way NaN
85
+ already was. `to_type` (`int32`, `as_int64`, ...) masks it to `UNDEF`;
86
+ storing it into an integer array raises `RangeError`
87
+ (`FloatDomainError` for an infinity). Before, it became whatever the
88
+ machine's C conversion gave, which differed between x86 and ARM.
89
+ `clip_int64` and the other `clip_<type>` methods saturate a float
90
+ source to the type's limits on every machine; integer `linspace` raises
91
+ `RangeError` for a span the type cannot hold.
92
+
93
+ - Change: a Ruby Array operand of a numeric or boolean array is read as
94
+ its cells: `a.eq([1, 5, 3])` compares cell by cell (it compared every
95
+ cell with the whole Array), and `a + [1, 2, 3]` adds (it raised).
96
+ Nested Arrays give the axes. An object array still takes an Array as
97
+ one value.
98
+
99
+ - Change: `window`'s `bounds:` is a policy named by a Symbol or String,
100
+ matched whole; an Integer and an abbreviation raise. A `fill_value:`
101
+ given with a policy that does not use it (`:nearest`, `:strict`, ...)
102
+ raises instead of being dropped.
103
+
104
+ - Change: a length, count, offset or shift given to a view
105
+ (`sliding_windows`, `block_view`, `tile`, `roll`, `shift`, `field`,
106
+ `diagonal`) must be an Integer; a Float raises `TypeError` instead of
107
+ being truncated. `transpose` reads its axes as the other axis arguments
108
+ are read: negative from the end, an Integer only.
109
+
110
+ - Change: `drop_axis` on an array whose every axis has size 1 keeps one
111
+ axis of size 1, and `reshape` with no axes raises.
112
+
113
+ - Change: in an index of one key per axis, an index array of more than
114
+ one axis on one axis raises `ArgumentError`; it was read flat. Pass
115
+ `idx.flatten` for the old reading.
116
+
117
+ - Change: `elem_fetch`, `elem_store` and the other `elem_*` methods read
118
+ an index as `[]` reads a key: a Float with no fraction is an index, a
119
+ Float with a fraction raises `IndexError`.
120
+
121
+ - Change: two string arrays of different kinds (`CAString`,
122
+ `CAFixlenString`, `CAConstString`) or of different widths compare by
123
+ their strings. A String query longer than a fixed-width cell matches
124
+ no cell in `eq`, `count`, `search`, `bsearch` and `is_in`; it was cut
125
+ to the cell's width.
126
+
127
+ - Change: `str_index` and `rindex` give `UNDEF` for a cell that does not
128
+ hold the substring; they raised for the whole array.
129
+
130
+ - Change: `bsearch` and `bsearch_addr` answer the first of several equal
131
+ cells.
132
+
133
+ - Change: `search` and `search_addr` raise `ArgumentError` for a negative
134
+ or NaN `eps`, which acted as an exact match.
135
+
136
+ - Change: `inherit_mask` and `inherit_mask_replace` raise `ArgumentError`
137
+ for a source whose number of cells differs from the receiver's (a
138
+ scalar source still applies to every cell).
139
+
140
+ - Change: a reduction's `fill_value:` that its result cannot hold raises
141
+ even when no cell needs it, and `fill` on an empty array checks its
142
+ value as an assignment does.
143
+
144
+ - Change: rounding a `:M` or `:Y` `CATime` to a calendar bucket
145
+ (`round(unit: :Y)`, `"3 months"`) measures the distance by the instant,
146
+ so it agrees with the same dates on `:D`.
147
+
148
+ - Change: a `CATime` reduction (`mean`, `median`, ...) sends a tie to the
149
+ later tick on both sides of 1970; before 1970 it went to the earlier
150
+ one.
151
+
152
+ - Change: a duration String added to or subtracted from a `CATime` is
153
+ one step of its own resolution, so `"15 minutes"` on a `"10 minutes"`
154
+ grid raises, as the same duration as a `CATimedelta` does. It was read
155
+ as fifteen one-minute steps and cut to the grid.
156
+
157
+ - Change: of `-0.0` and `0.0`, `pmax` gives `0.0` and `pmin` gives
158
+ `-0.0`, in either order and on every platform, as `maximum` and
159
+ `minimum` do. Which zero `min` and `max` answer is not specified.
160
+
161
+ - Change: a one-sided `clip` passes a NaN cell through, as a two-sided
162
+ `clip` does.
163
+
164
+ - Change: a categorical's `fill_value:` (of `shift`, `window`, `project`)
165
+ is a label; a `CAConstString` takes only `UNDEF` as a fill value.
166
+
167
+ - Change: a lazy operator with a Face operand (a categorical, a time, a
168
+ string array) answers as the eager operator does; it read the Face's
169
+ storage. `CAConstString#eq` with another array compares cell by cell.
170
+
171
+ - Change: a boolean member of a record (or `field(offset, :boolean)` of a
172
+ fixed-length array) raises `RangeError` when read as a byte that is not
173
+ 0 or 1, instead of answering differently in each method.
174
+
175
+ - Change: unmasking a cell of a `CAString` that holds no String gives an
176
+ empty String.
177
+
178
+ - Change: `swap_bytes` keeps the attributes, as `refer` and `bitfield`
179
+ do. An array with no cells has no say in the attributes a `meld`,
180
+ `stack` or `concatenate` keeps.
181
+
182
+ - Change: `dim_view` keeps a Face, as `transpose` does.
183
+
184
+ - Change: `CArray.string(n)` without a block, and `CArray.string("ab")`,
185
+ raise; `fixlen_string` and `to_fixlen_string` raise for `bytes:` below 1.
186
+ `project` raises for a keyword argument, `paste` into a frozen array
187
+ raises `FrozenError`, and `CArray.result_type` refuses a MemoryView
188
+ operand whose format carray cannot read, as the operators do.
189
+
190
+ - Change: `CArray.sort_addr` with numeric keys is two to three times as fast, and
191
+ `nlargest` / `nsmallest` read each fiber once with a work area of a
192
+ few times n.
193
+
194
+ - Fix: x86-64 Linux. Inputs that reached an integer division by zero
195
+ inside the library stopped the process with SIGFPE there (on ARM they
196
+ were refused later or gave a wrong answer): a sum over a view with a
197
+ zero-length axis, `wsum` / `wmean` with 1-D weights over a zero-length
198
+ axis, a view of a stack of empty arrays, `window` with a step of 0, and
199
+ `wrap_readonly(String, CA_FIXLEN)`. Each now answers or raises
200
+ `ArgumentError`. The extension builds with GCC 14 without warnings.
201
+
202
+ - Fix: big-endian hosts. `bitfield` read 0 and lost writes, a struct's
203
+ bit members overwrote each other, and an element-wise operation applied
204
+ in place could give a wrong cell.
205
+
206
+ - Fix: `save` and `dump` with `endian: :little` or `:big` wrote the other
207
+ byte order. `load` reads the marker, so files written so far still load
208
+ correctly.
209
+
210
+ - Fix: running out of memory inside a kernel left a view attached, lost
211
+ the keywords of the call (`a.sum(axis: 1)` returned the total), or
212
+ leaked the array being built.
213
+
214
+ - Fix: an array with 16 axes (the maximum) given to `bitarray`, `field`,
215
+ a narrowing `refer` or a `:_` index wrote past an internal array.
216
+
217
+ - Fix: a lazy chain whose step narrows the cells (`a.lazy.abs` of a
218
+ complex array) overran the heap; `seq` on an empty object array wrote
219
+ past its end.
220
+
221
+ - Fix: a CAObject's copy and sync hooks: a view the hook kept of the
222
+ array it was lent, or the lent array's mask, pointed at freed memory
223
+ after the hook returned.
224
+
225
+ - Fix: `CArray.fuse` crashed when several Ractors ran a fuse block for the
226
+ first time at once.
227
+
228
+ - Fix: a grouped `variancep` / `stddevp` matches `CArray#variancep` to the
229
+ last bit.
230
+
231
+ - Fix: `count` with an array of values honours `keep_axis:`.
232
+
233
+ - Fix: `CARecord.wrap` of a record array wraps its storage, not the
234
+ record array.
235
+
236
+ - Fix: an unnamed struct's `order_by` survives `save` / `load` and
237
+ Marshal.
238
+
239
+ - Fix: `CAFrame.from_csv` and `cast(name => :time)` read a leap second
240
+ (`23:59:60`) as `CArray.time` does, into the next minute.
241
+
242
+ ## 3.0.4
243
+
244
+ - New: `CAFrame#verify(rules)` judges every row against named rules (each
245
+ a callable that returns a boolean CArray) and returns the verdicts as a
246
+ frame, one column per rule; a row whose rule read a masked value is
247
+ `UNDEF`, so `count(false)` counts the rows that break it.
248
+
249
+ - New: `CAFrame#join` takes `how: :semi` and `:anti` (the left rows that
250
+ have, or have no, match), several key columns (`on: ["station",
251
+ "date"]`), and the index as a key by the row axis name.
252
+ `CAFrame#join_asof` takes the index too, and `by:` columns that must
253
+ match exactly before the nearest key is taken.
254
+
255
+ - New: a `CAFrame` grouping has more verbs. The short form of `prod`,
256
+ `accumulate`, `median`, `variance`, `stddev`, `variancep`, `stddevp`,
257
+ `first`, `last`, `nunique`, `count`, `all` and `any`, beside `sum` /
258
+ `mean` / `min` / `max`; `filter` (keep the groups a block chooses);
259
+ `lag`, `order`, `cumsum` and the other running values, and
260
+ `fill(name, :ffill)` / `:bfill`, all kept on the frame's rows; and
261
+ `to_frame`. The reductions take column names (`grp.mean("temp")` is a
262
+ CArray) and `keep_rows: true`, which gives each row its own group's
263
+ result.
264
+
265
+ - New: `CAFrame#resample` takes `by:`, columns whose groups are binned
266
+ apart: `df.resample("time", "1 day", by: "station").max("temp")`.
267
+
268
+ - New: `CArray#windows(on:, before:, after:)` bounds each window by a
269
+ width of a key (a time, a duration or a number) instead of a count of
270
+ cells, with `by:`, `exclude:`, `interval:` and `at:` (windows placed at
271
+ given points, which may overlap). The key need not be sorted, and the
272
+ value may have several columns (shape `(N, ...)`). `CAFrame#windows(on:
273
+ "time", ...)` does the same for a frame's columns.
274
+
275
+ - New: `CArray#lag(n = 1, axis:)` is the value `n` steps earlier along an
276
+ axis, `UNDEF` where there is none, so `x - x.lag` starts with `UNDEF`.
277
+
278
+ - New: the slab, block, segment, categorical and axis-group iterators
279
+ have `lag`, `order` (each cell's rank within its piece) and
280
+ `strip_mask(method: :ffill / :bfill)`; each of them works within one
281
+ piece and never takes a value from another. Every iterator has `first`,
282
+ `last` and `nunique`.
283
+
284
+ - New: `CArray#is_between(lo, hi, exclude:)` (or a Range) is true where a
285
+ value lies between two bounds; `exclude: :lower`, `:upper` or `:both`
286
+ leaves bounds out, and `nil` or an open end leaves a side unbounded.
287
+
288
+ - New: `CArray#round(ndigits)` rounds each element to `ndigits` decimal
289
+ places (negative for tens, hundreds, ...), as `Float#round` and
290
+ `Integer#round` do.
291
+
292
+ - New: `CArray#to_frame(*names, axis: -1)` shows an array as a CAFrame
293
+ whose columns are views of it, one per position along `axis`.
294
+
295
+ - New: `CACategorical#contrast(base:, full:)` gives one int8 column per
296
+ category (1 in the cell's category, the base left out unless `full:
297
+ true`), and `CAFrame#contrast_columns(name, ...)` puts those columns in
298
+ the frame in place of the categorical.
299
+
300
+ - New: `CAFrame#is_duplicate(*names, except:)` is true for the rows that
301
+ repeat an earlier row in the named columns; `except: :last` or `:none`
302
+ chooses which occurrence stays unmarked.
303
+
304
+ - New: `CAFrame#append(name, col, before:, after:)` puts the column next
305
+ to another one.
306
+
307
+ - New: a `CAFrame` carries attributes of the frame as a whole (`attr`,
308
+ `set_attr`, `attrs`, ..., and `CAFrame.new(..., attrs:)`), separate from
309
+ each column's. A row selection or a change of columns keeps them; a
310
+ summary, a join or a reshape does not.
311
+
312
+ - New: `CAFrame#to_csv(attrs: [:units, ...])` writes one line per
313
+ attribute key below the names, and `CAFrame.from_csv(attrs: [...])`
314
+ reads them back as column attributes; in a reading block,
315
+ `r.header(:units)` does the same for a line anywhere in the header.
316
+
317
+ - New: `CAFrame.from_csv` `columns:` takes a Hash that selects and names
318
+ columns, and the names `c0`, `c1`, ... of a file without a header;
319
+ `cast` and `from_csv` `types:` take `:categorical`. `CAFrame.new` takes
320
+ `types:` and `on_error:`, as `from_records` does.
321
+
322
+ - New: `CArray#delete_attr(key)` removes an attribute and returns its
323
+ value.
324
+
325
+ - New: `CATime#end_of(unit:, origin:)` (the last tick of each time's
326
+ bucket), `days_in_month`, `quarter`, and the ISO 8601 week `iso_week`
327
+ with its year `iso_year`.
328
+
329
+ - New: a time or duration array takes a single value in `+` and `-`
330
+ (`t + "3 days"`, `t - t.min`, `t - Time.utc(2024, 1, 1)`), and a month
331
+ or year duration moves a time on a day or finer grid as `Date#>>` does
332
+ (`2024-01-31 + 1 month` is `2024-02-29`). A bare number is still
333
+ refused.
334
+
335
+ - New: a time array compares with a value off its grid (`days.eq(
336
+ "2024-01-03T05:00")`, `<`, `search_nearest`, `is_in`, ...) in the finer
337
+ unit the two share, where it raised `ArgumentError`. An assignment
338
+ still raises.
339
+
340
+ - New: `CATime#pmax` / `pmin` (and `maximum` / `minimum` / `fmax` /
341
+ `fmin`) give the later / earlier time cell by cell.
342
+
343
+ - New: CArray can be used in a Ractor other than the main one, `fuse`
344
+ included, and a frozen array is shared between Ractors without
345
+ copying. See `docs/topics/Ractor.md`.
346
+
347
+ - New: C extensions: `CA_FOR_EACH_WHOLE` and `CA_FOR_EACH_WHOLE_MASKED`
348
+ hand a kernel the whole array as one contiguous run.
349
+
350
+ - Change: `CArray#rank` is removed; use `#ndim`.
351
+
352
+ - Change: `CArray::TableMethods` (`column_names=`, `column`, `row`, `rows`
353
+ and `select` on a 2-D array) is removed; use `a.to_frame("x", "y")`,
354
+ then `df["x"]` for a column or `df.to_records[i]` for a row.
355
+
356
+ - Change: `CArray.load_arrow_tensor`, `CArray#save_arrow_tensor` and
357
+ `CArray::ArrowTensor`, the experimental Arrow tensor IPC reader and
358
+ writer, are removed.
359
+
360
+ - Change: methods whose names start and end with `__` that were public
361
+ internals are now private, renamed or removed. Call the public method
362
+ they served instead.
363
+
364
+ - Change: CAFrame takes column names as Strings only. A Symbol name
365
+ (`df.drop(:a)`, `join(on: :a)`, `CAFrame.new(axis_name: :row)`) raises
366
+ `TypeError`; write `"a"`. Record keys given to `from_records` may still
367
+ be Symbols, and `df[:x]` stays the predicate syntax.
368
+
369
+ - Change: a masked cell of an integer index array keeps its place:
370
+ `x[i]`, the grid forms and `CAFrame` row selection `df[i]` give a
371
+ result shaped like `i`, `UNDEF` where `i` is masked, where they dropped
372
+ those positions. To drop them as before, index by
373
+ `i[i.is_not_masked]`.
374
+
375
+ - Change: an index beside a CArray key is read as it is without one: a
376
+ range ending before its start reads backwards (`a[i, -1..1]`), and an
377
+ Integer key drops its axis (`a[i, 1]` has the shape of `i`; add `:_`
378
+ or use `1..1` to keep it).
379
+
380
+ - Change: an index with a Float that has a fraction (`a[1.5..3]`, a step
381
+ of `0.5`) raises `IndexError`; it was cut to an integer. Convert with
382
+ `to_i` or `round` first. A Float that holds an integer, such as a count
383
+ from `sum`, is still that position.
384
+
385
+ - Change: an index step says the direction, as in Ruby: a step pointing
386
+ away from the end reads nothing (`a[(0..4).step(-1)]` read `a[0]`).
387
+
388
+ - Change: a boolean selector of more than one axis must have the array's
389
+ shape; it picked cells by flat position. Flatten both sides to keep the
390
+ old reading.
391
+
392
+ - Change: storing an integer a cell cannot hold raises `RangeError`
393
+ (`CA_INT8([300])`, `a[0] = 300`, `fill`, `scatter_add!`, a record
394
+ member); it wrapped (`300` into int8 was `44`). Storing or reading a
395
+ NaN into an integer cell (`ints[] = floats`, `as_type`, `fake`) raises
396
+ `FloatDomainError`. To keep C's conversion, use `to_type`, which is
397
+ unchanged.
398
+
399
+ - Change: `CArray.time` reads an Integer as a count of ticks of `unit:`
400
+ (`CArray.time(CA_INT64([0, 10]), unit: :m)` is 00:00 and 00:10); it
401
+ read Unix seconds. To read Unix seconds onto another unit, write
402
+ `CArray.time(secs).to_unit(:m)`.
403
+
404
+ - Change: `CArray.time` without `unit:`, and `CAFrame#parse_to_time` with
405
+ a format or `:mixed`, read the values in the finest unit they show
406
+ (dates alone `:D`, fractions of a second `:ms` / `:us` / `:ns`); it was
407
+ always `:s`. Pass `unit: :s` to keep the old unit.
408
+
409
+ - Change: adding a duration that is coarser than a time's unit and not a
410
+ whole number of its ticks (`"1 day"` on a `"7 hours"` time) raises, and
411
+ so does `CArray#time(origin:)` between two ticks of `unit:`; both were
412
+ cut to the grid. Convert the time to a unit both share first.
413
+
414
+ - Change: `order(descending: true)` puts NaN last and keeps tied cells in
415
+ their original order (`[5, 3, 5, 1, 5]` gives `[0, 3, 1, 4, 2]`, was
416
+ `[2, 3, 1, 4, 0]`); with `method: :dense` the largest value is 0 and
417
+ the ranks have no gaps. Code that used `(n - 1) - order` for the
418
+ descending rank needs that formula written out. `nlargest` no longer
419
+ returns NaN or masked cells first, and `nsmallest` / `nlargest` and
420
+ their `_index` forms break ties by position.
421
+
422
+ - Change: a CAFrame column built from Ruby values is typed by them:
423
+ Integers `int64`, numbers `float64`, Strings a text column (`CAString`),
424
+ arrays of one shape an N-D column, anything else `:object`; it was
425
+ `:object`. This holds for `CAFrame.new("x" => [...])`, `df["x"] = [...]`,
426
+ a group's `table` block and a Proc in `aggregate`. Wrap the values in
427
+ `CA_OBJECT(...)` to keep an object column. A returned array is read
428
+ from the N-D column as `col[i, nil]`.
429
+
430
+ - Change: `CAFrame#melt` names each row's source in a text column
431
+ (`CAString`); it was an object column.
432
+
433
+ - Change: `CAFrame#group_by` on several keys gives a result with no
434
+ index: each key is a column, before the reduced columns. Read the keys
435
+ with `result["station"]` and so on, where the index held tuples.
436
+
437
+ - Change: `CAFrame#data_types`, `describe` and `p df` name a Face column
438
+ by its class (`CATime[D]`, `CAString`) where they gave its storage
439
+ `data_type` (`:fixlen` for most). Read the storage through the Face's
440
+ accessor (`ticks`, `codes`, ...).
441
+
442
+ - Change: a CAFrame verb that takes a list of columns refuses a name
443
+ given twice (`select("a", "a")`, `group_by("a", "a")`) with
444
+ `ArgumentError`. `df["a", "a"]` still gives the column twice.
445
+
446
+ - Change: a CAFrame group or window reduction over a column whose type
447
+ lacks it raises `CArray::DataTypeError`; it raised `ArgumentError`.
448
+
449
+ - Change: a `CAString` holds only Strings: storing `nil`, a number or an
450
+ Array into it raises (use `UNDEF` to mask a cell). A selection among
451
+ Strings (`then_else`, `choose`, `select`, `conditional`) and a
452
+ `CAString`'s String operators give a `CAString`, where they gave an
453
+ object array.
454
+
455
+ - Change: attributes follow conversions, views and copies but not
456
+ reductions: `categorize`, `cast`, `parse_to_time`, `dup`, Marshal and a
457
+ Face's views keep them, and `first` / `last` of a grouping no longer
458
+ carry them. A joined or concatenated array shows the keys every piece
459
+ shows with the same value. An attribute value is stored frozen; change
460
+ it by setting it again.
461
+
462
+ - Change: an error names the method you called, and the common refusals
463
+ open with it ("+: shape mismatch between operands ...", "fill: can not
464
+ modify read-only array"). The exception classes are unchanged; code
465
+ that matches a message needs the new text.
466
+
467
+ - Change: `clip` refuses `UNDEF` or a masked cell as a bound with
468
+ `ArgumentError`. To mask the cells out of range, pass `UNDEF` as the
469
+ fill (`clip(0, 10, UNDEF)`).
470
+
471
+ - Change: `is_in`, `intersection`, `difference` and `union` refuse a
472
+ Range; pass an Array (`(1..3).to_a`), or use `is_between` for an
473
+ interval.
474
+
475
+ - Change: `median`, `percentile` and `quantile` along the only axis of a
476
+ 1-D array give a bare value, as `sum` does. `nunique(axis:)` naming
477
+ every axis gives an Integer; pass `keep_axis: true` to keep an array.
478
+
479
+ - Change: `valid_index?` and `valid_addr?` count a negative index from
480
+ the end, as `[]` does. `elem_fetch` on an empty array raises
481
+ `IndexError`; it returned `nil`.
482
+
483
+ - Change: `seq` / `seq!` on an integer array take a Float or Rational
484
+ start or step as `init_val + step*i` cut toward zero
485
+ (`int32.seq(0.5, 0.5)` is `[0, 1, 1, 2]`, was `[0, 0, 1, 1]`), and
486
+ raise `RangeError` for a start or Integer step the type cannot hold.
487
+
488
+ - Change: `random!` on an integer array raises for bounds the type
489
+ cannot hold or a Float bound, and clears the mask. `bin`, `bincount`,
490
+ `bincount_nd` and the histograms raise for a non-Integer count and for
491
+ edges that decrease.
492
+
493
+ - Change: MemoryView: `wrap_memory_view` refuses a boolean buffer (any
494
+ byte other than 0 or 1 cannot be told apart; use `from_memory_view`,
495
+ which reads it as true), and a wrap with a read-only `mask:` is
496
+ read-only. `CArray.memory_view_reject_reason` returns `nil` for an
497
+ object that is not a CArray.
498
+
499
+ - Change: C extensions: fifteen kernel iterator shorthand macros
500
+ (`CA_SLAB_REDUCE_F64`, `CA_SLAB_REDUCE_T_PLUS`,
501
+ `CA_L2_FOR_EACH_UNMASKED` and others) are removed; write the macro they
502
+ stood for (`CA_SLAB_REDUCE_T` with `double`, ...).
503
+ `ca_iter_state_next_slab_strided` is removed, and
504
+ `ca_iter_state_init_l2` takes `CA_SLAB_AXES` only.
505
+
37
506
  ## 3.0.3
38
507
 
39
508
  - New: `CAFrame.from_csv` reads messy tables: `types: :infer` (numbers,
data/README.md CHANGED
@@ -10,11 +10,11 @@ Ruby/CArray is an extension library for the multi-dimensional array class. It pr
10
10
 
11
11
  * Every array carries a per-element mask for missing values, respected by reductions and statistics
12
12
  * Views compose without copying — a write through the outermost view reaches the source data
13
- * MemoryView protocol on both sides: share buffers with other numerical libraries without copying
13
+ * [MemoryView protocol](guides/users/15_memory_view.md) on both sides: share buffers with other numerical libraries without copying
14
14
  * Define your own array class in pure Ruby while keeping the full CArray interface
15
15
  * Kernel-style iteration: run a Ruby block over each sub-array spanning the axes you choose
16
16
  * Faces: array types for time, strings and categories, with methods of their own on top of everything CArray does
17
- * Comes with a DataFrame (`CAFrame`) whose columns are plain CArrays, so masks and views keep working on them
17
+ * Comes with a DataFrame ([`CAFrame`](guides/dataframe/README.md)) whose columns are plain CArrays, so masks and views keep working on them
18
18
 
19
19
  Each of these is shown, briefly and with a runnable example, in [A tour of the features](docs/FeatureTour.md).
20
20
 
@@ -119,6 +119,7 @@ b.strip_mask(Float::NAN).sum(axis: 0)
119
119
  * [Views](guides/users/06_views.md) — referring to data without copying
120
120
  * [Reduction and statistics](guides/users/04_reduction_and_statistics.md) — summaries, whole or per axis
121
121
  * [Masks and missing values](guides/users/05_masks.md) — undefined elements, and how calculations treat them
122
+ * [Data frames](guides/dataframe/README.md) — tables of named columns, each column a CArray
122
123
 
123
124
  ## Contributing
124
125
 
data/carray.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "carray"
3
- s.version = "3.0.3"
3
+ s.version = "3.0.5"
4
4
  s.authors = ["himotoyoshi"]
5
5
  s.email = ["himotoyoshi@users.noreply.github.com"]
6
6
  s.summary = "Multi-dimensional numerical array class for Ruby"
data/ext/ca_array_pool.c CHANGED
@@ -43,18 +43,42 @@
43
43
  ---------------------------------------------------------------------------- */
44
44
 
45
45
  #include "carray.h"
46
+ #include "carray_internal.h"
46
47
  #include <string.h>
47
48
 
48
49
  /* Allocate struct + pool in one shot, then run pool_init.
49
50
  *
50
51
  * Called by per-class C `*_new` constructors. */
52
+ typedef struct {
53
+ CArray *ca;
54
+ int8_t obj_type;
55
+ int8_t ndim;
56
+ } ca_array_alloc_arg;
57
+
58
+ static VALUE
59
+ ca_array_alloc_pool (VALUE varg)
60
+ {
61
+ ca_array_alloc_arg *a = (ca_array_alloc_arg *) varg;
62
+ ca_array_pool_alloc(a->ca, a->obj_type, a->ndim);
63
+ return Qnil;
64
+ }
65
+
51
66
  void *
52
67
  ca_array_alloc (int8_t obj_type, int8_t ndim)
53
68
  {
54
69
  ca_operation_function_t *func = &ca_func[obj_type];
55
70
  CArray *ca = xmalloc(func->struct_size);
71
+ ca_array_alloc_arg a;
56
72
  memset(ca, 0, func->struct_size);
57
- ca_array_pool_alloc(ca, obj_type, ndim);
73
+ /* The type is set now so that a constructor whose setup raises can hand
74
+ the struct to ca_free, which dispatches on it. The setup sets it
75
+ again. */
76
+ ca->obj_type = obj_type;
77
+ /* The pool is a second allocation; when it fails, the struct goes too. */
78
+ a.ca = ca;
79
+ a.obj_type = obj_type;
80
+ a.ndim = ndim;
81
+ ca_fill_or_xfree(ca, ca_array_alloc_pool, (VALUE) &a);
58
82
  return ca;
59
83
  }
60
84
 
@@ -2,13 +2,10 @@
2
2
 
3
3
  ca_axis_descriptor.h
4
4
 
5
- Per-axis descriptor framework (D1 + D2 + D3) — shared C-level vocabulary
6
- that lets CSA, CAGrid, CASelectAxis, CAWindow, CAShift, and future
5
+ Per-axis descriptor framework — shared C-level vocabulary that lets
6
+ CASelectAxis, CAGrid, CASelect, CAWindow, CAShift, and future
7
7
  per-axis-mixed views describe each axis the same way so a common
8
- attach dispatch engine (D3, ca_axis_dispatch.c) can drive them
9
- uniformly.
10
-
11
- See devel/PROPOSAL_AXIS_DESCRIPTOR_FRAMEWORK.md for the design.
8
+ attach dispatch engine (ca_axis_dispatch.c) can drive them uniformly.
12
9
 
13
10
  Status: TWO-TIER FREEZE CONTRACT (3.0 onward), the same split
14
11
  ca_kernel_iterator.h declares, for the same reason: this header is
@@ -50,14 +47,14 @@
50
47
  When this header is included from carray.h mid-file, those typedefs
51
48
  are already in scope by the time we reach the include site. */
52
49
 
53
- /* ---- D1: per-axis descriptor types ----------------------------------------
50
+ /* ---- per-axis descriptor types --------------------------------------------
54
51
 
55
52
  STRIDE = linear stride axis: parent index = start + i*step,
56
53
  i in [0, count). Subsumes nil / Integer / Range index args.
57
54
  INDEX = integer index axis: parent index = indices[i],
58
55
  i in [0, count). Subsumes integer-array (CAGrid)
59
56
  and boolean-mask-after-snapshot (CASelectAxis) axes.
60
- SHIFT = bound-aware stride axis (CAWindow/CAShift, Tier 2.B):
57
+ SHIFT = bound-aware stride axis (CAWindow/CAShift):
61
58
  parent index = start + i*step normalised by `policy`
62
59
  (CA_BOUNDS_FILL / PERIODIC / REFLECT / NEAREST / ...)
63
60
  against `size0` (= parent dim along this axis). When
@@ -86,16 +83,17 @@ typedef struct {
86
83
  uint8_t policy; /* CA_BOUNDS_FILL / PERIODIC / REFLECT / ... */
87
84
  } ca_axis_desc_t;
88
85
 
89
- /* ---- D2: producer interface ----------------------------------------------
86
+ /* ---- producer interface --------------------------------------------------
90
87
 
91
- Both implementations write ndim entries into `out` (caller-allocated)
92
- and `out_parent_dims` (caller-allocated, sized CA_RANK_MAX). See
93
- devel/PROPOSAL_AXIS_DESCRIPTOR_FRAMEWORK.md §5 Framework Phase 1 and
94
- devel/PROPOSAL_FLAT_INDEX_VIEWS.md §2.3 for rationale.
88
+ A producer writes one entry per descriptor axis into `out`
89
+ (caller-allocated) and `out_parent_dims` (caller-allocated, sized
90
+ CA_RANK_MAX). The producers declared here are CASelectAxis and CAGrid;
91
+ CASelect and CAWindow have their own (ca_select_describe_axes /
92
+ ca_window_describe_axes).
95
93
 
96
94
  `out_parent_dims[k]` is the **effective** parent dim along descriptor
97
- axis k — for CSA / CAGrid this is just `parent->dim[k]`, but for
98
- flat-index views (CASelect / CAMapping, Tier 2.A.3+) it is
95
+ axis k — for CASelectAxis / CAGrid this is just `parent->dim[k]`, but
96
+ for a flat-index view (CASelect) it is
99
97
  `{parent->elements}` (a single-axis flat view of parent). This
100
98
  decouples descriptor.ndim from parent.ndim so the engine can drive
101
99
  views whose iteration axes don't match the parent's physical shape.
@@ -103,13 +101,17 @@ typedef struct {
103
101
  Pointer arguments are typed `void *` here to avoid pulling the
104
102
  private CASelectAxis / CAGrid struct definitions (which live in
105
103
  their respective .c files) into this header. Each implementation
106
- casts to its concrete type inside the .c file. */
104
+ casts to its concrete type inside the .c file.
105
+
106
+ An INDEX axis has no way to say "no cell": a CAGrid index that is
107
+ masked (a hole) is written as index 0, so a caller driving a holed grid
108
+ through the engine reads and writes parent cell 0 there. */
107
109
  void ca_select_axis_describe_axes (void *ca, ca_axis_desc_t *out,
108
110
  ca_size_t *out_parent_dims);
109
111
  void ca_grid_describe_axes (void *ca, ca_axis_desc_t *out,
110
112
  ca_size_t *out_parent_dims);
111
113
 
112
- /* ---- D3: common attach engine --------------------------------------------
114
+ /* ---- common attach engine -------------------------------------------------
113
115
 
114
116
  Drives gather from `parent` into an output buffer driven by the
115
117
  per-axis descriptor array. Caller must have parent attached before
@@ -119,14 +121,15 @@ void ca_grid_describe_axes (void *ca, ca_axis_desc_t *out,
119
121
  descriptor axis (see producer interface above). The engine never
120
122
  reads `parent->dim` directly — it only reads `parent->ptr` for
121
123
  data access — which is what allows flat-index views to lie about
122
- parent's apparent shape (Tier 2.A, PROPOSAL_FLAT_INDEX_VIEWS.md).
124
+ parent's apparent shape.
123
125
 
124
126
  `bound_fill` is the bytes-wide value written into gather output
125
- cells whose SHIFT axes resolve to an out-of-bounds parent index
126
- (Tier 2.B, PROPOSAL_BOUND_AWARE_VIEWS.md). Pass NULL when no
127
- SHIFT axis is present (CSA / CAGrid / CASelect / CAMapping); the
128
- engine ignores it. On scatter, the engine simply skips parent
129
- writes for OOB cells regardless of bound_fill.
127
+ cells whose SHIFT axes resolve to an out-of-bounds parent index.
128
+ Pass NULL when no SHIFT axis is present (CASelectAxis / CAGrid /
129
+ CASelect); the engine ignores it. On scatter, the engine simply skips
130
+ parent writes for OOB cells regardless of bound_fill. A SHIFT axis
131
+ under the RUBY or STRICT policy raises IndexError part way through the
132
+ walk for an index outside the parent.
130
133
 
131
134
  _gather — caller provides out_buf (must be sized total_elements*bytes)
132
135
  _attach — wrapper that mallocs the buffer; caller xfrees
@@ -160,7 +163,7 @@ void ca_axis_dispatch_scatter (struct _CArray *parent,
160
163
  ca_size_t total_elements,
161
164
  const char *in_buf);
162
165
  /* Broadcast scatter: write the single value `val` (bytes wide) into
163
- every selected parent cell. See D6 of the framework piece.
166
+ every selected parent cell.
164
167
  (SHIFT axis OOB cells are skipped — fill semantics aren't
165
168
  meaningful for broadcast-write since the destination value already
166
169
  IS the broadcast value.) */