carray 3.0.1 → 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 +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- 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 +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- 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 +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -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 +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -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 +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- 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 +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- 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 +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- 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 +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- 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 +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- 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 +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- 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 +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- 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/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- 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 +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -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 +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- 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 +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -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_block.rb +2 -7
- 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 +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- 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 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -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 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/lib/carray/iterator.rb
CHANGED
|
@@ -29,6 +29,16 @@ class CAIterator
|
|
|
29
29
|
attr_reader :ndim, :shape
|
|
30
30
|
alias dim shape
|
|
31
31
|
|
|
32
|
+
# The keywords a member passes on to a core reduction over its own axes.
|
|
33
|
+
# The member sets `axis:`, so one from the caller is refused; the rest go
|
|
34
|
+
# to the core, which checks them.
|
|
35
|
+
def self.reduce_keywords (op, kw) # :nodoc:
|
|
36
|
+
if kw.key?(:axis)
|
|
37
|
+
raise ArgumentError, "#{op}: unknown keyword: :axis (the iterator sets the axes)"
|
|
38
|
+
end
|
|
39
|
+
kw
|
|
40
|
+
end
|
|
41
|
+
|
|
32
42
|
# The required reduction surface, modelled on the two reference members
|
|
33
43
|
# CASlabIterator and CACategoricalIterator (the surface they both provide).
|
|
34
44
|
# Declared abstract so a later member
|
|
@@ -36,7 +46,115 @@ class CAIterator
|
|
|
36
46
|
# rather than reading as "no such method" -- that gap is the member's to close.
|
|
37
47
|
# A member that genuinely cannot provide one overrides it to raise with its
|
|
38
48
|
# own reason.
|
|
39
|
-
|
|
49
|
+
# The methods below are declared here, so that the family surface is
|
|
50
|
+
# documented in one place; each member generates its own implementation and
|
|
51
|
+
# a member for which one is ill-defined overrides it to raise with a reason.
|
|
52
|
+
# "Piece" is the unit a member iterates over: a slab, a window, a block, a
|
|
53
|
+
# category, or a group.
|
|
54
|
+
#
|
|
55
|
+
# @!method sum
|
|
56
|
+
# Returns the sum of each piece.
|
|
57
|
+
# @return [CArray] one value per piece, shaped {#shape}.
|
|
58
|
+
# @!method accumulate
|
|
59
|
+
# Returns the sum of each piece kept in the source's own `data_type`,
|
|
60
|
+
# wrapping at its width, where {#sum} answers in the type the core
|
|
61
|
+
# promotes to (`:float64` for integers).
|
|
62
|
+
# @return [CArray] one value per piece.
|
|
63
|
+
# @!method prod
|
|
64
|
+
# Returns the product of each piece.
|
|
65
|
+
# @return [CArray] one value per piece.
|
|
66
|
+
# @!method mean
|
|
67
|
+
# Returns the arithmetic mean of each piece.
|
|
68
|
+
# @return [CArray] one value per piece.
|
|
69
|
+
# @!method min
|
|
70
|
+
# Returns the smallest value in each piece.
|
|
71
|
+
# @return [CArray] one value per piece.
|
|
72
|
+
# @!method max
|
|
73
|
+
# Returns the largest value in each piece.
|
|
74
|
+
# @return [CArray] one value per piece.
|
|
75
|
+
# @!method minmax
|
|
76
|
+
# Returns the smallest and largest value of each piece, found in one pass.
|
|
77
|
+
# @return [Array<CArray>] the pair `[min, max]`.
|
|
78
|
+
# @!method variance
|
|
79
|
+
# Returns the sample variance (divisor `n - 1`) of each piece.
|
|
80
|
+
# @return [CArray] one value per piece.
|
|
81
|
+
# @!method variancep
|
|
82
|
+
# Returns the population variance (divisor `n`) of each piece.
|
|
83
|
+
# @return [CArray] one value per piece.
|
|
84
|
+
# @!method stddev
|
|
85
|
+
# Returns the sample standard deviation (divisor `n - 1`) of each piece.
|
|
86
|
+
# @return [CArray] one value per piece.
|
|
87
|
+
# @!method stddevp
|
|
88
|
+
# Returns the population standard deviation (divisor `n`) of each piece.
|
|
89
|
+
# @return [CArray] one value per piece.
|
|
90
|
+
# @!method all
|
|
91
|
+
# Returns whether every cell of each piece is true.
|
|
92
|
+
# @return [CArray] `:boolean`, one value per piece.
|
|
93
|
+
# @!method any
|
|
94
|
+
# Returns whether any cell of each piece is true.
|
|
95
|
+
# @return [CArray] `:boolean`, one value per piece.
|
|
96
|
+
# @!method min_index
|
|
97
|
+
# Returns the position of the smallest value **within** each piece.
|
|
98
|
+
# @return [CArray] one index per piece.
|
|
99
|
+
# @!method max_index
|
|
100
|
+
# Returns the position of the largest value within each piece.
|
|
101
|
+
# @return [CArray] one index per piece.
|
|
102
|
+
# @!method min_addr
|
|
103
|
+
# Returns the flat address **in the source** of the smallest value of each
|
|
104
|
+
# piece -- which source cell holds it, rather than where it sits inside the
|
|
105
|
+
# piece. Use it to read the same cell out of another source-shaped array.
|
|
106
|
+
# @return [CArray] one flat address per piece.
|
|
107
|
+
# @!method max_addr
|
|
108
|
+
# Returns the flat address in the source of the largest value of each piece.
|
|
109
|
+
# @return [CArray] one flat address per piece.
|
|
110
|
+
# @!method wsum(weights)
|
|
111
|
+
# Returns the weighted sum of each piece.
|
|
112
|
+
# @param weights [CArray] one weight per source cell, shaped like the source.
|
|
113
|
+
# @return [CArray] one value per piece.
|
|
114
|
+
# @!method wmean(weights)
|
|
115
|
+
# Returns the weighted mean of each piece.
|
|
116
|
+
# @param weights [CArray] one weight per source cell, shaped like the source.
|
|
117
|
+
# @return [CArray] one value per piece.
|
|
118
|
+
# @!method median
|
|
119
|
+
# Returns the median of each piece.
|
|
120
|
+
# @return [CArray] one value per piece.
|
|
121
|
+
# @!method percentile(*pers)
|
|
122
|
+
# Returns the requested percentile(s) of each piece.
|
|
123
|
+
# @param pers [Array<Numeric>] percentile positions in `0..100`.
|
|
124
|
+
# @return [CArray, Array<CArray>] one array per requested position; a
|
|
125
|
+
# single position returns that array directly.
|
|
126
|
+
# @!method quantile
|
|
127
|
+
# Returns the five-number summary of each piece,
|
|
128
|
+
# `[min, Q1, median, Q3, max]`.
|
|
129
|
+
# @return [Array<CArray>] five arrays, one per position.
|
|
130
|
+
# @!method count(value = nil)
|
|
131
|
+
# Returns a count per piece: with no argument the cells that are not
|
|
132
|
+
# masked, with `UNDEF` the masked cells, and with any other value the
|
|
133
|
+
# cells equal to it.
|
|
134
|
+
# @param value [Object] value to match, or `UNDEF`.
|
|
135
|
+
# @return [CArray] one count per piece.
|
|
136
|
+
# @!method count_not_masked
|
|
137
|
+
# Returns the number of cells of each piece that are not masked.
|
|
138
|
+
# @return [CArray] one count per piece.
|
|
139
|
+
# @!method count_masked
|
|
140
|
+
# Returns the number of masked cells of each piece.
|
|
141
|
+
# @return [CArray] one count per piece.
|
|
142
|
+
# @!method elements
|
|
143
|
+
# Returns the total number of cells in each piece, masked or not.
|
|
144
|
+
# @return [CArray] one count per piece.
|
|
145
|
+
# @!method each
|
|
146
|
+
# Yields each piece in turn as a CArray.
|
|
147
|
+
# @yieldparam piece [CArray]
|
|
148
|
+
# @return [Enumerator, self] an Enumerator when no block is given.
|
|
149
|
+
# @!method reduce(init = nil)
|
|
150
|
+
# Folds the pieces with a block, for a reduction the family does not name.
|
|
151
|
+
# Without `init` the first piece seeds the accumulator.
|
|
152
|
+
# @param init [Object] initial accumulator value.
|
|
153
|
+
# @yieldparam acc [Object] running accumulator.
|
|
154
|
+
# @yieldparam piece [CArray] next piece.
|
|
155
|
+
# @yieldreturn [Object] updated accumulator.
|
|
156
|
+
# @return [Object] the final accumulator.
|
|
157
|
+
REQUIRED_SURFACE = [
|
|
40
158
|
:sum, :accumulate, :prod, :mean, :min, :max, # tier 1
|
|
41
159
|
:variance, :stddev, :all, :any,
|
|
42
160
|
:variancep, :stddevp, :minmax, # tier 2
|
|
@@ -45,7 +163,9 @@ class CAIterator
|
|
|
45
163
|
:median, :percentile, :quantile, # tier 3
|
|
46
164
|
:count, :count_not_masked, :count_masked, :elements, # count family
|
|
47
165
|
:each, :reduce, # generic iterate
|
|
48
|
-
].
|
|
166
|
+
].freeze
|
|
167
|
+
|
|
168
|
+
REQUIRED_SURFACE.each do |name|
|
|
49
169
|
define_method(name) do |*, **, &_blk|
|
|
50
170
|
raise NotImplementedError, "#{self.class} must implement ##{name}"
|
|
51
171
|
end
|
|
@@ -66,6 +186,41 @@ class CAIterator
|
|
|
66
186
|
# sort_addr. Un-overridden each is simply unavailable, not a contract
|
|
67
187
|
# violation. min_addr / max_addr stay required: a single winner address is
|
|
68
188
|
# well-defined even for an overlapping window.
|
|
189
|
+
# @!method map
|
|
190
|
+
# Returns a source-shaped array built by applying the block to each piece
|
|
191
|
+
# and scattering the result back into that piece's cells.
|
|
192
|
+
# @yieldparam piece [CArray]
|
|
193
|
+
# @yieldreturn [CArray, Numeric] replacement values for the piece.
|
|
194
|
+
# @return [CArray] shaped like the source.
|
|
195
|
+
# @raise [NotImplementedError] for a member whose pieces overlap, where a
|
|
196
|
+
# cell would receive more than one value.
|
|
197
|
+
# @!method sort_addr
|
|
198
|
+
# Returns a source-shaped array whose cells, read piece by piece, give the
|
|
199
|
+
# flat source addresses that put that piece in ascending order.
|
|
200
|
+
# @return [CArray] `:int64`, shaped like the source.
|
|
201
|
+
# @raise [NotImplementedError] for a member whose pieces overlap.
|
|
202
|
+
# @!method cumsum
|
|
203
|
+
# Returns a source-shaped array of the running sum within each piece.
|
|
204
|
+
# @return [CArray] shaped like the source.
|
|
205
|
+
# @raise [NotImplementedError] for a member whose pieces overlap, where a
|
|
206
|
+
# cell has no single running value.
|
|
207
|
+
# @!method cumprod
|
|
208
|
+
# Returns a source-shaped array of the running product within each piece.
|
|
209
|
+
# @return [CArray] shaped like the source.
|
|
210
|
+
# @raise [NotImplementedError] for a member whose pieces overlap.
|
|
211
|
+
# @!method cummax
|
|
212
|
+
# Returns a source-shaped array of the running maximum within each piece.
|
|
213
|
+
# @return [CArray] shaped like the source.
|
|
214
|
+
# @raise [NotImplementedError] for a member whose pieces overlap.
|
|
215
|
+
# @!method cummin
|
|
216
|
+
# Returns a source-shaped array of the running minimum within each piece.
|
|
217
|
+
# @return [CArray] shaped like the source.
|
|
218
|
+
# @raise [NotImplementedError] for a member whose pieces overlap.
|
|
219
|
+
# @!method cumcount
|
|
220
|
+
# Returns a source-shaped array of the running count of cells that are not
|
|
221
|
+
# masked within each piece.
|
|
222
|
+
# @return [CArray] shaped like the source.
|
|
223
|
+
# @raise [NotImplementedError] for a member whose pieces overlap.
|
|
69
224
|
[:map, :sort_addr,
|
|
70
225
|
:cumsum, :cumprod, :cummax, :cummin, :cumcount].each do |name|
|
|
71
226
|
define_method(name) do |*, **, &_blk|
|
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
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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]
|
|
557
|
+
end
|
|
558
|
+
__lazy_view__? ? [scalar, self] : [scalar, receiver]
|
|
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)
|
|
547
585
|
end
|
|
548
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.
|
|
@@ -901,41 +925,4 @@ class << CArray
|
|
|
901
925
|
end
|
|
902
926
|
CArray::FuseSource.evaluate(block)
|
|
903
927
|
end
|
|
904
|
-
|
|
905
|
-
# @overload jit_for (*extents) { |i, j, ...| ... }
|
|
906
|
-
# Runs a block over an index space, so that a cell may reach the ones
|
|
907
|
-
# around it -- a recurrence, a stencil. The block is compiled, and the
|
|
908
|
-
# compiler is the carray-jit gem.
|
|
909
|
-
# @raise [NotImplementedError] when that gem is not installed.
|
|
910
|
-
def jit_for (*extents, **options)
|
|
911
|
-
raise NotImplementedError, no_compiler("jit_for")
|
|
912
|
-
end
|
|
913
|
-
|
|
914
|
-
# @overload jit_each { ... }
|
|
915
|
-
# Runs a block over the cells of arrays at once, naming each cell by the
|
|
916
|
-
# array it came from, and writing what it computes into arrays of yours:
|
|
917
|
-
# `CArray.jit_each { out = a + b * c }`. The block is compiled, and the
|
|
918
|
-
# compiler is the carray-jit gem.
|
|
919
|
-
# @raise [NotImplementedError] when that gem is not installed.
|
|
920
|
-
def jit_each (&block)
|
|
921
|
-
raise NotImplementedError, no_compiler("jit_each")
|
|
922
|
-
end
|
|
923
|
-
|
|
924
|
-
# @overload jit_map { ... }
|
|
925
|
-
# The same block with its value asked for: the last statement is what
|
|
926
|
-
# every cell of the result gets, and the result comes back. The block is
|
|
927
|
-
# compiled, and the compiler is the carray-jit gem.
|
|
928
|
-
# @raise [NotImplementedError] when that gem is not installed.
|
|
929
|
-
def jit_map (&block)
|
|
930
|
-
raise NotImplementedError, no_compiler("jit_map")
|
|
931
|
-
end
|
|
932
|
-
|
|
933
|
-
private
|
|
934
|
-
|
|
935
|
-
def no_compiler (name)
|
|
936
|
-
"CArray.#{name} compiles its block, and the compiler is the carray-jit " \
|
|
937
|
-
"gem, which is not installed. An expression over whole arrays can be " \
|
|
938
|
-
"written as `CArray.fuse { ... }` instead, which needs no compiler; " \
|
|
939
|
-
"reaching a neighbouring cell, or writing the loop itself, does."
|
|
940
|
-
end
|
|
941
928
|
end
|
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,44 +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
|
-
|
|
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
|
|
176
192
|
end
|
|
177
193
|
|
|
178
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
|