carray 2.0.0 → 3.0.0
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 +5 -25
- data/CHANGELOG.md +16 -0
- data/LICENSE +1 -1
- data/NEWS.md +3 -0
- data/README.md +128 -44
- data/carray.gemspec +22 -24
- data/ext/ca_array_pool.c +91 -0
- data/ext/ca_axis_descriptor.h +186 -0
- data/ext/ca_axis_dispatch.c +924 -0
- data/ext/ca_axis_group.c +1208 -0
- data/ext/ca_bincmp_dispatch.c +76 -0
- data/ext/ca_bincmp_dispatch.h +85 -0
- data/ext/ca_binop_dispatch.c +125 -0
- data/ext/ca_binop_dispatch.h +159 -0
- data/ext/ca_categorical_iterator.c +1375 -0
- data/ext/ca_compare.c +94 -0
- data/ext/ca_compare.h +26 -0
- data/ext/ca_composite_dispatch.c +414 -0
- data/ext/ca_composite_dispatch.h +116 -0
- data/ext/ca_for_buffer.h +96 -0
- data/ext/ca_for_each_element.h +241 -0
- data/ext/ca_group_iter.c +304 -0
- data/ext/ca_iter_substrate.h +325 -0
- data/ext/ca_kernel_iterator.c +4321 -0
- data/ext/ca_kernel_iterator.h +2603 -0
- data/ext/ca_moncmp_dispatch.c +37 -0
- data/ext/ca_moncmp_dispatch.h +62 -0
- data/ext/ca_monop_dispatch.c +200 -0
- data/ext/ca_monop_dispatch.h +235 -0
- data/ext/ca_obj_array.c +355 -359
- data/ext/ca_obj_bincmp.c +809 -0
- data/ext/ca_obj_binop.c +892 -0
- data/ext/ca_obj_bitarray.c +369 -164
- data/ext/ca_obj_bitfield.c +294 -234
- data/ext/ca_obj_block.c +189 -711
- data/ext/ca_obj_byte_swap.c +766 -0
- data/ext/ca_obj_const_string.c +965 -0
- data/ext/ca_obj_face.c +670 -0
- data/ext/ca_obj_face.h +247 -0
- data/ext/ca_obj_fake.c +228 -100
- data/ext/ca_obj_farray.c +54 -441
- data/ext/ca_obj_field.c +82 -529
- data/ext/ca_obj_fixlen_string.c +306 -0
- data/ext/ca_obj_grid.c +858 -440
- data/ext/ca_obj_meld.c +1034 -0
- data/ext/ca_obj_moncmp.c +569 -0
- data/ext/ca_obj_monop.c +1111 -0
- data/ext/ca_obj_object.c +774 -298
- data/ext/ca_obj_record.c +468 -0
- data/ext/ca_obj_reduce.c +97 -82
- data/ext/ca_obj_refer.c +569 -459
- data/ext/ca_obj_remap.c +475 -0
- data/ext/ca_obj_repeat.c +92 -477
- data/ext/ca_obj_roll.c +616 -0
- data/ext/ca_obj_select.c +344 -296
- data/ext/ca_obj_select_axis.c +1296 -0
- data/ext/ca_obj_shift.c +230 -792
- data/ext/ca_obj_source.c +78 -0
- data/ext/ca_obj_stack.c +1173 -0
- data/ext/ca_obj_stride.c +2501 -0
- data/ext/ca_obj_string.c +268 -0
- data/ext/ca_obj_tile.c +614 -0
- data/ext/ca_obj_time.c +546 -0
- data/ext/ca_obj_timedelta.c +435 -0
- data/ext/ca_obj_transpose.c +62 -516
- data/ext/ca_obj_triop.c +746 -0
- data/ext/ca_obj_unbound_repeat.c +208 -241
- data/ext/ca_obj_window.c +1131 -563
- data/ext/ca_op_byte_swap.c +175 -0
- data/ext/ca_op_ipower.c +319 -0
- data/ext/ca_op_powi.h +88 -0
- data/ext/ca_sort_kernels.h +132 -0
- data/ext/ca_sweep_engine.c +430 -0
- data/ext/ca_sweep_engine.h +157 -0
- data/ext/ca_transform_common.c +228 -0
- data/ext/ca_triop_dispatch.c +55 -0
- data/ext/ca_triop_dispatch.h +62 -0
- data/ext/carray.h +795 -402
- data/ext/carray_access.c +831 -711
- data/ext/carray_attribute.c +98 -330
- data/ext/carray_bincount.c +255 -0
- data/ext/carray_broadcast.c +283 -0
- data/ext/carray_call_cfunc.c +1360 -828
- data/ext/carray_call_cfunc.h +160 -0
- data/ext/carray_cast.c +1212 -301
- data/ext/carray_cast_func.rb +81 -40
- data/ext/carray_class.c +53 -63
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +350 -346
- data/ext/carray_copy.c +156 -268
- data/ext/carray_core.c +1342 -199
- data/ext/carray_count.c +312 -0
- data/ext/carray_data_type.c +43 -19
- data/ext/carray_element.c +585 -213
- data/ext/carray_factorize.c +2542 -0
- data/ext/carray_generate.c +230 -559
- data/ext/carray_histogram.c +490 -0
- data/ext/carray_hold.c +228 -0
- data/ext/carray_index_classifier.c +1035 -0
- data/ext/carray_index_classifier.h +27 -0
- data/ext/carray_internal.h +120 -0
- data/ext/carray_kernels_bincmp.c +4445 -0
- data/ext/carray_kernels_binop.c +10979 -0
- data/ext/carray_kernels_init.c +36 -0
- data/ext/carray_kernels_map.c +3466 -0
- data/ext/carray_kernels_moncmp.c +2096 -0
- data/ext/carray_kernels_monop.c +18312 -0
- data/ext/carray_kernels_reduce_aggregate.c +25836 -0
- data/ext/carray_kernels_reduce_boolean.c +329 -0
- data/ext/carray_kernels_reduce_cumulative.c +14592 -0
- data/ext/carray_kernels_reduce_extreme.c +16947 -0
- data/ext/carray_kernels_reduce_variance.c +3909 -0
- data/ext/carray_kernels_scan.c +3692 -0
- data/ext/carray_kernels_search.c +32137 -0
- data/ext/carray_kernels_sort.c +10625 -0
- data/ext/carray_kernels_triop.c +1391 -0
- data/ext/carray_lazy.c +567 -0
- data/ext/carray_loop.c +88 -200
- data/ext/carray_mask.c +848 -154
- data/ext/carray_math_kernel.h +120 -0
- data/ext/carray_mathfunc.c +10 -241
- data/ext/carray_median_percentile.c +1257 -0
- data/ext/carray_memory_view.c +1625 -0
- data/ext/carray_operator.c +1526 -318
- data/ext/carray_order.c +664 -1394
- data/ext/carray_partition.c +416 -0
- data/ext/carray_random.c +518 -0
- data/ext/carray_scatter.c +357 -0
- data/ext/carray_slab.c +1219 -0
- data/ext/carray_slab.h +84 -0
- data/ext/carray_sort.c +829 -0
- data/ext/carray_sort_kernel.c +620 -0
- data/ext/carray_struct.c +695 -0
- data/ext/carray_test.c +343 -229
- data/ext/carray_undef.c +34 -17
- data/ext/carray_utils.c +175 -74
- data/ext/extconf.rb +216 -55
- data/ext/mk_call_cfunc.rb +480 -0
- data/ext/mkkernel.rb +8842 -0
- data/ext/ruby_carray.c +202 -101
- data/ext/version.h +4 -14
- data/ext/version.rb +5 -13
- data/lib/carray/arrow_tensor.rb +401 -0
- data/lib/carray/attribute.rb +166 -0
- data/lib/carray/autoload_carray.rb +220 -0
- data/lib/carray/autoload_method_extension.rb +44 -0
- data/lib/carray/axis_group.rb +711 -0
- data/lib/carray/basics.rb +481 -0
- data/lib/carray/bincount_nd.rb +358 -0
- data/lib/carray/block_iterator.rb +604 -0
- data/lib/carray/boolean_reduce.rb +109 -0
- data/lib/carray/categorical.rb +561 -0
- data/lib/carray/categorical_iterator.rb +1062 -0
- data/lib/carray/complex.rb +150 -0
- data/lib/carray/conditional.rb +216 -0
- data/lib/carray/const_string.rb +228 -0
- data/lib/carray/construct.rb +139 -328
- data/lib/carray/core_extensions.rb +240 -0
- data/lib/carray/data_type_extension.rb +233 -0
- data/lib/carray/fixlen_string.rb +95 -0
- data/lib/carray/frame/concat.rb +132 -0
- data/lib/carray/frame/convert.rb +95 -0
- data/lib/carray/frame/csv_parser.rb +211 -0
- data/lib/carray/frame/frame.rb +649 -0
- data/lib/carray/frame/group.rb +186 -0
- data/lib/carray/frame/io.rb +164 -0
- data/lib/carray/frame/join.rb +248 -0
- data/lib/carray/frame/records.rb +99 -0
- data/lib/carray/frame/sort.rb +113 -0
- data/lib/carray/frame/verbs.rb +299 -0
- data/lib/carray/frame.rb +16 -0
- data/lib/carray/histogram.rb +512 -0
- data/lib/carray/inspect.rb +37 -20
- data/lib/carray/iterator.rb +57 -349
- data/lib/carray/lazy.rb +889 -0
- data/lib/carray/mask_gap_fill.rb +200 -0
- data/lib/carray/math.rb +78 -342
- data/lib/carray/meld_reduce.rb +289 -0
- data/lib/carray/methods/align_addr.rb +116 -0
- data/lib/carray/methods/bin.rb +128 -0
- data/lib/carray/methods/bincount.rb +87 -0
- data/lib/carray/methods/bit_string.rb +92 -0
- data/lib/carray/methods/broadcast.rb +63 -0
- data/lib/carray/methods/choose.rb +39 -0
- data/lib/carray/methods/composition.rb +280 -0
- data/lib/carray/methods/gather_nd.rb +206 -0
- data/lib/carray/methods/index.rb +39 -0
- data/lib/carray/methods/insert_block.rb +99 -0
- data/lib/carray/methods/is_in.rb +141 -0
- data/lib/carray/methods/join.rb +90 -0
- data/lib/carray/methods/locate_addr.rb +47 -0
- data/lib/carray/methods/mask_duplicates.rb +41 -0
- data/lib/carray/methods/meshgrid.rb +91 -0
- data/lib/carray/methods/mode.rb +126 -0
- data/lib/carray/methods/nunique.rb +46 -0
- data/lib/carray/methods/resize.rb +56 -0
- data/lib/carray/methods/snap.rb +156 -0
- data/lib/carray/methods/string_format.rb +57 -0
- data/lib/carray/methods/unique.rb +47 -0
- data/lib/carray/methods/value_counts.rb +71 -0
- data/lib/carray/mkmf.rb +124 -101
- data/lib/carray/runtime.rb +108 -0
- data/lib/carray/serialize.rb +478 -167
- data/lib/carray/slab_iterator.rb +292 -0
- data/lib/carray/stack.rb +291 -0
- data/lib/carray/string.rb +56 -180
- data/lib/carray/string_operation_extension.rb +289 -0
- data/lib/carray/struct.rb +335 -323
- data/lib/carray/struct_builder.rb +697 -0
- data/lib/carray/table.rb +41 -2
- data/lib/carray/time.rb +2255 -38
- data/lib/carray/window_iterator.rb +655 -0
- data/lib/carray.rb +55 -57
- metadata +163 -130
- data/Rakefile +0 -51
- data/TODO.md +0 -18
- data/ext/ca_iter_block.c +0 -257
- data/ext/ca_iter_dimension.c +0 -299
- data/ext/ca_iter_window.c +0 -214
- data/ext/ca_obj_mapping.c +0 -644
- data/ext/carray_iterator.c +0 -641
- data/ext/carray_math.rb +0 -850
- data/ext/carray_numeric.c +0 -259
- data/ext/carray_sort_addr.c +0 -254
- data/ext/carray_stat.c +0 -2100
- data/ext/carray_stat_proc.rb +0 -1999
- data/ext/mkmath.rb +0 -741
- data/ext/ruby_ccomplex.c +0 -509
- data/ext/ruby_float_func.c +0 -86
- data/lib/carray/array.rb +0 -8
- data/lib/carray/autoload/autoload_base.rb +0 -19
- data/lib/carray/autoload/autoload_gem_cairo.rb +0 -9
- data/lib/carray/autoload/autoload_gem_ffi.rb +0 -9
- data/lib/carray/autoload/autoload_gem_gnuplot.rb +0 -2
- data/lib/carray/autoload/autoload_gem_io_csv.rb +0 -14
- data/lib/carray/autoload/autoload_gem_io_pg.rb +0 -6
- data/lib/carray/autoload/autoload_gem_io_sqlite3.rb +0 -12
- data/lib/carray/autoload/autoload_gem_narray.rb +0 -10
- data/lib/carray/autoload/autoload_gem_numo_narray.rb +0 -15
- data/lib/carray/autoload/autoload_gem_opencv.rb +0 -16
- data/lib/carray/autoload/autoload_gem_random.rb +0 -8
- data/lib/carray/autoload/autoload_gem_rmagick.rb +0 -23
- data/lib/carray/autoload/autoload_gem_zimg.rb +0 -3
- data/lib/carray/autoload/autoload_io_imagemagick.rb +0 -6
- data/lib/carray/autoload/autoload_math_histogram.rb +0 -5
- data/lib/carray/autoload/autoload_math_recurrence.rb +0 -6
- data/lib/carray/autoload/autoload_object_iterator.rb +0 -1
- data/lib/carray/autoload/autoload_object_link.rb +0 -1
- data/lib/carray/autoload/autoload_object_pack.rb +0 -2
- data/lib/carray/autoload.rb +0 -141
- data/lib/carray/basic.rb +0 -191
- data/lib/carray/broadcast.rb +0 -101
- data/lib/carray/compose.rb +0 -315
- data/lib/carray/convert.rb +0 -115
- data/lib/carray/info.rb +0 -110
- data/lib/carray/io/imagemagick.rb +0 -235
- data/lib/carray/mask.rb +0 -102
- data/lib/carray/math/histogram.rb +0 -177
- data/lib/carray/math/recurrence.rb +0 -93
- data/lib/carray/object/ca_obj_iterator.rb +0 -50
- data/lib/carray/object/ca_obj_link.rb +0 -50
- data/lib/carray/object/ca_obj_pack.rb +0 -99
- data/lib/carray/obsolete.rb +0 -256
- data/lib/carray/ordering.rb +0 -181
- data/lib/carray/testing.rb +0 -51
- data/lib/carray/transform.rb +0 -109
- data/misc/Methods.ja.md +0 -182
- data/misc/NOTE +0 -51
- data/spec/Classes/CABitfield_spec.rb +0 -58
- data/spec/Classes/CABlockIterator_spec.rb +0 -114
- data/spec/Classes/CABlock_spec.rb +0 -205
- data/spec/Classes/CAField_spec.rb +0 -39
- data/spec/Classes/CAGrid_spec.rb +0 -75
- data/spec/Classes/CAMap_spec.rb +0 -0
- data/spec/Classes/CAMapping_spec.rb +0 -105
- data/spec/Classes/CAObject_attribute_spec.rb +0 -33
- data/spec/Classes/CAObject_spec.rb +0 -33
- data/spec/Classes/CARefer_spec.rb +0 -93
- data/spec/Classes/CARepeat_spec.rb +0 -65
- data/spec/Classes/CASelect_spec.rb +0 -22
- data/spec/Classes/CAShift_spec.rb +0 -16
- data/spec/Classes/CAStruct_spec.rb +0 -71
- data/spec/Classes/CATranspose_spec.rb +0 -60
- data/spec/Classes/CAUnboudRepeat_spec.rb +0 -102
- data/spec/Classes/CAWindow_spec.rb +0 -54
- data/spec/Classes/CAWrap_spec.rb +0 -8
- data/spec/Classes/CArray_spec.rb +0 -184
- data/spec/Classes/CScalar_spec.rb +0 -55
- data/spec/Classes/ex1.rb +0 -46
- data/spec/Features/feature_130_spec.rb +0 -19
- data/spec/Features/feature_attributes_spec.rb +0 -280
- data/spec/Features/feature_boolean_spec.rb +0 -98
- data/spec/Features/feature_broadcast.rb +0 -116
- data/spec/Features/feature_cast_function.rb +0 -19
- data/spec/Features/feature_cast_spec.rb +0 -33
- data/spec/Features/feature_class_spec.rb +0 -84
- data/spec/Features/feature_complex_spec.rb +0 -42
- data/spec/Features/feature_composite_spec.rb +0 -124
- data/spec/Features/feature_convert_spec.rb +0 -46
- data/spec/Features/feature_copy_spec.rb +0 -123
- data/spec/Features/feature_creation_spec.rb +0 -84
- data/spec/Features/feature_element_spec.rb +0 -144
- data/spec/Features/feature_extream_spec.rb +0 -54
- data/spec/Features/feature_generate_spec.rb +0 -74
- data/spec/Features/feature_index_spec.rb +0 -69
- data/spec/Features/feature_mask_spec.rb +0 -580
- data/spec/Features/feature_math_spec.rb +0 -97
- data/spec/Features/feature_order_spec.rb +0 -146
- data/spec/Features/feature_ref_store_spec.rb +0 -209
- data/spec/Features/feature_serialization_spec.rb +0 -125
- data/spec/Features/feature_stat_spec.rb +0 -397
- data/spec/Features/feature_virtual_spec.rb +0 -48
- data/spec/Features/method_eq_spec.rb +0 -81
- data/spec/Features/method_is_nan_spec.rb +0 -12
- data/spec/Features/method_map_spec.rb +0 -54
- data/spec/Features/method_max_with.rb +0 -20
- data/spec/Features/method_min_with.rb +0 -19
- data/spec/Features/method_ne_spec.rb +0 -18
- data/spec/Features/method_project_spec.rb +0 -188
- data/spec/Features/method_ref_spec.rb +0 -27
- data/spec/Features/method_round_spec.rb +0 -11
- data/spec/Features/method_s_linspace_spec.rb +0 -48
- data/spec/Features/method_s_span_spec.rb +0 -14
- data/spec/Features/method_seq_spec.rb +0 -47
- data/spec/Features/method_sort_with.rb +0 -43
- data/spec/Features/method_sorted_with.rb +0 -29
- data/spec/Features/method_span_spec.rb +0 -42
- data/spec/Features/method_wrap_readonly_spec.rb +0 -43
- data/spec/UnitTest/test_CAVirtual.rb +0 -214
- data/spec/spec_all.rb +0 -10
- data/utils/ca_ase.rb +0 -21
- data/utils/ca_methods.rb +0 -15
- data/utils/cast_checker.rb +0 -30
- data/utils/convert_test.rb +0 -73
- data/utils/extract_yard.rb +0 -22
- data/utils/guess_shape.rb +0 -76
- data/utils/monkey_patch_methods.rb +0 -62
- data/utils/remove_resource_fork.sh +0 -5
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Complex-component accessors (real / real= / imag / imag= / real? /
|
|
2
|
+
# is_real). Loaded eagerly BEFORE carray/lazy.rb, because lazy.rb does
|
|
3
|
+
# `alias_method :__real_eager__, :real` (and the imag equivalent) at load
|
|
4
|
+
# time -- these defs must exist by then.
|
|
5
|
+
|
|
6
|
+
class CArray
|
|
7
|
+
|
|
8
|
+
# complex number
|
|
9
|
+
#
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
# DO NOT RETIRE real / real= / imag / imag= IN FAVOUR OF THE LAZY FRAMEWORK
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
#
|
|
14
|
+
# A recurring temptation is to consider these methods redundant now that the
|
|
15
|
+
# lazy substrate provides `c.lazy.real` / `c.lazy.imag` via CAMonOp chains
|
|
16
|
+
# (cast_<float> for real; imag_i + cast_<float> for imag — see
|
|
17
|
+
# lib/carray/lazy.rb). They are NOT redundant. The two paths are
|
|
18
|
+
# **complementary** and serve different abstractions:
|
|
19
|
+
#
|
|
20
|
+
# c.real (here) -> CAField: mutable zero-copy view into
|
|
21
|
+
# the byte slot of complex
|
|
22
|
+
# storage. Read AND write.
|
|
23
|
+
# c.lazy.real (lazy.rb) -> CAMonOp: read-only lazy chain node
|
|
24
|
+
# for streaming consumption.
|
|
25
|
+
#
|
|
26
|
+
# The CAField path supports in-place mutation idioms that the lazy framework
|
|
27
|
+
# cannot express:
|
|
28
|
+
#
|
|
29
|
+
# c = CArray.cmplx128(10)
|
|
30
|
+
# c.real.seq!(1) # write 1..10 into real slot, zero-copy
|
|
31
|
+
# c.imag.seq!(-1,-1) # write -1..-10 into imag slot
|
|
32
|
+
# c.real = some_array # bulk write into real slot
|
|
33
|
+
#
|
|
34
|
+
# These are used by spec/Features/feature_stat_spec.rb and by user code
|
|
35
|
+
# patterns CArray's "byte-slot mutable view" capability is designed to
|
|
36
|
+
# support (= writing to `.real` stores into the real part in place;
|
|
37
|
+
# CAField makes it a zero-copy abstraction available across all
|
|
38
|
+
# CAStride-based view algebra).
|
|
39
|
+
#
|
|
40
|
+
# Architecturally:
|
|
41
|
+
# - lib/carray/lazy.rb's `real`/`imag` overrides dispatch to CAMonOp
|
|
42
|
+
# when self is a lazy view, and fall through to the defs here for eager
|
|
43
|
+
# parents (via `alias_method :__real_eager__, :real` at load time).
|
|
44
|
+
# This file MUST be required before carray/lazy.rb (see carray.rb), and
|
|
45
|
+
# removing these defs would break that alias and the lazy.rb load.
|
|
46
|
+
#
|
|
47
|
+
# - ext/ca_obj_stride.c recognises `CAField .real/.imag over complex`
|
|
48
|
+
# as a first-class byte-mismatched reinterpret pattern. Architectural
|
|
49
|
+
# commitment is already written into the C layer.
|
|
50
|
+
#
|
|
51
|
+
# Outright deletion is a regression on a documented capability (the lazy
|
|
52
|
+
# framework's read-only chain does not replace the CAField mutable view).
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
# @overload real
|
|
56
|
+
# Returns the real part of `self` as a zero-copy view. For a
|
|
57
|
+
# complex array the view is a mutable {CAField} into the
|
|
58
|
+
# real-part slot; for a real numeric array it is a {CARefer}
|
|
59
|
+
# over `self`. Writing to the view updates `self` in place.
|
|
60
|
+
# @return [CArray]
|
|
61
|
+
def real
|
|
62
|
+
if not @__real__
|
|
63
|
+
if complex?
|
|
64
|
+
@__real__ = case data_type
|
|
65
|
+
when CA_CMPLX64
|
|
66
|
+
field(0, CA_FLOAT32)
|
|
67
|
+
when CA_CMPLX128
|
|
68
|
+
field(0, CA_FLOAT64)
|
|
69
|
+
end
|
|
70
|
+
else
|
|
71
|
+
@__real__ = self[]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
@__real__
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @overload real=(val)
|
|
78
|
+
# Sets the real-part slot to `val` via {#real}.
|
|
79
|
+
# @param val [CArray, Numeric] value to broadcast.
|
|
80
|
+
# @return [Object] `val`.
|
|
81
|
+
def real= (val)
|
|
82
|
+
real[] = val
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# @overload imag
|
|
86
|
+
# Returns the imaginary part of `self`. For a complex array the
|
|
87
|
+
# result is a mutable {CAField} view of the imaginary slot;
|
|
88
|
+
# writing to it updates `self` in place. For a real array the
|
|
89
|
+
# result is a fresh independent CArray filled with 0.
|
|
90
|
+
# @return [CArray]
|
|
91
|
+
def imag
|
|
92
|
+
if not @__imag__
|
|
93
|
+
if complex?
|
|
94
|
+
@__imag__ = case data_type
|
|
95
|
+
when CA_CMPLX64
|
|
96
|
+
field(4, CA_FLOAT32)
|
|
97
|
+
when CA_CMPLX128
|
|
98
|
+
field(8, CA_FLOAT64)
|
|
99
|
+
end
|
|
100
|
+
else
|
|
101
|
+
@__imag__ = self.template { 0 }
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
return @__imag__
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @overload imag=(val)
|
|
108
|
+
# Sets the imaginary-part slot to `val` (complex arrays only).
|
|
109
|
+
# @param val [CArray, Numeric] value to broadcast.
|
|
110
|
+
# @return [Object] `val`.
|
|
111
|
+
# @raise [RuntimeError] when `self` is not a complex array.
|
|
112
|
+
def imag= (val)
|
|
113
|
+
if complex?
|
|
114
|
+
imag[] = val
|
|
115
|
+
else
|
|
116
|
+
raise "not a complex array"
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# @overload real?
|
|
121
|
+
# Returns whether every element of `self` is real (imaginary
|
|
122
|
+
# part is zero for complex arrays; always `true` for real
|
|
123
|
+
# numeric arrays; `nil` for non-numeric arrays).
|
|
124
|
+
# @return [Boolean, nil]
|
|
125
|
+
def real?
|
|
126
|
+
if complex?
|
|
127
|
+
imag.eq(0).all
|
|
128
|
+
elsif numeric?
|
|
129
|
+
true
|
|
130
|
+
else
|
|
131
|
+
nil
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# @overload is_real
|
|
136
|
+
# Returns an element-wise boolean CArray marking cells whose
|
|
137
|
+
# imaginary part is zero (all-true for real numeric arrays,
|
|
138
|
+
# `nil` for non-numeric arrays).
|
|
139
|
+
# @return [CArray, nil]
|
|
140
|
+
def is_real
|
|
141
|
+
if complex?
|
|
142
|
+
imag.eq(0)
|
|
143
|
+
elsif numeric?
|
|
144
|
+
self.true
|
|
145
|
+
else
|
|
146
|
+
nil
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
end
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# ----------------------------------------------------------------------------
|
|
2
|
+
#
|
|
3
|
+
# carray/conditional.rb
|
|
4
|
+
#
|
|
5
|
+
# Element-wise conditional selection primitives. Three flavours share the
|
|
6
|
+
# same "pick a value per cell based on a boolean condition" contract but
|
|
7
|
+
# differ in where the condition lives and how the branches are supplied:
|
|
8
|
+
#
|
|
9
|
+
# cond.then_else(x, y) # boolean receiver, 2 values (eager)
|
|
10
|
+
# self.replace_where(cond, b) # value receiver, 1 replacement (eager)
|
|
11
|
+
# self.conditional(cond, f_then, f_else) # value receiver, 2 callables (per-region)
|
|
12
|
+
#
|
|
13
|
+
# `then_else` and `replace_where` evaluate both branches over the full array
|
|
14
|
+
# and pick per cell — fast but requires every branch to be domain-safe over
|
|
15
|
+
# the whole receiver. `conditional` extracts the two subsets first and
|
|
16
|
+
# applies each callable only to its own region, which is domain-safe by
|
|
17
|
+
# construction (e.g. `x.log` is never evaluated on negative cells).
|
|
18
|
+
#
|
|
19
|
+
# ----------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
class CArray
|
|
22
|
+
|
|
23
|
+
# @overload then_else(x, y)
|
|
24
|
+
# Returns a ternary selection on `self` (a boolean CArray),
|
|
25
|
+
# reading as "if `self` then `x` else `y`". The boolean 2-way
|
|
26
|
+
# case of {#choose} that additionally propagates `self`'s mask
|
|
27
|
+
# (`UNDEF` in `self` produces `UNDEF` in the result).
|
|
28
|
+
# @param x [CArray, Numeric, Object] true-branch value(s).
|
|
29
|
+
# @param y [CArray, Numeric, Object] false-branch value(s).
|
|
30
|
+
# @return [CArray] new array with the same shape as `self`.
|
|
31
|
+
# @raise [ArgumentError] when `self` is not a boolean CArray.
|
|
32
|
+
def then_else (x, y)
|
|
33
|
+
# Guard: self must be boolean. Integer / float receiver would be
|
|
34
|
+
# silently reinterpreted by the indexer setter (`result[self] = ...`)
|
|
35
|
+
# as an index array, producing surprising scatter rather than the
|
|
36
|
+
# intended ternary select. Fail fast.
|
|
37
|
+
unless self.boolean?
|
|
38
|
+
raise ArgumentError,
|
|
39
|
+
"then_else: receiver must be a boolean CArray (data_type == CA_BOOLEAN), got #{self.data_type}"
|
|
40
|
+
end
|
|
41
|
+
# Promote data_type from both branches via CArray.result_type
|
|
42
|
+
# (a CScalar contributes its own data_type, so CA_INT32(0) keeps int32
|
|
43
|
+
# where a bare Ruby Integer would widen to int64).
|
|
44
|
+
dt = CArray.result_type(x, y)
|
|
45
|
+
# A CScalar (scalar? CArray) is treated as a scalar value, not as a
|
|
46
|
+
# self-shaped operand: full CArray -> gather/copy, scalar -> broadcast.
|
|
47
|
+
y_full = y.is_a?(CArray) && !y.scalar?
|
|
48
|
+
result =
|
|
49
|
+
if y_full
|
|
50
|
+
y.data_type == dt ? y.copy : y.to_type(dt)
|
|
51
|
+
else
|
|
52
|
+
CArray.new(dt, self.shape).fill(y.is_a?(CArray) ? y[0] : y)
|
|
53
|
+
end
|
|
54
|
+
x_full = x.is_a?(CArray) && !x.scalar?
|
|
55
|
+
result[self] = x_full ? x[self] : x
|
|
56
|
+
# Propagate cond's mask: UNDEF in self -> UNDEF in result.
|
|
57
|
+
if self.has_mask?
|
|
58
|
+
result[self.is_masked] = UNDEF
|
|
59
|
+
end
|
|
60
|
+
result
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @overload replace_where(cond, b)
|
|
64
|
+
# Returns a copy of `self` with cells where `cond` is true
|
|
65
|
+
# replaced by `b`. Functional sibling of the destructive
|
|
66
|
+
# indexer `a[cond] = b`; mask handling matches the indexer.
|
|
67
|
+
# Preserves `self`'s `data_type` (unlike {#then_else}, which
|
|
68
|
+
# promotes via `CArray.result_type`).
|
|
69
|
+
# @param cond [CArray] boolean selector; same shape as `self`
|
|
70
|
+
# or broadcastable.
|
|
71
|
+
# @param b [CArray, Numeric, Object] replacement value(s).
|
|
72
|
+
# @return [CArray] new array.
|
|
73
|
+
# @raise [ArgumentError] when `cond` is not a boolean CArray.
|
|
74
|
+
def replace_where (cond, b)
|
|
75
|
+
unless cond.is_a?(CArray) && cond.boolean?
|
|
76
|
+
raise ArgumentError,
|
|
77
|
+
"replace_where: cond must be a boolean CArray (data_type == CA_BOOLEAN)"
|
|
78
|
+
end
|
|
79
|
+
result = self.copy
|
|
80
|
+
result[cond] = b.is_a?(CArray) ? b[cond] : b
|
|
81
|
+
result
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @overload conditional(cond, then_fn, else_fn, dtype: nil)
|
|
85
|
+
# Returns per-cell `then_fn.call(self[cond])` where `cond` is
|
|
86
|
+
# true and `else_fn.call(self[cond.not])` where it is false.
|
|
87
|
+
# The two callables are applied only to their own subset of
|
|
88
|
+
# `self`, so a branch that would fail on the other region
|
|
89
|
+
# (e.g. `->(v) { v.log }` on negative cells) stays safe.
|
|
90
|
+
#
|
|
91
|
+
# Scalar returns from a callable (e.g. `->(v) { 0 }`) broadcast
|
|
92
|
+
# to the subset shape. The result `data_type` is the promotion
|
|
93
|
+
# of the two subset results via `CArray.result_type`, or
|
|
94
|
+
# `dtype` when given. Masked cells in `cond` propagate to
|
|
95
|
+
# `UNDEF` in the result.
|
|
96
|
+
#
|
|
97
|
+
# @param cond [CArray] boolean selector; same shape as `self`.
|
|
98
|
+
# @param then_fn [#call] callable applied to `self[cond]`.
|
|
99
|
+
# @param else_fn [#call] callable applied to `self[cond.not]`.
|
|
100
|
+
# @param dtype [Symbol, Integer, nil] override for the result
|
|
101
|
+
# `data_type`.
|
|
102
|
+
# @return [CArray] new array with the same shape as `self`.
|
|
103
|
+
# @raise [ArgumentError] when `cond` is not a same-shape
|
|
104
|
+
# boolean CArray.
|
|
105
|
+
# @example
|
|
106
|
+
# x = CArray.float64(6).span(-2.0..3.0)
|
|
107
|
+
# x.conditional(x > 0,
|
|
108
|
+
# ->(v) { v.log }, # domain-safe: only positive cells
|
|
109
|
+
# ->(v) { -v })
|
|
110
|
+
# # => [2.0, 1.0, -0.0, 0.0, 0.6931..., 1.0986...]
|
|
111
|
+
def conditional (cond, then_fn, else_fn, dtype: nil)
|
|
112
|
+
unless cond.is_a?(CArray) && cond.boolean? && cond.shape == self.shape
|
|
113
|
+
raise ArgumentError,
|
|
114
|
+
"conditional: cond must be a boolean CArray with same shape as self"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
x_then = self[cond]
|
|
118
|
+
x_else = self[cond.not]
|
|
119
|
+
y_then = then_fn.call(x_then)
|
|
120
|
+
y_else = else_fn.call(x_else)
|
|
121
|
+
|
|
122
|
+
# A callable that returns a scalar (e.g. `->(v) { 0 }`) broadcasts
|
|
123
|
+
# to the subset shape; wrap it here so the scatter step below sees a
|
|
124
|
+
# same-length CArray.
|
|
125
|
+
unless y_then.is_a?(CArray)
|
|
126
|
+
y_then = CArray.new(dtype || CArray.result_type(y_then), x_then.shape).fill(y_then)
|
|
127
|
+
end
|
|
128
|
+
unless y_else.is_a?(CArray)
|
|
129
|
+
y_else = CArray.new(dtype || CArray.result_type(y_else), x_else.shape).fill(y_else)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
dt = dtype || CArray.result_type(y_then, y_else)
|
|
133
|
+
out = CArray.new(dt, self.shape)
|
|
134
|
+
out[cond] = y_then
|
|
135
|
+
out[cond.not] = y_else
|
|
136
|
+
# Propagate cond's mask (mirrors then_else's rule): UNDEF in cond ->
|
|
137
|
+
# UNDEF in out. Kleene `cond.not` also carries UNDEF at the same
|
|
138
|
+
# positions, so both scatters leave the cell untouched — an explicit
|
|
139
|
+
# fix-up is required.
|
|
140
|
+
out[cond.is_masked] = UNDEF if cond.has_mask?
|
|
141
|
+
out
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @overload select(condlist, choicelist, default: 0, dtype: nil)
|
|
145
|
+
# Multi-way ternary select: for each cell, picks the value from
|
|
146
|
+
# the first `choicelist[k]` whose matching `condlist[k]` is true,
|
|
147
|
+
# falling back to `default` when no condition holds. When several
|
|
148
|
+
# conditions overlap, the earliest one in `condlist` wins.
|
|
149
|
+
#
|
|
150
|
+
# All entries in `condlist` must be same-shape boolean CArrays.
|
|
151
|
+
# Each `choicelist[k]` is either a same-shape CArray or a scalar
|
|
152
|
+
# broadcast to every cell. The result `data_type` is the promotion
|
|
153
|
+
# of every choice plus `default` via `CArray.result_type`, or
|
|
154
|
+
# `dtype` when given.
|
|
155
|
+
#
|
|
156
|
+
# @param condlist [Array<CArray>] boolean selectors.
|
|
157
|
+
# @param choicelist [Array<CArray, Numeric, Object>] values, one
|
|
158
|
+
# per condition (same length as `condlist`).
|
|
159
|
+
# @param default [CArray, Numeric, Object] value written where no
|
|
160
|
+
# condition holds.
|
|
161
|
+
# @param dtype [Symbol, Integer, nil] override for the result
|
|
162
|
+
# `data_type`.
|
|
163
|
+
# @return [CArray] new array with the shape of `condlist[0]`.
|
|
164
|
+
# @raise [ArgumentError] on size mismatch, empty `condlist`, or a
|
|
165
|
+
# non-boolean / wrong-shape entry in `condlist`.
|
|
166
|
+
# @example
|
|
167
|
+
# x = CArray.float64(6).span(-5.0..5.0)
|
|
168
|
+
# CArray.select([x < 0, x < 2],
|
|
169
|
+
# [-x, x * 10],
|
|
170
|
+
# default: 999)
|
|
171
|
+
# # => [5.0, 3.0, -10.0, 0.0, 10.0, 999.0]
|
|
172
|
+
def self.select (condlist, choicelist, default: 0, dtype: nil)
|
|
173
|
+
unless condlist.is_a?(Array) && choicelist.is_a?(Array)
|
|
174
|
+
raise ArgumentError, "select: condlist and choicelist must be Arrays"
|
|
175
|
+
end
|
|
176
|
+
if condlist.size != choicelist.size
|
|
177
|
+
raise ArgumentError,
|
|
178
|
+
"select: condlist (#{condlist.size}) and choicelist (#{choicelist.size}) size mismatch"
|
|
179
|
+
end
|
|
180
|
+
if condlist.empty?
|
|
181
|
+
raise ArgumentError, "select: at least one condition required"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
first = condlist.first
|
|
185
|
+
unless first.is_a?(CArray) && first.boolean?
|
|
186
|
+
raise ArgumentError, "select: condlist[0] must be a boolean CArray"
|
|
187
|
+
end
|
|
188
|
+
shape = first.shape
|
|
189
|
+
|
|
190
|
+
dt = dtype || CArray.result_type(*choicelist, default)
|
|
191
|
+
# `default` can be either a same-shape CArray (per-cell fallback) or a
|
|
192
|
+
# scalar (broadcast to every cell).
|
|
193
|
+
default_full = default.is_a?(CArray) && !default.scalar?
|
|
194
|
+
out =
|
|
195
|
+
if default_full
|
|
196
|
+
default.data_type == dt ? default.copy : default.to_type(dt)
|
|
197
|
+
else
|
|
198
|
+
CArray.new(dt, shape).fill(default.is_a?(CArray) ? default[0] : default)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Iterate from lowest priority to highest (reverse) so the earliest
|
|
202
|
+
# entry in `condlist` ends up on top — matches `np.select`'s
|
|
203
|
+
# first-match semantics.
|
|
204
|
+
(condlist.size - 1).downto(0) do |k|
|
|
205
|
+
c = condlist[k]
|
|
206
|
+
unless c.is_a?(CArray) && c.boolean? && c.shape == shape
|
|
207
|
+
raise ArgumentError,
|
|
208
|
+
"select: condlist[#{k}] must be a same-shape boolean CArray"
|
|
209
|
+
end
|
|
210
|
+
v = choicelist[k]
|
|
211
|
+
out[c] = v.is_a?(CArray) ? v[c] : v
|
|
212
|
+
end
|
|
213
|
+
out
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
end
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# ----------------------------------------------------------------------------
|
|
2
|
+
#
|
|
3
|
+
# carray/const_string.rb
|
|
4
|
+
#
|
|
5
|
+
# CAConstString high-level construction + conversion surface.
|
|
6
|
+
#
|
|
7
|
+
# CAConstString itself (the Face + tail buffer + fetch decode + numeric gate) lives
|
|
8
|
+
# in ext/ca_obj_const_string.c. This file provides the ergonomic builders that pack
|
|
9
|
+
# Ruby Strings into the internal length-prefix buffer + int64 offset entity
|
|
10
|
+
# and wrap them via the CAConstString.wrap C primitive.
|
|
11
|
+
#
|
|
12
|
+
# Internal buffer format: concatenation of `[int32 length][bytes...]` records
|
|
13
|
+
# (self-delimiting → one offset per element, permutation-safe view).
|
|
14
|
+
#
|
|
15
|
+
# ----------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
class CArray
|
|
18
|
+
|
|
19
|
+
# Build a CAConstString (read-only variable-length string column) from Ruby data.
|
|
20
|
+
#
|
|
21
|
+
# CArray.const_string(["alpha", "", "gamma"]) # 1-D from Array
|
|
22
|
+
# CArray.const_string(3) { |i| "item#{i}" } # block form
|
|
23
|
+
# CArray.const_string([a, nil, b]) # nil → masked element
|
|
24
|
+
#
|
|
25
|
+
# B1: "" (length 0) is a valid empty string, distinct from a masked element
|
|
26
|
+
# (nil → masked). B2: element encoding must match :encoding (strict),
|
|
27
|
+
# pure-ASCII strings pass regardless (ASCII-compatible relaxation).
|
|
28
|
+
#
|
|
29
|
+
# Storage is one `(start, end)` byte-range pair per element over a
|
|
30
|
+
# pure-concatenation buffer (Arrow string layout). For a high-duplication
|
|
31
|
+
# column (categorical labels), use {CACategorical} (= Arrow DictionaryArray)
|
|
32
|
+
# instead — CAConstString stores every element's bytes, without dedup.
|
|
33
|
+
# @overload const_string(values, encoding: Encoding::UTF_8)
|
|
34
|
+
# Returns a read-only {CAConstString} column packing each String's
|
|
35
|
+
# bytes into a shared buffer. `values` may be any Array (or
|
|
36
|
+
# Array-like) of Strings; `nil` entries are masked.
|
|
37
|
+
# @param values [Array<String, nil>] source values.
|
|
38
|
+
# @param encoding [Encoding] column encoding.
|
|
39
|
+
# @return [CAConstString]
|
|
40
|
+
# @overload const_string(ca, encoding: Encoding::UTF_8)
|
|
41
|
+
# Builds from a string-bearing CArray (String Face / CA_OBJECT / raw
|
|
42
|
+
# CA_FIXLEN, the last read as NUL-stripped strings); always materialises.
|
|
43
|
+
# @param ca [CArray] source array.
|
|
44
|
+
# @return [CAConstString]
|
|
45
|
+
# @raise [CArray::DataTypeError] if `ca` is numeric / boolean.
|
|
46
|
+
# @overload const_string(n, encoding: Encoding::UTF_8) { |i| ... }
|
|
47
|
+
# Returns an `n`-element {CAConstString} column filled by the
|
|
48
|
+
# block, following the arity-0 broadcast convention.
|
|
49
|
+
# @param n [Integer] element count.
|
|
50
|
+
# @yieldparam i [Integer] cell index.
|
|
51
|
+
# @yieldreturn [String, nil] value for cell `i`.
|
|
52
|
+
# @return [CAConstString]
|
|
53
|
+
def self.const_string (arg, encoding: Encoding::UTF_8, &block)
|
|
54
|
+
if arg.is_a?(CArray)
|
|
55
|
+
return string_face_of(arg).to_const_string(encoding: encoding)
|
|
56
|
+
end
|
|
57
|
+
if block
|
|
58
|
+
n = Integer(arg)
|
|
59
|
+
# B5: follow CArray.<type>(n){ ... } arity-0 broadcast quirk for
|
|
60
|
+
# consistency — arity-0 block is evaluated once and broadcast.
|
|
61
|
+
if block.arity == 0
|
|
62
|
+
v = block.call
|
|
63
|
+
values = Array.new(n) { v }
|
|
64
|
+
else
|
|
65
|
+
values = Array.new(n) { |i| block.call(i) }
|
|
66
|
+
end
|
|
67
|
+
else
|
|
68
|
+
values = arg.to_a
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Arrow-style layout, built in one C pass: pure-concatenation buffer +
|
|
72
|
+
# one (start,end) int64 pair per element, mask for nil.
|
|
73
|
+
CAConstString.__build__(values, encoding)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Read-only column of variable-length Strings: every element's bytes are
|
|
79
|
+
# packed into one shared buffer, with a `(start, end)` byte-range pair per
|
|
80
|
+
# element (the Arrow string layout).
|
|
81
|
+
#
|
|
82
|
+
# Built through `CArray.const_string`. For a column with heavy duplication
|
|
83
|
+
# (categorical labels) prefer {CACategorical}, which stores each distinct
|
|
84
|
+
# value once.
|
|
85
|
+
class CAConstString
|
|
86
|
+
|
|
87
|
+
# Read-only String Face: L1 string operations only (no in-place Mutable).
|
|
88
|
+
# Its C-native byte predicates / search / comparison (ext/ca_obj_const_string.c)
|
|
89
|
+
# override the L1 generics where present.
|
|
90
|
+
include CArray::StringOperationMixin
|
|
91
|
+
|
|
92
|
+
# @overload sort
|
|
93
|
+
# Returns a byte-order sorted view built by gathering the
|
|
94
|
+
# offsets with `sort_index`. Neither bytes nor offsets are
|
|
95
|
+
# copied.
|
|
96
|
+
# @return [CAConstString]
|
|
97
|
+
def sort
|
|
98
|
+
self[sort_index]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @overload sort_copy
|
|
102
|
+
# Returns an owned sorted {CAConstString}; the materialised
|
|
103
|
+
# counterpart to {#sort}.
|
|
104
|
+
# @return [CAConstString]
|
|
105
|
+
def sort_copy
|
|
106
|
+
self[sort_index].copy
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# CAConstString is the one Face with three separate entities -- storage
|
|
110
|
+
# (int64 offset), surface (fixlen), and the length-prefixed buffer -- so it
|
|
111
|
+
# has no byte-compatible blank form (other Faces have surface == storage or
|
|
112
|
+
# a struct tail, which the core template lift handles). A same-class
|
|
113
|
+
# template would be an unusable shell, so override it: with an explicit type
|
|
114
|
+
# defer to the generic (plain) path; with no type return a plain same-shape
|
|
115
|
+
# `object` array (a fillable string container), honouring a block.
|
|
116
|
+
# @overload template(type = nil, **opts)
|
|
117
|
+
# @return [CArray]
|
|
118
|
+
def template (*args, &block)
|
|
119
|
+
return super unless args.empty? # a type was given: generic plain path
|
|
120
|
+
out = CArray.object(*shape)
|
|
121
|
+
if block
|
|
122
|
+
if block.arity == 0
|
|
123
|
+
out[] = block.call
|
|
124
|
+
else
|
|
125
|
+
out.map_with_index! { |_, *idx| block.call(*idx) }
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
out
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# ---- value-hash discovery family --------------------------------------
|
|
132
|
+
#
|
|
133
|
+
# A storage cell is a `(start, end)` byte range into the shared buffer, so
|
|
134
|
+
# storage equality is NOT string equality: "ab" appearing twice occupies two
|
|
135
|
+
# distinct ranges. The family's Face gate only descends a Face whose storage
|
|
136
|
+
# equality *is* its surface equality (docs/authoring/FaceOrderingSearch.md
|
|
137
|
+
# §5.0), and CAConstString is the Face it deliberately excludes -- without
|
|
138
|
+
# these overrides `%w[ab cd ab ef].nunique` answered 4.
|
|
139
|
+
#
|
|
140
|
+
# So the family runs on {#to_string}, where a cell *is* the string, and value
|
|
141
|
+
# outputs come back as a CAConstString. Counts, booleans and addresses need
|
|
142
|
+
# no conversion.
|
|
143
|
+
|
|
144
|
+
# @overload unique(sort: false)
|
|
145
|
+
# @return [CAConstString] the distinct strings.
|
|
146
|
+
def unique (sort: false)
|
|
147
|
+
to_string.unique(sort: sort).to_const_string
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# @overload value_counts(sort: false)
|
|
151
|
+
# @return [Array(CAConstString, CArray)] `[values, counts]`.
|
|
152
|
+
def value_counts (sort: false)
|
|
153
|
+
values, counts = to_string.value_counts(sort: sort)
|
|
154
|
+
[values.to_const_string, counts]
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# @overload nunique(axis: nil, keep_axis: false)
|
|
158
|
+
# @return [Integer, CArray] the number of distinct strings.
|
|
159
|
+
def nunique (axis: nil, keep_axis: false)
|
|
160
|
+
to_string.nunique(axis: axis, keep_axis: keep_axis)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# @overload mode(axis: nil)
|
|
164
|
+
# @return [CAConstString, Array] the most frequent string(s).
|
|
165
|
+
def mode (axis: nil)
|
|
166
|
+
r = to_string.mode(axis: axis)
|
|
167
|
+
case r
|
|
168
|
+
when CArray then r.to_const_string
|
|
169
|
+
when Array then r.map { |c| c.is_a?(CArray) ? c.to_const_string : c }
|
|
170
|
+
else r
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# @overload is_mode(axis: nil)
|
|
175
|
+
# @return [CArray] boolean, true where the cell holds a modal string.
|
|
176
|
+
def is_mode (axis: nil)
|
|
177
|
+
to_string.is_mode(axis: axis)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# @overload mask_duplicates(axis: nil)
|
|
181
|
+
# @return [CAConstString] a copy with every repeat occurrence masked.
|
|
182
|
+
def mask_duplicates (axis: nil)
|
|
183
|
+
to_string.mask_duplicates(axis: axis).to_const_string
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# @overload is_in(values)
|
|
187
|
+
# @return [CArray] boolean, true where the cell's string is in `values`.
|
|
188
|
+
def is_in (values)
|
|
189
|
+
to_string.is_in(string_operand(values))
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# @overload intersection(other, sort: false)
|
|
193
|
+
# @return [CAConstString] the distinct strings present in both.
|
|
194
|
+
def intersection (other, sort: false)
|
|
195
|
+
to_string.intersection(string_operand(other), sort: sort).to_const_string
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# @overload difference(other, sort: false)
|
|
199
|
+
# @return [CAConstString] the distinct strings only `self` has.
|
|
200
|
+
def difference (other, sort: false)
|
|
201
|
+
to_string.difference(string_operand(other), sort: sort).to_const_string
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# @overload union(other, sort: false)
|
|
205
|
+
# @return [CAConstString] the distinct strings of either side.
|
|
206
|
+
def union (other, sort: false)
|
|
207
|
+
to_string.union(string_operand(other), sort: sort).to_const_string
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# @overload locate_addr(ref)
|
|
211
|
+
# @return [CArray] for each cell, its address in `ref` (UNDEF when absent).
|
|
212
|
+
def locate_addr (ref)
|
|
213
|
+
to_string.locate_addr(string_operand(ref))
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# @overload categorize(labels: nil, sort_labels: false)
|
|
217
|
+
# @return [CACategorical] categories keyed on the strings.
|
|
218
|
+
def categorize (labels: nil, sort_labels: false)
|
|
219
|
+
to_string.categorize(labels: labels, sort_labels: sort_labels)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# A CAConstString operand has to be decoded too; anything else (a CAString,
|
|
223
|
+
# an object array, an Array) already compares as strings.
|
|
224
|
+
private def string_operand (other)
|
|
225
|
+
other.is_a?(CAConstString) ? other.to_string : other
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
end
|