carray 3.0.4 → 3.0.6

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +438 -0
  3. data/README.md +1 -1
  4. data/carray.gemspec +3 -2
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_dispatch.c +19 -20
  7. data/ext/ca_axis_group.c +1 -1
  8. data/ext/ca_categorical_iterator.c +34 -27
  9. data/ext/ca_compare.c +4 -4
  10. data/ext/ca_composite_dispatch.c +9 -9
  11. data/ext/ca_kernel_iterator.c +122 -237
  12. data/ext/ca_kernel_iterator.h +522 -337
  13. data/ext/ca_obj_array.c +69 -19
  14. data/ext/ca_obj_bincmp.c +10 -1
  15. data/ext/ca_obj_binop.c +11 -1
  16. data/ext/ca_obj_bitarray.c +5 -1
  17. data/ext/ca_obj_bitfield.c +60 -43
  18. data/ext/ca_obj_byte_swap.c +4 -1
  19. data/ext/ca_obj_const_string.c +15 -3
  20. data/ext/ca_obj_face.c +44 -1
  21. data/ext/ca_obj_fake.c +3 -1
  22. data/ext/ca_obj_field.c +13 -3
  23. data/ext/ca_obj_grid.c +219 -17
  24. data/ext/ca_obj_meld.c +69 -113
  25. data/ext/ca_obj_moncmp.c +9 -1
  26. data/ext/ca_obj_monop.c +86 -12
  27. data/ext/ca_obj_object.c +118 -32
  28. data/ext/ca_obj_record.c +3 -0
  29. data/ext/ca_obj_reduce.c +19 -1
  30. data/ext/ca_obj_refer.c +80 -26
  31. data/ext/ca_obj_remap.c +69 -10
  32. data/ext/ca_obj_roll.c +27 -6
  33. data/ext/ca_obj_select.c +38 -6
  34. data/ext/ca_obj_select_axis.c +1 -0
  35. data/ext/ca_obj_shift.c +32 -7
  36. data/ext/ca_obj_stack.c +311 -111
  37. data/ext/ca_obj_stride.c +159 -64
  38. data/ext/ca_obj_string.c +27 -2
  39. data/ext/ca_obj_tile.c +28 -7
  40. data/ext/ca_obj_transpose.c +8 -4
  41. data/ext/ca_obj_triop.c +12 -1
  42. data/ext/ca_obj_window.c +80 -50
  43. data/ext/ca_op_ipower.c +12 -12
  44. data/ext/ca_sort_kernels.h +6 -3
  45. data/ext/caframe_csv_reader.c +1 -1
  46. data/ext/carray.h +35 -1
  47. data/ext/carray_access.c +43 -67
  48. data/ext/carray_address_basis.c +134 -0
  49. data/ext/carray_attribute.c +32 -0
  50. data/ext/carray_broadcast.c +3 -4
  51. data/ext/carray_build_flags.h +1 -1
  52. data/ext/carray_cast.c +251 -93
  53. data/ext/carray_cast_func.rb +56 -26
  54. data/ext/carray_conversion.c +11 -7
  55. data/ext/carray_core.c +814 -72
  56. data/ext/carray_count.c +6 -0
  57. data/ext/carray_element.c +22 -13
  58. data/ext/carray_factorize.c +20 -20
  59. data/ext/carray_generate.c +8 -2
  60. data/ext/carray_histogram.c +26 -4
  61. data/ext/carray_index_classifier.c +4 -4
  62. data/ext/carray_internal.h +159 -12
  63. data/ext/carray_kernels_bincmp.c +2174 -170
  64. data/ext/carray_kernels_binop.c +25653 -5487
  65. data/ext/carray_kernels_init.c +8 -8
  66. data/ext/carray_kernels_moncmp.c +96 -96
  67. data/ext/carray_kernels_monop.c +12253 -5235
  68. data/ext/carray_kernels_reduce_aggregate.c +6150 -2423
  69. data/ext/carray_kernels_reduce_boolean.c +1533 -15
  70. data/ext/carray_kernels_reduce_cumulative.c +2442 -882
  71. data/ext/carray_kernels_reduce_extreme.c +5658 -1661
  72. data/ext/carray_kernels_reduce_variance.c +2534 -402
  73. data/ext/carray_kernels_scan.c +368 -368
  74. data/ext/carray_kernels_search.c +4551 -604
  75. data/ext/carray_kernels_sort.c +659 -751
  76. data/ext/carray_kernels_triop.c +114 -114
  77. data/ext/carray_key_windows.c +4 -0
  78. data/ext/carray_lazy.c +47 -0
  79. data/ext/carray_loop.c +1 -1
  80. data/ext/carray_mask.c +175 -161
  81. data/ext/carray_median_percentile.c +4 -4
  82. data/ext/carray_memory_view.c +15 -9
  83. data/ext/carray_operator.c +152 -49
  84. data/ext/carray_order.c +230 -10
  85. data/ext/carray_random.c +22 -19
  86. data/ext/carray_scatter.c +24 -7
  87. data/ext/carray_slab.c +128 -29
  88. data/ext/carray_sort.c +224 -16
  89. data/ext/carray_sort_kernel.c +5 -7
  90. data/ext/carray_struct.c +35 -43
  91. data/ext/carray_test.c +74 -19
  92. data/ext/carray_time_text.c +6 -4
  93. data/ext/carray_utils.c +63 -21
  94. data/ext/extconf.rb +11 -0
  95. data/ext/mkkernel.rb +546 -199
  96. data/ext/ruby_carray.c +4 -1
  97. data/ext/version.h +4 -4
  98. data/lib/carray/attribute.rb +42 -5
  99. data/lib/carray/autoload_carray.rb +3 -3
  100. data/lib/carray/autoload_method_extension.rb +5 -3
  101. data/lib/carray/axis_group.rb +13 -7
  102. data/lib/carray/basics.rb +28 -8
  103. data/lib/carray/block_iterator.rb +17 -3
  104. data/lib/carray/categorical.rb +35 -23
  105. data/lib/carray/categorical_iterator.rb +8 -8
  106. data/lib/carray/complex.rb +2 -2
  107. data/lib/carray/conditional.rb +3 -2
  108. data/lib/carray/const_string.rb +10 -0
  109. data/lib/carray/data_type_extension.rb +8 -1
  110. data/lib/carray/fixlen_string.rb +41 -2
  111. data/lib/carray/frame/column_verbs.rb +48 -16
  112. data/lib/carray/frame/concat.rb +17 -3
  113. data/lib/carray/frame/convert.rb +19 -0
  114. data/lib/carray/frame/csv_parser.rb +32 -32
  115. data/lib/carray/frame/describe.rb +4 -2
  116. data/lib/carray/frame/frame.rb +405 -85
  117. data/lib/carray/frame/group.rb +777 -64
  118. data/lib/carray/frame/io.rb +212 -72
  119. data/lib/carray/frame/join.rb +146 -37
  120. data/lib/carray/frame/records.rb +3 -3
  121. data/lib/carray/frame/reshape.rb +89 -11
  122. data/lib/carray/frame/sort.rb +57 -9
  123. data/lib/carray/frame/verbs.rb +384 -49
  124. data/lib/carray/frame/windows.rb +44 -6
  125. data/lib/carray/fuse_source.rb +31 -2
  126. data/lib/carray/inspect.rb +7 -2
  127. data/lib/carray/iterator.rb +32 -0
  128. data/lib/carray/lazy.rb +52 -8
  129. data/lib/carray/mask_gap_fill.rb +37 -17
  130. data/lib/carray/meld_reduce.rb +1 -1
  131. data/lib/carray/methods/choose.rb +3 -2
  132. data/lib/carray/methods/is_in.rb +8 -1
  133. data/lib/carray/methods/meshgrid.rb +3 -1
  134. data/lib/carray/runtime.rb +47 -8
  135. data/lib/carray/segment_iterator.rb +35 -16
  136. data/lib/carray/serialize.rb +53 -19
  137. data/lib/carray/stack.rb +33 -18
  138. data/lib/carray/string.rb +8 -0
  139. data/lib/carray/string_operation_extension.rb +13 -5
  140. data/lib/carray/struct_builder.rb +5 -3
  141. data/lib/carray/time.rb +112 -68
  142. data/lib/carray/window_iterator.rb +16 -4
  143. data/yard-stubs/ca_obj_array.rb +26 -1
  144. data/yard-stubs/ca_obj_transpose.rb +5 -4
  145. data/yard-stubs/carray_attribute.rb +3 -1
  146. data/yard-stubs/carray_cast.rb +10 -5
  147. data/yard-stubs/carray_conversion.rb +13 -3
  148. data/yard-stubs/carray_element.rb +7 -6
  149. data/yard-stubs/carray_mask.rb +28 -4
  150. data/yard-stubs/carray_math.rb +45 -20
  151. data/yard-stubs/carray_memory_view.rb +7 -0
  152. data/yard-stubs/carray_order.rb +100 -4
  153. data/yard-stubs/carray_scatter.rb +7 -5
  154. data/yard-stubs/carray_test.rb +7 -4
  155. metadata +18 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2edeb545754cf31d330c667913471c1a0035c97de72dabad7e7b2afb4fe272b
