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/lazy.rb
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
#
|
|
3
3
|
# Per-op lazy-or-eager method redefinition on CArray.
|
|
4
4
|
#
|
|
5
|
-
# For each of the monop/monfunc methods,
|
|
6
|
-
# implementation as
|
|
5
|
+
# For each of the monop/monfunc methods, keep the existing eager
|
|
6
|
+
# implementation as an UnboundMethod and redefine `<name>` to dispatch:
|
|
7
7
|
#
|
|
8
|
-
# - if self.
|
|
8
|
+
# - if self.lazy_view? → CAMonOp.__build__(self, OP_<NAME>)
|
|
9
9
|
# (cast node insertion handled in C if data_type mismatch)
|
|
10
|
-
# - else →
|
|
10
|
+
# - else → the eager implementation
|
|
11
11
|
#
|
|
12
12
|
# CAREFUL: the redefinition must run once at load time AFTER the eager
|
|
13
13
|
# methods are bound by Init_carray_math. carray_ext.bundle Init order
|
|
@@ -84,31 +84,42 @@ class CArray
|
|
|
84
84
|
imag_i: CAMonOp::OP_IMAG_I,
|
|
85
85
|
}.freeze
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
87
|
+
# The lazy-or-eager dispatch of the operators, in a module in front of
|
|
88
|
+
# the eager methods: each reaches its eager method with super. The
|
|
89
|
+
# blocks are shareable (they capture an op id at most), so the operators
|
|
90
|
+
# can be called from any Ractor.
|
|
91
|
+
module LazyDispatch; end
|
|
92
|
+
prepend LazyDispatch
|
|
93
|
+
|
|
94
|
+
CArray.send(:define_named_methods, LazyDispatch,
|
|
95
|
+
LAZY_MONOP_OP_IDS.reject { |name, _| name == :round }, template: <<~'RUBY')
|
|
96
|
+
def __NAME__
|
|
97
|
+
if lazy_view?
|
|
98
|
+
CAMonOp.__build__(self, __VALUE__)
|
|
98
99
|
else
|
|
99
|
-
|
|
100
|
+
super()
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
RUBY
|
|
104
|
+
|
|
105
|
+
# round takes digits, which the lazy node does not carry: rounding to
|
|
106
|
+
# digits evaluates the expression and rounds the result.
|
|
107
|
+
module LazyDispatch
|
|
108
|
+
def round(*digits)
|
|
109
|
+
if digits.empty? && lazy_view?
|
|
110
|
+
CAMonOp.__build__(self, CAMonOp::OP_ROUND)
|
|
111
|
+
else
|
|
112
|
+
super
|
|
100
113
|
end
|
|
101
114
|
end
|
|
102
115
|
end
|
|
103
116
|
|
|
104
|
-
# Operator aliases (`~` -> bit_neg, `-@` -> neg) were installed
|
|
105
|
-
# rb_define_alias at Init time (see MkKernel.alias_monop in
|
|
106
|
-
# ext/carray_kernels_monop.c)
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
# of building a CAMonOp node. Re-alias here so the operator form
|
|
111
|
-
# follows the redefined lazy-or-eager dispatch.
|
|
117
|
+
# Operator aliases (`~` -> bit_neg, `-@` -> neg) were installed in
|
|
118
|
+
# CArray by rb_define_alias at Init time (see MkKernel.alias_monop in
|
|
119
|
+
# ext/carray_kernels_monop.c), and name the eager C function: `~a` on a
|
|
120
|
+
# lazy view would materialise instead of building a CAMonOp node. Made
|
|
121
|
+
# again here, an alias resolves through the prepended modules, so the
|
|
122
|
+
# operator form takes the dispatch above.
|
|
112
123
|
alias_method :"~", :bit_neg
|
|
113
124
|
alias_method :"-@", :neg
|
|
114
125
|
|
|
@@ -129,22 +140,24 @@ class CArray
|
|
|
129
140
|
# ---------------------------------------------------------------------------
|
|
130
141
|
|
|
131
142
|
# @private
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
module LazyDispatch
|
|
144
|
+
def abs
|
|
145
|
+
if lazy_view?
|
|
146
|
+
# A boolean has no absolute value: the eager abs refuses it.
|
|
147
|
+
return super() if boolean?
|
|
148
|
+
abs_i_node = CAMonOp.__build__(self, CAMonOp::OP_ABS_I)
|
|
149
|
+
if complex?
|
|
150
|
+
# float_dt is a Symbol; convert via data_type_code so the cast
|
|
151
|
+
# op_id can be computed by Integer arithmetic.
|
|
152
|
+
float_dt = (data_type == CA_CMPLX64) ? CA_FLOAT32 : CA_FLOAT64
|
|
153
|
+
CAMonOp.__build__(abs_i_node,
|
|
154
|
+
CAMonOp::CAST_BASE + CArray.data_type_code(float_dt))
|
|
155
|
+
else
|
|
156
|
+
abs_i_node
|
|
157
|
+
end
|
|
143
158
|
else
|
|
144
|
-
|
|
159
|
+
super()
|
|
145
160
|
end
|
|
146
|
-
else
|
|
147
|
-
__abs_eager_um__.bind_call(self)
|
|
148
161
|
end
|
|
149
162
|
end
|
|
150
163
|
|
|
@@ -179,44 +192,48 @@ class CArray
|
|
|
179
192
|
# ---------------------------------------------------------------------------
|
|
180
193
|
|
|
181
194
|
# @private
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
195
|
+
module LazyDispatch
|
|
196
|
+
def real
|
|
197
|
+
if lazy_view?
|
|
198
|
+
if complex?
|
|
199
|
+
float_dt = (data_type == CA_CMPLX64) ? CA_FLOAT32 : CA_FLOAT64
|
|
200
|
+
# float_dt is a Symbol; convert via data_type_code for kernel
|
|
201
|
+
# op_id arithmetic.
|
|
202
|
+
CAMonOp.__build__(self,
|
|
203
|
+
CAMonOp::CAST_BASE + CArray.data_type_code(float_dt))
|
|
204
|
+
else
|
|
205
|
+
# `real` of a real array is the array itself; preserve the lazy
|
|
206
|
+
# chain unchanged (eager returns self[] = CARefer wrap, but for
|
|
207
|
+
# lazy chain consumption returning self keeps streaming intact).
|
|
208
|
+
self
|
|
209
|
+
end
|
|
192
210
|
else
|
|
193
|
-
|
|
194
|
-
# chain unchanged (eager returns self[] = CARefer wrap, but for
|
|
195
|
-
# lazy chain consumption returning self keeps streaming intact).
|
|
196
|
-
self
|
|
211
|
+
super()
|
|
197
212
|
end
|
|
198
|
-
else
|
|
199
|
-
__real_eager_um__.bind_call(self)
|
|
200
213
|
end
|
|
201
214
|
end
|
|
202
215
|
|
|
203
216
|
# @!visibility private
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
module LazyDispatch
|
|
218
|
+
def imag
|
|
219
|
+
if lazy_view?
|
|
220
|
+
imag_i_node = CAMonOp.__build__(self, CAMonOp::OP_IMAG_I)
|
|
221
|
+
if boolean?
|
|
222
|
+
# imag_i reads a boolean as int64; the eager imag stays boolean.
|
|
223
|
+
CAMonOp.__build__(imag_i_node,
|
|
224
|
+
CAMonOp::CAST_BASE + CArray.data_type_code(CA_BOOLEAN))
|
|
225
|
+
elsif complex?
|
|
226
|
+
float_dt = (data_type == CA_CMPLX64) ? CA_FLOAT32 : CA_FLOAT64
|
|
227
|
+
# float_dt is a Symbol; convert via data_type_code for kernel
|
|
228
|
+
# op_id arithmetic.
|
|
229
|
+
CAMonOp.__build__(imag_i_node,
|
|
230
|
+
CAMonOp::CAST_BASE + CArray.data_type_code(float_dt))
|
|
231
|
+
else
|
|
232
|
+
imag_i_node
|
|
233
|
+
end
|
|
215
234
|
else
|
|
216
|
-
|
|
235
|
+
super()
|
|
217
236
|
end
|
|
218
|
-
else
|
|
219
|
-
__imag_eager_um__.bind_call(self)
|
|
220
237
|
end
|
|
221
238
|
end
|
|
222
239
|
|
|
@@ -235,31 +252,31 @@ class CArray
|
|
|
235
252
|
#
|
|
236
253
|
# Both paths keep the operand's float / complex width (f32 → f32,
|
|
237
254
|
# cmplx64 → f32), and both send integers to f64 since pi does not fit
|
|
238
|
-
# an integer slot.
|
|
239
|
-
# "scalar keeps operand's precision" (see ca_lazy_wrap_scalar header).
|
|
255
|
+
# an integer slot.
|
|
240
256
|
# ---------------------------------------------------------------------------
|
|
241
257
|
|
|
242
258
|
# @private
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
259
|
+
module LazyDispatch
|
|
260
|
+
def arg
|
|
261
|
+
if lazy_view?
|
|
262
|
+
return super() if boolean? # the eager arg refuses it
|
|
263
|
+
parent = self
|
|
264
|
+
if integer?
|
|
265
|
+
parent = CAMonOp.__build__(parent,
|
|
266
|
+
CAMonOp::CAST_BASE +
|
|
267
|
+
CArray.data_type_code(CA_FLOAT64))
|
|
268
|
+
end
|
|
269
|
+
arg_i_node = CAMonOp.__build__(parent, CAMonOp::OP_ARG_I)
|
|
270
|
+
if complex?
|
|
271
|
+
float_dt = (data_type == CA_CMPLX64) ? CA_FLOAT32 : CA_FLOAT64
|
|
272
|
+
CAMonOp.__build__(arg_i_node,
|
|
273
|
+
CAMonOp::CAST_BASE + CArray.data_type_code(float_dt))
|
|
274
|
+
else
|
|
275
|
+
arg_i_node
|
|
276
|
+
end
|
|
258
277
|
else
|
|
259
|
-
|
|
278
|
+
super()
|
|
260
279
|
end
|
|
261
|
-
else
|
|
262
|
-
__arg_eager_um__.bind_call(self)
|
|
263
280
|
end
|
|
264
281
|
end
|
|
265
282
|
|
|
@@ -313,26 +330,26 @@ class CArray
|
|
|
313
330
|
# branch uses C99 `remainder`, round-half-to-even).
|
|
314
331
|
}.freeze
|
|
315
332
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
define_method(method_name) do |other|
|
|
321
|
-
if __lazy_view__? || (other.is_a?(CArray) && other.__lazy_view__?)
|
|
322
|
-
CABinOp.__build__(self, other, op_id)
|
|
333
|
+
CArray.send(:define_named_methods, LazyDispatch, LAZY_BINOP_OP_IDS, template: <<~'RUBY')
|
|
334
|
+
def __NAME__(other)
|
|
335
|
+
if lazy_view? || (other.is_a?(CArray) && other.lazy_view?)
|
|
336
|
+
CABinOp.__build__(self, other, __VALUE__)
|
|
323
337
|
else
|
|
324
|
-
|
|
338
|
+
super(other)
|
|
325
339
|
end
|
|
326
340
|
end
|
|
327
|
-
|
|
341
|
+
RUBY
|
|
342
|
+
|
|
343
|
+
# The shift count of an Integer is brought into the array's type before
|
|
344
|
+
# either form sees it (see CArray::IntegerShiftCount).
|
|
345
|
+
prepend IntegerShiftCount
|
|
328
346
|
|
|
329
347
|
# Binop word aliases (`add` -> `+`, `mul` -> `*`, `bit_and` -> `&`, …) were
|
|
330
|
-
# installed by rb_define_alias at Init time (see
|
|
331
|
-
# ext/carray_kernels_*.c)
|
|
332
|
-
#
|
|
333
|
-
#
|
|
334
|
-
#
|
|
335
|
-
# word form follows the redefined operator method.
|
|
348
|
+
# installed in CArray by rb_define_alias at Init time (see
|
|
349
|
+
# MkKernel.alias_binop in ext/carray_kernels_*.c) and name the eager C
|
|
350
|
+
# function, so `a.lazy.add(1)` would materialise. Made again here, an
|
|
351
|
+
# alias resolves through the prepended modules -- IntegerShiftCount, then
|
|
352
|
+
# LazyDispatch -- so the word form takes the operator's.
|
|
336
353
|
{
|
|
337
354
|
add: :+,
|
|
338
355
|
sub: :-,
|
|
@@ -345,21 +362,20 @@ class CArray
|
|
|
345
362
|
bit_lshift: :<<,
|
|
346
363
|
bit_rshift: :>>,
|
|
347
364
|
}.each do |word, op|
|
|
348
|
-
alias_method
|
|
365
|
+
alias_method word, op
|
|
349
366
|
end
|
|
350
367
|
|
|
351
368
|
# `pow` is the canonical C method (defined by rb_define_method in
|
|
352
369
|
# ext/ca_op_ipower.c) that `**` is rb_define_alias'd to. The `**`
|
|
353
|
-
#
|
|
354
|
-
#
|
|
355
|
-
# falls to eager. Re-alias so `pow` follows the redefined `**`.
|
|
370
|
+
# dispatch in this file does not reach `pow` through the C alias, so
|
|
371
|
+
# `a.lazy.pow(2)` would fall to eager; `pow` is aliased again here.
|
|
356
372
|
alias_method :pow, :**
|
|
357
373
|
|
|
358
374
|
# `fmax` / `fmin` are rb_define_alias'd to `pmax` / `pmin` at Init
|
|
359
|
-
# time (same C
|
|
360
|
-
#
|
|
361
|
-
alias_method :fmax, :pmax
|
|
362
|
-
alias_method :fmin, :pmin
|
|
375
|
+
# time (the same C alias); they are aliased again beside them, in
|
|
376
|
+
# LazyDispatch.
|
|
377
|
+
LazyDispatch.send(:alias_method, :fmax, :pmax)
|
|
378
|
+
LazyDispatch.send(:alias_method, :fmin, :pmin)
|
|
363
379
|
|
|
364
380
|
# ---------------------------------------------------------------------------
|
|
365
381
|
# Triop dispatch (fma / fms / clip). CATriOp is the CABinOp analog for
|
|
@@ -367,7 +383,7 @@ class CArray
|
|
|
367
383
|
# dispatches to CATriOp.__build__ when any of self / op2 / op3 is a
|
|
368
384
|
# lazy view, and falls to the eager C method otherwise.
|
|
369
385
|
#
|
|
370
|
-
# `clip` is the strict-clamp entry (`
|
|
386
|
+
# `clip` is the strict-clamp entry (`clamp_between`, called by the
|
|
371
387
|
# lib/carray/basics.rb `clip` wrapper's both-bounds-present path). The
|
|
372
388
|
# nil-bound one-sided cases route through the wrapper's `pmax` / `pmin`
|
|
373
389
|
# calls, which themselves lazy-fuse via LAZY_BINOP_OP_IDS above — so
|
|
@@ -376,26 +392,26 @@ class CArray
|
|
|
376
392
|
# ---------------------------------------------------------------------------
|
|
377
393
|
|
|
378
394
|
LAZY_TRIOP_OP_IDS = {
|
|
379
|
-
fma:
|
|
380
|
-
fms:
|
|
381
|
-
|
|
395
|
+
fma: CATriOp::OP_FMA,
|
|
396
|
+
fms: CATriOp::OP_FMS,
|
|
397
|
+
clamp_between: CATriOp::OP_CLIP,
|
|
382
398
|
}.freeze
|
|
383
399
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
lazy_receiver = __lazy_view__? ||
|
|
390
|
-
(op2.is_a?(CArray) && op2.__lazy_view__?) ||
|
|
391
|
-
(op3.is_a?(CArray) && op3.__lazy_view__?)
|
|
400
|
+
CArray.send(:define_named_methods, LazyDispatch, LAZY_TRIOP_OP_IDS, template: <<~'RUBY')
|
|
401
|
+
def __NAME__(op2, op3)
|
|
402
|
+
lazy_receiver = lazy_view? ||
|
|
403
|
+
(op2.is_a?(CArray) && op2.lazy_view?) ||
|
|
404
|
+
(op3.is_a?(CArray) && op3.lazy_view?)
|
|
392
405
|
if lazy_receiver
|
|
393
|
-
CATriOp.__build__(self, op2, op3,
|
|
406
|
+
CATriOp.__build__(self, op2, op3, __VALUE__)
|
|
394
407
|
else
|
|
395
|
-
|
|
408
|
+
super(op2, op3)
|
|
396
409
|
end
|
|
397
410
|
end
|
|
398
|
-
|
|
411
|
+
RUBY
|
|
412
|
+
# The clip kernel takes both bounds; the public entry is `clip`.
|
|
413
|
+
private :clamp_between
|
|
414
|
+
LazyDispatch.send(:private, :clamp_between)
|
|
399
415
|
|
|
400
416
|
# `**` integer-exponent lazy fast path.
|
|
401
417
|
#
|
|
@@ -417,16 +433,17 @@ class CArray
|
|
|
417
433
|
# `power` binop kernel already uses `op_powi_<type>` for integer data_types
|
|
418
434
|
# via the `int:` expr in MkKernel.binop :power, so OP_POW + int parent
|
|
419
435
|
# is already fast. The lazy-substrate gap was Float/Complex only.
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
436
|
+
module LazyDispatch
|
|
437
|
+
def **(other)
|
|
438
|
+
if other.is_a?(Integer) && (float? || complex?) &&
|
|
439
|
+
(lazy_view? || (other.is_a?(CArray) && other.lazy_view?))
|
|
440
|
+
CABinOp.__build__(self, CScalar.int64.tap { |s| s[0] = other },
|
|
441
|
+
CABinOp::OP_IPOWER)
|
|
442
|
+
elsif lazy_view? || (other.is_a?(CArray) && other.lazy_view?)
|
|
443
|
+
CABinOp.__build__(self, other, CABinOp::OP_POW)
|
|
444
|
+
else
|
|
445
|
+
super(other)
|
|
446
|
+
end
|
|
430
447
|
end
|
|
431
448
|
end
|
|
432
449
|
|
|
@@ -472,40 +489,34 @@ class CArray
|
|
|
472
489
|
:feq => CABinCmp::OP_FEQ,
|
|
473
490
|
}.freeze
|
|
474
491
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
define_method(method_name) do |other|
|
|
480
|
-
if __lazy_view__? || (other.is_a?(CArray) && other.__lazy_view__?)
|
|
481
|
-
CABinCmp.__build__(self, other, op_id)
|
|
492
|
+
CArray.send(:define_named_methods, LazyDispatch, LAZY_BINCMP_OP_IDS, template: <<~'RUBY')
|
|
493
|
+
def __NAME__(other)
|
|
494
|
+
if lazy_view? || (other.is_a?(CArray) && other.lazy_view?)
|
|
495
|
+
CABinCmp.__build__(self, other, __VALUE__)
|
|
482
496
|
else
|
|
483
|
-
|
|
497
|
+
super(other)
|
|
484
498
|
end
|
|
485
499
|
end
|
|
486
|
-
|
|
500
|
+
RUBY
|
|
487
501
|
|
|
488
502
|
# tolerance-bearing bincmp ops (= is_close / is_equiv) use the same
|
|
489
503
|
# CABinCmp dispatch but with a 2nd `tol` positional arg. Kept in a
|
|
490
|
-
# separate dict because the LAZY_BINCMP_OP_IDS
|
|
504
|
+
# separate dict because the LAZY_BINCMP_OP_IDS template above
|
|
491
505
|
# uses arity 1 (|other|); these need arity 2 (|other, tol|).
|
|
492
506
|
LAZY_BINCMP_TOL_OP_IDS = {
|
|
493
507
|
:is_close => CABinCmp::OP_IS_CLOSE,
|
|
494
508
|
:is_equiv => CABinCmp::OP_IS_EQUIV,
|
|
495
509
|
}.freeze
|
|
496
510
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
define_method(method_name) do |other, tol|
|
|
502
|
-
if __lazy_view__? || (other.is_a?(CArray) && other.__lazy_view__?)
|
|
503
|
-
CABinCmp.__build__(self, other, op_id, tol.to_f.abs)
|
|
511
|
+
CArray.send(:define_named_methods, LazyDispatch, LAZY_BINCMP_TOL_OP_IDS, template: <<~'RUBY')
|
|
512
|
+
def __NAME__(other, tol)
|
|
513
|
+
if lazy_view? || (other.is_a?(CArray) && other.lazy_view?)
|
|
514
|
+
CABinCmp.__build__(self, other, __VALUE__, tol.to_f.abs)
|
|
504
515
|
else
|
|
505
|
-
|
|
516
|
+
super(other, tol)
|
|
506
517
|
end
|
|
507
518
|
end
|
|
508
|
-
|
|
519
|
+
RUBY
|
|
509
520
|
|
|
510
521
|
# @!visibility private
|
|
511
522
|
LAZY_MONCMP_OP_IDS = {
|
|
@@ -516,36 +527,58 @@ class CArray
|
|
|
516
527
|
signbit: CAMonCmp::OP_SIGNBIT,
|
|
517
528
|
}.freeze
|
|
518
529
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
define_method(name) do
|
|
524
|
-
if __lazy_view__?
|
|
525
|
-
CAMonCmp.__build__(self, op_id)
|
|
530
|
+
CArray.send(:define_named_methods, LazyDispatch, LAZY_MONCMP_OP_IDS, template: <<~'RUBY')
|
|
531
|
+
def __NAME__
|
|
532
|
+
if lazy_view?
|
|
533
|
+
CAMonCmp.__build__(self, __VALUE__)
|
|
526
534
|
else
|
|
527
|
-
|
|
535
|
+
super()
|
|
528
536
|
end
|
|
529
537
|
end
|
|
530
|
-
|
|
538
|
+
RUBY
|
|
531
539
|
|
|
540
|
+
# A lazy receiver takes the scalar the eager coerce makes, and stays
|
|
541
|
+
# lazy itself: the builder promotes the pair as the eager operator does.
|
|
532
542
|
# @!visibility private
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
s[0] = other
|
|
541
|
-
[s, self]
|
|
542
|
-
else
|
|
543
|
-
coerce_um.bind_call(self, other)
|
|
543
|
+
module LazyDispatch
|
|
544
|
+
def coerce(other)
|
|
545
|
+
begin
|
|
546
|
+
scalar, receiver = super(other)
|
|
547
|
+
rescue RangeError => e
|
|
548
|
+
raise unless other.is_a?(Integer)
|
|
549
|
+
return [OutOfRangeInteger.new(other, self, e), self]
|
|
544
550
|
end
|
|
545
|
-
|
|
546
|
-
coerce_um.bind_call(self, other)
|
|
551
|
+
lazy_view? ? [scalar, self] : [scalar, receiver]
|
|
547
552
|
end
|
|
548
553
|
end
|
|
554
|
+
|
|
555
|
+
# An Integer the array's type cannot hold, on the left of an operator.
|
|
556
|
+
# A comparison is answered from the array's side, where it compares by
|
|
557
|
+
# value; any other operator refuses the Integer as the array would.
|
|
558
|
+
class OutOfRangeInteger
|
|
559
|
+
def initialize (value, array, error)
|
|
560
|
+
@value, @array, @error = value, array, error
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
def < (other) = flip(other, :>)
|
|
564
|
+
def <= (other) = flip(other, :>=)
|
|
565
|
+
def > (other) = flip(other, :<)
|
|
566
|
+
def >= (other) = flip(other, :<=)
|
|
567
|
+
|
|
568
|
+
def method_missing (*)
|
|
569
|
+
raise @error
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
def respond_to_missing? (*) = false
|
|
573
|
+
|
|
574
|
+
private
|
|
575
|
+
|
|
576
|
+
def flip (other, op)
|
|
577
|
+
raise @error unless other.equal?(@array)
|
|
578
|
+
@array.send(op, @value)
|
|
579
|
+
end
|
|
580
|
+
end
|
|
581
|
+
private_constant :OutOfRangeInteger
|
|
549
582
|
end
|
|
550
583
|
|
|
551
584
|
# ---------------------------------------------------------------------------
|
|
@@ -618,14 +651,6 @@ class CAMonOp
|
|
|
618
651
|
to_ca.to_a
|
|
619
652
|
end
|
|
620
653
|
|
|
621
|
-
# @overload sort(*args, **kwargs)
|
|
622
|
-
# Materialises `self` into a copy and returns
|
|
623
|
-
# `entity.sort(*args, **kwargs)`.
|
|
624
|
-
# @return [CArray]
|
|
625
|
-
def sort(*args, **kwargs)
|
|
626
|
-
copy.sort(*args, **kwargs)
|
|
627
|
-
end
|
|
628
|
-
|
|
629
654
|
# --- MemoryView export → TypeError + .copy recommendation -----------
|
|
630
655
|
|
|
631
656
|
# bulk-memory-view / Numo / Apache Arrow consumers go through the MV
|
|
@@ -714,13 +739,6 @@ class CABinOp
|
|
|
714
739
|
to_ca.to_a
|
|
715
740
|
end
|
|
716
741
|
|
|
717
|
-
# @overload sort(*args, **kwargs)
|
|
718
|
-
# Materialises `self` and sorts the resulting entity.
|
|
719
|
-
# @return [CArray]
|
|
720
|
-
def sort(*args, **kwargs)
|
|
721
|
-
to_ca.sort(*args, **kwargs)
|
|
722
|
-
end
|
|
723
|
-
|
|
724
742
|
# @overload to_memory_view
|
|
725
743
|
# Not supported for lazy binops.
|
|
726
744
|
# @raise [TypeError] always.
|
|
@@ -856,8 +874,13 @@ class << CArray
|
|
|
856
874
|
# is not an answer: one that raises is dropped, with a warning, and
|
|
857
875
|
# expressions are walked from there on.
|
|
858
876
|
#
|
|
877
|
+
# Only the main Ractor asks it: it is registered there, and is not
|
|
878
|
+
# shared with the others, where expressions are walked.
|
|
879
|
+
#
|
|
859
880
|
# @return [#call, nil]
|
|
860
|
-
|
|
881
|
+
def expression_evaluator
|
|
882
|
+
Ractor.current == Ractor.main ? @expression_evaluator : nil
|
|
883
|
+
end
|
|
861
884
|
|
|
862
885
|
# @param object [#call, nil] see {#expression_evaluator}
|
|
863
886
|
# @raise [ArgumentError] when it cannot be called.
|