carray 3.0.3 → 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 +264 -0
- data/README.md +3 -2
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +1 -6
- data/ext/ca_axis_group.c +27 -27
- data/ext/ca_binop_dispatch.c +1 -29
- data/ext/ca_binop_dispatch.h +0 -1
- data/ext/ca_categorical_iterator.c +205 -134
- data/ext/ca_compare.c +7 -18
- data/ext/ca_group_iter.c +16 -17
- data/ext/ca_kernel_iterator.c +1234 -1994
- data/ext/ca_kernel_iterator.h +391 -437
- data/ext/ca_monop_dispatch.c +82 -59
- data/ext/ca_monop_dispatch.h +1 -0
- data/ext/ca_obj_array.c +96 -39
- data/ext/ca_obj_bincmp.c +24 -21
- data/ext/ca_obj_binop.c +15 -26
- data/ext/ca_obj_bitarray.c +3 -2
- data/ext/ca_obj_bitfield.c +5 -6
- data/ext/ca_obj_block.c +18 -9
- data/ext/ca_obj_byte_swap.c +5 -6
- data/ext/ca_obj_const_string.c +173 -19
- data/ext/ca_obj_face.c +238 -57
- data/ext/ca_obj_face.h +19 -0
- data/ext/ca_obj_fake.c +15 -29
- data/ext/ca_obj_farray.c +6 -3
- data/ext/ca_obj_field.c +17 -5
- data/ext/ca_obj_fixlen_string.c +2 -3
- data/ext/ca_obj_grid.c +406 -132
- data/ext/ca_obj_meld.c +172 -34
- data/ext/ca_obj_moncmp.c +23 -8
- data/ext/ca_obj_monop.c +67 -57
- data/ext/ca_obj_object.c +157 -51
- data/ext/ca_obj_record.c +12 -7
- data/ext/ca_obj_reduce.c +13 -8
- data/ext/ca_obj_refer.c +25 -27
- data/ext/ca_obj_remap.c +30 -9
- data/ext/ca_obj_repeat.c +9 -10
- data/ext/ca_obj_roll.c +6 -5
- data/ext/ca_obj_select.c +14 -9
- data/ext/ca_obj_select_axis.c +15 -47
- data/ext/ca_obj_shift.c +11 -1
- data/ext/ca_obj_stack.c +179 -34
- data/ext/ca_obj_stride.c +162 -115
- data/ext/ca_obj_string.c +71 -4
- data/ext/ca_obj_tile.c +6 -5
- data/ext/ca_obj_time.c +22 -6
- data/ext/ca_obj_timedelta.c +22 -6
- data/ext/ca_obj_transpose.c +5 -3
- data/ext/ca_obj_triop.c +23 -32
- data/ext/ca_obj_window.c +190 -26
- data/ext/ca_sweep_engine.c +2 -2
- data/ext/caframe_csv_reader.c +80 -1
- data/ext/carray.h +181 -75
- data/ext/carray_access.c +184 -96
- data/ext/carray_address_basis.c +343 -87
- data/ext/carray_attribute.c +89 -6
- data/ext/carray_bincount.c +10 -8
- data/ext/carray_broadcast.c +13 -8
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +108 -0
- data/ext/carray_cast.c +142 -24
- data/ext/carray_cast_func.rb +46 -6
- data/ext/carray_class.c +4 -3
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +16 -7
- data/ext/carray_copy.c +51 -14
- data/ext/carray_core.c +147 -55
- data/ext/carray_count.c +50 -20
- data/ext/carray_element.c +76 -33
- data/ext/carray_factorize.c +118 -64
- data/ext/carray_generate.c +191 -50
- data/ext/carray_histogram.c +62 -17
- data/ext/carray_hold.c +12 -15
- data/ext/carray_index_classifier.c +388 -176
- data/ext/carray_internal.h +336 -29
- data/ext/carray_kernels_bincmp.c +4453 -0
- data/ext/carray_kernels_binop.c +11368 -0
- data/ext/carray_kernels_init.c +1734 -0
- data/ext/carray_kernels_moncmp.c +2104 -0
- data/ext/carray_kernels_monop.c +18369 -0
- data/ext/carray_kernels_reduce_aggregate.c +23818 -0
- data/ext/carray_kernels_reduce_boolean.c +406 -0
- data/ext/carray_kernels_reduce_cumulative.c +10086 -0
- data/ext/carray_kernels_reduce_extreme.c +17634 -0
- data/ext/carray_kernels_reduce_variance.c +3849 -0
- data/ext/carray_kernels_scan.c +4302 -0
- data/ext/carray_kernels_search.c +33829 -0
- data/ext/carray_kernels_sort.c +10906 -0
- data/ext/carray_kernels_triop.c +1864 -0
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +170 -111
- data/ext/carray_mask.c +292 -72
- data/ext/carray_median_percentile.c +82 -28
- data/ext/carray_memory_view.c +669 -561
- data/ext/carray_operator.c +124 -47
- data/ext/carray_order.c +384 -76
- data/ext/carray_partition.c +28 -27
- data/ext/carray_random.c +67 -13
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +63 -38
- data/ext/carray_segment.c +3 -3
- data/ext/carray_slab.c +91 -28
- data/ext/carray_sort.c +35 -35
- data/ext/carray_struct.c +19 -18
- data/ext/carray_test.c +26 -5
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +246 -45
- data/ext/mk_call_cfunc.rb +19 -2
- data/ext/mkkernel.rb +198 -240
- data/ext/ruby_carray.c +10 -4
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +126 -22
- data/lib/carray/autoload_carray.rb +8 -31
- data/lib/carray/autoload_method_extension.rb +14 -5
- data/lib/carray/axis_group.rb +255 -106
- data/lib/carray/basics.rb +78 -10
- data/lib/carray/bincount_nd.rb +12 -2
- data/lib/carray/block_iterator.rb +126 -23
- data/lib/carray/boolean_reduce.rb +17 -17
- data/lib/carray/categorical.rb +165 -43
- data/lib/carray/categorical_iterator.rb +130 -27
- data/lib/carray/complex.rb +5 -5
- data/lib/carray/conditional.rb +67 -18
- data/lib/carray/const_string.rb +14 -5
- 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/convert.rb +69 -0
- data/lib/carray/frame/csv_parser.rb +111 -17
- data/lib/carray/frame/describe.rb +3 -2
- data/lib/carray/frame/frame.rb +246 -21
- data/lib/carray/frame/group.rb +510 -95
- data/lib/carray/frame/io.rb +115 -28
- data/lib/carray/frame/join.rb +312 -51
- data/lib/carray/frame/records.rb +83 -7
- data/lib/carray/frame/reshape.rb +42 -35
- data/lib/carray/frame/sort.rb +7 -19
- data/lib/carray/frame/verbs.rb +188 -48
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +11 -4
- data/lib/carray/fusion.rb +40 -16
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +31 -8
- data/lib/carray/iterator.rb +85 -7
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +182 -183
- data/lib/carray/mask_gap_fill.rb +63 -57
- data/lib/carray/meld_reduce.rb +12 -14
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +16 -0
- data/lib/carray/methods/bit_string.rb +1 -1
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +3 -1
- data/lib/carray/methods/gather_nd.rb +14 -5
- data/lib/carray/methods/insert_block.rb +2 -2
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +53 -36
- data/lib/carray/methods/join.rb +1 -6
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +47 -51
- data/lib/carray/methods/mode.rb +1 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/resize.rb +3 -3
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +3 -3
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +53 -8
- data/lib/carray/segment_iterator.rb +313 -82
- data/lib/carray/serialize.rb +24 -10
- data/lib/carray/slab_iterator.rb +50 -0
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +8 -1
- data/lib/carray/struct.rb +9 -21
- data/lib/carray/struct_builder.rb +19 -8
- data/lib/carray/time.rb +726 -104
- data/lib/carray/window_iterator.rb +122 -16
- data/lib/carray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +4 -0
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +2 -1
- data/yard-stubs/ca_obj_roll.rb +2 -2
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +8 -3
- data/yard-stubs/carray_access.rb +6 -1
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_cast.rb +10 -0
- data/yard-stubs/carray_conversion.rb +2 -1
- data/yard-stubs/carray_copy.rb +4 -2
- data/yard-stubs/carray_count.rb +4 -4
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_mask.rb +26 -2
- data/yard-stubs/carray_math.rb +27 -1
- data/yard-stubs/carray_median_percentile.rb +5 -2
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +29 -18
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +14 -9
- data/yard-stubs/carray_slab.rb +9 -2
- data/yard-stubs/carray_sort.rb +6 -5
- data/yard-stubs/carray_test.rb +5 -3
- metadata +25 -3
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/lib/carray/fusion.rb
CHANGED
|
@@ -66,6 +66,7 @@ class CArray
|
|
|
66
66
|
Plan = Struct.new(:nodes, :leaves, :data_type, :dim, :masked, :signature)
|
|
67
67
|
|
|
68
68
|
LAZY_CLASSES = [CAMonOp, CABinOp, CATriOp, CAMonCmp, CABinCmp, CALazyMarker]
|
|
69
|
+
Ractor.make_shareable(LAZY_CLASSES)
|
|
69
70
|
|
|
70
71
|
# A lazy node names its operation by an id and the kernels name it by a
|
|
71
72
|
# symbol. These are the same operations, spelled the way each side
|
|
@@ -76,7 +77,7 @@ class CArray
|
|
|
76
77
|
:& => :bit_and_i, :| => :bit_or_i, :^ => :bit_xor_i,
|
|
77
78
|
:<< => :bit_lshift, :>> => :bit_rshift,
|
|
78
79
|
}.freeze
|
|
79
|
-
TRIOP_NAMES = { :
|
|
80
|
+
TRIOP_NAMES = { :clamp_between => :clip }.freeze
|
|
80
81
|
|
|
81
82
|
MONOP_BY_ID = CArray::LAZY_MONOP_OP_IDS.invert.freeze
|
|
82
83
|
# A Float or Complex array to an Integer power is its own node, ipow,
|
|
@@ -118,7 +119,7 @@ class CArray
|
|
|
118
119
|
# Returns the array, or nil where nothing computed it.
|
|
119
120
|
def self.evaluate (view)
|
|
120
121
|
plan = worth_asking(view) or return nil
|
|
121
|
-
out = CArray.__alloc_uninit__(view.data_type, view.
|
|
122
|
+
out = CArray.__alloc_uninit__(view.data_type, view.shape)
|
|
122
123
|
ask(plan, out) ? out : nil
|
|
123
124
|
end
|
|
124
125
|
|
|
@@ -131,30 +132,46 @@ class CArray
|
|
|
131
132
|
end
|
|
132
133
|
|
|
133
134
|
# The plan to hand over, or nil. A marker over an array, or anything
|
|
134
|
-
# else with nothing to compute, is not worth handing over.
|
|
135
|
+
# else with nothing to compute, is not worth handing over. Nothing here
|
|
136
|
+
# is the evaluator's doing, so nothing here retires it: an array that
|
|
137
|
+
# raises when it is looked at (a CAObject whose backing is gone) raises
|
|
138
|
+
# again in the walk, where the caller sees it.
|
|
135
139
|
def self.worth_asking (view)
|
|
136
140
|
return nil unless askable?(view)
|
|
137
141
|
plan = plan(view) or return nil
|
|
138
142
|
plan.nodes.any? { |n| n.is_a?(Op) } ? plan : nil
|
|
139
|
-
rescue StandardError
|
|
140
|
-
retire(error)
|
|
143
|
+
rescue StandardError
|
|
141
144
|
nil
|
|
142
145
|
end
|
|
143
146
|
|
|
144
147
|
def self.ask (plan, out)
|
|
145
148
|
evaluator = CArray.expression_evaluator or return false
|
|
146
149
|
return false if overlaps?(plan, out)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
return false unless ready_mask(plan, out)
|
|
151
|
+
begin
|
|
152
|
+
evaluator.call(plan, out) ? true : false
|
|
153
|
+
rescue AddressBasis::Failure
|
|
154
|
+
# Raised by CArray lending the arrays or taking them back: a refusal,
|
|
155
|
+
# or an array that cannot be read. The walk meets the same array.
|
|
156
|
+
false
|
|
157
|
+
rescue StandardError => error
|
|
158
|
+
retire(error)
|
|
159
|
+
false
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# The walk leaves the destination masked where the expression is, so a
|
|
164
|
+
# destination that arrives masked loses its mask to an expression that
|
|
165
|
+
# has none. A destination that cannot hold a mask (a value array) is
|
|
166
|
+
# left to the walk, which says so.
|
|
167
|
+
def self.ready_mask (plan, out)
|
|
150
168
|
if plan.masked
|
|
151
169
|
out.mask = 0 unless out.has_mask?
|
|
152
170
|
elsif out.has_mask?
|
|
153
171
|
out.mask = 0
|
|
154
172
|
end
|
|
155
|
-
|
|
156
|
-
rescue StandardError
|
|
157
|
-
retire(error)
|
|
173
|
+
true
|
|
174
|
+
rescue StandardError
|
|
158
175
|
false
|
|
159
176
|
end
|
|
160
177
|
|
|
@@ -171,13 +188,15 @@ class CArray
|
|
|
171
188
|
if leaf.equal?(out)
|
|
172
189
|
shifted.include?(index)
|
|
173
190
|
else
|
|
174
|
-
storages(leaf).any? { |r| mine.any? { |m| m.
|
|
191
|
+
storages(leaf).any? { |r| mine.any? { |m| m.send(:storage_overlaps?, r) } }
|
|
175
192
|
end
|
|
176
193
|
end
|
|
177
194
|
end
|
|
178
195
|
|
|
179
196
|
# The arrays that hold an array's cells: its root, or each parent's
|
|
180
|
-
# where a view stands over several.
|
|
197
|
+
# where a view stands over several. Two of them share storage when
|
|
198
|
+
# they are one array, or entities whose memory overlaps (an array and a
|
|
199
|
+
# wrap_memory_view of it).
|
|
181
200
|
def self.storages (array, found = [])
|
|
182
201
|
root = array.root_array
|
|
183
202
|
if ! root.entity? && root.respond_to?(:parents)
|
|
@@ -213,7 +232,7 @@ class CArray
|
|
|
213
232
|
w.visit(view)
|
|
214
233
|
masked = w.leaves.any? { |a| a.has_mask? } ||
|
|
215
234
|
w.nodes.any? { |n| n.is_a?(Shifted) && n.bounds.include?(:mask) }
|
|
216
|
-
Plan.new(w.nodes, w.leaves, view.data_type, view.
|
|
235
|
+
Plan.new(w.nodes, w.leaves, view.data_type, view.shape, masked, w.signature)
|
|
217
236
|
end
|
|
218
237
|
|
|
219
238
|
def self.lazy? (x)
|
|
@@ -350,8 +369,8 @@ class CArray
|
|
|
350
369
|
# expression, say -- has no array to read and is taken as a whole.
|
|
351
370
|
def shifted (n)
|
|
352
371
|
array = n.parent
|
|
353
|
-
bounds = n.
|
|
354
|
-
if Fusion.lazy?(array) || array.
|
|
372
|
+
bounds = n.__boundary_rule_of_each_axis__
|
|
373
|
+
if Fusion.lazy?(array) || array.shape != n.shape ||
|
|
355
374
|
! bounds.all? { |b| b == :fill || b == :mask }
|
|
356
375
|
return leaf(n)
|
|
357
376
|
end
|
|
@@ -366,8 +385,13 @@ class CArray
|
|
|
366
385
|
offset, bounds, fill)
|
|
367
386
|
end
|
|
368
387
|
|
|
388
|
+
# A leaf the address bases would refuse to lend cannot be read by an
|
|
389
|
+
# evaluator, so the expression is not described.
|
|
369
390
|
def leaf_index (array)
|
|
370
391
|
@leaf_index.fetch(array.object_id) do
|
|
392
|
+
if (reason = AddressBasis.classify(array)[:refusal])
|
|
393
|
+
raise Refused, "a leaf: #{reason}"
|
|
394
|
+
end
|
|
371
395
|
@leaves << array
|
|
372
396
|
@leaf_index[array.object_id] = @leaves.size - 1
|
|
373
397
|
end
|
data/lib/carray/histogram.rb
CHANGED
|
@@ -321,6 +321,7 @@ class CArray
|
|
|
321
321
|
|
|
322
322
|
if weights
|
|
323
323
|
raise ArgumentError, "weights given but accumulator is unweighted" unless @weighted
|
|
324
|
+
# coerce: the accumulator's type, declared by weights_data_type:
|
|
324
325
|
weights = CArray.wrap_readonly(weights, @counts_data_type)
|
|
325
326
|
expected_w_shape = chunk.shape.dup
|
|
326
327
|
expected_w_shape.delete_at(channel_ax)
|
|
@@ -447,7 +448,7 @@ class CArray
|
|
|
447
448
|
# @param weights [CArray, nil] optional per-sample weights.
|
|
448
449
|
# @return [Histogram] 1-D accumulator (`m == 1`).
|
|
449
450
|
def histogram1d (edges:, axis: -1, include_max: false, weights: nil)
|
|
450
|
-
ax = normalize_axis(axis, "histogram1d")
|
|
451
|
+
ax = normalize_axis(axis.nil? ? -1 : axis, "histogram1d")
|
|
451
452
|
|
|
452
453
|
new_shape = shape + [1]
|
|
453
454
|
arr_with_channel = reshape(*new_shape)
|
|
@@ -491,6 +492,10 @@ class CArray
|
|
|
491
492
|
def histogram (edges:, axis: [-2, -1], include_max: false, weights: nil)
|
|
492
493
|
raise ArgumentError, "edges must be an Array of edges arrays" unless edges.is_a?(Array)
|
|
493
494
|
arr = self
|
|
495
|
+
axis = [-2, -1] if axis.nil?
|
|
496
|
+
unless axis.is_a?(Array) && axis.size == 2
|
|
497
|
+
raise ArgumentError, "histogram: axis: is a [sample, channel] pair (got #{axis.inspect})"
|
|
498
|
+
end
|
|
494
499
|
sample_ax = normalize_axis(axis[0], "histogram sample axis")
|
|
495
500
|
channel_ax = normalize_axis(axis[1], "histogram channel axis")
|
|
496
501
|
fiber_shape = arr.shape.dup
|
data/lib/carray/inspect.rb
CHANGED
|
@@ -34,16 +34,39 @@ class CArray::Inspector # :nodoc:
|
|
|
34
34
|
|
|
35
35
|
private
|
|
36
36
|
|
|
37
|
-
# The name before the shape: the class and the storage type, or
|
|
38
|
-
# Face
|
|
39
|
-
# tick, which the storage type does not tell).
|
|
37
|
+
# The name before the shape: the class and the storage type, or for a
|
|
38
|
+
# Face its own name (see .face_label).
|
|
40
39
|
def get_label
|
|
41
|
-
if @carray.
|
|
42
|
-
return @carray.send(:inspect_label)
|
|
43
|
-
end
|
|
40
|
+
return CArray::Inspector.face_label(@carray) if @carray.face?
|
|
44
41
|
return format("%s.%s", get_class_name, get_type_name)
|
|
45
42
|
end
|
|
46
43
|
|
|
44
|
+
public
|
|
45
|
+
|
|
46
|
+
# The name a Face goes by where a person reads it -- the head of inspect,
|
|
47
|
+
# a frame's column list. A Face's data_type is the surface the kernels
|
|
48
|
+
# dispatch on (fixlen for a time, so arithmetic on it raises), which says
|
|
49
|
+
# nothing to a reader, so it is named by its class: what a private
|
|
50
|
+
# inspect_label gives (CATime adds its tick), or the class, with the
|
|
51
|
+
# surface type only for a Face whose surface is numeric.
|
|
52
|
+
# The type of an array as a person reads it in a message or a table: a
|
|
53
|
+
# Face by its name (face_label), any other array by its data type name.
|
|
54
|
+
# Every message and listing that names a type goes through here, so a
|
|
55
|
+
# Face is never named by its storage (:fixlen for a time).
|
|
56
|
+
def self.type_label (ca)
|
|
57
|
+
ca.face? ? face_label(ca) : CArray.data_type_name(ca.data_type).to_s
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.face_label (ca)
|
|
61
|
+
return ca.send(:inspect_label) if ca.respond_to?(:inspect_label, true)
|
|
62
|
+
klass = ca.class
|
|
63
|
+
klass = klass.superclass while klass.name.nil?
|
|
64
|
+
return klass.name if [CA_FIXLEN, CA_OBJECT].include?(ca.data_type)
|
|
65
|
+
"#{klass.name}.#{CArray.data_type_name(ca.data_type)}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
47
70
|
def get_class_name
|
|
48
71
|
return @carray.class.to_s
|
|
49
72
|
end
|
|
@@ -277,10 +300,10 @@ class CArray
|
|
|
277
300
|
case data_type
|
|
278
301
|
when CA_FIXLEN
|
|
279
302
|
output << sprintf("CArray.%s(%s, :bytes=>%i)",
|
|
280
|
-
data_type_name,
|
|
303
|
+
data_type_name, shape.inspect[1..-2], bytes)
|
|
281
304
|
else
|
|
282
305
|
output << sprintf("CArray.%s(%s)",
|
|
283
|
-
data_type_name,
|
|
306
|
+
data_type_name, shape.inspect[1..-2])
|
|
284
307
|
end
|
|
285
308
|
return output
|
|
286
309
|
end
|
data/lib/carray/iterator.rb
CHANGED
|
@@ -32,6 +32,45 @@ class CAIterator
|
|
|
32
32
|
# The keywords a member passes on to a core reduction over its own axes.
|
|
33
33
|
# The member sets `axis:`, so one from the caller is refused; the rest go
|
|
34
34
|
# to the core, which checks them.
|
|
35
|
+
# Whether a fill method carries values backward: :forward / :ffill carry
|
|
36
|
+
# them forward, :backward / :bfill back. A member fills within its own
|
|
37
|
+
# pieces by holding the nearest present value; :linear, which needs a
|
|
38
|
+
# coordinate, is the core's alone.
|
|
39
|
+
def self.hold_backward? (method) # :nodoc:
|
|
40
|
+
case method
|
|
41
|
+
when :forward, :ffill then false
|
|
42
|
+
when :backward, :bfill then true
|
|
43
|
+
else
|
|
44
|
+
raise ArgumentError,
|
|
45
|
+
"strip_mask: method must be :forward, :ffill, :backward or :bfill " \
|
|
46
|
+
"within a piece (got #{method.inspect})"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# A one-cell (1, 1) array of the kind `value` holds, for asking the core
|
|
51
|
+
# what a reduction or scan of it answers in: its data type, cell width and,
|
|
52
|
+
# for a Face, its Face. A member that answers by a route of its own
|
|
53
|
+
# (a fused kernel, a fold by offset) takes its output type from here, so
|
|
54
|
+
# the route and the core cannot disagree. A Face is a view of the values
|
|
55
|
+
# themselves rather than a blank -- a Face cannot be allocated from its
|
|
56
|
+
# surface data type alone, and a zeroed record is not a valid cell for every
|
|
57
|
+
# one (a const string's record indexes a shared pool). A Face with no cell
|
|
58
|
+
# is asked with the blank cell its resize gives, so a reduction over no
|
|
59
|
+
# groups answers in the same kind as over some; this is nil only when the
|
|
60
|
+
# Face has no blank cell.
|
|
61
|
+
def self.core_probe (value) # :nodoc:
|
|
62
|
+
unless value.face?
|
|
63
|
+
return CArray.new(value.data_type, [1, 1], bytes: value.bytes)
|
|
64
|
+
end
|
|
65
|
+
flat = value.reshape(value.elements)
|
|
66
|
+
return flat[[0]].reshape(1, 1) if value.elements > 0
|
|
67
|
+
begin
|
|
68
|
+
flat.resize(1).reshape(1, 1)
|
|
69
|
+
rescue StandardError
|
|
70
|
+
nil
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
35
74
|
def self.reduce_keywords (op, kw) # :nodoc:
|
|
36
75
|
if kw.key?(:axis)
|
|
37
76
|
raise ArgumentError, "#{op}: unknown keyword: :axis (the iterator sets the axes)"
|
|
@@ -127,6 +166,18 @@ class CAIterator
|
|
|
127
166
|
# Returns the five-number summary of each piece,
|
|
128
167
|
# `[min, Q1, median, Q3, max]`.
|
|
129
168
|
# @return [Array<CArray>] five arrays, one per position.
|
|
169
|
+
# @!method first
|
|
170
|
+
# Returns the first present value of each piece, in the piece's own
|
|
171
|
+
# order; a piece with no present value is UNDEF.
|
|
172
|
+
# @return [CArray] one value per piece, in the source's data type.
|
|
173
|
+
# @!method last
|
|
174
|
+
# Returns the last present value of each piece; a piece with no present
|
|
175
|
+
# value is UNDEF.
|
|
176
|
+
# @return [CArray] one value per piece, in the source's data type.
|
|
177
|
+
# @!method nunique
|
|
178
|
+
# Returns the number of distinct present values in each piece, as
|
|
179
|
+
# `CArray#nunique` counts them; a piece with none counts 0.
|
|
180
|
+
# @return [CArray] `:int64`, one count per piece.
|
|
130
181
|
# @!method count(value = nil)
|
|
131
182
|
# Returns a count per piece: with no argument the cells that are not
|
|
132
183
|
# masked, with `UNDEF` the masked cells, and with any other value the
|
|
@@ -161,14 +212,16 @@ class CAIterator
|
|
|
161
212
|
:min_index, :max_index, :min_addr, :max_addr, # position
|
|
162
213
|
:wsum, :wmean, # weighted
|
|
163
214
|
:median, :percentile, :quantile, # tier 3
|
|
215
|
+
:first, :last, :nunique, # position / distinct
|
|
164
216
|
:count, :count_not_masked, :count_masked, :elements, # count family
|
|
165
217
|
:each, :reduce, # generic iterate
|
|
166
218
|
].freeze
|
|
167
219
|
|
|
168
220
|
REQUIRED_SURFACE.each do |name|
|
|
169
|
-
define_method
|
|
221
|
+
# define_method: a stub that names itself in its own message
|
|
222
|
+
define_method(name, &Ractor.make_shareable(proc do |*, **, &_blk|
|
|
170
223
|
raise NotImplementedError, "#{self.class} must implement ##{name}"
|
|
171
|
-
end
|
|
224
|
+
end))
|
|
172
225
|
end
|
|
173
226
|
|
|
174
227
|
# Recommended (should) surface -- template methods. These are well-defined
|
|
@@ -176,7 +229,8 @@ class CAIterator
|
|
|
176
229
|
# required: `map` is a per-piece element-wise transform scattered back to the
|
|
177
230
|
# source, `sort_addr` is a per-piece sort returning source flat addresses, and
|
|
178
231
|
# the segment scans (cumsum / cumprod / cummax / cummin / cumcount) write a
|
|
179
|
-
# per-cell running statistic of each piece
|
|
232
|
+
# per-cell running statistic of each piece, and `lag` the value some steps
|
|
233
|
+
# earlier in the same piece. A member implements each when it
|
|
180
234
|
# is well-defined and overrides it to raise with a reason when it is not. The
|
|
181
235
|
# scans belong here for the same reason as map: a running per-cell value is
|
|
182
236
|
# single-valued only when each cell belongs to exactly one piece, so the
|
|
@@ -221,11 +275,35 @@ class CAIterator
|
|
|
221
275
|
# masked within each piece.
|
|
222
276
|
# @return [CArray] shaped like the source.
|
|
223
277
|
# @raise [NotImplementedError] for a member whose pieces overlap.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
278
|
+
# @!method lag(n = 1)
|
|
279
|
+
# Returns a source-shaped array whose cell holds the value `n` steps
|
|
280
|
+
# earlier within the same piece, as `CArray#lag` does along an axis; a
|
|
281
|
+
# cell with no such value in its piece is UNDEF, so a lag never reaches
|
|
282
|
+
# across into another piece.
|
|
283
|
+
# @param n [Integer] steps back; a negative `n` looks ahead.
|
|
284
|
+
# @return [CArray] shaped like the source.
|
|
285
|
+
# @raise [NotImplementedError] for a member whose pieces overlap, where a
|
|
286
|
+
# cell has no single position within a piece.
|
|
287
|
+
# @!method strip_mask(method:)
|
|
288
|
+
# Returns a source-shaped array with each masked cell filled from its own
|
|
289
|
+
# piece, as `CArray#strip_mask(method:)` fills: `:forward` (`:ffill`)
|
|
290
|
+
# carries the last present value forward, `:backward` (`:bfill`) the next
|
|
291
|
+
# one back, never across into another piece.
|
|
292
|
+
# @param method [Symbol] `:forward`, `:ffill`, `:backward` or `:bfill`.
|
|
293
|
+
# @return [CArray] shaped like the source.
|
|
294
|
+
# @raise [NotImplementedError] for a member whose pieces overlap.
|
|
295
|
+
# @!method order(descending: false, method: :ordinal, kind: :quick)
|
|
296
|
+
# Returns a source-shaped int64 array of each cell's rank among the cells
|
|
297
|
+
# of its piece, as `CArray#order` ranks them (`0` the smallest).
|
|
298
|
+
# @return [CArray] shaped like the source.
|
|
299
|
+
# @raise [NotImplementedError] for a member whose pieces overlap, where a
|
|
300
|
+
# cell has no single rank.
|
|
301
|
+
[:map, :sort_addr, :order, :strip_mask,
|
|
302
|
+
:cumsum, :cumprod, :cummax, :cummin, :cumcount, :lag].each do |name|
|
|
303
|
+
# define_method: a stub that names itself in its own message
|
|
304
|
+
define_method(name, &Ractor.make_shareable(proc do |*, **, &_blk|
|
|
227
305
|
raise NotImplementedError, "#{self.class} does not provide ##{name} (optional)"
|
|
228
|
-
end
|
|
306
|
+
end))
|
|
229
307
|
end
|
|
230
308
|
|
|
231
309
|
end
|