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,46 @@
|
|
|
1
|
+
class CArray
|
|
2
|
+
|
|
3
|
+
# @overload nunique(axis: nil, keep_axis: false)
|
|
4
|
+
# Counts the distinct values of `self`. This is the scalar-reduction
|
|
5
|
+
# member of the value-hash discovery family ({#unique},
|
|
6
|
+
# {#mask_duplicates}, {#value_counts}): where {#unique} compresses
|
|
7
|
+
# and {#value_counts} tabulates, `nunique` just counts.
|
|
8
|
+
#
|
|
9
|
+
# With `axis: nil` (default) it counts distinct values across the
|
|
10
|
+
# whole array and returns an Integer. With `axis: k` it counts per
|
|
11
|
+
# fiber along axis `k`, returning a reduced `CA_INT64` CArray
|
|
12
|
+
# (shape = self.shape with axis `k` removed; `keep_axis: true` keeps
|
|
13
|
+
# it as a length-1 axis). The shape rule matches other per-axis
|
|
14
|
+
# reductions such as `sum(axis:)`.
|
|
15
|
+
#
|
|
16
|
+
# The distinct count has identity 0: an empty array, an all-masked
|
|
17
|
+
# fiber, or a zero-length axis counts 0 (not UNDEF) — an empty set
|
|
18
|
+
# has zero distinct values. Masked cells do not participate.
|
|
19
|
+
#
|
|
20
|
+
# Numeric distinctness follows `==` with the family's two float
|
|
21
|
+
# special cases: all NaN collapse to a single value and
|
|
22
|
+
# -0.0 / +0.0 are the same value. For `CA_OBJECT` / `CA_FIXLEN`
|
|
23
|
+
# distinctness follows Ruby `eql?` / `hash` (which, unlike numeric,
|
|
24
|
+
# does not collapse distinct NaN objects).
|
|
25
|
+
#
|
|
26
|
+
# @param axis [Integer, nil] axis to count along; `nil` counts over
|
|
27
|
+
# the whole array.
|
|
28
|
+
# @param keep_axis [Boolean] when `axis` is given, keep the reduced
|
|
29
|
+
# axis as a length-1 axis instead of dropping it.
|
|
30
|
+
# @return [Integer, CArray] Integer for `axis: nil`, otherwise a
|
|
31
|
+
# reduced `CA_INT64` CArray.
|
|
32
|
+
def nunique (axis: nil, keep_axis: false)
|
|
33
|
+
# Per-fiber single-pass seen-set hash (C __nunique__), one lane per dtype
|
|
34
|
+
# family (numeric widen / NaN collapse, object rb_hash + rb_eql, fixlen
|
|
35
|
+
# byte-hash + memcmp). Masked cells are skipped; the accumulator is a no-op
|
|
36
|
+
# (the distinct count is the interned-key count).
|
|
37
|
+
if axis.nil?
|
|
38
|
+
# Whole-array distinct count: flatten to 1-D and reduce its only axis,
|
|
39
|
+
# then read the single reduced cell as an Integer.
|
|
40
|
+
flatten.send(:__nunique__, 0, false)[0]
|
|
41
|
+
else
|
|
42
|
+
__nunique__(normalize_axis(axis, "nunique"), keep_axis)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
class CArray
|
|
2
|
+
|
|
3
|
+
# @overload resize(*newdim, fill_value: 0)
|
|
4
|
+
# Returns `self` resized to `newdim`. The original data is
|
|
5
|
+
# placed at offset 0 (positive size) or right-aligned (negative
|
|
6
|
+
# size); the new area outside the original region is filled
|
|
7
|
+
# with `fill_value`, or -- for fixlen storage -- left as zero
|
|
8
|
+
# bytes. Pass `UNDEF` to mask the new area.
|
|
9
|
+
#
|
|
10
|
+
# Each entry of `newdim` is: `nil` to keep the current
|
|
11
|
+
# `shape[i]`, a positive Integer for a new size with the
|
|
12
|
+
# original left-aligned at offset 0, or a negative Integer
|
|
13
|
+
# `d` for a new size `|d|` with the original right-aligned.
|
|
14
|
+
#
|
|
15
|
+
# Works on Face arrays (CARecord / CATime / ...) and
|
|
16
|
+
# plain fixlen: the resize is done on the storage layout
|
|
17
|
+
# (preserving bytes) and re-wrapped as the same Face.
|
|
18
|
+
#
|
|
19
|
+
# @param newdim [Array<Integer, nil>] new shape spec, one entry
|
|
20
|
+
# per axis.
|
|
21
|
+
# @param fill_value [Object] value for the extended area.
|
|
22
|
+
# @return [CArray] resized copy.
|
|
23
|
+
def resize (*newdim, fill_value: 0)
|
|
24
|
+
raise "ndim mismatch" if newdim.size != ndim
|
|
25
|
+
offset = Array.new(ndim, 0)
|
|
26
|
+
newdim = newdim.each_with_index.map do |d, i|
|
|
27
|
+
case d
|
|
28
|
+
when nil
|
|
29
|
+
shape[i]
|
|
30
|
+
when Integer
|
|
31
|
+
size = d.abs
|
|
32
|
+
offset[i] = size - shape[i] if d < 0
|
|
33
|
+
size
|
|
34
|
+
else
|
|
35
|
+
raise "invalid dimension size"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
face_parent = self.face? ? self : nil
|
|
39
|
+
src = self
|
|
40
|
+
src = src.parent while src.face?
|
|
41
|
+
dt = src.data_type
|
|
42
|
+
bytes = (dt == :fixlen) ? src.bytes : nil
|
|
43
|
+
out = CArray.new(dt, newdim, bytes: bytes)
|
|
44
|
+
# Fill the new area: numeric storage takes fill_value as-is; fixlen
|
|
45
|
+
# storage cannot hold a numeric 0, so leave zero bytes and honor only
|
|
46
|
+
# UNDEF (mask) or an explicit String fill.
|
|
47
|
+
if dt != :fixlen || fill_value.equal?(UNDEF) || fill_value.is_a?(String)
|
|
48
|
+
out[] = fill_value
|
|
49
|
+
end
|
|
50
|
+
out.mask.paste(offset, src.false) if out.has_mask?
|
|
51
|
+
out.paste(offset, src)
|
|
52
|
+
out = out.face_lift(face_parent) if face_parent
|
|
53
|
+
out
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
class CArray
|
|
2
|
+
|
|
3
|
+
# @overload snap(step, offset: 0.0, direction: :round)
|
|
4
|
+
# Returns each element snapped to a point on the uniform grid
|
|
5
|
+
# `..., -step + offset, offset, step + offset, 2*step + offset, ...`.
|
|
6
|
+
# The rounding rule follows `direction:` (default `:round`,
|
|
7
|
+
# matching `CArray#round`; `:floor` snaps toward `-inf`, `:ceil`
|
|
8
|
+
# toward `+inf`).
|
|
9
|
+
#
|
|
10
|
+
# The output has the same dtype as `self` (integer input is coerced
|
|
11
|
+
# to float internally when `step` / `offset` are floats, following
|
|
12
|
+
# normal arithmetic promotion). NaN / Inf are preserved as a mask
|
|
13
|
+
# on the output; the rounding kernels map NaN to 0.0, which would
|
|
14
|
+
# silently land NaN cells on the grid, so NaN is detected
|
|
15
|
+
# explicitly on the scaled chain.
|
|
16
|
+
#
|
|
17
|
+
# Use `snap_to(list)` when the target grid is non-uniform; use
|
|
18
|
+
# `bin(vmin, vmax, step)` when the desired output is a bin index.
|
|
19
|
+
#
|
|
20
|
+
# @param step [Numeric] positive grid spacing.
|
|
21
|
+
# @param offset [Numeric] phase / origin of the grid; the grid
|
|
22
|
+
# always passes through `offset`.
|
|
23
|
+
# @param direction [:round, :floor, :ceil] rounding rule; `:round`
|
|
24
|
+
# picks the nearest grid point (ties half-away-from-zero),
|
|
25
|
+
# `:floor` picks the grid point at or below the value, `:ceil`
|
|
26
|
+
# picks the grid point at or above.
|
|
27
|
+
# @return [CArray] snapped values, same shape as `self`.
|
|
28
|
+
# @raise [ArgumentError] when `step <= 0` or `direction` is not one
|
|
29
|
+
# of the accepted symbols.
|
|
30
|
+
# @example
|
|
31
|
+
# temp.snap(0.5) # nearest 0.5 K grid point
|
|
32
|
+
# temp.snap(0.5, offset: 0.25) # to 0.25, 0.75, 1.25, ... (bin centers)
|
|
33
|
+
# temp.snap(0.5, direction: :floor) # bin lower edge
|
|
34
|
+
# temp.snap(0.5, direction: :ceil) # bin upper edge
|
|
35
|
+
def snap(step, offset: 0.0, direction: :round)
|
|
36
|
+
raise ArgumentError, "snap: step must be > 0" unless step > 0
|
|
37
|
+
unless [:round, :floor, :ceil].include?(direction)
|
|
38
|
+
raise ArgumentError,
|
|
39
|
+
"snap: direction must be :round / :floor / :ceil " \
|
|
40
|
+
"(got #{direction.inspect})"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
scaled = (self - offset) / step
|
|
44
|
+
|
|
45
|
+
# Detect NaN / Inf before rounding (which maps NaN -> 0.0 silently).
|
|
46
|
+
invalid_mask = scaled.float? ? scaled.is_invalid : nil
|
|
47
|
+
|
|
48
|
+
out = scaled.send(direction) * step + offset
|
|
49
|
+
|
|
50
|
+
if invalid_mask && invalid_mask.count(true) > 0
|
|
51
|
+
out.mask = out.has_mask? ? (out.mask | invalid_mask) : invalid_mask
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
out
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @overload snap_to(list, lfill: :clamp, ufill: :clamp, direction: :round)
|
|
58
|
+
# Returns each element snapped to a value in `list` (non-uniform
|
|
59
|
+
# grid). The rounding rule follows `direction:` (default `:round`
|
|
60
|
+
# for nearest neighbour; `:floor` picks the list value at or below
|
|
61
|
+
# the sample, `:ceil` at or above), and delegates to
|
|
62
|
+
# `locate_nearest_addr(direction:)`.
|
|
63
|
+
#
|
|
64
|
+
# `list` must be a 1-D ascending numeric CArray (or convertible via
|
|
65
|
+
# `CArray.wrap_readonly`). Out-of-range and NaN handling follows the
|
|
66
|
+
# same pattern as `bin_to`, but with an additional `:clamp`
|
|
67
|
+
# sentinel that snaps out-of-range cells to the nearest list end.
|
|
68
|
+
#
|
|
69
|
+
# - `:clamp` (default) — below-range cells become `list[0]`,
|
|
70
|
+
# above-range cells become `list[-1]`.
|
|
71
|
+
# - `nil` — the side is masked in the output.
|
|
72
|
+
# - any other value — the side is filled with that value.
|
|
73
|
+
#
|
|
74
|
+
# NaN / masked input cells are always masked in the output,
|
|
75
|
+
# regardless of `lfill` / `ufill`.
|
|
76
|
+
#
|
|
77
|
+
# Use `snap(step, offset:)` when the target grid is uniform; use
|
|
78
|
+
# `bin_to(edges)` when the output is a bin index against half-open
|
|
79
|
+
# intervals rather than a nearest-value snap.
|
|
80
|
+
#
|
|
81
|
+
# @param list [CArray, Array<Numeric>] 1-D ascending grid, at least
|
|
82
|
+
# one value.
|
|
83
|
+
# @param lfill [:clamp, nil, Numeric] handling for below-`list[0]`
|
|
84
|
+
# cells.
|
|
85
|
+
# @param ufill [:clamp, nil, Numeric] handling for above-`list[-1]`
|
|
86
|
+
# cells.
|
|
87
|
+
# @param direction [:round, :floor, :ceil] rounding rule; forwarded
|
|
88
|
+
# to `locate_nearest_addr`.
|
|
89
|
+
# @return [CArray] snapped values with `list`'s data_type, same
|
|
90
|
+
# shape as `self`.
|
|
91
|
+
# @raise [ArgumentError] when `list` is not 1-D or is empty, or
|
|
92
|
+
# `direction` is not one of the accepted symbols.
|
|
93
|
+
# @example
|
|
94
|
+
# temp.snap_to([270.0, 280.0, 290.0, 300.0]) # clamp OOB
|
|
95
|
+
# temp.snap_to(grid, lfill: nil, ufill: nil) # mask OOB
|
|
96
|
+
# rain.snap_to([0.0, 1.0, 5.0, 20.0], direction: :floor) # list value at or below
|
|
97
|
+
def snap_to(list, lfill: :clamp, ufill: :clamp, direction: :round)
|
|
98
|
+
ref = list.is_a?(CArray) ? list : CArray.wrap_readonly(list, self.data_type)
|
|
99
|
+
raise ArgumentError, "snap_to: list must be 1-D" unless ref.ndim == 1
|
|
100
|
+
n = ref.elements
|
|
101
|
+
raise ArgumentError, "snap_to: list must have at least one value" if n < 1
|
|
102
|
+
|
|
103
|
+
if n == 1
|
|
104
|
+
# Degenerate: every finite cell snaps to the only value.
|
|
105
|
+
out = CArray.new(ref.data_type, shape).fill(ref[0])
|
|
106
|
+
out.mask = self.mask.to_ca if self.has_mask?
|
|
107
|
+
if self.float?
|
|
108
|
+
inv = self.is_invalid
|
|
109
|
+
if inv.count(true) > 0
|
|
110
|
+
out.mask = out.has_mask? ? (out.mask | inv) : inv
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
return out
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# `locate_nearest_addr` (via `linear_section`) accepts a 1-D `val` only;
|
|
117
|
+
# flatten multi-D input and reshape the result back to preserve the
|
|
118
|
+
# element-wise semantic on any shape.
|
|
119
|
+
if ndim > 1
|
|
120
|
+
return reshape(-1).snap_to(ref, lfill: lfill, ufill: ufill,
|
|
121
|
+
direction: direction).reshape(*shape)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# locate_nearest_addr returns int64 indices; OOB (below / above / NaN)
|
|
125
|
+
# cells come back masked. We split OOB into below / above with
|
|
126
|
+
# explicit comparisons so the two sides can be filled independently.
|
|
127
|
+
idx = self.locate_nearest_addr(ref, direction: direction)
|
|
128
|
+
out = ref.project(idx)
|
|
129
|
+
|
|
130
|
+
below = self.lt(ref[0])
|
|
131
|
+
above = self.gt(ref[-1])
|
|
132
|
+
|
|
133
|
+
case lfill
|
|
134
|
+
when :clamp then out[below] = ref[0]
|
|
135
|
+
when nil then # leave masked (locate_nearest_addr already masked OOB)
|
|
136
|
+
else out[below] = lfill
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
case ufill
|
|
140
|
+
when :clamp then out[above] = ref[-1]
|
|
141
|
+
when nil then # leave masked
|
|
142
|
+
else out[above] = ufill
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Propagate input mask (locate_nearest_addr / project do not forward
|
|
146
|
+
# `self`'s mask on their own; a masked input cell must produce a
|
|
147
|
+
# masked output cell regardless of the fill options above).
|
|
148
|
+
if self.has_mask?
|
|
149
|
+
m = self.mask.to_ca
|
|
150
|
+
out.mask = out.has_mask? ? (out.mask | m) : m
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
out
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# CArray.format (class) and CArray#format (instance) — element-wise
|
|
2
|
+
# Kernel.format producing a CAString. The instance form is the explicit
|
|
3
|
+
# numeric->string escape (a numeric array carries no implicit to_string).
|
|
4
|
+
# Single-feature method file (autoloaded on first format call).
|
|
5
|
+
|
|
6
|
+
class CArray
|
|
7
|
+
|
|
8
|
+
# @overload format(fmt, *argv)
|
|
9
|
+
# Returns a {CAString} of formatted strings. Each output cell at index
|
|
10
|
+
# `idx` is `Kernel.format(fmt, *args)` where a CArray argument contributes
|
|
11
|
+
# its `[*idx]` cell and any non-CArray argument is broadcast as-is. The
|
|
12
|
+
# output shape is taken from the first CArray argument; every CArray
|
|
13
|
+
# argument must share that shape.
|
|
14
|
+
# @param fmt [String] `Kernel.format` template.
|
|
15
|
+
# @param argv [Array<CArray, Object>] per-cell CArrays and/or broadcast scalars.
|
|
16
|
+
# @return [CAString]
|
|
17
|
+
# @raise [ArgumentError] when no CArray argument is given, or CArray shapes differ.
|
|
18
|
+
def self.format (fmt, *argv)
|
|
19
|
+
cas = argv.select { |a| a.is_a?(CArray) }
|
|
20
|
+
raise ArgumentError, "CArray.format: at least one CArray argument is required" if cas.empty?
|
|
21
|
+
shape = cas.first.shape
|
|
22
|
+
cas.each do |a|
|
|
23
|
+
next if a.shape == shape
|
|
24
|
+
raise ArgumentError,
|
|
25
|
+
"CArray.format: shape mismatch (#{a.shape.inspect} vs #{shape.inspect})"
|
|
26
|
+
end
|
|
27
|
+
out = CArray.object(*shape)
|
|
28
|
+
out.map_with_index! do |_, *idx|
|
|
29
|
+
args = argv.map { |a| a.is_a?(CArray) ? a[*idx] : a }
|
|
30
|
+
# a masked cell in any source array masks the output (UNDEF), rather
|
|
31
|
+
# than feeding UNDEF into Kernel.format.
|
|
32
|
+
args.any? { |v| v.equal?(UNDEF) } ? UNDEF : Kernel.format(fmt, *args)
|
|
33
|
+
end
|
|
34
|
+
CAString.wrap(out)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @overload format(fmt, *argv)
|
|
38
|
+
# Returns a {CAString} formatting each cell of `self` with `fmt`; `self`
|
|
39
|
+
# is the first `Kernel.format` argument, so `arr.format("%03d")` renders
|
|
40
|
+
# the cells and `arr.format("%s=%d", other)` interleaves a second array.
|
|
41
|
+
# This is the explicit stringify path for numeric (and any) arrays — the
|
|
42
|
+
# `to_*` string conversions are String-Face only. Equivalent to
|
|
43
|
+
# `CArray.format(fmt, self, *argv)`.
|
|
44
|
+
#
|
|
45
|
+
# Defining a public `CArray#format` shadows the private `Kernel#format`
|
|
46
|
+
# for CArray instances; internal CArray methods therefore use `sprintf` /
|
|
47
|
+
# `Kernel.format` explicitly (verified: no bare `format(...)` call runs on
|
|
48
|
+
# a CArray receiver anywhere in the library).
|
|
49
|
+
# @param fmt [String] `Kernel.format` template.
|
|
50
|
+
# @param argv [Array<CArray, Object>] additional per-cell CArrays / broadcast scalars.
|
|
51
|
+
# @return [CAString]
|
|
52
|
+
# @raise [ArgumentError] when a CArray argument's shape differs from self.
|
|
53
|
+
def format (fmt, *argv)
|
|
54
|
+
CArray.format(fmt, self, *argv)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
class CArray
|
|
2
|
+
|
|
3
|
+
# @overload unique(sort: false)
|
|
4
|
+
# Returns a 1-D CArray of the distinct values of `self`, in
|
|
5
|
+
# first-appearance (row-major flatten) order. This is the
|
|
6
|
+
# compressing counterpart of {#mask_duplicates} (which marks
|
|
7
|
+
# without compressing): because different fibers may hold
|
|
8
|
+
# different numbers of distinct values, compression is only
|
|
9
|
+
# well-defined over the whole array, so `unique` is always flat.
|
|
10
|
+
#
|
|
11
|
+
# Named `unique` (not `uniq`) because distinctness is value-based
|
|
12
|
+
# like NumPy / pandas `unique`: unlike Ruby `Array#uniq` it
|
|
13
|
+
# collapses all NaN to a single value (see below), so the name
|
|
14
|
+
# avoids promising `Array#uniq` semantics.
|
|
15
|
+
#
|
|
16
|
+
# Masked cells do not participate and never appear in the result;
|
|
17
|
+
# an all-masked array yields an empty CArray.
|
|
18
|
+
#
|
|
19
|
+
# Distinctness follows `==` for numeric dtypes, with two float
|
|
20
|
+
# special cases so the result matches value-based expectations:
|
|
21
|
+
# all NaN collapse to a single distinct value (rather than one per
|
|
22
|
+
# cell) and -0.0 / +0.0 are the same value. The value kept for
|
|
23
|
+
# each key is the first one seen, so a leading -0.0 keeps its sign.
|
|
24
|
+
# For `CA_OBJECT` / `CA_FIXLEN` distinctness follows Ruby
|
|
25
|
+
# `eql?` / `hash`; note that Ruby does not collapse distinct NaN
|
|
26
|
+
# objects, so a `CA_OBJECT` array of Float NaN is not collapsed
|
|
27
|
+
# (unlike the numeric path).
|
|
28
|
+
#
|
|
29
|
+
# @param sort [Boolean] when true, return the distinct values
|
|
30
|
+
# sorted ascending instead of in first-appearance order.
|
|
31
|
+
# A time array (`CATime` / `CATimedelta`) answers with its own type on
|
|
32
|
+
# its own unit: the distinct values are values, so the array comes back
|
|
33
|
+
# as itself rather than as raw storage ticks.
|
|
34
|
+
#
|
|
35
|
+
# @return [CArray] 1-D CArray of the distinct values, same dtype
|
|
36
|
+
# as `self`.
|
|
37
|
+
def unique (sort: false)
|
|
38
|
+
# Single-pass seen-set hash (C __unique_flat__), one lane per dtype family:
|
|
39
|
+
# integer widens to a 64-bit key; float uses the bitwise key with all-NaN
|
|
40
|
+
# collapsed and -0.0 / +0.0 normalized; object keys on rb_hash + rb_eql and
|
|
41
|
+
# fixlen on a byte-hash + memcmp, both reproducing Ruby Hash distinctness.
|
|
42
|
+
# Masked cells are skipped in the kernel.
|
|
43
|
+
levels = __unique_flat__
|
|
44
|
+
sort ? levels.sort : levels
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
class CArray
|
|
2
|
+
|
|
3
|
+
# @overload value_counts(sort: false)
|
|
4
|
+
# Returns `[values, counts]`, the distinct values of `self` paired
|
|
5
|
+
# with the number of times each occurs. `values` is a 1-D CArray of
|
|
6
|
+
# `self`'s dtype; `counts` is a 1-D `CA_INT64` where `counts[i]` is
|
|
7
|
+
# the number of occurrences of `values[i]`. This is the frequency-
|
|
8
|
+
# table member of the value-hash discovery family ({#unique},
|
|
9
|
+
# {#mask_duplicates}, {#nunique}); like {#unique} it always
|
|
10
|
+
# flattens, because per-fiber distinct counts would be ragged.
|
|
11
|
+
#
|
|
12
|
+
# By default the pairs are in first-appearance (row-major flatten)
|
|
13
|
+
# order, matching {#unique}. `sort:` reorders both arrays together:
|
|
14
|
+
#
|
|
15
|
+
# - `false` (default) — first-appearance order.
|
|
16
|
+
# - `:count` — descending frequency; ties keep first-appearance
|
|
17
|
+
# order (deterministic).
|
|
18
|
+
# - `:value` — ascending value (float NaN sorts last, as in
|
|
19
|
+
# `unique(sort: true)`).
|
|
20
|
+
#
|
|
21
|
+
# Masked cells do not participate and never appear; an all-masked
|
|
22
|
+
# array yields two empty CArrays.
|
|
23
|
+
#
|
|
24
|
+
# Numeric distinctness follows `==` with two float special cases so
|
|
25
|
+
# the result matches value-based expectations: all NaN collapse to a
|
|
26
|
+
# single value (their counts add up) and -0.0 / +0.0 are the same
|
|
27
|
+
# value (the first-seen value is kept, so a leading -0.0 keeps its
|
|
28
|
+
# sign). For `CA_OBJECT` / `CA_FIXLEN` distinctness follows Ruby
|
|
29
|
+
# `eql?` / `hash`; Ruby does not collapse distinct NaN objects, so a
|
|
30
|
+
# `CA_OBJECT` array of Float NaN is not collapsed (unlike numeric).
|
|
31
|
+
#
|
|
32
|
+
# @param sort [false, :count, :value] pair ordering.
|
|
33
|
+
# The values keep `self`'s type (a `CATime` comes back as a `CATime` on
|
|
34
|
+
# its own unit); the counts are always a plain `:int64` CArray.
|
|
35
|
+
#
|
|
36
|
+
# @return [Array(CArray, CArray)] `[values, counts]`.
|
|
37
|
+
def value_counts (sort: false)
|
|
38
|
+
unless [false, :count, :value].include?(sort)
|
|
39
|
+
raise ArgumentError, "value_counts: sort must be false, :count, or :value"
|
|
40
|
+
end
|
|
41
|
+
# Single-pass frequency-table hash (C __value_counts_flat__), one lane per
|
|
42
|
+
# dtype family: integer widens to a 64-bit key; float uses the bitwise key
|
|
43
|
+
# with all NaN collapsed and -0.0 / +0.0 normalized; object keys on rb_hash +
|
|
44
|
+
# rb_eql and fixlen on a byte-hash + memcmp, both reproducing Ruby Hash
|
|
45
|
+
# distinctness. Masked cells are skipped in the kernel.
|
|
46
|
+
values, counts = __value_counts_flat__
|
|
47
|
+
case sort
|
|
48
|
+
when :count
|
|
49
|
+
# Descending count, ties broken by first-appearance index (stable).
|
|
50
|
+
c = counts.to_a
|
|
51
|
+
order = (0...c.size).sort_by { |i| [-c[i], i] }
|
|
52
|
+
[ values[CArray.int64(order.size) { |i| order[i] }],
|
|
53
|
+
counts[CArray.int64(order.size) { |i| order[i] }] ]
|
|
54
|
+
when :value
|
|
55
|
+
# Ascending value; NaN (numeric) or non-comparable last. Build the
|
|
56
|
+
# permutation with an explicit NaN-last key so float NaN doesn't blow up
|
|
57
|
+
# the Ruby sort, then gather both arrays through it.
|
|
58
|
+
v = values.to_a
|
|
59
|
+
order = (0...v.size).sort_by do |i|
|
|
60
|
+
x = v[i]
|
|
61
|
+
nan = x.is_a?(Float) && x.nan?
|
|
62
|
+
[nan ? 1 : 0, nan ? 0 : x, i]
|
|
63
|
+
end
|
|
64
|
+
[ values[CArray.int64(order.size) { |i| order[i] }],
|
|
65
|
+
counts[CArray.int64(order.size) { |i| order[i] }] ]
|
|
66
|
+
else
|
|
67
|
+
[values, counts]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|