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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +568 -0
- data/README.md +6 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +220 -0
- data/ext/ca_axis_group.c +201 -123
- data/ext/ca_binop_dispatch.c +46 -52
- data/ext/ca_binop_dispatch.h +1 -1
- data/ext/ca_categorical_iterator.c +249 -183
- data/ext/ca_compare.c +7 -12
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +38 -23
- data/ext/ca_kernel_iterator.c +1765 -2076
- data/ext/ca_kernel_iterator.h +584 -566
- data/ext/ca_monop_dispatch.c +86 -63
- data/ext/ca_monop_dispatch.h +5 -0
- data/ext/ca_obj_array.c +223 -56
- data/ext/ca_obj_bincmp.c +172 -138
- data/ext/ca_obj_binop.c +116 -230
- data/ext/ca_obj_bitarray.c +40 -26
- data/ext/ca_obj_bitfield.c +100 -68
- data/ext/ca_obj_block.c +19 -9
- data/ext/ca_obj_byte_swap.c +45 -46
- data/ext/ca_obj_const_string.c +269 -44
- data/ext/ca_obj_face.c +612 -89
- data/ext/ca_obj_face.h +111 -47
- data/ext/ca_obj_fake.c +36 -79
- data/ext/ca_obj_farray.c +7 -3
- data/ext/ca_obj_field.c +33 -8
- data/ext/ca_obj_fixlen_string.c +23 -24
- data/ext/ca_obj_grid.c +541 -210
- data/ext/ca_obj_meld.c +331 -111
- data/ext/ca_obj_moncmp.c +80 -65
- data/ext/ca_obj_monop.c +177 -149
- data/ext/ca_obj_object.c +664 -248
- data/ext/ca_obj_record.c +63 -23
- data/ext/ca_obj_reduce.c +18 -16
- data/ext/ca_obj_refer.c +140 -58
- data/ext/ca_obj_remap.c +85 -24
- data/ext/ca_obj_repeat.c +24 -9
- data/ext/ca_obj_roll.c +121 -16
- data/ext/ca_obj_select.c +61 -58
- data/ext/ca_obj_select_axis.c +73 -107
- data/ext/ca_obj_shift.c +32 -102
- data/ext/ca_obj_stack.c +372 -122
- data/ext/ca_obj_stride.c +348 -140
- data/ext/ca_obj_string.c +88 -22
- data/ext/ca_obj_tile.c +38 -21
- data/ext/ca_obj_time.c +45 -31
- data/ext/ca_obj_timedelta.c +43 -29
- data/ext/ca_obj_transpose.c +17 -6
- data/ext/ca_obj_triop.c +125 -141
- data/ext/ca_obj_window.c +330 -44
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +104 -81
- data/ext/ca_sweep_engine.h +7 -20
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +542 -0
- data/ext/carray.h +241 -92
- data/ext/carray_access.c +608 -276
- data/ext/carray_address_basis.c +494 -97
- data/ext/carray_attribute.c +129 -4
- data/ext/carray_bincount.c +39 -7
- data/ext/carray_broadcast.c +56 -19
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_call_cfunc.c +108 -28
- data/ext/carray_cast.c +1576 -223
- data/ext/carray_cast_func.rb +77 -24
- data/ext/carray_class.c +4 -3
- data/ext/carray_conversion.c +208 -75
- data/ext/carray_copy.c +82 -24
- data/ext/carray_core.c +646 -162
- data/ext/carray_count.c +171 -88
- data/ext/carray_element.c +94 -60
- data/ext/carray_factorize.c +670 -324
- data/ext/carray_generate.c +260 -83
- data/ext/carray_histogram.c +209 -106
- data/ext/carray_hold.c +14 -16
- data/ext/carray_index_classifier.c +422 -243
- data/ext/carray_internal.h +692 -3
- data/ext/carray_kernels_bincmp.c +7 -0
- data/ext/carray_kernels_binop.c +487 -120
- data/ext/carray_kernels_init.c +653 -50
- data/ext/carray_kernels_moncmp.c +15 -8
- data/ext/carray_kernels_monop.c +99 -43
- data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
- data/ext/carray_kernels_reduce_boolean.c +112 -36
- data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
- data/ext/carray_kernels_reduce_extreme.c +3032 -2892
- data/ext/carray_kernels_reduce_variance.c +439 -500
- data/ext/carray_kernels_scan.c +1097 -488
- data/ext/carray_kernels_search.c +3787 -2176
- data/ext/carray_kernels_sort.c +1200 -920
- data/ext/carray_kernels_triop.c +479 -7
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +967 -153
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +910 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +299 -100
- data/ext/carray_memory_view.c +872 -758
- data/ext/carray_operator.c +1171 -364
- data/ext/carray_order.c +505 -133
- data/ext/carray_partition.c +112 -65
- data/ext/carray_random.c +327 -239
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +346 -78
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +249 -86
- data/ext/carray_sort.c +224 -227
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +118 -39
- data/ext/carray_test.c +193 -69
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +579 -113
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +19 -4
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1202 -1014
- data/ext/ruby_carray.c +17 -5
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +160 -17
- data/lib/carray/autoload_carray.rb +23 -27
- data/lib/carray/autoload_method_extension.rb +20 -5
- data/lib/carray/axis_group.rb +360 -63
- data/lib/carray/basics.rb +162 -28
- data/lib/carray/bincount_nd.rb +18 -2
- data/lib/carray/block_iterator.rb +231 -58
- data/lib/carray/boolean_reduce.rb +34 -42
- data/lib/carray/categorical.rb +242 -52
- data/lib/carray/categorical_iterator.rb +437 -827
- data/lib/carray/complex.rb +41 -34
- data/lib/carray/conditional.rb +150 -14
- data/lib/carray/const_string.rb +59 -4
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +82 -7
- data/lib/carray/frame/csv_parser.rb +688 -87
- data/lib/carray/frame/describe.rb +80 -0
- data/lib/carray/frame/frame.rb +369 -45
- data/lib/carray/frame/group.rb +631 -90
- data/lib/carray/frame/io.rb +506 -79
- data/lib/carray/frame/join.rb +411 -62
- data/lib/carray/frame/records.rb +116 -19
- data/lib/carray/frame/reshape.rb +455 -0
- data/lib/carray/frame/sort.rb +30 -18
- data/lib/carray/frame/verbs.rb +868 -61
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +4 -0
- data/lib/carray/fuse_source.rb +118 -2
- data/lib/carray/fusion.rb +257 -42
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +54 -13
- data/lib/carray/iterator.rb +99 -9
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +216 -193
- data/lib/carray/mask_gap_fill.rb +112 -92
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +52 -21
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +18 -2
- data/lib/carray/methods/bit_string.rb +15 -4
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +18 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +25 -5
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +140 -10
- data/lib/carray/methods/join.rb +2 -7
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +182 -45
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +65 -17
- data/lib/carray/segment_iterator.rb +1221 -0
- data/lib/carray/serialize.rb +214 -30
- data/lib/carray/slab_iterator.rb +101 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +12 -4
- data/lib/carray/struct.rb +137 -58
- data/lib/carray/struct_builder.rb +124 -17
- data/lib/carray/time.rb +1222 -186
- data/lib/carray/window_iterator.rb +242 -81
- data/lib/carray.rb +9 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +5 -1
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +5 -4
- data/yard-stubs/ca_obj_roll.rb +2 -3
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +9 -5
- data/yard-stubs/carray_access.rb +11 -5
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +88 -43
- data/yard-stubs/carray_conversion.rb +15 -2
- data/yard-stubs/carray_copy.rb +12 -5
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +60 -12
- data/yard-stubs/carray_math.rb +52 -14
- data/yard-stubs/carray_median_percentile.rb +15 -8
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +61 -29
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +21 -9
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +10 -2
- data/yard-stubs/carray_sort.rb +49 -8
- data/yard-stubs/carray_test.rb +15 -3
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -5
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_kernels_map.c +0 -3467
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/lib/carray/basics.rb
CHANGED
|
@@ -13,9 +13,19 @@
|
|
|
13
13
|
|
|
14
14
|
class CArray
|
|
15
15
|
|
|
16
|
+
# The order sort puts two object values in (ca_obj_order_cmp in C): a
|
|
17
|
+
# Float NaN after every other value, NaN ties NaN, other pairs by `<=>`.
|
|
18
|
+
# nil when `<=>` cannot order the pair; the caller says what refused.
|
|
19
|
+
private_class_method def self.object_order_cmp (a, b)
|
|
20
|
+
a_nan = a.is_a?(Float) && a.nan?
|
|
21
|
+
b_nan = b.is_a?(Float) && b.nan?
|
|
22
|
+
return (a_nan ? 1 : 0) - (b_nan ? 1 : 0) if a_nan || b_nan
|
|
23
|
+
a <=> b
|
|
24
|
+
end
|
|
25
|
+
|
|
16
26
|
# reshape / flatten / transpose! are defined in C
|
|
17
27
|
# (ext/ca_obj_refer.c and ext/ca_obj_transpose.c). The bare size-1
|
|
18
|
-
# insertion primitive is `
|
|
28
|
+
# insertion primitive is `insert_size_one_axes` (C); `insert_axis` below
|
|
19
29
|
# is the user-facing method that owns the name and adds `repeat:`.
|
|
20
30
|
|
|
21
31
|
# @overload insert_axis(*positions, repeat: nil)
|
|
@@ -58,7 +68,7 @@ class CArray
|
|
|
58
68
|
|
|
59
69
|
# No repeat: -> plain size-1 insertion. The source-frame C primitive
|
|
60
70
|
# handles normalization, range check and multiplicity directly.
|
|
61
|
-
return
|
|
71
|
+
return insert_size_one_axes(*flat) if repeat.nil?
|
|
62
72
|
|
|
63
73
|
# Source frame: each position names the source axis the new axis goes
|
|
64
74
|
# before. Gaps live in [0, ndim] (ndim = append at end); negatives count
|
|
@@ -80,31 +90,31 @@ class CArray
|
|
|
80
90
|
Array.new(flat.length, repeat)
|
|
81
91
|
end
|
|
82
92
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
# Validate each value. A positive Integer only; nil is not a valid
|
|
94
|
+
# per-axis repeat.
|
|
95
|
+
reps.each do |r|
|
|
96
|
+
unless r.is_a?(Integer)
|
|
97
|
+
raise ArgumentError,
|
|
98
|
+
"insert_axis: repeat must be a positive Integer, got #{r.inspect}"
|
|
99
|
+
end
|
|
100
|
+
raise ArgumentError, "insert_axis: repeat count must be >= 1" if r < 1
|
|
89
101
|
end
|
|
90
|
-
raise ArgumentError, "insert_axis: repeat count must be >= 1" if r < 1
|
|
91
|
-
end
|
|
92
102
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
# Final output layout: stable order by (gap, argument index) keeps
|
|
104
|
+
# same-gap axes in argument order; the k-th inserted axis lands at output
|
|
105
|
+
# position gap + k. This output position only drives broadcast_to; the
|
|
106
|
+
# insertion itself always goes through the source-frame primitive.
|
|
107
|
+
order = (0...flat.length).sort_by { |i| [gaps[i], i] }
|
|
108
|
+
final = {}
|
|
109
|
+
order.each_with_index { |i, k| final[i] = gaps[i] + k }
|
|
100
110
|
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
inter = insert_size_one_axes(*order.map { |i| gaps[i] })
|
|
112
|
+
return inter unless order.any? { |i| reps[i] > 1 }
|
|
103
113
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
end
|
|
114
|
+
shp = inter.shape
|
|
115
|
+
order.each { |i| shp[final[i]] = reps[i] if reps[i] > 1 }
|
|
116
|
+
inter.broadcast_to(*shp)
|
|
117
|
+
end
|
|
108
118
|
|
|
109
119
|
# @overload drop_axis
|
|
110
120
|
# Returns a view of `self` with every size-1 axis dropped.
|
|
@@ -142,6 +152,28 @@ end
|
|
|
142
152
|
return template(:boolean) { 1 }
|
|
143
153
|
end
|
|
144
154
|
|
|
155
|
+
# A Face is clipped in its own terms: its comparisons decide which cells are
|
|
156
|
+
# out of range (a time array reads its bounds as times, a record array
|
|
157
|
+
# orders by its declared members, a Face that cannot be ordered refuses),
|
|
158
|
+
# and its store writes the bound or the fill value into them.
|
|
159
|
+
private def face_clip (min, max, fill_value, lfill, ufill)
|
|
160
|
+
lfill = fill_value if lfill.nil?
|
|
161
|
+
ufill = fill_value if ufill.nil?
|
|
162
|
+
out = copy
|
|
163
|
+
out[self < min] = lfill.nil? ? min : lfill unless min.nil?
|
|
164
|
+
out[self > max] = ufill.nil? ? max : ufill unless max.nil?
|
|
165
|
+
out
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# An array of +shape+ of the same kind as self: its data type and cell
|
|
169
|
+
# width, or its Face over a zero storage. Nothing is written into it, so
|
|
170
|
+
# it can be built for a read-only Face too.
|
|
171
|
+
private def blank_like (shape)
|
|
172
|
+
storage = face_storage
|
|
173
|
+
out = CArray.new(storage.data_type, shape, bytes: storage.bytes)
|
|
174
|
+
face? ? out.face_lift(self) : out
|
|
175
|
+
end
|
|
176
|
+
|
|
145
177
|
# Sub-region copy (paste / crop), the old C `ca_paste` / `ca_clip` pair.
|
|
146
178
|
# `clip` is reserved for value clamping (clamp to a min/max range), so
|
|
147
179
|
# the read-out side is `crop`. Kept together as a pair (crop is rare, but paste is reached
|
|
@@ -250,6 +282,31 @@ end
|
|
|
250
282
|
|
|
251
283
|
# @!endgroup
|
|
252
284
|
|
|
285
|
+
# An Integer shift count on an integer array means what it means to
|
|
286
|
+
# Integer#<< and #>>: negative shifts the other way, and a count past the
|
|
287
|
+
# width shifts every bit out. The kernels do that for a count of the
|
|
288
|
+
# array's own type; this brings a count the type cannot hold -- -1 for a
|
|
289
|
+
# uint8 array, 300 for an int8 one -- to one it can.
|
|
290
|
+
module IntegerShiftCount
|
|
291
|
+
UNSIGNED = [CA_UINT8, CA_UINT16, CA_UINT32, CA_UINT64].freeze
|
|
292
|
+
|
|
293
|
+
def << (other)
|
|
294
|
+
return super unless other.is_a?(Integer) && integer? && ! face?
|
|
295
|
+
w = bytes * 8
|
|
296
|
+
return self >> -other if other < 0 && UNSIGNED.include?(data_type)
|
|
297
|
+
super(other.clamp(-w, w))
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def >> (other)
|
|
301
|
+
return super unless other.is_a?(Integer) && integer? && ! face?
|
|
302
|
+
w = bytes * 8
|
|
303
|
+
return self << -other if other < 0 && UNSIGNED.include?(data_type)
|
|
304
|
+
super(other.clamp(-w, w))
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
# Prepended by carray/lazy, after it has wrapped << and >>: prepended
|
|
308
|
+
# here, the method lazy aliases as the eager form would be this one.
|
|
309
|
+
|
|
253
310
|
# @overload clip(min, max = nil, fill_value = nil, lfill: nil, ufill: nil)
|
|
254
311
|
# Returns `self` with every element clamped to `[min, max]`.
|
|
255
312
|
#
|
|
@@ -258,7 +315,14 @@ end
|
|
|
258
315
|
# `fill_value` (or `lfill` / `ufill`) is given, out-of-range
|
|
259
316
|
# cells are replaced by the fill instead of clamped -- pass
|
|
260
317
|
# `UNDEF` to mask that end. `fill_value` is sugar for symmetric
|
|
261
|
-
# dual-fill; `lfill` / `ufill` override per side
|
|
318
|
+
# dual-fill; `lfill` / `ufill` override per side, and a side
|
|
319
|
+
# given no fill is still clamped.
|
|
320
|
+
#
|
|
321
|
+
# `min` may not exceed `max` (in any cell, when a bound is an
|
|
322
|
+
# array); equal bounds give every unmasked cell that value.
|
|
323
|
+
# A NaN in a bound array leaves that cell unbounded on that side,
|
|
324
|
+
# as `nil` does for the whole side. A bound is never UNDEF or
|
|
325
|
+
# masked: a missing bound is not read as either, so fill it first.
|
|
262
326
|
#
|
|
263
327
|
# Boundary is strict `[min, max]`: values equal to a bound
|
|
264
328
|
# remain unchanged in both the clamped and filled variants.
|
|
@@ -272,7 +336,9 @@ end
|
|
|
272
336
|
# @param lfill [Object, nil] override below-range fill.
|
|
273
337
|
# @param ufill [Object, nil] override above-range fill.
|
|
274
338
|
# @return [CArray] new CArray with clamped or filled values.
|
|
275
|
-
# @raise [ArgumentError] when both `min` and `max` are `nil
|
|
339
|
+
# @raise [ArgumentError] when both `min` and `max` are `nil`,
|
|
340
|
+
# when either is `UNDEF` or has a masked cell, or when `min`
|
|
341
|
+
# exceeds `max`.
|
|
276
342
|
# @example
|
|
277
343
|
# a.clip(0, 10) # strict clamp
|
|
278
344
|
# a.clip(0, 10, -1) # both ends -> -1
|
|
@@ -281,20 +347,42 @@ end
|
|
|
281
347
|
if min.nil? && max.nil?
|
|
282
348
|
raise ArgumentError, "clip: at least one of (min, max) must be given"
|
|
283
349
|
end
|
|
350
|
+
[min, max].each do |bound|
|
|
351
|
+
undefined = UNDEF.equal?(bound) ||
|
|
352
|
+
(bound.is_a?(CArray) && bound.any_masked?) ||
|
|
353
|
+
(bound.is_a?(Array) && bound.flatten.any? { |v| UNDEF.equal?(v) })
|
|
354
|
+
next unless undefined
|
|
355
|
+
raise ArgumentError, "clip: a bound can not be UNDEF or masked " \
|
|
356
|
+
"(fill the bound first; a NaN bound leaves its cell " \
|
|
357
|
+
"unbounded, and UNDEF as the fill masks the cells out of range)"
|
|
358
|
+
end
|
|
359
|
+
return face_clip(min, max, fill_value, lfill, ufill) if face?
|
|
360
|
+
if !min.nil? && !max.nil?
|
|
361
|
+
reversed = if min.is_a?(CArray) then min.gt(max).any
|
|
362
|
+
elsif max.is_a?(CArray) then max.lt(min).any
|
|
363
|
+
else min > max
|
|
364
|
+
end
|
|
365
|
+
if reversed
|
|
366
|
+
raise ArgumentError, "clip: min must be less than or equal to max"
|
|
367
|
+
end
|
|
368
|
+
end
|
|
284
369
|
|
|
285
370
|
# `fill_value` as a single argument is sugar applied to both ends; kwargs override.
|
|
286
371
|
lfill = fill_value if lfill.nil?
|
|
287
372
|
ufill = fill_value if ufill.nil?
|
|
288
373
|
|
|
289
374
|
if lfill.nil? && ufill.nil?
|
|
290
|
-
return
|
|
375
|
+
return clamp_between(min, max) if !min.nil? && !max.nil?
|
|
291
376
|
return pmax(min) if max.nil?
|
|
292
377
|
return pmin(max)
|
|
293
378
|
end
|
|
294
379
|
|
|
380
|
+
# A side without a fill still clamps.
|
|
295
381
|
out = self.copy
|
|
296
|
-
out
|
|
297
|
-
out
|
|
382
|
+
out = out.pmax(min) if !min.nil? && lfill.nil?
|
|
383
|
+
out = out.pmin(max) if !max.nil? && ufill.nil?
|
|
384
|
+
out[self.lt(min)] = lfill unless min.nil? || lfill.nil?
|
|
385
|
+
out[self.gt(max)] = ufill unless max.nil? || ufill.nil?
|
|
298
386
|
out
|
|
299
387
|
end
|
|
300
388
|
|
|
@@ -483,3 +571,49 @@ class Enumerator::ArithmeticSequence
|
|
|
483
571
|
return CA_OBJECT(to_a)
|
|
484
572
|
end
|
|
485
573
|
end
|
|
574
|
+
|
|
575
|
+
class CArray
|
|
576
|
+
# map_slab / reduce_slab over a Face answer in that Face, as its other
|
|
577
|
+
# reductions do: each block value is written into a blank of the Face
|
|
578
|
+
# (which reads a CATime::Element, a string, a Face array ...) and handed
|
|
579
|
+
# to the slab engine as the storage it became; the result is lifted back
|
|
580
|
+
# at the end. A read-only Face has no blank to write into, so its values
|
|
581
|
+
# are collected as the surface objects they are. A `data_type:` from the
|
|
582
|
+
# caller is the caller's, and passes through.
|
|
583
|
+
module FaceSlabResult
|
|
584
|
+
def map_slab (**kw, &block)
|
|
585
|
+
return super unless face? && kw[:data_type].nil? && block
|
|
586
|
+
return super(**kw, data_type: :object, &block) if read_only?
|
|
587
|
+
out = super(**kw, data_type: face_storage.data_type) { |slab|
|
|
588
|
+
face_slab_storage(block.call(slab), slab.shape)
|
|
589
|
+
}
|
|
590
|
+
out.face_lift(self)
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def reduce_slab (**kw, &block)
|
|
594
|
+
return super unless face? && kw[:data_type].nil? && block
|
|
595
|
+
return super(**kw, data_type: :object, &block) if read_only?
|
|
596
|
+
fiber = kw.key?(:init)
|
|
597
|
+
init = kw.delete(:init)
|
|
598
|
+
out = super(**kw, data_type: face_storage.data_type) { |slab|
|
|
599
|
+
value = if fiber
|
|
600
|
+
slab.to_a.flatten.inject(init) { |acc, e| block.call(acc, e) }
|
|
601
|
+
else
|
|
602
|
+
block.call(slab)
|
|
603
|
+
end
|
|
604
|
+
face_slab_storage(value, [1])[0]
|
|
605
|
+
}
|
|
606
|
+
out.face_lift(self)
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
private
|
|
610
|
+
|
|
611
|
+
def face_slab_storage (value, shape)
|
|
612
|
+
cell = blank_like(shape)
|
|
613
|
+
cell[] = value
|
|
614
|
+
cell.__send__(:face_storage)
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
prepend FaceSlabResult
|
|
619
|
+
end
|
data/lib/carray/bincount_nd.rb
CHANGED
|
@@ -78,8 +78,13 @@ class CArray
|
|
|
78
78
|
# accumulators; `nil` for pure counts (int64).
|
|
79
79
|
# @return [BincountND]
|
|
80
80
|
def initialize (lengths:, fiber_shape: [], weights_data_type: nil)
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
raise ArgumentError, "lengths must be a non-empty list" if lengths.empty?
|
|
82
|
+
lengths.each_with_index do |l, k|
|
|
83
|
+
unless l.is_a?(Integer)
|
|
84
|
+
raise TypeError, "lengths[#{k}] must be an Integer (got #{l.inspect})"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
@lengths = lengths.dup
|
|
83
88
|
@lengths.each_with_index do |l, k|
|
|
84
89
|
raise ArgumentError, "lengths[#{k}] must be >= 1" if l < 1
|
|
85
90
|
end
|
|
@@ -209,6 +214,7 @@ class CArray
|
|
|
209
214
|
|
|
210
215
|
if weights
|
|
211
216
|
raise ArgumentError, "weights given but accumulator is unweighted" unless @weighted
|
|
217
|
+
# coerce: the accumulator's type, declared by weights_data_type:
|
|
212
218
|
weights = CArray.wrap_readonly(weights, @counts_data_type)
|
|
213
219
|
expected_w_shape = chunk.shape.dup
|
|
214
220
|
expected_w_shape.delete_at(channel_ax)
|
|
@@ -269,6 +275,12 @@ class CArray
|
|
|
269
275
|
term = strides_ext[k] == 1 ? b : b * strides_ext[k]
|
|
270
276
|
ravel = ravel.nil? ? term : ravel + term
|
|
271
277
|
end
|
|
278
|
+
# A NaN weight drops its sample, as the fiber kernel and histogram
|
|
279
|
+
# do; bincount itself would add the NaN in.
|
|
280
|
+
if tweights && tweights.float?
|
|
281
|
+
nan = tweights.is_nan
|
|
282
|
+
tweights = tweights.mask_where(nan) if nan.any
|
|
283
|
+
end
|
|
272
284
|
chunk_counts = ravel.bincount(weights: tweights, length: total_ext)
|
|
273
285
|
@full_counts[] = @full_counts + chunk_counts.reshape(*@full_counts.shape)
|
|
274
286
|
else
|
|
@@ -338,6 +350,10 @@ class CArray
|
|
|
338
350
|
# @return [BincountND]
|
|
339
351
|
def bincount_nd (lengths:, axis: [-2, -1], weights: nil)
|
|
340
352
|
raise ArgumentError, "lengths must be an Array of per-dim extents" unless lengths.is_a?(Array)
|
|
353
|
+
axis = [-2, -1] if axis.nil?
|
|
354
|
+
unless axis.is_a?(Array) && axis.size == 2
|
|
355
|
+
raise ArgumentError, "bincount_nd: axis: is a [sample, channel] pair (got #{axis.inspect})"
|
|
356
|
+
end
|
|
341
357
|
sample_ax = normalize_axis(axis[0], "bincount_nd sample axis")
|
|
342
358
|
channel_ax = normalize_axis(axis[1], "bincount_nd channel axis")
|
|
343
359
|
fiber_shape = shape.dup
|