carray 3.0.2 → 3.0.3
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 +304 -0
- data/README.md +3 -4
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +225 -0
- data/ext/ca_axis_group.c +177 -99
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +66 -71
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +663 -214
- data/ext/ca_kernel_iterator.h +231 -167
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +132 -22
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +1 -0
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +96 -25
- data/ext/ca_obj_face.c +406 -64
- data/ext/ca_obj_face.h +92 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +21 -21
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +189 -107
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +543 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +47 -49
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -118
- data/ext/ca_obj_stride.c +195 -34
- data/ext/ca_obj_string.c +17 -18
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +149 -27
- 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 +102 -79
- 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 +463 -0
- data/ext/carray.h +70 -27
- data/ext/carray_access.c +455 -211
- data/ext/carray_address_basis.c +177 -36
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +46 -14
- data/ext/carray_call_cfunc.c +0 -28
- data/ext/carray_cast.c +1444 -209
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +32 -11
- data/ext/carray_core.c +514 -122
- data/ext/carray_count.c +140 -87
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +569 -277
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +385 -3
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +682 -316
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +221 -76
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1089 -359
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +273 -239
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +170 -70
- data/ext/carray_sort.c +215 -218
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +0 -2
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1076 -846
- data/ext/ruby_carray.c +7 -1
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +19 -0
- data/lib/carray/autoload_method_extension.rb +6 -0
- data/lib/carray/axis_group.rb +174 -26
- data/lib/carray/basics.rb +91 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +118 -48
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +94 -26
- data/lib/carray/categorical_iterator.rb +333 -826
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +46 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +589 -82
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +124 -25
- data/lib/carray/frame/group.rb +189 -63
- data/lib/carray/frame/io.rb +412 -72
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +37 -16
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +715 -48
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +29 -11
- data/lib/carray/iterator.rb +14 -2
- data/lib/carray/lazy.rb +54 -30
- data/lib/carray/mask_gap_fill.rb +66 -52
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +117 -4
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +177 -36
- data/lib/carray/methods/mode.rb +18 -1
- 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/record_order.rb +208 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +51 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +4 -3
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +517 -103
- data/lib/carray/window_iterator.rb +127 -72
- data/lib/carray.rb +2 -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 +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +1 -2
- data/yard-stubs/carray_access.rb +5 -4
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +25 -13
- data/yard-stubs/carray_median_percentile.rb +10 -6
- data/yard-stubs/carray_order.rb +34 -13
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +2 -1
- data/yard-stubs/carray_sort.rb +43 -3
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +11 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -26005
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14862
- data/ext/carray_kernels_reduce_extreme.c +0 -17494
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32218
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/lib/carray/lazy.rb
CHANGED
|
@@ -133,6 +133,10 @@ class CArray
|
|
|
133
133
|
__abs_eager_um__ = instance_method(:__abs_eager__)
|
|
134
134
|
define_method(:abs) do
|
|
135
135
|
if __lazy_view__?
|
|
136
|
+
# A boolean has no absolute value to change type for, as eager says.
|
|
137
|
+
raise CArray::DataTypeError,
|
|
138
|
+
"data_type-changing monop not implemented for input data_type " \
|
|
139
|
+
"#{CArray.data_type_code(CA_BOOLEAN)}" if boolean?
|
|
136
140
|
abs_i_node = CAMonOp.__build__(self, CAMonOp::OP_ABS_I)
|
|
137
141
|
if complex?
|
|
138
142
|
# float_dt is a Symbol; convert via data_type_code so the cast
|
|
@@ -206,7 +210,11 @@ class CArray
|
|
|
206
210
|
define_method(:imag) do
|
|
207
211
|
if __lazy_view__?
|
|
208
212
|
imag_i_node = CAMonOp.__build__(self, CAMonOp::OP_IMAG_I)
|
|
209
|
-
if
|
|
213
|
+
if boolean?
|
|
214
|
+
# imag_i reads a boolean as int64; the eager imag stays boolean.
|
|
215
|
+
CAMonOp.__build__(imag_i_node,
|
|
216
|
+
CAMonOp::CAST_BASE + CArray.data_type_code(CA_BOOLEAN))
|
|
217
|
+
elsif complex?
|
|
210
218
|
float_dt = (data_type == CA_CMPLX64) ? CA_FLOAT32 : CA_FLOAT64
|
|
211
219
|
# float_dt is a Symbol; convert via data_type_code for kernel
|
|
212
220
|
# op_id arithmetic.
|
|
@@ -235,8 +243,7 @@ class CArray
|
|
|
235
243
|
#
|
|
236
244
|
# Both paths keep the operand's float / complex width (f32 → f32,
|
|
237
245
|
# 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).
|
|
246
|
+
# an integer slot.
|
|
240
247
|
# ---------------------------------------------------------------------------
|
|
241
248
|
|
|
242
249
|
# @private
|
|
@@ -244,8 +251,11 @@ class CArray
|
|
|
244
251
|
__arg_eager_um__ = instance_method(:__arg_eager__)
|
|
245
252
|
define_method(:arg) do
|
|
246
253
|
if __lazy_view__?
|
|
254
|
+
raise CArray::DataTypeError,
|
|
255
|
+
"data_type-changing monop not implemented for input data_type " \
|
|
256
|
+
"#{CArray.data_type_code(CA_BOOLEAN)}" if boolean?
|
|
247
257
|
parent = self
|
|
248
|
-
if integer?
|
|
258
|
+
if integer?
|
|
249
259
|
parent = CAMonOp.__build__(parent,
|
|
250
260
|
CAMonOp::CAST_BASE +
|
|
251
261
|
CArray.data_type_code(CA_FLOAT64))
|
|
@@ -326,6 +336,10 @@ class CArray
|
|
|
326
336
|
end
|
|
327
337
|
end
|
|
328
338
|
|
|
339
|
+
# The shift count of an Integer is brought into the array's type before
|
|
340
|
+
# either form sees it (see CArray::IntegerShiftCount).
|
|
341
|
+
prepend IntegerShiftCount
|
|
342
|
+
|
|
329
343
|
# Binop word aliases (`add` -> `+`, `mul` -> `*`, `bit_and` -> `&`, …) were
|
|
330
344
|
# installed by rb_define_alias at Init time (see MkKernel.alias_binop in
|
|
331
345
|
# ext/carray_kernels_*.c) BEFORE the redefinitions above. The C alias
|
|
@@ -529,23 +543,48 @@ class CArray
|
|
|
529
543
|
end
|
|
530
544
|
end
|
|
531
545
|
|
|
546
|
+
# A lazy receiver takes the scalar the eager coerce makes, and stays
|
|
547
|
+
# lazy itself: the builder promotes the pair as the eager operator does.
|
|
532
548
|
# @!visibility private
|
|
533
549
|
alias_method :__coerce_eager__, :coerce
|
|
534
550
|
coerce_um = instance_method(:__coerce_eager__)
|
|
535
551
|
define_method(:coerce) do |other|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
[s, self]
|
|
542
|
-
else
|
|
543
|
-
coerce_um.bind_call(self, other)
|
|
544
|
-
end
|
|
545
|
-
else
|
|
546
|
-
coerce_um.bind_call(self, other)
|
|
552
|
+
begin
|
|
553
|
+
scalar, receiver = coerce_um.bind_call(self, other)
|
|
554
|
+
rescue RangeError => e
|
|
555
|
+
raise unless other.is_a?(Integer)
|
|
556
|
+
return [OutOfRangeInteger.new(other, self, e), self]
|
|
547
557
|
end
|
|
558
|
+
__lazy_view__? ? [scalar, self] : [scalar, receiver]
|
|
548
559
|
end
|
|
560
|
+
|
|
561
|
+
# An Integer the array's type cannot hold, on the left of an operator.
|
|
562
|
+
# A comparison is answered from the array's side, where it compares by
|
|
563
|
+
# value; any other operator refuses the Integer as the array would.
|
|
564
|
+
class OutOfRangeInteger
|
|
565
|
+
def initialize (value, array, error)
|
|
566
|
+
@value, @array, @error = value, array, error
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
def < (other) = flip(other, :>)
|
|
570
|
+
def <= (other) = flip(other, :>=)
|
|
571
|
+
def > (other) = flip(other, :<)
|
|
572
|
+
def >= (other) = flip(other, :<=)
|
|
573
|
+
|
|
574
|
+
def method_missing (*)
|
|
575
|
+
raise @error
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
def respond_to_missing? (*) = false
|
|
579
|
+
|
|
580
|
+
private
|
|
581
|
+
|
|
582
|
+
def flip (other, op)
|
|
583
|
+
raise @error unless other.equal?(@array)
|
|
584
|
+
@array.send(op, @value)
|
|
585
|
+
end
|
|
586
|
+
end
|
|
587
|
+
private_constant :OutOfRangeInteger
|
|
549
588
|
end
|
|
550
589
|
|
|
551
590
|
# ---------------------------------------------------------------------------
|
|
@@ -618,14 +657,6 @@ class CAMonOp
|
|
|
618
657
|
to_ca.to_a
|
|
619
658
|
end
|
|
620
659
|
|
|
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
660
|
# --- MemoryView export → TypeError + .copy recommendation -----------
|
|
630
661
|
|
|
631
662
|
# bulk-memory-view / Numo / Apache Arrow consumers go through the MV
|
|
@@ -714,13 +745,6 @@ class CABinOp
|
|
|
714
745
|
to_ca.to_a
|
|
715
746
|
end
|
|
716
747
|
|
|
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
748
|
# @overload to_memory_view
|
|
725
749
|
# Not supported for lazy binops.
|
|
726
750
|
# @raise [TypeError] always.
|
data/lib/carray/mask_gap_fill.rb
CHANGED
|
@@ -46,15 +46,10 @@ class CArray
|
|
|
46
46
|
raise ArgumentError,
|
|
47
47
|
"unmask: pass either a constant fill value or method:, not both"
|
|
48
48
|
end
|
|
49
|
-
held = __gap_fill__(method, axis)
|
|
50
|
-
# Copy the filled values in place
|
|
51
|
-
#
|
|
52
|
-
|
|
53
|
-
if face?
|
|
54
|
-
parent.value[] = held.parent.value
|
|
55
|
-
else
|
|
56
|
-
value[] = held.value
|
|
57
|
-
end
|
|
49
|
+
held = __gap_fill__(method, axis, "unmask")
|
|
50
|
+
# Copy the filled values in place (a Face takes a Face of its own kind
|
|
51
|
+
# as it is).
|
|
52
|
+
value[] = held.value
|
|
58
53
|
if held.has_mask?
|
|
59
54
|
self.mask = held.mask # residual leading/trailing mask
|
|
60
55
|
else
|
|
@@ -71,7 +66,7 @@ class CArray
|
|
|
71
66
|
raise ArgumentError,
|
|
72
67
|
"strip_mask: pass either a constant fill value or method:, not both"
|
|
73
68
|
end
|
|
74
|
-
return __gap_fill__(method, axis)
|
|
69
|
+
return __gap_fill__(method, axis, "strip_mask")
|
|
75
70
|
end
|
|
76
71
|
if fill.equal?(MASK_FILL_UNSET)
|
|
77
72
|
raise ArgumentError, "strip_mask: a fill value is required (or method:)"
|
|
@@ -85,7 +80,8 @@ 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 __gap_fill__ (method, axis)
|
|
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_axis__(axis, false)
|
|
@@ -100,8 +96,8 @@ 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
102
|
def __hold_axis__ (axis, backward)
|
|
107
103
|
if axis.nil?
|
|
@@ -111,11 +107,10 @@ class CArray
|
|
|
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__, axis).flip(axis)
|
|
117
112
|
else
|
|
118
|
-
send(:__hold__,
|
|
113
|
+
send(:__hold__, axis)
|
|
119
114
|
end
|
|
120
115
|
end
|
|
121
116
|
end
|
|
@@ -123,11 +118,18 @@ 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
|
-
#
|
|
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.
|
|
129
124
|
def __gap_fill_linear__ (axis)
|
|
130
|
-
|
|
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})"
|
|
@@ -135,46 +137,58 @@ class CArray
|
|
|
135
137
|
if axis.nil?
|
|
136
138
|
return __linear_fiber__(flatten).reshape(*shape)
|
|
137
139
|
end
|
|
138
|
-
ax = axis
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
|
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
|
|
147
145
|
__each_fiber_key__(ax) do |key|
|
|
148
|
-
|
|
149
|
-
sink[*key] = face? ? fiber.parent : fiber
|
|
146
|
+
out[*key] = __linear_fiber__(self[*key])
|
|
150
147
|
end
|
|
151
|
-
|
|
148
|
+
out
|
|
152
149
|
end
|
|
153
150
|
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
|
|
158
|
-
|
|
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?
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# 1-D linear-by-index fill of a single (possibly masked) fiber.
|
|
159
159
|
def __linear_fiber__ (vec)
|
|
160
|
-
|
|
161
|
-
|
|
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
|
+
interp = value.float64[present].linear_fetch(addr)
|
|
184
|
+
# Built from the values alone, so a fully filled result carries no mask.
|
|
185
|
+
out = value.copy
|
|
186
|
+
masked = is_masked
|
|
187
|
+
fill = masked & addr.is_finite
|
|
188
|
+
exterior = masked & fill.not
|
|
189
|
+
out[fill] = interp[fill] if fill.any
|
|
190
|
+
out[exterior] = UNDEF if exterior.any
|
|
191
|
+
out
|
|
178
192
|
end
|
|
179
193
|
|
|
180
194
|
# Yield an index key (Array with `nil` at `axis`, integers elsewhere)
|
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
|
@@ -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
|
|
@@ -78,12 +81,12 @@ 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
91
|
return super if parents.all? { |p| p.dim[meld_axis] == 0 }
|
|
89
92
|
nonempty = parents.reject { |p| p.dim[meld_axis] == 0 }
|
|
@@ -99,10 +102,10 @@ 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
110
|
return super if parents.all? { |p| p.dim[meld_axis] == 0 }
|
|
108
111
|
nonempty = parents.reject { |p| p.dim[meld_axis] == 0 }
|
|
@@ -168,6 +171,9 @@ 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?
|
|
@@ -177,9 +183,30 @@ class CAMeld
|
|
|
177
183
|
end
|
|
178
184
|
return false if has_mask?
|
|
179
185
|
parents.each { |p| return false if p.has_mask? }
|
|
186
|
+
# A meld of Face arrays keeps its parents in their Face; the per-parent
|
|
187
|
+
# calls would reach the Face's own reductions, which answer in the Face's
|
|
188
|
+
# terms (or refuse), not in storage.
|
|
189
|
+
parents.each { |p| return false if p.face? }
|
|
180
190
|
true
|
|
181
191
|
end
|
|
182
192
|
|
|
193
|
+
# The axis a fast path reduces along. A 1-D meld has only the meld axis,
|
|
194
|
+
# and reducing it is reducing the whole array: the answer is a scalar, as
|
|
195
|
+
# for the flat call.
|
|
196
|
+
def meld_fast_path_axis(kw)
|
|
197
|
+
ndim == 1 ? nil : kw[:axis]
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# The per-parent answers of a whole-array min / max, combined by core's
|
|
201
|
+
# own min / max so NaN loses the way it loses inside one parent (Ruby's
|
|
202
|
+
# Array#min would raise on it).
|
|
203
|
+
def meld_combine_flat(op)
|
|
204
|
+
vals = parents.reject { |p| p.elements == 0 }.map(&op)
|
|
205
|
+
part = CArray.new(data_type, [vals.size])
|
|
206
|
+
vals.each_with_index { |v, i| part[i] = v }
|
|
207
|
+
part.public_send(op)
|
|
208
|
+
end
|
|
209
|
+
|
|
183
210
|
# Non-meld-axis decompose: each parent reduces the same axis independently,
|
|
184
211
|
# then the K per-parent results are concatenated back along the meld axis.
|
|
185
212
|
# Materialised to entity (`.copy`) to match CArray#reduce entity semantics.
|
|
@@ -198,7 +225,13 @@ class CAMeld
|
|
|
198
225
|
|
|
199
226
|
def variance_family(args, kw, sample:, sqrt:)
|
|
200
227
|
return yield unless args.empty? && meld_reduce_fast_path_ok?(kw)
|
|
201
|
-
|
|
228
|
+
# The merge works in Float; an object array's variance stays exact
|
|
229
|
+
# (Rational, BigDecimal) on the core path.
|
|
230
|
+
return yield if object?
|
|
231
|
+
# The merge squares the difference of means, which for complex values is
|
|
232
|
+
# not |δ|²; the core path computes the variance of a complex array.
|
|
233
|
+
return yield if complex?
|
|
234
|
+
axis = meld_fast_path_axis(kw)
|
|
202
235
|
# Empty-parent / short-parent handling — Welford needs n >= 2 per parent
|
|
203
236
|
# to recover m2 from p.variance for sample, n >= 1 for variancep (n=1
|
|
204
237
|
# gives m2=0, fine). Any parent below its threshold punts to super,
|
|
@@ -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}).
|
|
@@ -38,7 +38,7 @@ class CArray
|
|
|
38
38
|
|
|
39
39
|
if elements.zero?
|
|
40
40
|
if weights
|
|
41
|
-
out = CArray.new(weights.data_type, [length])
|
|
41
|
+
out = CArray.new(weights.data_type, [length], bytes: weights.bytes)
|
|
42
42
|
else
|
|
43
43
|
out_type = (length > 0xFFFFFFFF) ? CA_UINT64 : CA_UINT32
|
|
44
44
|
out = CArray.new(out_type, [length])
|
|
@@ -54,7 +54,7 @@ class CArray
|
|
|
54
54
|
# Every cell is masked: no labels to count, same result as an empty
|
|
55
55
|
# input (all-zero output of the requested minimum length).
|
|
56
56
|
if weights
|
|
57
|
-
out = CArray.new(weights.data_type, [length])
|
|
57
|
+
out = CArray.new(weights.data_type, [length], bytes: weights.bytes)
|
|
58
58
|
else
|
|
59
59
|
out_type = (length > 0xFFFFFFFF) ? CA_UINT64 : CA_UINT32
|
|
60
60
|
out = CArray.new(out_type, [length])
|
|
@@ -58,9 +58,12 @@ class CArray
|
|
|
58
58
|
# multiple of 8) are zero-filled. The byte order matches the packed-bit
|
|
59
59
|
# convention used by Apache Arrow validity bitmaps and PEP 3118 `?` /
|
|
60
60
|
# `_Bool` at the bit level.
|
|
61
|
+
# A masked cell has no bit to pack, so a receiver with masked cells is
|
|
62
|
+
# refused; pack the mask separately with {#validity_bits}.
|
|
61
63
|
# @return [CArray] uint8 CArray of shape `[ceil(n / 8)]`.
|
|
62
|
-
# @raise [ArgumentError] when the receiver is not 1-D
|
|
63
|
-
#
|
|
64
|
+
# @raise [ArgumentError] when the receiver is not 1-D, its `data_type`
|
|
65
|
+
# is not one of `CA_BOOLEAN` / `CA_UINT8` / `CA_INT8`, or it has
|
|
66
|
+
# masked cells.
|
|
64
67
|
def pack_bits
|
|
65
68
|
unless data_type == CA_BOOLEAN || data_type == CA_UINT8 || data_type == CA_INT8
|
|
66
69
|
raise ArgumentError,
|
|
@@ -71,7 +74,15 @@ class CArray
|
|
|
71
74
|
n_bytes = (n + 7) / 8
|
|
72
75
|
packed = CArray.uint8(n_bytes) { 0 }
|
|
73
76
|
return packed if n == 0
|
|
74
|
-
|
|
77
|
+
source = self
|
|
78
|
+
if has_mask?
|
|
79
|
+
if count_masked > 0
|
|
80
|
+
raise ArgumentError,
|
|
81
|
+
"pack_bits: masked cells have no bit to pack; pack the mask with validity_bits"
|
|
82
|
+
end
|
|
83
|
+
source = value
|
|
84
|
+
end
|
|
85
|
+
packed.bitarray.reshape(-1)[0..n-1] = source
|
|
75
86
|
packed
|
|
76
87
|
end
|
|
77
88
|
|