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/mask_gap_fill.rb
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# `strip_mask(:na)`). Passing both raises ArgumentError.
|
|
16
16
|
#
|
|
17
17
|
# Design / rationale: devel/PROPOSAL_UNMASK_FILL_METHOD.md. The forward
|
|
18
|
-
# hold is the C primitive #
|
|
18
|
+
# hold is the C primitive #hold_forward; backward = flip -> forward -> flip,
|
|
19
19
|
# flatten = flatten -> hold -> reshape, and :linear composes
|
|
20
20
|
# linear_section / linear_fetch. User-facing YARD docs live in
|
|
21
21
|
# yard-stubs/carray_mask.rb.
|
|
@@ -29,55 +29,50 @@
|
|
|
29
29
|
|
|
30
30
|
class CArray
|
|
31
31
|
|
|
32
|
-
# Preserve the C constant-fill primitives under private names so the
|
|
33
|
-
# Ruby wrappers can delegate the non-method path unchanged.
|
|
34
|
-
alias __unmask_const__ unmask
|
|
35
|
-
alias __strip_mask_const__ strip_mask
|
|
36
|
-
private :__unmask_const__, :__strip_mask_const__
|
|
37
|
-
|
|
38
32
|
# Sentinel for "no positional fill value given" (distinct from any real
|
|
39
33
|
# fill value, including nil / false / a Symbol).
|
|
40
34
|
MASK_FILL_UNSET = ::Object.new
|
|
35
|
+
Ractor.make_shareable(MASK_FILL_UNSET)
|
|
41
36
|
private_constant :MASK_FILL_UNSET
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
else
|
|
38
|
+
# unmask / strip_mask with method:, in front of the C constant-fill
|
|
39
|
+
# primitives, which they reach with super.
|
|
40
|
+
module GapFill
|
|
41
|
+
def unmask (fill = MASK_FILL_UNSET, method: nil, axis: nil)
|
|
42
|
+
if method
|
|
43
|
+
unless fill.equal?(MASK_FILL_UNSET)
|
|
44
|
+
raise ArgumentError,
|
|
45
|
+
"unmask: pass either a constant fill value or method:, not both"
|
|
46
|
+
end
|
|
47
|
+
held = gap_fill(method, axis, "unmask")
|
|
48
|
+
# Copy the filled values in place (a Face takes a Face of its own kind
|
|
49
|
+
# as it is).
|
|
56
50
|
value[] = held.value
|
|
51
|
+
if held.has_mask?
|
|
52
|
+
self.mask = held.mask # residual leading/trailing mask
|
|
53
|
+
else
|
|
54
|
+
super() # fully filled: drop the mask
|
|
55
|
+
end
|
|
56
|
+
return self
|
|
57
57
|
end
|
|
58
|
-
|
|
59
|
-
self.mask = held.mask # residual leading/trailing mask
|
|
60
|
-
else
|
|
61
|
-
__unmask_const__ # fully filled: drop the mask
|
|
62
|
-
end
|
|
63
|
-
return self
|
|
58
|
+
fill.equal?(MASK_FILL_UNSET) ? super() : super(fill)
|
|
64
59
|
end
|
|
65
|
-
fill.equal?(MASK_FILL_UNSET) ? __unmask_const__ : __unmask_const__(fill)
|
|
66
|
-
end
|
|
67
60
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
61
|
+
def strip_mask (fill = MASK_FILL_UNSET, method: nil, axis: nil)
|
|
62
|
+
if method
|
|
63
|
+
unless fill.equal?(MASK_FILL_UNSET)
|
|
64
|
+
raise ArgumentError,
|
|
65
|
+
"strip_mask: pass either a constant fill value or method:, not both"
|
|
66
|
+
end
|
|
67
|
+
return carry_attrs(gap_fill(method, axis, "strip_mask"))
|
|
73
68
|
end
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
if fill.equal?(MASK_FILL_UNSET)
|
|
70
|
+
raise ArgumentError, "strip_mask: a fill value is required (or method:)"
|
|
71
|
+
end
|
|
72
|
+
carry_attrs(super(fill))
|
|
78
73
|
end
|
|
79
|
-
__strip_mask_const__(fill)
|
|
80
74
|
end
|
|
75
|
+
prepend GapFill
|
|
81
76
|
|
|
82
77
|
private
|
|
83
78
|
|
|
@@ -85,14 +80,15 @@ class CArray
|
|
|
85
80
|
# unfillable cells stay masked; a fully filled result carries no mask
|
|
86
81
|
# (hold allocates the output mask only when a leading run goes UNDEF;
|
|
87
82
|
# :linear masks only the exterior via mask_invalid).
|
|
88
|
-
def
|
|
83
|
+
def gap_fill (method, axis, name)
|
|
84
|
+
axis = normalize_axis(axis, name) unless axis.nil?
|
|
89
85
|
case method
|
|
90
86
|
when :forward, :ffill
|
|
91
|
-
|
|
87
|
+
hold_along_axis(axis, false)
|
|
92
88
|
when :backward, :bfill
|
|
93
|
-
|
|
89
|
+
hold_along_axis(axis, true)
|
|
94
90
|
when :linear
|
|
95
|
-
|
|
91
|
+
gap_fill_linear(axis)
|
|
96
92
|
else
|
|
97
93
|
raise ArgumentError,
|
|
98
94
|
"unmask/strip_mask: unknown method: #{method.inspect} " \
|
|
@@ -100,22 +96,21 @@ class CArray
|
|
|
100
96
|
end
|
|
101
97
|
end
|
|
102
98
|
|
|
103
|
-
# Forward (backward = false) or backward (true) hold along `axis
|
|
104
|
-
# (axis nil = flatten). Backward reuses the forward primitive on the
|
|
99
|
+
# Forward (backward = false) or backward (true) hold along `axis`, already
|
|
100
|
+
# normalised by gap_fill (axis nil = flatten). Backward reuses the forward primitive on the
|
|
105
101
|
# reversed view; flatten flattens, holds axis 0, reshapes back.
|
|
106
|
-
def
|
|
102
|
+
def hold_along_axis (axis, backward)
|
|
107
103
|
if axis.nil?
|
|
108
104
|
flat = flatten
|
|
109
105
|
flat = flat.reverse if backward
|
|
110
|
-
held = flat.send(:
|
|
106
|
+
held = flat.send(:hold_forward, 0)
|
|
111
107
|
held = held.reverse if backward
|
|
112
108
|
held.reshape(*shape)
|
|
113
109
|
else
|
|
114
|
-
ax = axis < 0 ? axis + ndim : axis
|
|
115
110
|
if backward
|
|
116
|
-
flip(
|
|
111
|
+
flip(axis).send(:hold_forward, axis).flip(axis)
|
|
117
112
|
else
|
|
118
|
-
send(:
|
|
113
|
+
send(:hold_forward, axis)
|
|
119
114
|
end
|
|
120
115
|
end
|
|
121
116
|
end
|
|
@@ -123,64 +118,89 @@ class CArray
|
|
|
123
118
|
# Linear-by-index gap fill: interpolate each masked cell from the two
|
|
124
119
|
# bracketing valid cells, x = cell index along the axis. Cells outside the
|
|
125
120
|
# valid range (leading/trailing) stay masked. A Face goes through its own
|
|
126
|
-
# linear_fetch, which keeps its unit and rounds to its grid
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
def
|
|
130
|
-
|
|
121
|
+
# linear_fetch, which keeps its unit and rounds to its grid. Defining one
|
|
122
|
+
# is how a Face says it interpolates: without it, the core linear_fetch
|
|
123
|
+
# reads the Face's storage and fails from inside.
|
|
124
|
+
def gap_fill_linear (axis)
|
|
125
|
+
if face?
|
|
126
|
+
unless interpolable?
|
|
127
|
+
raise ArgumentError,
|
|
128
|
+
"unmask/strip_mask(method: :linear): #{self.class} does not " \
|
|
129
|
+
"interpolate (it defines no linear_fetch of its own); " \
|
|
130
|
+
"use method: :forward or :backward"
|
|
131
|
+
end
|
|
132
|
+
elsif ! numeric?
|
|
131
133
|
raise ArgumentError,
|
|
132
134
|
"unmask/strip_mask(method: :linear): numeric or time data_type " \
|
|
133
135
|
"required (got #{data_type_name})"
|
|
134
136
|
end
|
|
135
137
|
if axis.nil?
|
|
136
|
-
return
|
|
138
|
+
return linear_fill_fiber(flatten).reshape(*shape)
|
|
137
139
|
end
|
|
138
|
-
ax = axis
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
ax = axis
|
|
141
|
+
# A fiber comes back in self's own type (a Face's linear_fetch has already
|
|
142
|
+
# rounded to its grid), so the result assembles in that type and the
|
|
143
|
+
# present cells are never carried through float64.
|
|
144
|
+
out = face? ? template : value.copy
|
|
145
|
+
each_fiber_key(ax) do |key|
|
|
146
|
+
out[*key] = linear_fill_fiber(self[*key])
|
|
141
147
|
end
|
|
142
|
-
|
|
143
|
-
# to the grid, so there is nothing left to hold in float64. A numeric
|
|
144
|
-
# array assembles in float64 and casts back once at the end.
|
|
145
|
-
out = face? ? template : float64.copy
|
|
146
|
-
sink = face? ? out.parent : out
|
|
147
|
-
__each_fiber_key__(ax) do |key|
|
|
148
|
-
fiber = __linear_fiber__(self[*key])
|
|
149
|
-
sink[*key] = face? ? fiber.parent : fiber
|
|
150
|
-
end
|
|
151
|
-
face? ? out : out.to_type(data_type)
|
|
148
|
+
out
|
|
152
149
|
end
|
|
153
150
|
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
151
|
+
# Whether linear interpolation can fill this array: a numeric array, or a
|
|
152
|
+
# Face that defines a linear_fetch of its own -- which is how a Face says it
|
|
153
|
+
# interpolates (the core linear_fetch would read its storage).
|
|
154
|
+
private def interpolable?
|
|
155
|
+
face? ? self.class.instance_method(:linear_fetch).owner != CArray : numeric? # type-label: asks what the Face can do, names nothing
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# 1-D linear-by-index fill of a single (possibly masked) fiber.
|
|
159
|
+
def linear_fill_fiber (vec)
|
|
160
|
+
vec.send(:linear_fill_along, CArray.float64(vec.elements) { |i| i.to_f })
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Fill the masked cells of this 1-D array by linear interpolation against
|
|
164
|
+
# the coordinate `x` (same length, ascending over the present cells).
|
|
165
|
+
# The one rule both the core (x = cell position) and CAFrame (x = index)
|
|
166
|
+
# use: present cells come back exactly as they are, in this array's own
|
|
167
|
+
# type; a masked cell inside the span of the present ones takes the
|
|
168
|
+
# interpolated value; one outside it stays masked. Outside is where
|
|
169
|
+
# linear_section answers NaN -- a property of x, not of the values, so a
|
|
170
|
+
# NaN or Inf stored in a present cell is left alone. A Face goes through
|
|
171
|
+
# its own linear_fetch, which keeps its unit and rounds to its grid.
|
|
172
|
+
def linear_fill_along (x)
|
|
173
|
+
present = is_not_masked
|
|
162
174
|
# Fewer than two valid points -> nothing to interpolate between; leave
|
|
163
|
-
# every masked cell masked
|
|
164
|
-
if present.count(true) < 2
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
pos = CArray.float64(n) { |i| i.to_f }
|
|
168
|
-
addr = pos[present].linear_section(pos) # valid positions -> monotonic grid
|
|
169
|
-
if vec.face?
|
|
175
|
+
# every masked cell masked.
|
|
176
|
+
return copy if present.count(true) < 2
|
|
177
|
+
addr = x[present].linear_section(x) # valid positions -> monotonic grid
|
|
178
|
+
if face?
|
|
170
179
|
# The Face's linear_fetch already masks the exterior (out of range) and
|
|
171
|
-
# lands on its own grid
|
|
172
|
-
return
|
|
180
|
+
# lands on its own grid.
|
|
181
|
+
return self[present].linear_fetch(addr)
|
|
173
182
|
end
|
|
174
|
-
|
|
175
|
-
#
|
|
176
|
-
|
|
177
|
-
|
|
183
|
+
v = value[present]
|
|
184
|
+
# A complex value interpolates its real and imaginary parts.
|
|
185
|
+
interp = v.complex? ? v.linear_fetch(addr) : v.float64.linear_fetch(addr)
|
|
186
|
+
# An integer array takes the nearest integer, half away from zero (as a
|
|
187
|
+
# time Face lands on its own grid), rounded before the store would cut
|
|
188
|
+
# the fraction off.
|
|
189
|
+
interp = interp.round if integer?
|
|
190
|
+
# Built from the values alone, so a fully filled result carries no mask.
|
|
191
|
+
out = value.copy
|
|
192
|
+
masked = is_masked
|
|
193
|
+
fill = masked & addr.is_finite
|
|
194
|
+
exterior = masked & fill.not
|
|
195
|
+
out[fill] = interp[fill] if fill.any
|
|
196
|
+
out[exterior] = UNDEF if exterior.any
|
|
197
|
+
out
|
|
178
198
|
end
|
|
179
199
|
|
|
180
200
|
# Yield an index key (Array with `nil` at `axis`, integers elsewhere)
|
|
181
201
|
# for every fiber along `axis`. `self[*key]` is that fiber as a masked
|
|
182
202
|
# 1-D view.
|
|
183
|
-
def
|
|
203
|
+
def each_fiber_key (axis)
|
|
184
204
|
outer = shape
|
|
185
205
|
outer_dims = outer.each_index.reject { |k| k == axis }.map { |k| outer[k] }
|
|
186
206
|
idx = Array.new(outer_dims.size, 0)
|
|
@@ -196,7 +216,7 @@ class CArray
|
|
|
196
216
|
end
|
|
197
217
|
end
|
|
198
218
|
end
|
|
199
|
-
private :
|
|
200
|
-
:
|
|
219
|
+
private :hold_along_axis, :gap_fill_linear, :linear_fill_fiber,
|
|
220
|
+
:each_fiber_key
|
|
201
221
|
|
|
202
222
|
end
|
data/lib/carray/math.rb
CHANGED
|
@@ -3,23 +3,30 @@ module CAMath
|
|
|
3
3
|
module_function
|
|
4
4
|
|
|
5
5
|
# Module-function front-ends for binop math methods registered on
|
|
6
|
-
# CArray by mkkernel.
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# `arr.as_float64.hypot(...)`).
|
|
6
|
+
# CArray by mkkernel. A CArray first argument answers through its own
|
|
7
|
+
# method, in its own data_type; any other first argument, and an
|
|
8
|
+
# integer CArray for a function defined only on floats, is taken as
|
|
9
|
+
# float64, so `CAMath.hypot(3, arr)` works.
|
|
11
10
|
|
|
12
11
|
# @overload expm1(x)
|
|
13
|
-
# Returns `exp(x) - 1` element-wise
|
|
12
|
+
# Returns `exp(x) - 1` element-wise. A CArray answers in its own
|
|
13
|
+
# `data_type` (integer input widens to float64, as {CArray#expm1}
|
|
14
|
+
# does); any other value is taken as float64.
|
|
14
15
|
# @param x [CArray, Numeric] input value.
|
|
15
16
|
# @return [CArray]
|
|
16
|
-
def expm1(x)
|
|
17
|
+
def expm1(x)
|
|
18
|
+
x.is_a?(CArray) ? x.expm1 : CArray.wrap_readonly(x, :float64).expm1
|
|
19
|
+
end
|
|
17
20
|
|
|
18
21
|
# @overload log1p(x)
|
|
19
|
-
# Returns `log(1 + x)` element-wise
|
|
22
|
+
# Returns `log(1 + x)` element-wise. A CArray answers in its own
|
|
23
|
+
# `data_type` (integer input widens to float64, as {CArray#log1p}
|
|
24
|
+
# does); any other value is taken as float64.
|
|
20
25
|
# @param x [CArray, Numeric] input value.
|
|
21
26
|
# @return [CArray]
|
|
22
|
-
def log1p(x)
|
|
27
|
+
def log1p(x)
|
|
28
|
+
x.is_a?(CArray) ? x.log1p : CArray.wrap_readonly(x, :float64).log1p
|
|
29
|
+
end
|
|
23
30
|
|
|
24
31
|
# @overload atan2(y, x)
|
|
25
32
|
# Returns the element-wise arc tangent of `y / x` with quadrant
|
|
@@ -27,21 +34,21 @@ module CAMath
|
|
|
27
34
|
# @param y [CArray, Numeric] numerator.
|
|
28
35
|
# @param x [CArray, Numeric] denominator.
|
|
29
36
|
# @return [CArray]
|
|
30
|
-
def atan2(y, x);
|
|
37
|
+
def atan2(y, x); float_operand(y).atan2(x); end
|
|
31
38
|
|
|
32
39
|
# @overload hypot(x, y)
|
|
33
40
|
# Returns the element-wise Euclidean distance `sqrt(x^2 + y^2)`.
|
|
34
41
|
# @param x [CArray, Numeric] first leg.
|
|
35
42
|
# @param y [CArray, Numeric] second leg.
|
|
36
43
|
# @return [CArray]
|
|
37
|
-
def hypot(x, y);
|
|
44
|
+
def hypot(x, y); float_operand(x).hypot(y); end
|
|
38
45
|
|
|
39
46
|
# @overload copysign(x, y)
|
|
40
47
|
# Returns `|x|` with the sign of `y`, element-wise.
|
|
41
48
|
# @param x [CArray, Numeric] magnitude source.
|
|
42
49
|
# @param y [CArray, Numeric] sign source.
|
|
43
50
|
# @return [CArray]
|
|
44
|
-
def copysign(x, y);
|
|
51
|
+
def copysign(x, y); float_operand(x).copysign(y); end
|
|
45
52
|
|
|
46
53
|
# @overload logaddexp(x, y)
|
|
47
54
|
# Returns `log(exp(x) + exp(y))` computed to avoid overflow,
|
|
@@ -49,7 +56,7 @@ module CAMath
|
|
|
49
56
|
# @param x [CArray, Numeric] first log-space value.
|
|
50
57
|
# @param y [CArray, Numeric] second log-space value.
|
|
51
58
|
# @return [CArray]
|
|
52
|
-
def logaddexp(x, y);
|
|
59
|
+
def logaddexp(x, y); float_operand(x).logaddexp(y); end
|
|
53
60
|
|
|
54
61
|
# @overload nextafter(x, y)
|
|
55
62
|
# Returns the next representable float from `x` toward `y`,
|
|
@@ -57,21 +64,27 @@ module CAMath
|
|
|
57
64
|
# @param x [CArray, Numeric] starting value.
|
|
58
65
|
# @param y [CArray, Numeric] direction target.
|
|
59
66
|
# @return [CArray]
|
|
60
|
-
def nextafter(x, y);
|
|
67
|
+
def nextafter(x, y); float_operand(x).nextafter(y); end
|
|
61
68
|
|
|
62
69
|
# @overload fmod(x, y)
|
|
63
70
|
# Returns the C-style `fmod(x, y)` element-wise (sign follows `x`).
|
|
64
71
|
# @param x [CArray, Numeric] dividend.
|
|
65
72
|
# @param y [CArray, Numeric] divisor.
|
|
66
73
|
# @return [CArray]
|
|
67
|
-
def fmod(x, y); CArray.wrap_readonly(x, :float64).fmod(y);
|
|
74
|
+
def fmod(x, y); (x.is_a?(CArray) ? x : CArray.wrap_readonly(x, :float64)).fmod(y); end
|
|
75
|
+
|
|
76
|
+
# A float or complex CArray as it is; anything else as float64.
|
|
77
|
+
def float_operand(x)
|
|
78
|
+
x.is_a?(CArray) && (x.float? || x.complex?) ? x : CArray.wrap_readonly(x, :float64)
|
|
79
|
+
end
|
|
80
|
+
private_class_method :float_operand
|
|
68
81
|
|
|
69
82
|
# @overload min(*argv)
|
|
70
83
|
# Returns the element-wise minimum of the given CArray and other
|
|
71
84
|
# arguments. At least one argument must be a CArray.
|
|
72
85
|
# @param argv [Array<CArray, Numeric>] operands.
|
|
73
86
|
# @return [CArray] fresh CArray holding the running min.
|
|
74
|
-
# @raise [
|
|
87
|
+
# @raise [ArgumentError] when no CArray argument is present.
|
|
75
88
|
def min (*argv)
|
|
76
89
|
if ary = argv.find{|x| x.is_a?(CArray) }
|
|
77
90
|
out = ary.copy
|
|
@@ -80,7 +93,7 @@ module CAMath
|
|
|
80
93
|
out.pmin!(x)
|
|
81
94
|
end
|
|
82
95
|
else
|
|
83
|
-
raise "args should contain more than one CArray object"
|
|
96
|
+
raise ArgumentError, "args should contain more than one CArray object"
|
|
84
97
|
end
|
|
85
98
|
return out
|
|
86
99
|
end
|
|
@@ -90,7 +103,7 @@ module CAMath
|
|
|
90
103
|
# arguments. At least one argument must be a CArray.
|
|
91
104
|
# @param argv [Array<CArray, Numeric>] operands.
|
|
92
105
|
# @return [CArray] fresh CArray holding the running max.
|
|
93
|
-
# @raise [
|
|
106
|
+
# @raise [ArgumentError] when no CArray argument is present.
|
|
94
107
|
def max (*argv)
|
|
95
108
|
if ary = argv.find{|x| x.is_a?(CArray) }
|
|
96
109
|
out = ary.copy
|
|
@@ -99,7 +112,7 @@ module CAMath
|
|
|
99
112
|
out.pmax!(x)
|
|
100
113
|
end
|
|
101
114
|
else
|
|
102
|
-
raise "args should contain more than one CArray object"
|
|
115
|
+
raise ArgumentError, "args should contain more than one CArray object"
|
|
103
116
|
end
|
|
104
117
|
return out
|
|
105
118
|
end
|
data/lib/carray/meld_reduce.rb
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
#
|
|
17
17
|
# Fast path activates when:
|
|
18
18
|
# - axis kwarg is a single Integer (or absent for flat reduce)
|
|
19
|
-
# - no mask on CAMeld or any parent (
|
|
19
|
+
# - no mask on CAMeld or any parent (skipping masked cells needs per-cell dispatch;
|
|
20
20
|
# the decompose would not see correct mask propagation across parents)
|
|
21
21
|
# - no non-:axis kwargs (min_count / fill_value / keep_axis / etc. punt
|
|
22
22
|
# to super; those change finalisation semantics)
|
|
@@ -36,7 +36,7 @@ class CAMeld
|
|
|
36
36
|
|
|
37
37
|
def sum(*args, **kw)
|
|
38
38
|
return super unless args.empty? && meld_reduce_fast_path_ok?(kw)
|
|
39
|
-
axis = kw
|
|
39
|
+
axis = meld_fast_path_axis(kw)
|
|
40
40
|
if axis.nil?
|
|
41
41
|
parents.map(&:sum).inject(:+)
|
|
42
42
|
elsif meld_axis_normalized?(axis)
|
|
@@ -52,7 +52,10 @@ class CAMeld
|
|
|
52
52
|
# @return [CArray, Numeric]
|
|
53
53
|
def mean(*args, **kw)
|
|
54
54
|
return super unless args.empty? && meld_reduce_fast_path_ok?(kw)
|
|
55
|
-
|
|
55
|
+
# The combine divides in Float; an object array's mean stays exact
|
|
56
|
+
# (Rational, Integer division) on the core path.
|
|
57
|
+
return super if object?
|
|
58
|
+
axis = meld_fast_path_axis(kw)
|
|
56
59
|
# `mean` has no identity: an empty set of contributors has no defined
|
|
57
60
|
# mean (0/0 = NaN). Punt to super, which returns UNDEF: a reduction
|
|
58
61
|
# with no contributors yields the identity where one exists and UNDEF
|
|
@@ -63,9 +66,9 @@ class CAMeld
|
|
|
63
66
|
total_count = parents.map(&:elements).inject(:+)
|
|
64
67
|
total_sum / total_count.to_f
|
|
65
68
|
elsif meld_axis_normalized?(axis)
|
|
66
|
-
return super if parents.all? { |p| p.
|
|
69
|
+
return super if parents.all? { |p| p.shape[meld_axis] == 0 }
|
|
67
70
|
total_sum = parents.map { |p| p.sum(axis: axis) }.inject(:+)
|
|
68
|
-
total_count = parents.map { |p| p.
|
|
71
|
+
total_count = parents.map { |p| p.shape[meld_axis] }.inject(:+)
|
|
69
72
|
total_sum / total_count.to_f
|
|
70
73
|
else
|
|
71
74
|
non_meld_axis_decompose(:mean, axis)
|
|
@@ -78,15 +81,15 @@ class CAMeld
|
|
|
78
81
|
# @return [CArray, Numeric]
|
|
79
82
|
def min(*args, **kw)
|
|
80
83
|
return super unless args.empty? && meld_reduce_fast_path_ok?(kw)
|
|
81
|
-
axis = kw
|
|
84
|
+
axis = meld_fast_path_axis(kw)
|
|
82
85
|
# `min` has no identity — empty parent list / all-empty parents punt to
|
|
83
86
|
# super for UNDEF.
|
|
84
87
|
if axis.nil?
|
|
85
88
|
return super if parents.all? { |p| p.elements == 0 }
|
|
86
|
-
|
|
89
|
+
meld_combine_flat(:min)
|
|
87
90
|
elsif meld_axis_normalized?(axis)
|
|
88
|
-
return super if parents.all? { |p| p.
|
|
89
|
-
nonempty = parents.reject { |p| p.
|
|
91
|
+
return super if parents.all? { |p| p.shape[meld_axis] == 0 }
|
|
92
|
+
nonempty = parents.reject { |p| p.shape[meld_axis] == 0 }
|
|
90
93
|
CArray.stack(nonempty.map { |p| p.min(axis: axis) }).min(axis: 0)
|
|
91
94
|
else
|
|
92
95
|
non_meld_axis_decompose(:min, axis)
|
|
@@ -99,13 +102,13 @@ class CAMeld
|
|
|
99
102
|
# @return [CArray, Numeric]
|
|
100
103
|
def max(*args, **kw)
|
|
101
104
|
return super unless args.empty? && meld_reduce_fast_path_ok?(kw)
|
|
102
|
-
axis = kw
|
|
105
|
+
axis = meld_fast_path_axis(kw)
|
|
103
106
|
if axis.nil?
|
|
104
107
|
return super if parents.all? { |p| p.elements == 0 }
|
|
105
|
-
|
|
108
|
+
meld_combine_flat(:max)
|
|
106
109
|
elsif meld_axis_normalized?(axis)
|
|
107
|
-
return super if parents.all? { |p| p.
|
|
108
|
-
nonempty = parents.reject { |p| p.
|
|
110
|
+
return super if parents.all? { |p| p.shape[meld_axis] == 0 }
|
|
111
|
+
nonempty = parents.reject { |p| p.shape[meld_axis] == 0 }
|
|
109
112
|
CArray.stack(nonempty.map { |p| p.max(axis: axis) }).max(axis: 0)
|
|
110
113
|
else
|
|
111
114
|
non_meld_axis_decompose(:max, axis)
|
|
@@ -160,7 +163,7 @@ class CAMeld
|
|
|
160
163
|
private
|
|
161
164
|
|
|
162
165
|
def meld_axis_normalized?(axis)
|
|
163
|
-
(axis
|
|
166
|
+
normalize_axis(axis) == meld_axis
|
|
164
167
|
end
|
|
165
168
|
|
|
166
169
|
# Fast path fires when: no mask anywhere, no non-:axis kwargs, and axis
|
|
@@ -168,18 +171,40 @@ class CAMeld
|
|
|
168
171
|
# more elaborate (min_count / fill_value / keep_axis / multi-axis /
|
|
169
172
|
# mask propagation) punts to super.
|
|
170
173
|
def meld_reduce_fast_path_ok?(kw)
|
|
174
|
+
return false unless CArray.__fast_paths_enabled__
|
|
175
|
+
# The mask of a meld is a meld built in C, with no parents list.
|
|
176
|
+
return false unless parents
|
|
171
177
|
return false unless (kw.keys - [:axis]).empty?
|
|
172
178
|
axis = kw[:axis]
|
|
173
179
|
unless axis.nil?
|
|
174
|
-
return false unless axis.is_a?(Integer)
|
|
175
|
-
norm = axis < 0 ? axis + ndim : axis
|
|
176
|
-
return false unless norm >= 0 && norm < ndim
|
|
180
|
+
return false unless axis.is_a?(Integer) && axis >= -ndim && axis < ndim # axis-check: a gate only; super normalizes
|
|
177
181
|
end
|
|
178
182
|
return false if has_mask?
|
|
179
183
|
parents.each { |p| return false if p.has_mask? }
|
|
184
|
+
# A meld of Face arrays keeps its parents in their Face; the per-parent
|
|
185
|
+
# calls would reach the Face's own reductions, which answer in the Face's
|
|
186
|
+
# terms (or refuse), not in storage.
|
|
187
|
+
parents.each { |p| return false if p.face? }
|
|
180
188
|
true
|
|
181
189
|
end
|
|
182
190
|
|
|
191
|
+
# The axis a fast path reduces along. A 1-D meld has only the meld axis,
|
|
192
|
+
# and reducing it is reducing the whole array: the answer is a scalar, as
|
|
193
|
+
# for the flat call.
|
|
194
|
+
def meld_fast_path_axis(kw)
|
|
195
|
+
ndim == 1 ? nil : kw[:axis]
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# The per-parent answers of a whole-array min / max, combined by core's
|
|
199
|
+
# own min / max so NaN loses the way it loses inside one parent (Ruby's
|
|
200
|
+
# Array#min would raise on it).
|
|
201
|
+
def meld_combine_flat(op)
|
|
202
|
+
vals = parents.reject { |p| p.elements == 0 }.map(&op)
|
|
203
|
+
part = CArray.new(data_type, [vals.size])
|
|
204
|
+
vals.each_with_index { |v, i| part[i] = v }
|
|
205
|
+
part.public_send(op)
|
|
206
|
+
end
|
|
207
|
+
|
|
183
208
|
# Non-meld-axis decompose: each parent reduces the same axis independently,
|
|
184
209
|
# then the K per-parent results are concatenated back along the meld axis.
|
|
185
210
|
# Materialised to entity (`.copy`) to match CArray#reduce entity semantics.
|
|
@@ -191,14 +216,20 @@ class CAMeld
|
|
|
191
216
|
# meld_axis branch and never reaches here.)
|
|
192
217
|
def non_meld_axis_decompose(op, axis)
|
|
193
218
|
parts = parents.map { |p| p.public_send(op, axis: axis) }
|
|
194
|
-
axis_norm = axis
|
|
219
|
+
axis_norm = normalize_axis(axis)
|
|
195
220
|
new_meld_axis = axis_norm < meld_axis ? meld_axis - 1 : meld_axis
|
|
196
221
|
CArray.meld(parts, axis: new_meld_axis).copy
|
|
197
222
|
end
|
|
198
223
|
|
|
199
224
|
def variance_family(args, kw, sample:, sqrt:)
|
|
200
225
|
return yield unless args.empty? && meld_reduce_fast_path_ok?(kw)
|
|
201
|
-
|
|
226
|
+
# The merge works in Float; an object array's variance stays exact
|
|
227
|
+
# (Rational, BigDecimal) on the core path.
|
|
228
|
+
return yield if object?
|
|
229
|
+
# The merge squares the difference of means, which for complex values is
|
|
230
|
+
# not |δ|²; the core path computes the variance of a complex array.
|
|
231
|
+
return yield if complex?
|
|
232
|
+
axis = meld_fast_path_axis(kw)
|
|
202
233
|
# Empty-parent / short-parent handling — Welford needs n >= 2 per parent
|
|
203
234
|
# to recover m2 from p.variance for sample, n >= 1 for variancep (n=1
|
|
204
235
|
# gives m2=0, fine). Any parent below its threshold punts to super,
|
|
@@ -208,7 +239,7 @@ class CAMeld
|
|
|
208
239
|
return yield if parents.any? { |p| p.elements < min_n }
|
|
209
240
|
finalize_scalar(welford_flat, sample, sqrt)
|
|
210
241
|
elsif meld_axis_normalized?(axis)
|
|
211
|
-
return yield if parents.any? { |p| p.
|
|
242
|
+
return yield if parents.any? { |p| p.shape[meld_axis] < min_n }
|
|
212
243
|
finalize_vector(welford_axis(axis), sample, sqrt)
|
|
213
244
|
else
|
|
214
245
|
# Non-meld-axis: each parent's variance/stddev is independent along
|
|
@@ -255,7 +286,7 @@ class CAMeld
|
|
|
255
286
|
mean = nil
|
|
256
287
|
m2 = nil
|
|
257
288
|
parents.each do |p|
|
|
258
|
-
np = p.
|
|
289
|
+
np = p.shape[meld_axis]
|
|
259
290
|
mp = p.mean(axis: axis)
|
|
260
291
|
# variance is undefined at n=1; for variancep with n=1, m2_p = 0 by
|
|
261
292
|
# definition (variance_family already gated n >= min_n).
|
|
@@ -85,8 +85,10 @@ class CArray
|
|
|
85
85
|
# b_on_grid = b_data.project(ib)
|
|
86
86
|
#
|
|
87
87
|
# `direction:` (`:round` / `:floor` / `:ceil`) and `tolerance:` are
|
|
88
|
-
# forwarded to {#locate_nearest_addr}:
|
|
89
|
-
#
|
|
88
|
+
# forwarded to {#locate_nearest_addr}: grid points with no match in the
|
|
89
|
+
# direction (before an array's first value under `:floor`, after its last
|
|
90
|
+
# under `:ceil`), and points whose match is farther than `tolerance`, come
|
|
91
|
+
# back masked.
|
|
90
92
|
#
|
|
91
93
|
# @param arrays [Array<CArray>] one or more arrays (Array / Range coerced
|
|
92
94
|
# via `to_ca`).
|
|
@@ -94,8 +96,10 @@ class CArray
|
|
|
94
96
|
# `nil` uses the first array verbatim.
|
|
95
97
|
# @param direction [:round, :floor, :ceil] rounding rule for the nearest
|
|
96
98
|
# match.
|
|
97
|
-
# @param tolerance [Numeric, nil] maximum
|
|
98
|
-
# points are masked.
|
|
99
|
+
# @param tolerance [Numeric, String, CATimedelta::Element, nil] maximum
|
|
100
|
+
# accepted distance; farther grid points are masked. For time keys it
|
|
101
|
+
# is a duration (`"10 minutes"` or a CATimedelta value), as in
|
|
102
|
+
# {#locate_nearest_addr}. `nil` disables the check.
|
|
99
103
|
# @return [Array<CArray>] `[common, idx_0, idx_1, ...]`.
|
|
100
104
|
# @raise [ArgumentError] when no array is given (or `direction` is invalid,
|
|
101
105
|
# raised by {#locate_nearest_addr}).
|