carray 3.0.3 → 3.0.5
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 +469 -0
- data/README.md +3 -2
- data/carray.gemspec +1 -1
- data/ext/ca_array_pool.c +25 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +14 -26
- 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 +231 -153
- data/ext/ca_compare.c +9 -20
- data/ext/ca_composite_dispatch.c +9 -9
- data/ext/ca_group_iter.c +16 -17
- data/ext/ca_kernel_iterator.c +1240 -2000
- data/ext/ca_kernel_iterator.h +502 -519
- data/ext/ca_monop_dispatch.c +82 -59
- data/ext/ca_monop_dispatch.h +1 -0
- data/ext/ca_obj_array.c +152 -45
- data/ext/ca_obj_bincmp.c +25 -21
- data/ext/ca_obj_binop.c +16 -26
- data/ext/ca_obj_bitarray.c +8 -3
- data/ext/ca_obj_bitfield.c +63 -49
- data/ext/ca_obj_block.c +18 -9
- data/ext/ca_obj_byte_swap.c +7 -7
- data/ext/ca_obj_const_string.c +188 -22
- data/ext/ca_obj_face.c +280 -58
- 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 +30 -8
- data/ext/ca_obj_fixlen_string.c +2 -3
- data/ext/ca_obj_grid.c +455 -134
- data/ext/ca_obj_meld.c +172 -34
- data/ext/ca_obj_moncmp.c +23 -8
- data/ext/ca_obj_monop.c +113 -67
- data/ext/ca_obj_object.c +210 -52
- data/ext/ca_obj_record.c +15 -7
- data/ext/ca_obj_reduce.c +17 -8
- data/ext/ca_obj_refer.c +42 -35
- data/ext/ca_obj_remap.c +30 -9
- data/ext/ca_obj_repeat.c +9 -10
- data/ext/ca_obj_roll.c +31 -10
- data/ext/ca_obj_select.c +48 -14
- data/ext/ca_obj_select_axis.c +15 -47
- data/ext/ca_obj_shift.c +41 -7
- data/ext/ca_obj_stack.c +180 -34
- data/ext/ca_obj_stride.c +190 -134
- data/ext/ca_obj_string.c +80 -4
- data/ext/ca_obj_tile.c +32 -11
- data/ext/ca_obj_time.c +22 -6
- data/ext/ca_obj_timedelta.c +22 -6
- data/ext/ca_obj_transpose.c +13 -7
- data/ext/ca_obj_triop.c +26 -32
- data/ext/ca_obj_window.c +267 -74
- data/ext/ca_op_ipower.c +4 -4
- data/ext/ca_sort_kernels.h +6 -3
- data/ext/ca_sweep_engine.c +2 -2
- data/ext/caframe_csv_reader.c +80 -1
- data/ext/carray.h +214 -75
- data/ext/carray_access.c +200 -99
- data/ext/carray_address_basis.c +343 -87
- data/ext/carray_attribute.c +113 -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 +375 -96
- data/ext/carray_cast_func.rb +90 -20
- data/ext/carray_class.c +4 -3
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +18 -9
- data/ext/carray_copy.c +51 -14
- data/ext/carray_core.c +150 -55
- data/ext/carray_count.c +56 -20
- data/ext/carray_element.c +81 -33
- data/ext/carray_factorize.c +138 -84
- data/ext/carray_generate.c +199 -52
- data/ext/carray_histogram.c +63 -18
- data/ext/carray_hold.c +12 -15
- data/ext/carray_index_classifier.c +388 -176
- data/ext/carray_internal.h +348 -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 +10897 -0
- data/ext/carray_kernels_triop.c +1864 -0
- data/ext/carray_key_windows.c +220 -0
- data/ext/carray_lazy.c +170 -111
- data/ext/carray_mask.c +337 -94
- data/ext/carray_median_percentile.c +82 -28
- data/ext/carray_memory_view.c +669 -561
- data/ext/carray_operator.c +129 -52
- data/ext/carray_order.c +604 -77
- data/ext/carray_partition.c +28 -27
- data/ext/carray_random.c +85 -31
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +87 -45
- data/ext/carray_segment.c +3 -3
- data/ext/carray_slab.c +123 -37
- data/ext/carray_sort.c +259 -51
- data/ext/carray_sort_kernel.c +5 -7
- data/ext/carray_struct.c +54 -61
- data/ext/carray_test.c +26 -5
- data/ext/carray_time_text.c +4 -2
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +309 -66
- data/ext/mk_call_cfunc.rb +19 -2
- data/ext/mkkernel.rb +403 -350
- data/ext/ruby_carray.c +10 -4
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +139 -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 +105 -17
- 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 +195 -59
- data/lib/carray/categorical_iterator.rb +132 -29
- data/lib/carray/complex.rb +5 -5
- data/lib/carray/conditional.rb +67 -18
- data/lib/carray/const_string.rb +24 -5
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +9 -1
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +48 -3
- data/lib/carray/frame/column_verbs.rb +71 -0
- data/lib/carray/frame/concat.rb +17 -3
- 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 +252 -28
- data/lib/carray/frame/group.rb +603 -101
- data/lib/carray/frame/io.rb +117 -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 +42 -6
- 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 +217 -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 +61 -37
- 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 +323 -88
- data/lib/carray/serialize.rb +45 -14
- data/lib/carray/slab_iterator.rb +50 -0
- data/lib/carray/stack.rb +15 -12
- data/lib/carray/string.rb +113 -5
- data/lib/carray/string_operation_extension.rb +21 -6
- data/lib/carray/struct.rb +9 -21
- data/lib/carray/struct_builder.rb +24 -11
- data/lib/carray/time.rb +819 -158
- 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_transpose.rb +5 -4
- data/yard-stubs/ca_obj_window.rb +8 -3
- data/yard-stubs/carray_access.rb +6 -1
- data/yard-stubs/carray_attribute.rb +3 -6
- data/yard-stubs/carray_cast.rb +12 -0
- data/yard-stubs/carray_conversion.rb +7 -2
- data/yard-stubs/carray_copy.rb +4 -2
- data/yard-stubs/carray_count.rb +4 -4
- data/yard-stubs/carray_element.rb +17 -10
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_mask.rb +32 -3
- data/yard-stubs/carray_math.rb +41 -5
- data/yard-stubs/carray_median_percentile.rb +5 -2
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +129 -22
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +17 -10
- 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/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,26 +140,24 @@ class CArray
|
|
|
129
140
|
# ---------------------------------------------------------------------------
|
|
130
141
|
|
|
131
142
|
# @private
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
|
147
158
|
else
|
|
148
|
-
|
|
159
|
+
super()
|
|
149
160
|
end
|
|
150
|
-
else
|
|
151
|
-
__abs_eager_um__.bind_call(self)
|
|
152
161
|
end
|
|
153
162
|
end
|
|
154
163
|
|
|
@@ -183,48 +192,48 @@ class CArray
|
|
|
183
192
|
# ---------------------------------------------------------------------------
|
|
184
193
|
|
|
185
194
|
# @private
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
|
196
210
|
else
|
|
197
|
-
|
|
198
|
-
# chain unchanged (eager returns self[] = CARefer wrap, but for
|
|
199
|
-
# lazy chain consumption returning self keeps streaming intact).
|
|
200
|
-
self
|
|
211
|
+
super()
|
|
201
212
|
end
|
|
202
|
-
else
|
|
203
|
-
__real_eager_um__.bind_call(self)
|
|
204
213
|
end
|
|
205
214
|
end
|
|
206
215
|
|
|
207
216
|
# @!visibility private
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
|
223
234
|
else
|
|
224
|
-
|
|
235
|
+
super()
|
|
225
236
|
end
|
|
226
|
-
else
|
|
227
|
-
__imag_eager_um__.bind_call(self)
|
|
228
237
|
end
|
|
229
238
|
end
|
|
230
239
|
|
|
@@ -247,29 +256,27 @@ class CArray
|
|
|
247
256
|
# ---------------------------------------------------------------------------
|
|
248
257
|
|
|
249
258
|
# @private
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
|
268
277
|
else
|
|
269
|
-
|
|
278
|
+
super()
|
|
270
279
|
end
|
|
271
|
-
else
|
|
272
|
-
__arg_eager_um__.bind_call(self)
|
|
273
280
|
end
|
|
274
281
|
end
|
|
275
282
|
|
|
@@ -323,30 +330,45 @@ class CArray
|
|
|
323
330
|
# branch uses C99 `remainder`, round-half-to-even).
|
|
324
331
|
}.freeze
|
|
325
332
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
+
# A Face answers an operator by its own values (a label, an instant, a
|
|
334
|
+
# String) and refuses what it can't answer; the lazy kernels read the
|
|
335
|
+
# storage and see neither. With a Face among the operands the operator is
|
|
336
|
+
# the eager one, on the lazy operands computed.
|
|
337
|
+
module LazyDispatch
|
|
338
|
+
private
|
|
339
|
+
|
|
340
|
+
def face_among_operands? (*operands)
|
|
341
|
+
operands.any? { |o| o.is_a?(CArray) && o.face? }
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def computed_operand (operand)
|
|
345
|
+
( operand.is_a?(CArray) && operand.lazy_view? ) ? operand.copy : operand
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
CArray.send(:define_named_methods, LazyDispatch, LAZY_BINOP_OP_IDS, template: <<~'RUBY')
|
|
350
|
+
def __NAME__(other)
|
|
351
|
+
if lazy_view? || (other.is_a?(CArray) && other.lazy_view?)
|
|
352
|
+
if face_among_operands?(self, other)
|
|
353
|
+
return computed_operand(self).__send__(__method__, computed_operand(other))
|
|
354
|
+
end
|
|
355
|
+
CABinOp.__build__(self, other, __VALUE__)
|
|
333
356
|
else
|
|
334
|
-
|
|
357
|
+
super(other)
|
|
335
358
|
end
|
|
336
359
|
end
|
|
337
|
-
|
|
360
|
+
RUBY
|
|
338
361
|
|
|
339
362
|
# The shift count of an Integer is brought into the array's type before
|
|
340
363
|
# either form sees it (see CArray::IntegerShiftCount).
|
|
341
364
|
prepend IntegerShiftCount
|
|
342
365
|
|
|
343
366
|
# Binop word aliases (`add` -> `+`, `mul` -> `*`, `bit_and` -> `&`, …) were
|
|
344
|
-
# installed by rb_define_alias at Init time (see
|
|
345
|
-
# ext/carray_kernels_*.c)
|
|
346
|
-
#
|
|
347
|
-
#
|
|
348
|
-
#
|
|
349
|
-
# word form follows the redefined operator method.
|
|
367
|
+
# installed in CArray by rb_define_alias at Init time (see
|
|
368
|
+
# MkKernel.alias_binop in ext/carray_kernels_*.c) and name the eager C
|
|
369
|
+
# function, so `a.lazy.add(1)` would materialise. Made again here, an
|
|
370
|
+
# alias resolves through the prepended modules -- IntegerShiftCount, then
|
|
371
|
+
# LazyDispatch -- so the word form takes the operator's.
|
|
350
372
|
{
|
|
351
373
|
add: :+,
|
|
352
374
|
sub: :-,
|
|
@@ -359,21 +381,20 @@ class CArray
|
|
|
359
381
|
bit_lshift: :<<,
|
|
360
382
|
bit_rshift: :>>,
|
|
361
383
|
}.each do |word, op|
|
|
362
|
-
alias_method
|
|
384
|
+
alias_method word, op
|
|
363
385
|
end
|
|
364
386
|
|
|
365
387
|
# `pow` is the canonical C method (defined by rb_define_method in
|
|
366
388
|
# ext/ca_op_ipower.c) that `**` is rb_define_alias'd to. The `**`
|
|
367
|
-
#
|
|
368
|
-
#
|
|
369
|
-
# falls to eager. Re-alias so `pow` follows the redefined `**`.
|
|
389
|
+
# dispatch in this file does not reach `pow` through the C alias, so
|
|
390
|
+
# `a.lazy.pow(2)` would fall to eager; `pow` is aliased again here.
|
|
370
391
|
alias_method :pow, :**
|
|
371
392
|
|
|
372
393
|
# `fmax` / `fmin` are rb_define_alias'd to `pmax` / `pmin` at Init
|
|
373
|
-
# time (same C
|
|
374
|
-
#
|
|
375
|
-
alias_method :fmax, :pmax
|
|
376
|
-
alias_method :fmin, :pmin
|
|
394
|
+
# time (the same C alias); they are aliased again beside them, in
|
|
395
|
+
# LazyDispatch.
|
|
396
|
+
LazyDispatch.send(:alias_method, :fmax, :pmax)
|
|
397
|
+
LazyDispatch.send(:alias_method, :fmin, :pmin)
|
|
377
398
|
|
|
378
399
|
# ---------------------------------------------------------------------------
|
|
379
400
|
# Triop dispatch (fma / fms / clip). CATriOp is the CABinOp analog for
|
|
@@ -381,7 +402,7 @@ class CArray
|
|
|
381
402
|
# dispatches to CATriOp.__build__ when any of self / op2 / op3 is a
|
|
382
403
|
# lazy view, and falls to the eager C method otherwise.
|
|
383
404
|
#
|
|
384
|
-
# `clip` is the strict-clamp entry (`
|
|
405
|
+
# `clip` is the strict-clamp entry (`clamp_between`, called by the
|
|
385
406
|
# lib/carray/basics.rb `clip` wrapper's both-bounds-present path). The
|
|
386
407
|
# nil-bound one-sided cases route through the wrapper's `pmax` / `pmin`
|
|
387
408
|
# calls, which themselves lazy-fuse via LAZY_BINOP_OP_IDS above — so
|
|
@@ -390,26 +411,30 @@ class CArray
|
|
|
390
411
|
# ---------------------------------------------------------------------------
|
|
391
412
|
|
|
392
413
|
LAZY_TRIOP_OP_IDS = {
|
|
393
|
-
fma:
|
|
394
|
-
fms:
|
|
395
|
-
|
|
414
|
+
fma: CATriOp::OP_FMA,
|
|
415
|
+
fms: CATriOp::OP_FMS,
|
|
416
|
+
clamp_between: CATriOp::OP_CLIP,
|
|
396
417
|
}.freeze
|
|
397
418
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
lazy_receiver = __lazy_view__? ||
|
|
404
|
-
(op2.is_a?(CArray) && op2.__lazy_view__?) ||
|
|
405
|
-
(op3.is_a?(CArray) && op3.__lazy_view__?)
|
|
419
|
+
CArray.send(:define_named_methods, LazyDispatch, LAZY_TRIOP_OP_IDS, template: <<~'RUBY')
|
|
420
|
+
def __NAME__(op2, op3)
|
|
421
|
+
lazy_receiver = lazy_view? ||
|
|
422
|
+
(op2.is_a?(CArray) && op2.lazy_view?) ||
|
|
423
|
+
(op3.is_a?(CArray) && op3.lazy_view?)
|
|
406
424
|
if lazy_receiver
|
|
407
|
-
|
|
425
|
+
if face_among_operands?(self, op2, op3)
|
|
426
|
+
return computed_operand(self).__send__(__method__, computed_operand(op2),
|
|
427
|
+
computed_operand(op3))
|
|
428
|
+
end
|
|
429
|
+
CATriOp.__build__(self, op2, op3, __VALUE__)
|
|
408
430
|
else
|
|
409
|
-
|
|
431
|
+
super(op2, op3)
|
|
410
432
|
end
|
|
411
433
|
end
|
|
412
|
-
|
|
434
|
+
RUBY
|
|
435
|
+
# The clip kernel takes both bounds; the public entry is `clip`.
|
|
436
|
+
private :clamp_between
|
|
437
|
+
LazyDispatch.send(:private, :clamp_between)
|
|
413
438
|
|
|
414
439
|
# `**` integer-exponent lazy fast path.
|
|
415
440
|
#
|
|
@@ -431,16 +456,21 @@ class CArray
|
|
|
431
456
|
# `power` binop kernel already uses `op_powi_<type>` for integer data_types
|
|
432
457
|
# via the `int:` expr in MkKernel.binop :power, so OP_POW + int parent
|
|
433
458
|
# is already fast. The lazy-substrate gap was Float/Complex only.
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
459
|
+
module LazyDispatch
|
|
460
|
+
def **(other)
|
|
461
|
+
if ( lazy_view? || (other.is_a?(CArray) && other.lazy_view?) ) &&
|
|
462
|
+
face_among_operands?(self, other)
|
|
463
|
+
return computed_operand(self) ** computed_operand(other)
|
|
464
|
+
end
|
|
465
|
+
if other.is_a?(Integer) && (float? || complex?) &&
|
|
466
|
+
(lazy_view? || (other.is_a?(CArray) && other.lazy_view?))
|
|
467
|
+
CABinOp.__build__(self, CScalar.int64.tap { |s| s[0] = other },
|
|
468
|
+
CABinOp::OP_IPOWER)
|
|
469
|
+
elsif lazy_view? || (other.is_a?(CArray) && other.lazy_view?)
|
|
470
|
+
CABinOp.__build__(self, other, CABinOp::OP_POW)
|
|
471
|
+
else
|
|
472
|
+
super(other)
|
|
473
|
+
end
|
|
444
474
|
end
|
|
445
475
|
end
|
|
446
476
|
|
|
@@ -486,40 +516,40 @@ class CArray
|
|
|
486
516
|
:feq => CABinCmp::OP_FEQ,
|
|
487
517
|
}.freeze
|
|
488
518
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
CABinCmp.__build__(self, other,
|
|
519
|
+
CArray.send(:define_named_methods, LazyDispatch, LAZY_BINCMP_OP_IDS, template: <<~'RUBY')
|
|
520
|
+
def __NAME__(other)
|
|
521
|
+
if lazy_view? || (other.is_a?(CArray) && other.lazy_view?)
|
|
522
|
+
if face_among_operands?(self, other)
|
|
523
|
+
return computed_operand(self).__send__(__method__, computed_operand(other))
|
|
524
|
+
end
|
|
525
|
+
CABinCmp.__build__(self, other, __VALUE__)
|
|
496
526
|
else
|
|
497
|
-
|
|
527
|
+
super(other)
|
|
498
528
|
end
|
|
499
529
|
end
|
|
500
|
-
|
|
530
|
+
RUBY
|
|
501
531
|
|
|
502
532
|
# tolerance-bearing bincmp ops (= is_close / is_equiv) use the same
|
|
503
533
|
# CABinCmp dispatch but with a 2nd `tol` positional arg. Kept in a
|
|
504
|
-
# separate dict because the LAZY_BINCMP_OP_IDS
|
|
534
|
+
# separate dict because the LAZY_BINCMP_OP_IDS template above
|
|
505
535
|
# uses arity 1 (|other|); these need arity 2 (|other, tol|).
|
|
506
536
|
LAZY_BINCMP_TOL_OP_IDS = {
|
|
507
537
|
:is_close => CABinCmp::OP_IS_CLOSE,
|
|
508
538
|
:is_equiv => CABinCmp::OP_IS_EQUIV,
|
|
509
539
|
}.freeze
|
|
510
540
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
CABinCmp.__build__(self, other,
|
|
541
|
+
CArray.send(:define_named_methods, LazyDispatch, LAZY_BINCMP_TOL_OP_IDS, template: <<~'RUBY')
|
|
542
|
+
def __NAME__(other, tol)
|
|
543
|
+
if lazy_view? || (other.is_a?(CArray) && other.lazy_view?)
|
|
544
|
+
if face_among_operands?(self, other)
|
|
545
|
+
return computed_operand(self).__send__(__method__, computed_operand(other), tol)
|
|
546
|
+
end
|
|
547
|
+
CABinCmp.__build__(self, other, __VALUE__, tol.to_f.abs)
|
|
518
548
|
else
|
|
519
|
-
|
|
549
|
+
super(other, tol)
|
|
520
550
|
end
|
|
521
551
|
end
|
|
522
|
-
|
|
552
|
+
RUBY
|
|
523
553
|
|
|
524
554
|
# @!visibility private
|
|
525
555
|
LAZY_MONCMP_OP_IDS = {
|
|
@@ -530,32 +560,29 @@ class CArray
|
|
|
530
560
|
signbit: CAMonCmp::OP_SIGNBIT,
|
|
531
561
|
}.freeze
|
|
532
562
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
define_method(name) do
|
|
538
|
-
if __lazy_view__?
|
|
539
|
-
CAMonCmp.__build__(self, op_id)
|
|
563
|
+
CArray.send(:define_named_methods, LazyDispatch, LAZY_MONCMP_OP_IDS, template: <<~'RUBY')
|
|
564
|
+
def __NAME__
|
|
565
|
+
if lazy_view?
|
|
566
|
+
CAMonCmp.__build__(self, __VALUE__)
|
|
540
567
|
else
|
|
541
|
-
|
|
568
|
+
super()
|
|
542
569
|
end
|
|
543
570
|
end
|
|
544
|
-
|
|
571
|
+
RUBY
|
|
545
572
|
|
|
546
573
|
# A lazy receiver takes the scalar the eager coerce makes, and stays
|
|
547
574
|
# lazy itself: the builder promotes the pair as the eager operator does.
|
|
548
575
|
# @!visibility private
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
576
|
+
module LazyDispatch
|
|
577
|
+
def coerce(other)
|
|
578
|
+
begin
|
|
579
|
+
scalar, receiver = super(other)
|
|
580
|
+
rescue RangeError => e
|
|
581
|
+
raise unless other.is_a?(Integer)
|
|
582
|
+
return [OutOfRangeInteger.new(other, self, e), self]
|
|
583
|
+
end
|
|
584
|
+
lazy_view? ? [scalar, self] : [scalar, receiver]
|
|
557
585
|
end
|
|
558
|
-
__lazy_view__? ? [scalar, self] : [scalar, receiver]
|
|
559
586
|
end
|
|
560
587
|
|
|
561
588
|
# An Integer the array's type cannot hold, on the left of an operator.
|
|
@@ -604,6 +631,8 @@ class CAMonOp
|
|
|
604
631
|
op_id = __op_id__
|
|
605
632
|
if op_id >= CAMonOp::CAST_BASE
|
|
606
633
|
"cast_#{CArray.data_type_name(op_id - CAMonOp::CAST_BASE)}"
|
|
634
|
+
elsif op_id == CAMonOp::OP_BYTE_SWAP
|
|
635
|
+
"swap_bytes" # a view of its own, not a lazy operation by name
|
|
607
636
|
else
|
|
608
637
|
(OP_NAMES[op_id] || "op_#{op_id}").to_s
|
|
609
638
|
end
|
|
@@ -880,8 +909,13 @@ class << CArray
|
|
|
880
909
|
# is not an answer: one that raises is dropped, with a warning, and
|
|
881
910
|
# expressions are walked from there on.
|
|
882
911
|
#
|
|
912
|
+
# Only the main Ractor asks it: it is registered there, and is not
|
|
913
|
+
# shared with the others, where expressions are walked.
|
|
914
|
+
#
|
|
883
915
|
# @return [#call, nil]
|
|
884
|
-
|
|
916
|
+
def expression_evaluator
|
|
917
|
+
Ractor.current == Ractor.main ? @expression_evaluator : nil
|
|
918
|
+
end
|
|
885
919
|
|
|
886
920
|
# @param object [#call, nil] see {#expression_evaluator}
|
|
887
921
|
# @raise [ArgumentError] when it cannot be called.
|