4
- data.tar.gz: 8b34390fcabbb04c5e1f0926ae103052345196112ec3a6a16f244fb310df5583
3
+ metadata.gz: 7012a2c73c33e52e9b5dd18d5fd0e7c02b4c741bb650a41cefbfea117449da2f
4
+ data.tar.gz: 5731ca96689f1d87d9c4e1e6a4764893eac0e39f8126f91695b2042581ae198f
5
5
  SHA512:
6
- metadata.gz: 0f7430ff0556faf7b609673fb8cf9ef08279e226192995ea58a5dd203e5285733582c5cff0405fc753c39cad7056acd9194f55ba26ce9eb1d1a27cf1de8e37f0
7
- data.tar.gz: 48d35829402ba2949e865712d8aa89dd9d4228f0ca4abf62719d3b2d32280541d1c6b7b01dba3e2a68927a89e258e0d6b474a20fc6177415154e1ab57f2b380d
6
+ metadata.gz: 1e05efbfc29639882cc08753c9394400abb707df063025a7ae5bfed6c006979721d8b0030ae17a4eab1397c89c7c3803bf9fa2ec62fa7aa9d8c56e1adb38bd79
7
+ data.tar.gz: 21baa2d1fac6d2c45a1ed47b4235e9f1832beb4063e93491743470ac77805c266210139d7af834ca1d014ec410ae43191228679a72004c14af6c2fa91eb88eba
data/CHANGELOG.md CHANGED
@@ -34,6 +34,444 @@ 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.6
38
+
39
+ - New: `CAFrame` answers the column reductions itself, as a frame of one
40
+ row (`df.mean`, `df.sum("rain", "temp")`), and the running values down
41
+ all its rows (`df.cumsum("rain")`, `order`), as a grouped frame does
42
+ down each group. `percentile(p, *names)` and `quantile` (a column per
43
+ quartile, `"rain_p0"` ... `"rain_p100"`) are added to the frame, groups
44
+ and windows.
45
+
46
+ - New: `CAFrame` row picks: `nlargest` / `nsmallest` (also on
47
+ `GroupedFrame`), `drop_masked` for the rows with no masked cell,
48
+ `GroupedFrame#head` / `#tail` for the first and last rows of each group,
49
+ and `filter` given a boolean selector directly (`df.filter(df["n"] > 3)`).
50
+
51
+ - New: `CAFrame#transform` computes columns with a block, keeping their
52
+ names and the index. `select`, `drop`, `transform` and `describe` pick
53
+ columns by a Range of names, a Regexp, a kind (`:float`, `:integer`,
54
+ `:complex`, `:timedelta`, ...) or a data type.
55
+
56
+ - New: `CAFrame#value_counts` (how many rows hold each value, as a
57
+ frame), `#strip_mask` (the masked cells filled, in a new frame), `#to_a`
58
+ (the rows as Arrays, masked cells `UNDEF`), `#shape`, `#empty?`, and
59
+ `GroupedFrame#each` and `#size`. `CAFrame#==` compares two frames by
60
+ their table: names, columns, index and row axis name.
61
+
62
+ - New: `CAFrame#lag` and `GroupedFrame#lag` take a distance of the key,
63
+ `before: "1 hour"` or `after:`, giving each row the value of the row at
64
+ exactly that distance (`UNDEF` where there is none). The key is the
65
+ index or the column `on:` names: a time, a duration or a number.
66
+
67
+ - New: `join` and `join_asof` take a key named differently on the two
68
+ sides, and `view: :full`, which gives every column of the result as a
69
+ view, with holes for the unmatched rows, so a write reaches either
70
+ frame.
71
+
72
+ - New: `df[name] = value` with a single value repeats it on every row.
73
+ `fill` takes several columns, an Array of names or a Hash of column =>
74
+ value; `rename` takes a block, can exchange two names, and renames the
75
+ index under its name. `sort_by_key` and `sort_by` take `descending:`.
76
+
77
+ - New: `CAFrame#set_column_attrs` gives columns their names and common
78
+ attributes; `CArray#attrs_symkey` and `CAFrame#attrs_symkey` return the
79
+ attributes with Symbol keys. `CAFrame#to_csv` takes `precision:`.
80
+
81
+ - New: `GroupedFrame#fill(name, :linear)` interpolates within each group.
82
+ On a frame, `:linear` reads an index that is not in order as one series
83
+ in index order.
84
+
85
+ - New: `melt` brings number columns of different types (an `int64` and a
86
+ `float64` column) to their common type, still as a view. A mixture no
87
+ type holds without changing a value (`int64` beside `uint64`), or one
88
+ with text or time, is refused; cast the columns first.
89
+
90
+ - New: `wsum` and `wmean` take weights shaped as the reduced axes, matched
91
+ in ascending axis order, besides a scalar and weights of the receiver's
92
+ shape.
93
+
94
+ - New (C extensions and carray-jit): `CArray::AddressBasis.sweep(function,
95
+ fsync, arrays, *parts)` runs a chunked element-wise sweep
96
+ (`ca_call_cslab_N_r`, arities 1 to 7) from Ruby, handing the slab
97
+ pointers to the parts' own String bytes. An `fsync` character other than
98
+ `0` or `1` is refused.
99
+
100
+ - Change: CArray requires Ruby 3.2 or later, up from 3.0. On an older
101
+ Ruby, `gem install carray` does not offer this release; install a
102
+ newer Ruby with a version manager such as rbenv or mise, or stay on
103
+ 3.0.5.
104
+
105
+ - Change: CSV reading and writing are split by what they take.
106
+ `CAFrame.read_csv` and `#write_csv` take a path or an IO;
107
+ `CAFrame.from_csv` takes CSV text as a String and `#to_csv` returns it.
108
+ Code that gave `from_csv` a path or an IO calls `read_csv`, and
109
+ `to_csv(path)` becomes `write_csv(path)`. No aliases are kept.
110
+
111
+ - Change: `read_csv` and `from_csv` infer the column types by default
112
+ (`int64`, `float64`, `boolean`, `time`, otherwise text); `types:` names
113
+ some columns and the rest are still inferred. Pass `types: :string` to
114
+ read every column as text, as before. A column with a blank but present
115
+ value (a quoted `""`) stays text.
116
+
117
+ - Change: `CAFrame#set_index`, `#reset_index`, `#cast`, `#promote`,
118
+ `#parse_to_time` and `#to_time` return a new frame and leave the
119
+ receiver as it is (the two share their columns). Assign the result:
120
+ `df = df.set_index("time")`.
121
+
122
+ - Change: a `GroupedFrame` reduction given column names returns a frame of
123
+ those columns, one row per group, labelled as without names; it
124
+ returned the `CArray` (one name) or an `Array` of them. Take the column
125
+ (`grp.mean("temp")["temp"]`) or reduce the group iterator
126
+ (`grp["temp"].mean`) for the values alone.
127
+
128
+ - Change: a `GroupedFrame` or window value on the frame's rows given
129
+ several column names (`keep_rows: true`, the running values, `lag`,
130
+ `w.mean("a", "b")`) returns a frame of them on the frame's rows and
131
+ index, instead of an `Array`. One name still gives the `CArray`.
132
+
133
+ - Change: `CAFrame#filter` no longer takes `keep_masked:`, so every row
134
+ selection is a view. To keep the rows whose condition is undetermined,
135
+ say so in the selector: `df.filter(cond.is_masked)` or
136
+ `df.filter(cond.strip_mask(true))`.
137
+
138
+ - Change: `df[sel] = ...` refuses a Ruby Array as the row selector, as
139
+ `df[]` does; the column indexer would read `[0, 2]` as two rows from
140
+ row 0. Write `df[CA_INT64([0, 2])]` for rows 0 and 2.
141
+
142
+ - Change: a group key named in a `GroupedFrame` reduction, and the index's
143
+ name given to a verb that reads or changes columns (`df[...]`,
144
+ `select`, `fill`, `cast`, the reductions), raise and point at `size`
145
+ or `df.index`. A key argument (`group_by`, `sort_by_key`, `join(on:)`)
146
+ still names the index.
147
+
148
+ - Change: an `:inner` or `:right` `join` gives the other frame's columns
149
+ as views picked by row, not copies, so a write to them reaches that
150
+ frame. Call `copy` on the result to keep it apart.
151
+
152
+ - Change: a `CScalar` takes only `s[]` and `s[0]`, reading or writing its
153
+ one cell; any other index (`s[3]`, a range, `nil`, an index array)
154
+ raises. A view such as `s.refer(s.data_type, [1])` takes the usual
155
+ indexes.
156
+
157
+ - Change: `CArray.stack` and `CArray.meld` refuse a value array
158
+ (`a.value`) or a mask array (`a.mask`) as a part. Pass a copy
159
+ (`a.value.copy`), or `a.is_masked` for the mask's values.
160
+
161
+ - Change: `CArray#==` finds a NaN equal to a NaN, so an array holding NaN
162
+ equals its copy and the array read back from a file. The cell-by-cell
163
+ IEEE comparison is `eq`; `eql?` still compares bits.
164
+
165
+ - Change: `CARemap#mapper` returns a read-only array; writing it raises.
166
+ The index array given to `a[idx]` is not affected.
167
+
168
+ - Change: `Marshal.dump` of a `CAWrap` (from `CArray.wrap_memory_view`)
169
+ writes its values, and the load gives a plain array owning a copy of
170
+ them, as for a view of the wrap; it raised `TypeError`.
171
+
172
+ - Change: `as_type` returns a view also when the data type is the
173
+ receiver's own, and `CATime#to_unit` / `CATimedelta#to_unit` return a
174
+ new array when the unit does not change, so an attribute set on, or a
175
+ freeze of, the result does not reach the receiver.
176
+
177
+ - Change: `wmean` gives `UNDEF` where the weights sum to zero, on every
178
+ path; numeric arrays gave NaN or an infinity. A weight array with one
179
+ element is no longer read as a scalar: give a Ruby number or a
180
+ `CScalar`.
181
+
182
+ - Change: a computation over an object array that comes back into the
183
+ array (a cell holding the array, or a view of it) raises, as reading
184
+ such a cell does; it recursed until the process died. A lazy
185
+ expression over such an array (a cell holding `x + 1` for the array `x`)
186
+ raises the same way instead of overflowing the stack or not ending, and
187
+ so does `Marshal.dump` of an object view whose cells lead back to its
188
+ root.
189
+
190
+ - Change (CAObject authors): a `CAObject` without `create_mask` raises
191
+ `TypeError` when its `copy_data` writes `UNDEF`, as it does when a
192
+ fetcher answers `UNDEF`; the `UNDEF` was dropped and read as a value.
193
+
194
+ - Change (C extensions): `ca_install_obj_type` refuses an operation table
195
+ without `allocate`, `attach`, `sync` and `detach` slots;
196
+ `ca_iter_register_source_kind` refuses carray's own types; and the
197
+ kernel iterator's `FIBER_PAIR` forms refuse `CA_KERNEL_WRITE`.
198
+
199
+ - Fix: `require "carray"` works on Ruby 4.0; it raised
200
+ `Ractor::IsolationError` since 3.0.4.
201
+
202
+ - Fix: `CArray.fuse` works on Ruby 3.2 and 3.3. The gem now depends on
203
+ prism 1.0 or later, which `gem install` and Bundler bring in on Ruby
204
+ 3.2, which ships none, and 3.3, whose own prism is too old; Ruby 3.4
205
+ and later already ship it.
206
+
207
+ - Fix: a block of a reshape over a strided view
208
+ (`a[1..2, 1..3].reshape(3, 2)[0..1, nil]`) read and wrote past the end
209
+ of a row, outside the buffer at the edges.
210
+
211
+ - Fix: a frozen object array shared between Ractors can be computed over
212
+ in several at once; it was refused as cyclic. A cell holding a view of
213
+ other cells of the same array is no longer refused.
214
+
215
+ - Fix: a record array (`CARecord`) exports through MemoryView from a
216
+ Ractor other than the main one; it raised `Ractor::IsolationError`.
217
+
218
+ - Fix: `Marshal.dump` of a view no longer writes its whole parent (a
219
+ one-cell view of a 100,000-cell array dumped about 400 KB), and an
220
+ array's mask marshals as a plain boolean array.
221
+
222
+ - Fix: an `each_slab` Enumerator stopped part way with `next` leaves no
223
+ array attached once its Fiber is collected.
224
+
225
+ - Fix: a window or block iterator reads its source afresh on each call;
226
+ after the source changed, a later reduction mixed new sums with old
227
+ counts.
228
+
229
+ - Fix: a frozen or read-only `CArray.meld` refuses writes through a meld
230
+ of it (`CArray.meld(m, m)` wrote into the frozen root).
231
+
232
+ - Fix: a write to a `CArray.stack` or `CArray.meld` whose parts share
233
+ cells (`CArray.meld(a, a)`) gives those cells the value, or the mask, of
234
+ the last part; `add!` could leave an earlier part's result, and a mask
235
+ write masked the cells of every part.
236
+
237
+ - Fix: a write to a `CArray.stack` or `CArray.meld` that one part refuses
238
+ (a value outside a part's data type) writes nothing; the parts before
239
+ it were written.
240
+
241
+ - Fix: `blocks(...).sort_addr` works when the source holds more than one
242
+ tile; it failed with `IndexError`.
243
+
244
+ - Fix: `elem_fetch` answers a boolean cell with `true` or `false` when given
245
+ an index array over a view, as `[]` does; it answered `0` or `1`.
246
+
247
+ - Fix: `CAFrame#fill(:linear)` leaves a row with no coordinate out of the
248
+ interpolation; it was filled with 0.
249
+
250
+ - Fix: `bin_to` and `histogram1d` put a value next to an edge in the bin
251
+ that edge bounds when the edges are nearly but not exactly equally
252
+ spaced.
253
+
254
+ - Fix: `float ** Integer` takes any exponent that fits 64 bits, eagerly
255
+ as lazily, and `x.lazy.pow(k)` answers as `x.pow(k)`. A lazy array
256
+ compared with `UNDEF` (`eq`, `ne`) answers as the eager one does.
257
+
258
+ - Fix: writing `UNDEF` through a widening `refer` (`r.refer(:float64,
259
+ ...)`) no longer masks parent cells outside the written cells, and a
260
+ mask written onto a `CAObject` without mask hooks survives the next
261
+ read of its values.
262
+
263
+ - Fix: a masked cell that is not a String reads as `""` when a `CAString`
264
+ wraps a view, as it does over an entity.
265
+
266
+ - Fix (CASource authors): a source that leaves its `ptr` NULL at rest no
267
+ longer crashes `elem_*`, `dump_binary` to a File or `nlargest` over a
268
+ whole axis.
269
+
270
+ ## 3.0.5
271
+
272
+ - New: `GroupedFrame#aggregate` takes a block instead of a spec. The block
273
+ is given the grouping once and returns a Hash of output name => a
274
+ CArray with one value per group, built from `g["col"]` iterators and
275
+ CArray arithmetic (`g["temp"].max - g["temp"].min`). `grp[array]`
276
+ groups any CArray with one entry per row, such as a value computed
277
+ from columns or a column with cells masked.
278
+
279
+ - New: a `CAFrame` grouped reduction takes a Hash of column name => value
280
+ as `fill_value:`, filling only the named columns. A single
281
+ `fill_value:` still goes to every column and has to suit each.
282
+
283
+ - New: `CArray.meld` brings pieces of different data types to a common
284
+ one, as `CArray.stack` does, and takes `data_type:`. `CAFrame.meld` and
285
+ a frame splice still refuse a column whose pieces differ in data type;
286
+ cast the column first, or use `concatenate`.
287
+
288
+ - New: `scatter_replace!` takes an object or fixed-length array, as
289
+ `put_nd` and `put_along_axis` do. The accumulating members
290
+ (`scatter_add!` and the others) still take numeric arrays only.
291
+
292
+ - New: `CAConstString#count` and `CACategorical#count` with no argument
293
+ count the cells that are not masked, as `CArray#count` does.
294
+
295
+ - New: `CAFixlenString` answers `minmax`, `cummax` and `cummin`, as
296
+ `CAString` does.
297
+
298
+ - New (C extensions): `carray.h` defines `ca_u_<type>` cell types and
299
+ `CA_U(type)`, of the same size and value as the plain types but with no
300
+ alignment requirement, for reading cells that need not be aligned (a
301
+ refer with a byte offset, a struct member, a wrapped buffer). The slab
302
+ macros in `ca_kernel_iterator.h` use them for their pointers.
303
+
304
+ - Change: `CACategorical#sort_addr` is renamed `group_addr`, the order of
305
+ the cells by category. `sort_addr` on a categorical now raises, as
306
+ `sort_index` does, since a categorical has no order of values.
307
+
308
+ - Change: a Face's `parent` (of a `CATime`, `CARecord`, ...) is a
309
+ read-only view of its storage. Write the storage of a time through
310
+ `CATime#ticks`.
311
+
312
+ - Change: an operator that cannot bring two data types together raises
313
+ `CArray::DataTypeError` instead of `TypeError`. `DataTypeError` is a
314
+ `TypeError`, so `rescue TypeError` still catches it.
315
+
316
+ - Change: a float cell with no integer of the target type -- an infinity,
317
+ or a value out of the type's range -- is now treated the way NaN
318
+ already was. `to_type` (`int32`, `as_int64`, ...) masks it to `UNDEF`;
319
+ storing it into an integer array raises `RangeError`
320
+ (`FloatDomainError` for an infinity). Before, it became whatever the
321
+ machine's C conversion gave, which differed between x86 and ARM.
322
+ `clip_int64` and the other `clip_<type>` methods saturate a float
323
+ source to the type's limits on every machine; integer `linspace` raises
324
+ `RangeError` for a span the type cannot hold.
325
+
326
+ - Change: a Ruby Array operand of a numeric or boolean array is read as
327
+ its cells: `a.eq([1, 5, 3])` compares cell by cell (it compared every
328
+ cell with the whole Array), and `a + [1, 2, 3]` adds (it raised).
329
+ Nested Arrays give the axes. An object array still takes an Array as
330
+ one value.
331
+
332
+ - Change: `window`'s `bounds:` is a policy named by a Symbol or String,
333
+ matched whole; an Integer and an abbreviation raise. A `fill_value:`
334
+ given with a policy that does not use it (`:nearest`, `:strict`, ...)
335
+ raises instead of being dropped.
336
+
337
+ - Change: a length, count, offset or shift given to a view
338
+ (`sliding_windows`, `block_view`, `tile`, `roll`, `shift`, `field`,
339
+ `diagonal`) must be an Integer; a Float raises `TypeError` instead of
340
+ being truncated. `transpose` reads its axes as the other axis arguments
341
+ are read: negative from the end, an Integer only.
342
+
343
+ - Change: `drop_axis` on an array whose every axis has size 1 keeps one
344
+ axis of size 1, and `reshape` with no axes raises.
345
+
346
+ - Change: in an index of one key per axis, an index array of more than
347
+ one axis on one axis raises `ArgumentError`; it was read flat. Pass
348
+ `idx.flatten` for the old reading.
349
+
350
+ - Change: `elem_fetch`, `elem_store` and the other `elem_*` methods read
351
+ an index as `[]` reads a key: a Float with no fraction is an index, a
352
+ Float with a fraction raises `IndexError`.
353
+
354
+ - Change: two string arrays of different kinds (`CAString`,
355
+ `CAFixlenString`, `CAConstString`) or of different widths compare by
356
+ their strings. A String query longer than a fixed-width cell matches
357
+ no cell in `eq`, `count`, `search`, `bsearch` and `is_in`; it was cut
358
+ to the cell's width.
359
+
360
+ - Change: `str_index` and `rindex` give `UNDEF` for a cell that does not
361
+ hold the substring; they raised for the whole array.
362
+
363
+ - Change: `bsearch` and `bsearch_addr` answer the first of several equal
364
+ cells.
365
+
366
+ - Change: `search` and `search_addr` raise `ArgumentError` for a negative
367
+ or NaN `eps`, which acted as an exact match.
368
+
369
+ - Change: `inherit_mask` and `inherit_mask_replace` raise `ArgumentError`
370
+ for a source whose number of cells differs from the receiver's (a
371
+ scalar source still applies to every cell).
372
+
373
+ - Change: a reduction's `fill_value:` that its result cannot hold raises
374
+ even when no cell needs it, and `fill` on an empty array checks its
375
+ value as an assignment does.
376
+
377
+ - Change: rounding a `:M` or `:Y` `CATime` to a calendar bucket
378
+ (`round(unit: :Y)`, `"3 months"`) measures the distance by the instant,
379
+ so it agrees with the same dates on `:D`.
380
+
381
+ - Change: a `CATime` reduction (`mean`, `median`, ...) sends a tie to the
382
+ later tick on both sides of 1970; before 1970 it went to the earlier
383
+ one.
384
+
385
+ - Change: a duration String added to or subtracted from a `CATime` is
386
+ one step of its own resolution, so `"15 minutes"` on a `"10 minutes"`
387
+ grid raises, as the same duration as a `CATimedelta` does. It was read
388
+ as fifteen one-minute steps and cut to the grid.
389
+
390
+ - Change: of `-0.0` and `0.0`, `pmax` gives `0.0` and `pmin` gives
391
+ `-0.0`, in either order and on every platform, as `maximum` and
392
+ `minimum` do. Which zero `min` and `max` answer is not specified.
393
+
394
+ - Change: a one-sided `clip` passes a NaN cell through, as a two-sided
395
+ `clip` does.
396
+
397
+ - Change: a categorical's `fill_value:` (of `shift`, `window`, `project`)
398
+ is a label; a `CAConstString` takes only `UNDEF` as a fill value.
399
+
400
+ - Change: a lazy operator with a Face operand (a categorical, a time, a
401
+ string array) answers as the eager operator does; it read the Face's
402
+ storage. `CAConstString#eq` with another array compares cell by cell.
403
+
404
+ - Change: a boolean member of a record (or `field(offset, :boolean)` of a
405
+ fixed-length array) raises `RangeError` when read as a byte that is not
406
+ 0 or 1, instead of answering differently in each method.
407
+
408
+ - Change: unmasking a cell of a `CAString` that holds no String gives an
409
+ empty String.
410
+
411
+ - Change: `swap_bytes` keeps the attributes, as `refer` and `bitfield`
412
+ do. An array with no cells has no say in the attributes a `meld`,
413
+ `stack` or `concatenate` keeps.
414
+
415
+ - Change: `dim_view` keeps a Face, as `transpose` does.
416
+
417
+ - Change: `CArray.string(n)` without a block, and `CArray.string("ab")`,
418
+ raise; `fixlen_string` and `to_fixlen_string` raise for `bytes:` below 1.
419
+ `project` raises for a keyword argument, `paste` into a frozen array
420
+ raises `FrozenError`, and `CArray.result_type` refuses a MemoryView
421
+ operand whose format carray cannot read, as the operators do.
422
+
423
+ - Change: `CArray.sort_addr` with numeric keys is two to three times as fast, and
424
+ `nlargest` / `nsmallest` read each fiber once with a work area of a
425
+ few times n.
426
+
427
+ - Fix: x86-64 Linux. Inputs that reached an integer division by zero
428
+ inside the library stopped the process with SIGFPE there (on ARM they
429
+ were refused later or gave a wrong answer): a sum over a view with a
430
+ zero-length axis, `wsum` / `wmean` with 1-D weights over a zero-length
431
+ axis, a view of a stack of empty arrays, `window` with a step of 0, and
432
+ `wrap_readonly(String, CA_FIXLEN)`. Each now answers or raises
433
+ `ArgumentError`. The extension builds with GCC 14 without warnings.
434
+
435
+ - Fix: big-endian hosts. `bitfield` read 0 and lost writes, a struct's
436
+ bit members overwrote each other, and an element-wise operation applied
437
+ in place could give a wrong cell.
438
+
439
+ - Fix: `save` and `dump` with `endian: :little` or `:big` wrote the other
440
+ byte order. `load` reads the marker, so files written so far still load
441
+ correctly.
442
+
443
+ - Fix: running out of memory inside a kernel left a view attached, lost
444
+ the keywords of the call (`a.sum(axis: 1)` returned the total), or
445
+ leaked the array being built.
446
+
447
+ - Fix: an array with 16 axes (the maximum) given to `bitarray`, `field`,
448
+ a narrowing `refer` or a `:_` index wrote past an internal array.
449
+
450
+ - Fix: a lazy chain whose step narrows the cells (`a.lazy.abs` of a
451
+ complex array) overran the heap; `seq` on an empty object array wrote
452
+ past its end.
453
+
454
+ - Fix: a CAObject's copy and sync hooks: a view the hook kept of the
455
+ array it was lent, or the lent array's mask, pointed at freed memory
456
+ after the hook returned.
457
+
458
+ - Fix: `CArray.fuse` crashed when several Ractors ran a fuse block for the
459
+ first time at once.
460
+
461
+ - Fix: a grouped `variancep` / `stddevp` matches `CArray#variancep` to the
462
+ last bit.
463
+
464
+ - Fix: `count` with an array of values honours `keep_axis:`.
465
+
466
+ - Fix: `CARecord.wrap` of a record array wraps its storage, not the
467
+ record array.
468
+
469
+ - Fix: an unnamed struct's `order_by` survives `save` / `load` and
470
+ Marshal.
471
+
472
+ - Fix: `CAFrame.from_csv` and `cast(name => :time)` read a leap second
473
+ (`23:59:60`) as `CArray.time` does, into the next minute.
474
+
37
475
  ## 3.0.4
