carray 3.0.0 → 3.0.1
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/.yardopts +2 -1
- data/CHANGELOG.md +325 -3
- data/{NEWS.md → CHANGELOG.v1.md} +1 -1
- data/README.md +32 -32
- data/carray.gemspec +12 -8
- data/ext/ca_axis_group.c +55 -19
- data/ext/ca_binop_dispatch.c +5 -6
- data/ext/ca_binop_dispatch.h +0 -7
- data/ext/ca_categorical_iterator.c +13 -13
- data/ext/ca_for_each_element.h +6 -8
- data/ext/ca_group_iter.c +1 -1
- data/ext/ca_kernel_iterator.c +69 -23
- data/ext/ca_kernel_iterator.h +3 -10
- data/ext/ca_obj_bincmp.c +57 -27
- data/ext/ca_obj_binop.c +86 -30
- data/ext/ca_obj_const_string.c +3 -1
- data/ext/ca_obj_face.c +80 -0
- data/ext/ca_obj_face.h +33 -1
- data/ext/ca_obj_fake.c +11 -0
- data/ext/ca_obj_fixlen_string.c +3 -1
- data/ext/ca_obj_grid.c +11 -3
- data/ext/ca_obj_meld.c +13 -8
- data/ext/ca_obj_moncmp.c +33 -14
- data/ext/ca_obj_monop.c +19 -7
- data/ext/ca_obj_object.c +99 -4
- data/ext/ca_obj_record.c +3 -1
- data/ext/ca_obj_refer.c +30 -6
- data/ext/ca_obj_roll.c +13 -5
- data/ext/ca_obj_select_axis.c +16 -6
- data/ext/ca_obj_shift.c +3 -3
- data/ext/ca_obj_stride.c +106 -23
- data/ext/ca_obj_string.c +3 -1
- data/ext/ca_obj_tile.c +13 -5
- data/ext/ca_obj_time.c +3 -1
- data/ext/ca_obj_timedelta.c +3 -1
- data/ext/ca_obj_transpose.c +1 -1
- data/ext/ca_obj_triop.c +62 -23
- data/ext/ca_obj_window.c +86 -17
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +0 -3
- data/ext/ca_sort_kernels.h +5 -5
- data/ext/ca_sweep_engine.c +78 -35
- data/ext/ca_sweep_engine.h +13 -4
- data/ext/ca_transform_common.c +7 -0
- data/ext/carray.h +127 -130
- data/ext/carray_access.c +56 -34
- data/ext/carray_bincount.c +8 -8
- data/ext/carray_broadcast.c +99 -6
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +1491 -0
- data/ext/carray_call_cfunc.h +153 -0
- data/ext/carray_cast.c +69 -31
- data/ext/carray_conversion.c +22 -22
- data/ext/carray_copy.c +12 -2
- data/ext/carray_core.c +57 -10
- data/ext/carray_count.c +1 -1
- data/ext/carray_element.c +7 -7
- data/ext/carray_factorize.c +28 -28
- data/ext/carray_hold.c +1 -1
- data/ext/carray_index_classifier.c +7 -21
- data/ext/carray_internal.h +19 -3
- data/ext/carray_kernels_bincmp.c +1 -0
- data/ext/carray_kernels_binop.c +320 -298
- data/ext/carray_kernels_init.c +1095 -0
- data/ext/carray_kernels_map.c +1 -0
- data/ext/carray_kernels_moncmp.c +1 -0
- data/ext/carray_kernels_monop.c +412 -411
- data/ext/carray_kernels_reduce_aggregate.c +88 -87
- data/ext/carray_kernels_reduce_boolean.c +1 -0
- data/ext/carray_kernels_reduce_cumulative.c +54 -53
- data/ext/carray_kernels_reduce_extreme.c +51 -50
- data/ext/carray_kernels_reduce_variance.c +1 -0
- data/ext/carray_kernels_scan.c +1 -0
- data/ext/carray_kernels_search.c +93 -92
- data/ext/carray_kernels_sort.c +1 -0
- data/ext/carray_kernels_triop.c +1 -0
- data/ext/carray_lazy.c +175 -5
- data/ext/carray_mask.c +6 -5
- data/ext/carray_median_percentile.c +1 -1
- data/ext/carray_memory_view.c +46 -21
- data/ext/carray_operator.c +46 -49
- data/ext/carray_partition.c +4 -4
- data/ext/carray_random.c +7 -7
- data/ext/carray_scatter.c +1 -1
- data/ext/carray_sort.c +3 -3
- data/ext/carray_sort_kernel.c +10 -10
- data/ext/carray_test.c +1 -1
- data/ext/extconf.rb +18 -0
- data/ext/mk_call_cfunc.rb +243 -52
- data/ext/mkkernel.rb +354 -100
- data/ext/ruby_carray.c +18 -16
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +19 -0
- data/lib/carray/autoload_method_extension.rb +2 -1
- data/lib/carray/axis_group.rb +7 -7
- data/lib/carray/basics.rb +59 -59
- data/lib/carray/bincount_nd.rb +12 -12
- data/lib/carray/block_iterator.rb +24 -14
- data/lib/carray/categorical.rb +4 -4
- data/lib/carray/categorical_iterator.rb +98 -76
- data/lib/carray/conditional.rb +14 -14
- data/lib/carray/construct.rb +21 -0
- data/lib/carray/core_extensions.rb +62 -5
- data/lib/carray/data_type_extension.rb +18 -1
- data/lib/carray/frame/concat.rb +3 -3
- data/lib/carray/frame/convert.rb +1 -1
- data/lib/carray/frame/frame.rb +4 -11
- data/lib/carray/frame/io.rb +159 -2
- data/lib/carray/frame/sort.rb +1 -1
- data/lib/carray/frame/verbs.rb +18 -1
- data/lib/carray/fuse_source.rb +123 -0
- data/lib/carray/fusion.rb +218 -0
- data/lib/carray/histogram.rb +16 -16
- data/lib/carray/inspect.rb +1 -7
- data/lib/carray/iterator.rb +4 -3
- data/lib/carray/lazy.rb +125 -73
- data/lib/carray/meld_reduce.rb +2 -2
- data/lib/carray/methods/align_addr.rb +1 -1
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/is_in.rb +12 -12
- data/lib/carray/methods/locate_addr.rb +6 -1
- data/lib/carray/methods/mask_duplicates.rb +1 -1
- data/lib/carray/methods/meshgrid.rb +4 -5
- data/lib/carray/methods/mode.rb +2 -2
- data/lib/carray/methods/nunique.rb +1 -1
- data/lib/carray/methods/snap.rb +7 -2
- data/lib/carray/methods/unique.rb +3 -3
- data/lib/carray/methods/value_counts.rb +2 -2
- data/lib/carray/runtime.rb +0 -19
- data/lib/carray/slab_iterator.rb +20 -7
- data/lib/carray/string_operation_extension.rb +5 -5
- data/lib/carray/time.rb +890 -491
- data/lib/carray/window_iterator.rb +285 -13
- data/lib/carray.rb +5 -5
- data/yard-stubs/ca_obj_array.rb +385 -0
- data/yard-stubs/ca_obj_bitarray.rb +38 -0
- data/yard-stubs/ca_obj_bitfield.rb +43 -0
- data/yard-stubs/ca_obj_block.rb +73 -0
- data/yard-stubs/ca_obj_byte_swap.rb +56 -0
- data/yard-stubs/ca_obj_fake.rb +31 -0
- data/yard-stubs/ca_obj_farray.rb +32 -0
- data/yard-stubs/ca_obj_field.rb +45 -0
- data/yard-stubs/ca_obj_grid.rb +35 -0
- data/yard-stubs/ca_obj_refer.rb +72 -0
- data/yard-stubs/ca_obj_roll.rb +45 -0
- data/yard-stubs/ca_obj_shift.rb +43 -0
- data/yard-stubs/ca_obj_stride.rb +181 -0
- data/yard-stubs/ca_obj_tile.rb +29 -0
- data/yard-stubs/ca_obj_transpose.rb +40 -0
- data/yard-stubs/ca_obj_window.rb +49 -0
- data/yard-stubs/carray_access.rb +131 -0
- data/yard-stubs/carray_attribute.rb +246 -0
- data/yard-stubs/carray_broadcast.rb +37 -0
- data/yard-stubs/carray_cast.rb +489 -0
- data/yard-stubs/carray_class.rb +65 -0
- data/yard-stubs/carray_conversion.rb +76 -0
- data/yard-stubs/carray_copy.rb +79 -0
- data/yard-stubs/carray_core.rb +114 -0
- data/yard-stubs/carray_count.rb +79 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +23 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +132 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +89 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +312 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +57 -0
- data/yard-stubs/carray_sort.rb +163 -0
- data/yard-stubs/carray_test.rb +85 -0
- data/yard-stubs/carray_undef.rb +64 -0
- data/yard-stubs/carray_utils.rb +97 -0
- data/yard-stubs/ruby_carray.rb +193 -0
- metadata +59 -10
- data/ext/ca_obj_unbound_repeat.c +0 -496
data/lib/carray/construct.rb
CHANGED
|
@@ -35,6 +35,7 @@ class CArray
|
|
|
35
35
|
# CArray whose elements are `boolean`. Naming the element type as a
|
|
36
36
|
# class lets a constructor be spelled `CArray::Boolean.new(...)`; see
|
|
37
37
|
# {DataTypeNewConstructor} for what that form adds.
|
|
38
|
+
# @private
|
|
38
39
|
class Boolean
|
|
39
40
|
extend DataTypeNewConstructor
|
|
40
41
|
extend DataTypeExtension
|
|
@@ -47,6 +48,7 @@ class CArray
|
|
|
47
48
|
# CArray whose elements are `uint8`. Naming the element type as a
|
|
48
49
|
# class lets a constructor be spelled `CArray::UInt8.new(...)`; see
|
|
49
50
|
# {DataTypeNewConstructor} for what that form adds.
|
|
51
|
+
# @private
|
|
50
52
|
class UInt8
|
|
51
53
|
extend DataTypeNewConstructor
|
|
52
54
|
extend DataTypeExtension
|
|
@@ -59,6 +61,7 @@ class CArray
|
|
|
59
61
|
# CArray whose elements are `uint16`. Naming the element type as a
|
|
60
62
|
# class lets a constructor be spelled `CArray::UInt16.new(...)`; see
|
|
61
63
|
# {DataTypeNewConstructor} for what that form adds.
|
|
64
|
+
# @private
|
|
62
65
|
class UInt16
|
|
63
66
|
extend DataTypeNewConstructor
|
|
64
67
|
extend DataTypeExtension
|
|
@@ -71,6 +74,7 @@ class CArray
|
|
|
71
74
|
# CArray whose elements are `uint32`. Naming the element type as a
|
|
72
75
|
# class lets a constructor be spelled `CArray::UInt32.new(...)`; see
|
|
73
76
|
# {DataTypeNewConstructor} for what that form adds.
|
|
77
|
+
# @private
|
|
74
78
|
class UInt32
|
|
75
79
|
extend DataTypeNewConstructor
|
|
76
80
|
extend DataTypeExtension
|
|
@@ -83,6 +87,7 @@ class CArray
|
|
|
83
87
|
# CArray whose elements are `uint64`. Naming the element type as a
|
|
84
88
|
# class lets a constructor be spelled `CArray::UInt64.new(...)`; see
|
|
85
89
|
# {DataTypeNewConstructor} for what that form adds.
|
|
90
|
+
# @private
|
|
86
91
|
class UInt64
|
|
87
92
|
extend DataTypeNewConstructor
|
|
88
93
|
extend DataTypeExtension
|
|
@@ -95,6 +100,7 @@ class CArray
|
|
|
95
100
|
# CArray whose elements are `int8`. Naming the element type as a
|
|
96
101
|
# class lets a constructor be spelled `CArray::Int8.new(...)`; see
|
|
97
102
|
# {DataTypeNewConstructor} for what that form adds.
|
|
103
|
+
# @private
|
|
98
104
|
class Int8
|
|
99
105
|
extend DataTypeNewConstructor
|
|
100
106
|
extend DataTypeExtension
|
|
@@ -107,6 +113,7 @@ class CArray
|
|
|
107
113
|
# CArray whose elements are `int16`. Naming the element type as a
|
|
108
114
|
# class lets a constructor be spelled `CArray::Int16.new(...)`; see
|
|
109
115
|
# {DataTypeNewConstructor} for what that form adds.
|
|
116
|
+
# @private
|
|
110
117
|
class Int16
|
|
111
118
|
extend DataTypeNewConstructor
|
|
112
119
|
extend DataTypeExtension
|
|
@@ -119,6 +126,7 @@ class CArray
|
|
|
119
126
|
# CArray whose elements are `int32`. Naming the element type as a
|
|
120
127
|
# class lets a constructor be spelled `CArray::Int32.new(...)`; see
|
|
121
128
|
# {DataTypeNewConstructor} for what that form adds.
|
|
129
|
+
# @private
|
|
122
130
|
class Int32
|
|
123
131
|
extend DataTypeNewConstructor
|
|
124
132
|
extend DataTypeExtension
|
|
@@ -131,6 +139,7 @@ class CArray
|
|
|
131
139
|
# CArray whose elements are `int64`. Naming the element type as a
|
|
132
140
|
# class lets a constructor be spelled `CArray::Int64.new(...)`; see
|
|
133
141
|
# {DataTypeNewConstructor} for what that form adds.
|
|
142
|
+
# @private
|
|
134
143
|
class Int64
|
|
135
144
|
extend DataTypeNewConstructor
|
|
136
145
|
extend DataTypeExtension
|
|
@@ -143,6 +152,7 @@ class CArray
|
|
|
143
152
|
# CArray whose elements are `float32`. Naming the element type as a
|
|
144
153
|
# class lets a constructor be spelled `CArray::Float32.new(...)`; see
|
|
145
154
|
# {DataTypeNewConstructor} for what that form adds.
|
|
155
|
+
# @private
|
|
146
156
|
class Float32
|
|
147
157
|
extend DataTypeNewConstructor
|
|
148
158
|
extend DataTypeExtension
|
|
@@ -153,11 +163,13 @@ class CArray
|
|
|
153
163
|
end
|
|
154
164
|
|
|
155
165
|
# Numo-compatible alias of {Float32}.
|
|
166
|
+
# @private
|
|
156
167
|
SFloat = Float32
|
|
157
168
|
|
|
158
169
|
# CArray whose elements are `float64`. Naming the element type as a
|
|
159
170
|
# class lets a constructor be spelled `CArray::Float64.new(...)`; see
|
|
160
171
|
# {DataTypeNewConstructor} for what that form adds.
|
|
172
|
+
# @private
|
|
161
173
|
class Float64
|
|
162
174
|
extend DataTypeNewConstructor
|
|
163
175
|
extend DataTypeExtension
|
|
@@ -168,11 +180,13 @@ class CArray
|
|
|
168
180
|
end
|
|
169
181
|
|
|
170
182
|
# Numo-compatible alias of {Float64}.
|
|
183
|
+
# @private
|
|
171
184
|
DFloat = Float64
|
|
172
185
|
|
|
173
186
|
# CArray whose elements are `complex64`. Naming the element type as a
|
|
174
187
|
# class lets a constructor be spelled `CArray::Complex64.new(...)`; see
|
|
175
188
|
# {DataTypeNewConstructor} for what that form adds.
|
|
189
|
+
# @private
|
|
176
190
|
class Complex64
|
|
177
191
|
extend DataTypeNewConstructor
|
|
178
192
|
extend DataTypeExtension
|
|
@@ -183,11 +197,13 @@ class CArray
|
|
|
183
197
|
end
|
|
184
198
|
|
|
185
199
|
# Numo-compatible alias of {Complex64}.
|
|
200
|
+
# @private
|
|
186
201
|
SComplex = Complex64
|
|
187
202
|
|
|
188
203
|
# CArray whose elements are `complex128`. Naming the element type as a
|
|
189
204
|
# class lets a constructor be spelled `CArray::Complex128.new(...)`; see
|
|
190
205
|
# {DataTypeNewConstructor} for what that form adds.
|
|
206
|
+
# @private
|
|
191
207
|
class Complex128
|
|
192
208
|
extend DataTypeNewConstructor
|
|
193
209
|
extend DataTypeExtension
|
|
@@ -198,11 +214,13 @@ class CArray
|
|
|
198
214
|
end
|
|
199
215
|
|
|
200
216
|
# Numo-compatible alias of {Complex128}.
|
|
217
|
+
# @private
|
|
201
218
|
DComplex = Complex128
|
|
202
219
|
|
|
203
220
|
# CArray whose elements are `object`. Naming the element type as a
|
|
204
221
|
# class lets a constructor be spelled `CArray::Object.new(...)`; see
|
|
205
222
|
# {DataTypeNewConstructor} for what that form adds.
|
|
223
|
+
# @private
|
|
206
224
|
class Object
|
|
207
225
|
extend DataTypeNewConstructor
|
|
208
226
|
extend DataTypeExtension
|
|
@@ -213,11 +231,13 @@ class CArray
|
|
|
213
231
|
end
|
|
214
232
|
|
|
215
233
|
# Numo-compatible alias of {Object}.
|
|
234
|
+
# @private
|
|
216
235
|
RObject = Object
|
|
217
236
|
|
|
218
237
|
# CArray whose elements are `fixlen`. Naming the element type as a
|
|
219
238
|
# class lets a constructor be spelled `CArray::Fixlen.new(...)`; see
|
|
220
239
|
# {DataTypeNewConstructor} for what that form adds.
|
|
240
|
+
# @private
|
|
221
241
|
class Fixlen
|
|
222
242
|
extend DataTypeNewConstructor
|
|
223
243
|
extend DataTypeExtension
|
|
@@ -232,6 +252,7 @@ end
|
|
|
232
252
|
class CArray
|
|
233
253
|
extend DataTypeExtension
|
|
234
254
|
# @!visibility private
|
|
255
|
+
# @private
|
|
235
256
|
TypeSymbol = nil
|
|
236
257
|
# @!visibility private
|
|
237
258
|
DataType = nil
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
# - Postfix math on Float/Integer/Rational (sqrt, exp, log, sin, ...)
|
|
11
11
|
# enabling scalar/CArray polymorphism: the same expression
|
|
12
12
|
# `(0.0415*(t-218.8)).tanh` works whether t is a Float or a CArray.
|
|
13
|
+
# - The same postfix math on Complex, so an expression written for a
|
|
14
|
+
# complex CArray still reads for a single cell taken out of it.
|
|
13
15
|
# - Angle normalisation on Numeric (deg_360 / deg_180 / rad_2pi / rad_pi).
|
|
14
16
|
# - Comparison helpers on Numeric (#eq / #ne) for symmetric usage:
|
|
15
17
|
# `5.eq(ca)` dispatches to `ca.eq(5)`.
|
|
@@ -36,9 +38,9 @@ class CArray
|
|
|
36
38
|
# `using CArray::CoreExtensions`.
|
|
37
39
|
#
|
|
38
40
|
# It provides postfix math on scalars (so `(0.0415*(t-218.8)).tanh` reads
|
|
39
|
-
# the same whether `t` is a Float or a CArray), angle
|
|
40
|
-
# comparison helpers. Being a refinement, it is
|
|
41
|
-
# changes for code that does not opt in.
|
|
41
|
+
# the same whether `t` is a Float, a Complex or a CArray), angle
|
|
42
|
+
# normalisation, and comparison helpers. Being a refinement, it is
|
|
43
|
+
# lexically scoped: nothing changes for code that does not opt in.
|
|
42
44
|
module CoreExtensions
|
|
43
45
|
|
|
44
46
|
# @!visibility private
|
|
@@ -51,7 +53,11 @@ class CArray
|
|
|
51
53
|
[Float, Integer, Rational].each do |klass|
|
|
52
54
|
refine(klass) do
|
|
53
55
|
MATH_METHODS.each do |m|
|
|
54
|
-
|
|
56
|
+
module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
57
|
+
def #{m}
|
|
58
|
+
Math.#{m}(self)
|
|
59
|
+
end
|
|
60
|
+
RUBY
|
|
55
61
|
end
|
|
56
62
|
def rad
|
|
57
63
|
self.to_f * Math::PI / 180.0
|
|
@@ -65,7 +71,7 @@ class CArray
|
|
|
65
71
|
# M.1 (PyTorch alignment) scalar polymorphism additions.
|
|
66
72
|
# `trunc` is left to Ruby's built-in semantics (Float#truncate
|
|
67
73
|
# returns Integer when arg=0) — its CArray counterpart preserves
|
|
68
|
-
#
|
|
74
|
+
# data type, so scalar-side use should call .to_f.trunc explicitly.
|
|
69
75
|
# Math.expm1 / Math.log1p don't exist in stdlib; hand-roll.
|
|
70
76
|
def expm1
|
|
71
77
|
Math.exp(self) - 1.0
|
|
@@ -85,6 +91,57 @@ class CArray
|
|
|
85
91
|
end
|
|
86
92
|
end
|
|
87
93
|
|
|
94
|
+
# The subset of MATH_METHODS that CArray's complex kernels implement,
|
|
95
|
+
# plus the two elementwise helpers that also accept complex input.
|
|
96
|
+
#
|
|
97
|
+
# Absent, because a complex CArray raises CArray::DataTypeError for
|
|
98
|
+
# them: log10 (C99 has no clog10) and expm1 / log1p (no complex form
|
|
99
|
+
# in C99 either). Leaving them undefined on Complex keeps the scalar
|
|
100
|
+
# side failing wherever the array side fails. rad / deg / distance /
|
|
101
|
+
# signbit are absent for the same reason from the other direction:
|
|
102
|
+
# they go through #to_f, which Complex does not have.
|
|
103
|
+
#
|
|
104
|
+
# @!visibility private
|
|
105
|
+
COMPLEX_MATH_METHODS = %i[
|
|
106
|
+
sqrt exp log
|
|
107
|
+
sin cos tan sinh cosh tanh
|
|
108
|
+
asin acos atan asinh acosh atanh
|
|
109
|
+
square rsqrt
|
|
110
|
+
].freeze
|
|
111
|
+
|
|
112
|
+
# Complex is not handled the way Float / Integer / Rational are.
|
|
113
|
+
# Math.tanh(Complex(1,2)) raises RangeError -- of the stdlib Math
|
|
114
|
+
# methods only Math.sqrt accepts a Complex -- so the complex forms
|
|
115
|
+
# need their own implementation.
|
|
116
|
+
#
|
|
117
|
+
# Each one runs the value through a one-element cmplx128 CScalar, so
|
|
118
|
+
# the answer comes from the very kernel the array form would have
|
|
119
|
+
# used. That is the point: the branch cuts of csqrt / clog / casin /
|
|
120
|
+
# cacosh / catanh, and the sign of a zero on either side of them, are
|
|
121
|
+
# whatever the platform's C99 complex.h says they are, and they are
|
|
122
|
+
# not the same everywhere. On this machine, for instance,
|
|
123
|
+
# catanh(-1+0i) yields -Infinity+(pi/4)i where C99 Annex G describes
|
|
124
|
+
# -Infinity+0i. A hand-written Complex implementation would have to
|
|
125
|
+
# reproduce each such quirk to agree with the array form, and would
|
|
126
|
+
# stop agreeing on the next platform; delegating agrees by
|
|
127
|
+
# construction on all of them. The cost is one CScalar per call
|
|
128
|
+
# (~0.4 microseconds), which is the right trade for a scalar
|
|
129
|
+
# convenience whose whole purpose is to read the same as the array.
|
|
130
|
+
#
|
|
131
|
+
# `square` is delegated rather than written as `self * self`: Ruby's
|
|
132
|
+
# Complex multiplication and C's `double _Complex` multiplication part
|
|
133
|
+
# ways on infinities (Complex(1, Inf) squared gives -Inf+Inf*i in Ruby
|
|
134
|
+
# and -Inf+NaN*i in C).
|
|
135
|
+
refine Complex do
|
|
136
|
+
COMPLEX_MATH_METHODS.each do |m|
|
|
137
|
+
module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
138
|
+
def #{m}
|
|
139
|
+
CA_CMPLX128(self).#{m}[0]
|
|
140
|
+
end
|
|
141
|
+
RUBY
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
88
145
|
refine Numeric do
|
|
89
146
|
def deg_360
|
|
90
147
|
a = self.to_f
|
|
@@ -194,10 +194,27 @@ class CArray
|
|
|
194
194
|
start = 0
|
|
195
195
|
stop, = *args
|
|
196
196
|
step = 1
|
|
197
|
+
else
|
|
198
|
+
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 1..3)"
|
|
197
199
|
end
|
|
200
|
+
raise ArgumentError, "step must not be 0" if step == 0
|
|
198
201
|
data_type = self::DataType
|
|
199
202
|
data_type ||= guess_data_type_from_values(start, stop, step)
|
|
200
|
-
|
|
203
|
+
# Element count comes from the arguments as given, not from the
|
|
204
|
+
# target data type: CArray::Int32.arange(0, 1, 0.25) counts four
|
|
205
|
+
# elements from the float step and truncates them on store.
|
|
206
|
+
# Integer arguments count exactly (divmod) so that a step dividing
|
|
207
|
+
# the span evenly does not gain a spurious element through float
|
|
208
|
+
# rounding.
|
|
209
|
+
span = stop - start
|
|
210
|
+
if span.is_a?(Integer) && step.is_a?(Integer)
|
|
211
|
+
q, r = span.divmod(step)
|
|
212
|
+
n = r.zero? ? q : q + 1
|
|
213
|
+
else
|
|
214
|
+
n = (span.to_f / step).ceil
|
|
215
|
+
end
|
|
216
|
+
n = 0 if n < 0
|
|
217
|
+
CArray.new(data_type, [n]).seq(start, step)
|
|
201
218
|
end
|
|
202
219
|
|
|
203
220
|
# @overload full(shape, fill_value)
|
data/lib/carray/frame/concat.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#
|
|
3
3
|
# Two entry points, mirroring the CArray-level taxonomy:
|
|
4
4
|
#
|
|
5
|
-
# +CAFrame.meld+ view frame, strict same
|
|
5
|
+
# +CAFrame.meld+ view frame, strict same data type per column,
|
|
6
6
|
# each column is a CAMeld view over the inputs
|
|
7
7
|
# +CAFrame.concatenate+ eager frame, auto-casts per column,
|
|
8
8
|
# each column is a materialised entity
|
|
@@ -48,10 +48,10 @@ class CAFrame
|
|
|
48
48
|
|
|
49
49
|
# Concatenate frames along the row axis, eagerly. Each output column is
|
|
50
50
|
# +CArray.concatenate+ of that column across the input frames, so per-column
|
|
51
|
-
#
|
|
51
|
+
# data types auto-promote to a common type. The result is a fresh, independent
|
|
52
52
|
# frame — writes to it do not propagate back to the input frames.
|
|
53
53
|
#
|
|
54
|
-
# For a view frame that shares storage with the inputs (strict same
|
|
54
|
+
# For a view frame that shares storage with the inputs (strict same data type
|
|
55
55
|
# per column, chain composability preserved) use {CAFrame.meld}.
|
|
56
56
|
#
|
|
57
57
|
# Column matching, index handling, and column-set / index-mix rules
|
data/lib/carray/frame/convert.rb
CHANGED
|
@@ -31,7 +31,7 @@ class CAFrame
|
|
|
31
31
|
#
|
|
32
32
|
# Only same-shape scalar (1-D) columns qualify. An N-D column has no single
|
|
33
33
|
# matrix form and raises — escape it per column with +df["name"]+. A mixed
|
|
34
|
-
#
|
|
34
|
+
# data type set is promoted to a common type (+result_type+, §12-F) through
|
|
35
35
|
# lazy cast lanes, so the promotion costs no buffer either.
|
|
36
36
|
#
|
|
37
37
|
# +writable: true+ demands a result whose writes reach this frame's own
|
data/lib/carray/frame/frame.rb
CHANGED
|
@@ -436,13 +436,6 @@ class CAFrame
|
|
|
436
436
|
h
|
|
437
437
|
end
|
|
438
438
|
|
|
439
|
-
# @return [String]
|
|
440
|
-
def inspect
|
|
441
|
-
parts = @columns.map { |k, v| "#{k}:#{v.data_type}#{v.ndim > 1 ? v.shape[1..].inspect : ''}" }
|
|
442
|
-
idx = @index ? " index=#{@axis_name.inspect}" : ""
|
|
443
|
-
"#<CAFrame nrow=#{@nrow} vars=[#{parts.join(', ')}]#{idx}>"
|
|
444
|
-
end
|
|
445
|
-
|
|
446
439
|
private def rebuild(cols)
|
|
447
440
|
CAFrame.new(cols, axis_name: @axis_name, index: @index)
|
|
448
441
|
end
|
|
@@ -511,7 +504,7 @@ class CAFrame
|
|
|
511
504
|
end
|
|
512
505
|
|
|
513
506
|
# df[sel] = other : replace the selected contiguous span with other's rows
|
|
514
|
-
# (any length). Columns are concatenated head + other + tail, so
|
|
507
|
+
# (any length). Columns are concatenated head + other + tail, so data types
|
|
515
508
|
# promote and the row count shifts by other.nrow - span.
|
|
516
509
|
private def splice_rows(selector, other)
|
|
517
510
|
lo, hi = contiguous_span(selector)
|
|
@@ -536,9 +529,9 @@ class CAFrame
|
|
|
536
529
|
case pieces.size
|
|
537
530
|
when 0 then col[CArray.int32(0), *tail] # replaced every row with none
|
|
538
531
|
when 1 then pieces.first
|
|
539
|
-
else CArray.meld(pieces, axis: 0) # CAMeld view;
|
|
532
|
+
else CArray.meld(pieces, axis: 0) # CAMeld view; data type mismatch
|
|
540
533
|
end # across pieces raises.
|
|
541
|
-
# For
|
|
534
|
+
# For data type conversion, cast
|
|
542
535
|
# the incoming +other+'s
|
|
543
536
|
# column beforehand — silent
|
|
544
537
|
# promotion in a splice would
|
|
@@ -566,7 +559,7 @@ class CAFrame
|
|
|
566
559
|
case pieces.size
|
|
567
560
|
when 0 then @index[CArray.int32(0)]
|
|
568
561
|
when 1 then pieces.first
|
|
569
|
-
else CArray.meld(pieces, axis: 0) # index
|
|
562
|
+
else CArray.meld(pieces, axis: 0) # index data type must match across frames
|
|
570
563
|
end
|
|
571
564
|
end
|
|
572
565
|
|
data/lib/carray/frame/io.rb
CHANGED
|
@@ -62,8 +62,8 @@ class CAFrame
|
|
|
62
62
|
# is a view into it (§3.6).
|
|
63
63
|
# Write the frame as CSV. CSV is a flat table of scalar cells, so this is the
|
|
64
64
|
# text form of the same all-scalar subset +to_ca+ requires (§11.9): every
|
|
65
|
-
# column must be 1-D. Unlike +to_ca+ it does not promote to a common
|
|
66
|
-
# each column is formatted to text independently, so mixed
|
|
65
|
+
# column must be 1-D. Unlike +to_ca+ it does not promote to a common data type --
|
|
66
|
+
# each column is formatted to text independently, so mixed data types (numbers,
|
|
67
67
|
# strings, datetime / categorical Faces) sit side by side. An N-D column has
|
|
68
68
|
# no flat CSV cell and raises; export it per column, or use +to_records+ +
|
|
69
69
|
# JSON for the structured shape (memo §11.9, the N-D escape).
|
|
@@ -115,6 +115,163 @@ class CAFrame
|
|
|
115
115
|
end
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
+
# Render the frame as an aligned text table for reading:
|
|
119
|
+
#
|
|
120
|
+
# puts df.to_table
|
|
121
|
+
#
|
|
122
|
+
# time temp station
|
|
123
|
+
# ---------- ---- -------
|
|
124
|
+
# 2026-01-01 1.5 Tokyo
|
|
125
|
+
# 2026-01-02 _ Osaka
|
|
126
|
+
#
|
|
127
|
+
# This is the display counterpart of +to_csv+ and shares none of its
|
|
128
|
+
# constraints: it is text meant to be looked at, not read back. Numeric
|
|
129
|
+
# columns are right-aligned, everything else left-aligned; a masked cell
|
|
130
|
+
# shows as +_+, the same marker CArray's own inspect uses. An N-D column
|
|
131
|
+
# (which +to_csv+ rejects, having no flat cell) shows each row's slice as
|
|
132
|
+
# an Array literal.
|
|
133
|
+
#
|
|
134
|
+
# Float cells are rounded to +precision+ decimal places for display only
|
|
135
|
+
# (default 6); +precision: nil+ prints them at full precision, which is
|
|
136
|
+
# faithful but lets one long value set the column width.
|
|
137
|
+
#
|
|
138
|
+
# Long frames are truncated in the middle: +rows+ caps how many rows are
|
|
139
|
+
# printed (default 20, split evenly around an ellipsis row), and
|
|
140
|
+
# +rows: nil+ prints every row. +index: false+ drops the index column.
|
|
141
|
+
def to_table(rows: 20, index: true, precision: 6)
|
|
142
|
+
head = rows && (rows + 1) / 2
|
|
143
|
+
render_table(head: head, tail: rows && rows - head,
|
|
144
|
+
index: index, precision: precision, footer: true)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# +to_s+ is the whole frame, +inspect+ the middle-elided one -- so +puts df+
|
|
148
|
+
# dumps everything and +p df+ stays a screenful. +inspect+ leads with the
|
|
149
|
+
# same summary line it always had (nrow, variable data types, index), so the
|
|
150
|
+
# table under it needs no row-count footer.
|
|
151
|
+
def to_s
|
|
152
|
+
to_table(rows: nil)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# The summary line (nrow, variable data types, index) followed by the
|
|
156
|
+
# middle-elided table.
|
|
157
|
+
# @return [String]
|
|
158
|
+
def inspect
|
|
159
|
+
parts = @columns.map { |k, v| "#{k}:#{v.data_type}#{v.ndim > 1 ? v.shape[1..].inspect : ''}" }
|
|
160
|
+
idx = @index ? " index=#{@axis_name.inspect}" : ""
|
|
161
|
+
head = "#<CAFrame nrow=#{@nrow} vars=[#{parts.join(', ')}]#{idx}>"
|
|
162
|
+
return head if @columns.empty?
|
|
163
|
+
head + "\n" + render_table(head: 8, tail: 2, index: true, precision: 6,
|
|
164
|
+
footer: false)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
private def render_table(head:, tail:, index:, precision:, footer:)
|
|
168
|
+
names = []
|
|
169
|
+
columns = []
|
|
170
|
+
aligns = []
|
|
171
|
+
|
|
172
|
+
if index && @index
|
|
173
|
+
names << @axis_name
|
|
174
|
+
columns << @index
|
|
175
|
+
aligns << (@index.numeric? ? :right : :left)
|
|
176
|
+
end
|
|
177
|
+
@columns.each do |name, col|
|
|
178
|
+
names << name
|
|
179
|
+
columns << col
|
|
180
|
+
aligns << (col.ndim == 1 && col.numeric? ? :right : :left)
|
|
181
|
+
end
|
|
182
|
+
return "" if names.empty?
|
|
183
|
+
|
|
184
|
+
positions = table_row_positions(head, tail)
|
|
185
|
+
body = positions.map do |i|
|
|
186
|
+
if i.nil?
|
|
187
|
+
Array.new(columns.size, ":") # vertical ellipsis for the elided middle
|
|
188
|
+
else
|
|
189
|
+
columns.map { |col| format_table_cell(col, i, precision) }
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
widths = names.each_with_index.map do |name, j|
|
|
194
|
+
[display_width(name), *body.map { |cells| display_width(cells[j]) }].max
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
out = +""
|
|
198
|
+
out << table_row(names, widths, aligns) << "\n"
|
|
199
|
+
out << table_row(widths.map { |w| "-" * w }, widths, aligns) << "\n"
|
|
200
|
+
body.each { |cells| out << table_row(cells, widths, aligns) << "\n" }
|
|
201
|
+
if footer && positions.size - positions.count(nil) < @nrow
|
|
202
|
+
out << "(#{plural(@nrow, 'row')}, #{plural(@columns.size, 'variable')})\n"
|
|
203
|
+
end
|
|
204
|
+
out
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Row indices to print, with nil marking the elided middle. A nil head means
|
|
208
|
+
# no cap; a frame that already fits in head + tail is listed whole.
|
|
209
|
+
private def table_row_positions(head, tail)
|
|
210
|
+
return (0...@nrow).to_a if head.nil? || @nrow <= head + tail
|
|
211
|
+
(0...head).to_a + [nil] + ((@nrow - tail)...@nrow).to_a
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
private def table_row(cells, widths, aligns)
|
|
215
|
+
line = cells.each_with_index.map do |text, j|
|
|
216
|
+
pad = " " * (widths[j] - display_width(text))
|
|
217
|
+
aligns[j] == :right ? pad + text : text + pad
|
|
218
|
+
end.join(" ")
|
|
219
|
+
line.rstrip
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Column widths are counted in terminal cells, not characters: a CJK
|
|
223
|
+
# ideograph, kana, or full-width form occupies two cells, so counting
|
|
224
|
+
# characters would leave every column holding such a name ragged. The
|
|
225
|
+
# ranges below are the East Asian Wide / Fullwidth blocks; a combining
|
|
226
|
+
# mark takes no cell of its own.
|
|
227
|
+
WIDE_CHAR_RANGES = [
|
|
228
|
+
0x1100..0x115F, 0x2E80..0x303E, 0x3041..0x33FF, 0x3400..0x4DBF,
|
|
229
|
+
0x4E00..0x9FFF, 0xA000..0xA4CF, 0xA960..0xA97F, 0xAC00..0xD7A3,
|
|
230
|
+
0xF900..0xFAFF, 0xFE10..0xFE19, 0xFE30..0xFE6F, 0xFF00..0xFF60,
|
|
231
|
+
0xFFE0..0xFFE6, 0x1F300..0x1F64F, 0x1F900..0x1F9FF, 0x20000..0x3FFFD,
|
|
232
|
+
].freeze
|
|
233
|
+
private_constant :WIDE_CHAR_RANGES
|
|
234
|
+
|
|
235
|
+
COMBINING_RANGES = [0x0300..0x036F, 0x1AB0..0x1AFF, 0x20D0..0x20F0].freeze
|
|
236
|
+
private_constant :COMBINING_RANGES
|
|
237
|
+
|
|
238
|
+
private def display_width(text)
|
|
239
|
+
text.each_char.sum do |ch|
|
|
240
|
+
cp = ch.ord
|
|
241
|
+
if COMBINING_RANGES.any? { |r| r.cover?(cp) }
|
|
242
|
+
0
|
|
243
|
+
elsif WIDE_CHAR_RANGES.any? { |r| r.cover?(cp) }
|
|
244
|
+
2
|
|
245
|
+
else
|
|
246
|
+
1
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
private def plural(n, noun)
|
|
252
|
+
"#{n} #{noun}#{n == 1 ? '' : 's'}"
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
private def format_table_cell(col, i, precision)
|
|
256
|
+
e = elem_at(col, i)
|
|
257
|
+
if UNDEF.equal?(e) || e.nil?
|
|
258
|
+
"_"
|
|
259
|
+
elsif e.is_a?(Float) && precision
|
|
260
|
+
# Display rounding only: a full-precision float (141.67833333333334)
|
|
261
|
+
# sets the column width for every other row and makes the table hard
|
|
262
|
+
# to read. precision: nil prints the value as Ruby renders it.
|
|
263
|
+
e.round(precision).to_s
|
|
264
|
+
elsif e.is_a?(CArray)
|
|
265
|
+
e.to_a.inspect
|
|
266
|
+
elsif e.is_a?(String)
|
|
267
|
+
e
|
|
268
|
+
elsif e.respond_to?(:iso8601)
|
|
269
|
+
e.iso8601
|
|
270
|
+
else
|
|
271
|
+
e.to_s
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
118
275
|
private def format_csv_column(col)
|
|
119
276
|
col.to_a.map do |e|
|
|
120
277
|
if UNDEF.equal?(e) || e.nil?
|
data/lib/carray/frame/sort.rb
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
#
|
|
14
14
|
# sort_addr is ascending, so a descending key is expressed by replacing it with
|
|
15
15
|
# its dense descending rank (CArray#order(descending: true, method: :dense)):
|
|
16
|
-
# this works for every
|
|
16
|
+
# this works for every data type (unlike negation, which cannot reverse a string and
|
|
17
17
|
# silently wraps an unsigned integer), and the *dense* rank keeps equal values
|
|
18
18
|
# on one rank so ties fall through to later keys in a multi-key sort.
|
|
19
19
|
# masked_position (CArray.sort_addr's kwarg) places masked key rows first or
|
data/lib/carray/frame/verbs.rb
CHANGED
|
@@ -143,11 +143,28 @@ class CAFrame
|
|
|
143
143
|
# carry, so it raises rather than silently truncate. Make it the index with
|
|
144
144
|
# +set_index+ afterward.
|
|
145
145
|
#
|
|
146
|
+
# A +CATime::Grid+ carries the same (unit, epoch) pair as one value, so a
|
|
147
|
+
# netCDF +units+ attribute goes straight in. It also carries a phase the
|
|
148
|
+
# keyword form cannot: the keyword +epoch+ is read on the +unit+ grid, so
|
|
149
|
+
# an epoch off that grid ("days since 1980-01-01 12:00") loses its
|
|
150
|
+
# time-of-day, while a grid resolves the finer storage that holds it.
|
|
151
|
+
#
|
|
146
152
|
# df.to_time("time", unit: :h, epoch: "1990-01-01").set_index("time")
|
|
147
|
-
|
|
153
|
+
# df.to_time("time", CATime::Grid.parse("hours since 1990-01-01"))
|
|
154
|
+
# df.to_time("time", CATime::Grid.parse("days since 1980-01-01 12:00"))
|
|
155
|
+
def to_time(name, grid = nil, unit: :s, epoch: nil)
|
|
148
156
|
key = name.to_s
|
|
149
157
|
col = @columns.fetch(key) { raise KeyError, "no column #{key.inspect}" }
|
|
150
158
|
raw = integer_serial_column(col, key)
|
|
159
|
+
grid = unit if unit.is_a?(CATime::Grid)
|
|
160
|
+
if grid.is_a?(CATime::Grid)
|
|
161
|
+
@columns[key] = grid.at(raw)
|
|
162
|
+
return self
|
|
163
|
+
end
|
|
164
|
+
unless grid.nil?
|
|
165
|
+
raise ArgumentError,
|
|
166
|
+
"the positional argument must be a CATime::Grid (got #{grid.class})"
|
|
167
|
+
end
|
|
151
168
|
if epoch
|
|
152
169
|
raw = raw + CArray.time(epoch, unit: unit).ticks[0]
|
|
153
170
|
end
|