38
476
 
39
477
  - New: `CAFrame#verify(rules)` judges every row against named rules (each
data/README.md CHANGED
@@ -30,7 +30,7 @@ Or add it to your `Gemfile`:
30
30
  gem "carray"
31
31
  ```
32
32
 
33
- Requires Ruby 3.0 or later.
33
+ Requires Ruby 3.2 or later.
34
34
 
35
35
  On a multi-core machine, parallel `make` cuts install time noticeably:
36
36
 
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.4"
3
+ s.version = "3.0.6"
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"
@@ -17,7 +17,8 @@ Gem::Specification.new do |s|
17
17
  s.homepage = "https://github.com/himotoyoshi/carray"
18
18
  s.license = "MIT"
19
19
  s.platform = Gem::Platform::RUBY
20
- s.required_ruby_version = ">= 3.0"
20
+ s.required_ruby_version = ">= 3.2"
21
+ s.add_dependency "prism", ">= 1.0"
21
22
  s.files = [
22
23
  *Dir.glob("lib/**/*.rb"),
23
24
  *Dir.glob("yard-stubs/**/*.rb"),
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
 
@@ -647,15 +647,15 @@ ca_axis_dispatch_percell_gather (CArray *parent,
647
647
  break;
648
648
  case 2:
649
649
  for (j = 0; j < inner_count; j++)
650
- *(uint16_t *)(row_dst + j*2) = *(uint16_t *)(src + j*inner_step);
650
+ __builtin_memcpy(row_dst + j*2, src + j*inner_step, 2);
651
651
  break;
652
652
  case 4:
653
653
  for (j = 0; j < inner_count; j++)
654
- *(uint32_t *)(row_dst + j*4) = *(uint32_t *)(src + j*inner_step);
654
+ __builtin_memcpy(row_dst + j*4, src + j*inner_step, 4);
655
655
  break;
656
656
  case 8:
657
657
  for (j = 0; j < inner_count; j++)
658
- *(uint64_t *)(row_dst + j*8) = *(uint64_t *)(src + j*inner_step);
658
+ __builtin_memcpy(row_dst + j*8, src + j*inner_step, 8);
659
659
  break;
660
660
  default:
661
661
  for (j = 0; j < inner_count; j++)
@@ -672,18 +672,15 @@ ca_axis_dispatch_percell_gather (CArray *parent,
672
672
  break;
673
673
  case 2:
674
674
  for (j = 0; j < inner_count; j++)
675
- *(uint16_t *)(row_dst + j*2) =
676
- *(uint16_t *)(row_src_base + inner_indices[j]*inner_pstride);
675
+ __builtin_memcpy(row_dst + j*2, row_src_base + inner_indices[j]*inner_pstride, 2);
677
676
  break;
678
677
  case 4:
679
678
  for (j = 0; j < inner_count; j++)
680
- *(uint32_t *)(row_dst + j*4) =
681
- *(uint32_t *)(row_src_base + inner_indices[j]*inner_pstride);
679
+ __builtin_memcpy(row_dst + j*4, row_src_base + inner_indices[j]*inner_pstride, 4);
682
680
  break;
683
681
  case 8:
684
682
  for (j = 0; j < inner_count; j++)
685
- *(uint64_t *)(row_dst + j*8) =
686
- *(uint64_t *)(row_src_base + inner_indices[j]*inner_pstride);
683
+ __builtin_memcpy(row_dst + j*8, row_src_base + inner_indices[j]*inner_pstride, 8);
687
684
  break;
688
685
  default:
689
686
  for (j = 0; j < inner_count; j++)
@@ -761,8 +758,7 @@ ca_axis_dispatch_gather (CArray *parent,
761
758
  so clang lowers to NEON ldp/stp directly (no libc memcpy call). */
762
759
  if ( sbytes == 8 ) {
763
760
  for ( i = 0; i < n; i++ ) {
764
- *(uint64_t *)(out_buf + i*8) =
765
- *(uint64_t *)(base + indices[i] * pstride);
761
+ __builtin_memcpy(out_buf + i*8, base + indices[i] * pstride, 8);
766
762
  }
767
763
  } else if ( sbytes == 16 ) {
768
764
  for ( i = 0; i < n; i++ ) {
@@ -887,15 +883,15 @@ ca_axis_dispatch_percell_scatter (CArray *parent,
887
883
  break;
888
884
  case 2:
889
885
  for (j = 0; j < inner_count; j++)
890
- *(uint16_t *)(dst + j*inner_step) = *(uint16_t *)(row_src + j*2);
886
+ __builtin_memcpy(dst + j*inner_step, row_src + j*2, 2);
891
887
  break;
892
888
  case 4:
893
889
  for (j = 0; j < inner_count; j++)
894
- *(uint32_t *)(dst + j*inner_step) = *(uint32_t *)(row_src + j*4);
890
+ __builtin_memcpy(dst + j*inner_step, row_src + j*4, 4);
895
891
  break;
896
892
  case 8:
897
893
  for (j = 0; j < inner_count; j++)
898
- *(uint64_t *)(dst + j*inner_step) = *(uint64_t *)(row_src + j*8);
894
+ __builtin_memcpy(dst + j*inner_step, row_src + j*8, 8);
899
895
  break;
900
896
  default:
901
897
  for (j = 0; j < inner_count; j++)
@@ -912,18 +908,15 @@ ca_axis_dispatch_percell_scatter (CArray *parent,
912
908
  break;
913
909
  case 2:
914
910
  for (j = 0; j < inner_count; j++)
915
- *(uint16_t *)(row_dst_base + inner_indices[j]*inner_pstride) =
916
- *(uint16_t *)(row_src + j*2);
911
+ __builtin_memcpy(row_dst_base + inner_indices[j]*inner_pstride, row_src + j*2, 2);
917
912
  break;
918
913
  case 4:
919
914
  for (j = 0; j < inner_count; j++)
920
- *(uint32_t *)(row_dst_base + inner_indices[j]*inner_pstride) =
921
- *(uint32_t *)(row_src + j*4);
915
+ __builtin_memcpy(row_dst_base + inner_indices[j]*inner_pstride, row_src + j*4, 4);
922
916
  break;
923
917
  case 8:
924
918
  for (j = 0; j < inner_count; j++)
925
- *(uint64_t *)(row_dst_base + inner_indices[j]*inner_pstride) =
926
- *(uint64_t *)(row_src + j*8);
919
+ __builtin_memcpy(row_dst_base + inner_indices[j]*inner_pstride, row_src + j*8, 8);
927
920
  break;
928
921
  default:
929
922
  for (j = 0; j < inner_count; j++)
@@ -1108,6 +1101,12 @@ ca_axis_view_xfer_all (void *ap, ca_axis_view_fast_t fast, int region_ok,
1108
1101
  if ( ca_attach_is_alias(parent) ) {
1109
1102
  ca_attach(parent); /* window: an alias attach, cannot raise */
1110
1103
  fast(ca, (char *) data, dir);
1104
+ /* An entity that keeps no buffer at rest (the mask of a CAObject, a
1105
+ CASource) attaches a copy, which only its sync writes back; for
1106
+ memory it lends, the sync does nothing. */
1107
+ if ( dir == CA_XFER_PUT ) {
1108
+ ca_sync(parent);
1109
+ }
1111
1110
  ca_detach(parent);
1112
1111
  return;
1113
1112
  }
data/ext/ca_axis_group.c CHANGED
@@ -25,7 +25,7 @@
25
25
  (see the section comment above `rb_ca_axis_group_scan`).
26
26
 
27
27
  Group codes outside [0, k) at any bundle mark the slab element unassigned
28
- (skipped, contributing to no group) — mirrors digitize OOB.
28
+ (skipped, contributing to no group) — mirrors bin_to OOB.
29
29
 
30
30
  Float reductions carry the CArray ε-close contract: relative error bounded,
31
31
  not bit-exact.