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,416 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
Partition family (quickselect): `partition` (CARemap view via
|
|
4
|
+
partition_addr_ki) and `partition_copy` (eager per-fiber quickselect).
|
|
5
|
+
Sibling of carray_order.c (full sort + search surfaces) and
|
|
6
|
+
ca_sort_kernels.h (typed numeric kernels).
|
|
7
|
+
|
|
8
|
+
Dispatch by data_type:
|
|
9
|
+
numeric (i8..f64) -> typed ca_partition_quick_* kernels
|
|
10
|
+
CA_FIXLEN -> ca_quickselect_bytes (memcmp lexicographic order)
|
|
11
|
+
CA_OBJECT -> partition_index_ki trampoline (rb_funcall(<=>))
|
|
12
|
+
|
|
13
|
+
---------------------------------------------------------------------------- */
|
|
14
|
+
|
|
15
|
+
#include "ruby.h"
|
|
16
|
+
#include "carray.h"
|
|
17
|
+
#include "ca_kernel_iterator.h" /* CA_FOR_EACH_FIBER_INOUT */
|
|
18
|
+
#include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE */
|
|
19
|
+
#include "ca_sort_kernels.h" /* ca_partition_quick_* / ca_partition_nan_* */
|
|
20
|
+
#include <string.h> /* memcmp */
|
|
21
|
+
#include <math.h>
|
|
22
|
+
|
|
23
|
+
/* External entries reached at link time (extern declarations rather than
|
|
24
|
+
carray.h additions to keep the public header lean): */
|
|
25
|
+
extern VALUE rb_ca_remap_new (VALUE cary, VALUE rmapper); /* ca_obj_remap.c */
|
|
26
|
+
extern VALUE rb_ca_partition_addr_ki (VALUE self, VALUE vaxis, VALUE vkth); /* carray_kernels.c (generated, bind_ruby: false) */
|
|
27
|
+
/* _mp ("masked position") twin: explicit masked_last, used by `partition`
|
|
28
|
+
/ `partition_copy` to pass masked_position: through (see MASKED_POSITION
|
|
29
|
+
rev1 in mkkernel.rb's MkKernel.sort doc). */
|
|
30
|
+
extern VALUE rb_ca_partition_addr_ki_mp (VALUE self, VALUE vaxis, VALUE vkth, int masked_last);
|
|
31
|
+
|
|
32
|
+
/* Generic comparator-based quickselect on a flat byte buffer.
|
|
33
|
+
*
|
|
34
|
+
* Reorders `buf[lo..hi]` (cell size = `bytes`) in place so that
|
|
35
|
+
* `buf[kth]` is the kth-smallest element under `cmp`, with all cells
|
|
36
|
+
* before kth <= pivot and all after >= pivot. Order within the two
|
|
37
|
+
* regions is unspecified. Average O(n). Median-of-three pivot +
|
|
38
|
+
* Hoare partition + one-side recursion. Insertion-sort base case for
|
|
39
|
+
* small ranges (< 8 cells).
|
|
40
|
+
*
|
|
41
|
+
* Comparator-based dispatch keeps this routine data_type-generic (used
|
|
42
|
+
* by the CA_FIXLEN partition_copy path); the mkkernel-generated
|
|
43
|
+
* partition_index_quickselect_* functions inline the comparator per
|
|
44
|
+
* dtype for the numeric paths.
|
|
45
|
+
*
|
|
46
|
+
* `swap_tmp` and `pivot` must be caller-provided scratch buffers of size
|
|
47
|
+
* `bytes` (used for cell swaps via memcpy; avoids alloca / per-swap
|
|
48
|
+
* malloc).
|
|
49
|
+
*/
|
|
50
|
+
static void
|
|
51
|
+
ca_quickselect_bytes (char *buf, ca_size_t lo, ca_size_t hi,
|
|
52
|
+
ca_size_t kth, ca_size_t bytes,
|
|
53
|
+
int (*cmp)(const void *, const void *),
|
|
54
|
+
char *swap_tmp, char *pivot)
|
|
55
|
+
{
|
|
56
|
+
#define SWAP_CELL(_a, _b) \
|
|
57
|
+
do { \
|
|
58
|
+
memcpy(swap_tmp, (_a), (size_t) bytes); \
|
|
59
|
+
memcpy((_a), (_b), (size_t) bytes); \
|
|
60
|
+
memcpy((_b), swap_tmp, (size_t) bytes); \
|
|
61
|
+
} while (0)
|
|
62
|
+
#define CELL(_i) (buf + (_i) * bytes)
|
|
63
|
+
/* cmp == NULL signals raw memcmp over `bytes` (= CA_FIXLEN lexicographic
|
|
64
|
+
order; revived for the fixlen partition_copy path). Otherwise use the
|
|
65
|
+
supplied comparator (= numeric type-specific cmp). The ternary
|
|
66
|
+
evaluates each operand once (only one branch runs), so CELL(++i) side
|
|
67
|
+
effects are safe. */
|
|
68
|
+
#define QSCMP(_a, _b) ( cmp ? cmp((_a), (_b)) : memcmp((_a), (_b), (size_t) bytes) )
|
|
69
|
+
|
|
70
|
+
while ( lo < hi ) {
|
|
71
|
+
/* Small-range base case: insertion sort. */
|
|
72
|
+
if ( hi - lo < 8 ) {
|
|
73
|
+
for ( ca_size_t i = lo + 1; i <= hi; i++ ) {
|
|
74
|
+
memcpy(swap_tmp, CELL(i), (size_t) bytes);
|
|
75
|
+
ca_size_t j = i;
|
|
76
|
+
while ( j > lo && QSCMP(swap_tmp, CELL(j - 1)) < 0 ) {
|
|
77
|
+
memcpy(CELL(j), CELL(j - 1), (size_t) bytes);
|
|
78
|
+
j--;
|
|
79
|
+
}
|
|
80
|
+
memcpy(CELL(j), swap_tmp, (size_t) bytes);
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
/* Median-of-three pivot: order buf[lo], buf[mid], buf[hi]. */
|
|
85
|
+
ca_size_t mid = lo + (hi - lo) / 2;
|
|
86
|
+
if ( QSCMP(CELL(mid), CELL(lo)) < 0 ) SWAP_CELL(CELL(mid), CELL(lo));
|
|
87
|
+
if ( QSCMP(CELL(hi), CELL(lo)) < 0 ) SWAP_CELL(CELL(hi), CELL(lo));
|
|
88
|
+
if ( QSCMP(CELL(hi), CELL(mid)) < 0 ) SWAP_CELL(CELL(hi), CELL(mid));
|
|
89
|
+
/* Stash pivot at hi-1 (Hoare partition variant). */
|
|
90
|
+
SWAP_CELL(CELL(mid), CELL(hi - 1));
|
|
91
|
+
/* Copy pivot into caller-provided scratch (avoid per-iteration
|
|
92
|
+
xmalloc; pivot lifetime is just this partition step). */
|
|
93
|
+
memcpy(pivot, CELL(hi - 1), (size_t) bytes);
|
|
94
|
+
/* Hoare partition (pivot at hi-1; scan lo..hi-2). */
|
|
95
|
+
ca_size_t i = lo, j = hi - 1;
|
|
96
|
+
for (;;) {
|
|
97
|
+
while ( QSCMP(CELL(++i), pivot) < 0 );
|
|
98
|
+
while ( QSCMP(CELL(--j), pivot) > 0 );
|
|
99
|
+
if ( i >= j ) break;
|
|
100
|
+
SWAP_CELL(CELL(i), CELL(j));
|
|
101
|
+
}
|
|
102
|
+
/* Restore pivot to its final position. */
|
|
103
|
+
SWAP_CELL(CELL(i), CELL(hi - 1));
|
|
104
|
+
/* buf[lo..i-1] <= pivot, buf[i] == pivot, buf[i+1..hi] >= pivot. */
|
|
105
|
+
if ( kth == i ) return;
|
|
106
|
+
else if ( kth < i ) hi = i - 1;
|
|
107
|
+
else lo = i + 1;
|
|
108
|
+
}
|
|
109
|
+
#undef SWAP_CELL
|
|
110
|
+
#undef CELL
|
|
111
|
+
#undef QSCMP
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* partition_copy(kth, axis: 0) — eager counterpart to `partition(kth,
|
|
115
|
+
* axis:)`. Returns a fresh entity CArray with the kth fiber-local
|
|
116
|
+
* position holding the kth-smallest value. Average O(n) per fiber via
|
|
117
|
+
* quickselect. Mask handling, axis kwarg, kth validation: identical to
|
|
118
|
+
* rb_ca_partitioned_view.
|
|
119
|
+
*
|
|
120
|
+
* C-callable twin of rb_ca_partition_copy (the Ruby entry) that skips
|
|
121
|
+
* rb_scan_args (the `:`-options form requires a proper Ruby method
|
|
122
|
+
* dispatch frame and segfaults when called from C). Takes vkth + vaxis
|
|
123
|
+
* directly. Non-static so carray_median_percentile.c can call it via
|
|
124
|
+
* an extern decl.
|
|
125
|
+
*/
|
|
126
|
+
VALUE
|
|
127
|
+
rb_ca_partition_copy_c (VALUE self, VALUE vkth, VALUE vaxis)
|
|
128
|
+
{
|
|
129
|
+
/* Mask handling (= same as partition view). */
|
|
130
|
+
VALUE target = self;
|
|
131
|
+
CArray *cat;
|
|
132
|
+
TypedData_Get_Struct(target, CArray, &carray_data_type, cat);
|
|
133
|
+
if ( ca_has_mask(cat) ) {
|
|
134
|
+
if ( RTEST(rb_ca_is_any_masked(target)) ) {
|
|
135
|
+
rb_raise(rb_eArgError,
|
|
136
|
+
"partition_copy: masked input not supported "
|
|
137
|
+
"(use ca.value or ca.strip_mask(fill))");
|
|
138
|
+
}
|
|
139
|
+
target = rb_ca_value_array(target);
|
|
140
|
+
TypedData_Get_Struct(target, CArray, &carray_data_type, cat);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Normalize axis. */
|
|
144
|
+
int axis = NUM2INT(vaxis);
|
|
145
|
+
if ( axis < 0 ) axis += cat->ndim;
|
|
146
|
+
if ( axis < 0 || axis >= cat->ndim ) {
|
|
147
|
+
rb_raise(rb_eArgError, "partition_copy: axis %d out of range for ndim %d",
|
|
148
|
+
NUM2INT(vaxis), cat->ndim);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* Normalize kth (-dim[axis] <= kth < dim[axis], negative counts from end). */
|
|
152
|
+
ca_size_t fiber_n = cat->dim[axis];
|
|
153
|
+
ca_size_t kth = (ca_size_t) NUM2SSIZET(vkth);
|
|
154
|
+
if ( kth < 0 ) kth += fiber_n;
|
|
155
|
+
if ( kth < 0 || kth >= fiber_n ) {
|
|
156
|
+
rb_raise(rb_eArgError,
|
|
157
|
+
"partition_copy: kth %ld out of range for axis %d (dim=%ld)",
|
|
158
|
+
(long) NUM2SSIZET(vkth), axis, (long) fiber_n);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* CA_OBJECT branch: partition_index_ki carries the rb_funcall(<=>)
|
|
162
|
+
* comparator. Build the entity via partition_index_ki ->
|
|
163
|
+
* take_along_axis -> copy. Slower than the numeric inline quickselect,
|
|
164
|
+
* but the cost is the per-pair rb_funcall, not an architectural
|
|
165
|
+
* penalty. */
|
|
166
|
+
if ( cat->data_type == CA_OBJECT ) {
|
|
167
|
+
static ID id_partition_index_ki = 0;
|
|
168
|
+
static ID id_take_along_axis = 0;
|
|
169
|
+
static ID id_axis_sym = 0;
|
|
170
|
+
if ( !id_partition_index_ki ) {
|
|
171
|
+
id_partition_index_ki = rb_intern("partition_index_ki");
|
|
172
|
+
id_take_along_axis = rb_intern("take_along_axis");
|
|
173
|
+
id_axis_sym = rb_intern("axis");
|
|
174
|
+
}
|
|
175
|
+
VALUE idx = rb_funcall(target, id_partition_index_ki, 2,
|
|
176
|
+
INT2NUM(axis), SIZET2NUM(kth));
|
|
177
|
+
VALUE kw = rb_hash_new();
|
|
178
|
+
rb_hash_aset(kw, ID2SYM(id_axis_sym), INT2NUM(axis));
|
|
179
|
+
VALUE tla_argv[2] = { idx, kw };
|
|
180
|
+
VALUE view = rb_funcallv_kw(target, id_take_along_axis, 2, tla_argv,
|
|
181
|
+
RB_PASS_KEYWORDS);
|
|
182
|
+
return rb_ca_copy(view);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* CA_FIXLEN branch: per-fiber quickselect via the generic byte-buffer
|
|
186
|
+
selector with raw memcmp ordering (cmp == NULL). Same lexicographic
|
|
187
|
+
total order as the fixlen sort/partition kernels and the bincmp
|
|
188
|
+
operators. Output preserves the fixlen byte width. */
|
|
189
|
+
if ( ca_is_fixlen_type(cat) ) {
|
|
190
|
+
ca_size_t fbytes = (ca_size_t) cat->bytes;
|
|
191
|
+
volatile VALUE vout = rb_ca_template_with_type(target,
|
|
192
|
+
INT2NUM(cat->data_type),
|
|
193
|
+
INT2NUM((int) fbytes));
|
|
194
|
+
CArray *cao;
|
|
195
|
+
TypedData_Get_Struct(vout, CArray, &carray_data_type, cao);
|
|
196
|
+
char *swap_tmp = ALLOCA_N(char, fbytes);
|
|
197
|
+
char *pivot = ALLOCA_N(char, fbytes);
|
|
198
|
+
ca_iter_state st_in, st_out;
|
|
199
|
+
char *pi, *po;
|
|
200
|
+
ca_size_t n;
|
|
201
|
+
CA_FOR_EACH_FIBER_INOUT(st_in, st_out, cat, cao, (int8_t) axis,
|
|
202
|
+
CA_KERNEL_NO_MASK, pi, po, n) {
|
|
203
|
+
memcpy(po, pi, (size_t) n * (size_t) fbytes);
|
|
204
|
+
if ( n > 1 ) {
|
|
205
|
+
ca_quickselect_bytes(po, 0, n - 1, kth, fbytes, NULL, swap_tmp, pivot);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return vout;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if ( cat->data_type != CA_BOOLEAN &&
|
|
212
|
+
(cat->data_type < CA_INT8 || cat->data_type > CA_FLOAT64) ) {
|
|
213
|
+
rb_raise(rb_eCADataTypeError,
|
|
214
|
+
"partition_copy: data_type %d not supported "
|
|
215
|
+
"(expected one of: bool, i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, object)",
|
|
216
|
+
cat->data_type);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
volatile VALUE vout = rb_ca_template_with_type(target,
|
|
220
|
+
INT2NUM(cat->data_type),
|
|
221
|
+
INT2NUM(0));
|
|
222
|
+
CArray *cao;
|
|
223
|
+
TypedData_Get_Struct(vout, CArray, &carray_data_type, cao);
|
|
224
|
+
|
|
225
|
+
/* Numeric path: per-dtype quickselect with inline cmp via the typed
|
|
226
|
+
ca_partition_quick_* kernels (avoids the function-pointer
|
|
227
|
+
indirection of the comparator-based ca_quickselect_bytes).
|
|
228
|
+
Float NaN policy = pre-partition NaN to tail (same convention as
|
|
229
|
+
sort_copy); if kth falls in the finite slice, quickselect over
|
|
230
|
+
finite; if kth >= finite_count, the cell is already NaN and no
|
|
231
|
+
further work is needed. */
|
|
232
|
+
ca_size_t bytes = (ca_size_t) cat->bytes;
|
|
233
|
+
|
|
234
|
+
ca_iter_state st_in, st_out;
|
|
235
|
+
char *pi, *po;
|
|
236
|
+
ca_size_t n;
|
|
237
|
+
|
|
238
|
+
CA_FOR_EACH_FIBER_INOUT(st_in, st_out, cat, cao, (int8_t) axis,
|
|
239
|
+
CA_KERNEL_NO_MASK, pi, po, n) {
|
|
240
|
+
memcpy(po, pi, (size_t) n * (size_t) bytes);
|
|
241
|
+
if ( n <= 1 ) continue;
|
|
242
|
+
switch ( cat->data_type ) {
|
|
243
|
+
case CA_BOOLEAN: ca_partition_quick_u8 ((uint8_t *) po, n, kth); break;
|
|
244
|
+
case CA_INT8: ca_partition_quick_i8 ((int8_t *) po, n, kth); break;
|
|
245
|
+
case CA_UINT8: ca_partition_quick_u8 ((uint8_t *) po, n, kth); break;
|
|
246
|
+
case CA_INT16: ca_partition_quick_i16((int16_t *) po, n, kth); break;
|
|
247
|
+
case CA_UINT16: ca_partition_quick_u16((uint16_t *) po, n, kth); break;
|
|
248
|
+
case CA_INT32: ca_partition_quick_i32((int32_t *) po, n, kth); break;
|
|
249
|
+
case CA_UINT32: ca_partition_quick_u32((uint32_t *) po, n, kth); break;
|
|
250
|
+
case CA_INT64: ca_partition_quick_i64((int64_t *) po, n, kth); break;
|
|
251
|
+
case CA_UINT64: ca_partition_quick_u64((uint64_t *) po, n, kth); break;
|
|
252
|
+
case CA_FLOAT32: {
|
|
253
|
+
ca_size_t fin = ca_partition_nan_f32((float32_t *) po, n);
|
|
254
|
+
if ( kth < fin ) ca_partition_quick_f32((float32_t *) po, fin, kth);
|
|
255
|
+
/* else: po[kth] is NaN already (= NaN-at-end policy), nothing to do */
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
case CA_FLOAT64: {
|
|
259
|
+
ca_size_t fin = ca_partition_nan_f64((double *) po, n);
|
|
260
|
+
if ( kth < fin ) ca_partition_quick_f64((double *) po, fin, kth);
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
default:
|
|
264
|
+
rb_raise(rb_eCADataTypeError,
|
|
265
|
+
"partition_copy: BUG: unexpected data_type %d", cat->data_type);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return vout;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/* masked_position: -aware twin of {rb_ca_partition_copy_c}. Masked
|
|
273
|
+
* cells are an incomparable sentinel (same role NaN plays for float
|
|
274
|
+
* dtypes): unmasked input takes the fast rb_ca_partition_copy_c path
|
|
275
|
+
* unchanged; masked input delegates to {partition} (which handles the
|
|
276
|
+
* masked_position split via partition_addr_ki_mp) + copy, mirroring the
|
|
277
|
+
* CA_FIXLEN / CA_OBJECT delegation pattern already used by sort_copy.
|
|
278
|
+
* rb_ca_partition_copy_c itself keeps raising on masked input (its
|
|
279
|
+
* other callers -- carray_median_percentile.c's flat lane -- always
|
|
280
|
+
* pre-strip the mask before calling it, per
|
|
281
|
+
* devel/MEMO_PER_AXIS_ORDER_STAT_MASK.md; per-axis order statistics
|
|
282
|
+
* with mask are a separate, still-open gap).
|
|
283
|
+
*/
|
|
284
|
+
static VALUE
|
|
285
|
+
rb_ca_partition_copy_c_mp (VALUE self, VALUE vkth, VALUE vaxis, int masked_last)
|
|
286
|
+
{
|
|
287
|
+
CArray *ca;
|
|
288
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
289
|
+
if ( ! ca_has_mask(ca) ) {
|
|
290
|
+
return rb_ca_partition_copy_c(self, vkth, vaxis);
|
|
291
|
+
}
|
|
292
|
+
/* rb_ca_partitioned_view's rb_scan_args "1:" pattern needs call-frame
|
|
293
|
+
keyword-splat state, only set by full Ruby method dispatch -- a raw
|
|
294
|
+
C call segfaults/misparses (same constraint documented on
|
|
295
|
+
rb_ca_partition_copy_c above). Go through rb_funcallv_kw +
|
|
296
|
+
RB_PASS_KEYWORDS instead, same pattern as the CA_OBJECT branch in
|
|
297
|
+
rb_ca_partition_copy_c below. */
|
|
298
|
+
static ID id_partition = 0;
|
|
299
|
+
if ( !id_partition ) id_partition = rb_intern("partition");
|
|
300
|
+
VALUE kw = rb_hash_new();
|
|
301
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("axis")), vaxis);
|
|
302
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("masked_position")), masked_last ? ID2SYM(rb_intern("last")) : ID2SYM(rb_intern("first")));
|
|
303
|
+
VALUE pv_argv[2] = { vkth, kw };
|
|
304
|
+
VALUE view = rb_funcallv_kw(self, id_partition, 2, pv_argv, RB_PASS_KEYWORDS);
|
|
305
|
+
VALUE obj = rb_ca_copy(view);
|
|
306
|
+
CA_FACE_LIFT_IF_FACE(obj, self, ca);
|
|
307
|
+
return obj;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/* Ruby entry: partition_copy(kth, axis: 0, masked_position: :last) */
|
|
311
|
+
static VALUE
|
|
312
|
+
rb_ca_partition_copy (int argc, VALUE *argv, VALUE self)
|
|
313
|
+
{
|
|
314
|
+
VALUE vkth, rkw = Qnil;
|
|
315
|
+
VALUE vaxis = INT2NUM(0);
|
|
316
|
+
VALUE vmasked_position = Qnil;
|
|
317
|
+
rb_scan_args(argc, argv, "1:", &vkth, &rkw);
|
|
318
|
+
rb_scan_options(rkw, "axis,masked_position", &vaxis, &vmasked_position);
|
|
319
|
+
|
|
320
|
+
int masked_last = 1;
|
|
321
|
+
if ( !NIL_P(vmasked_position) ) {
|
|
322
|
+
static ID sym_first = 0, sym_last = 0;
|
|
323
|
+
if ( !sym_first ) sym_first = rb_intern("first");
|
|
324
|
+
if ( !sym_last ) sym_last = rb_intern("last");
|
|
325
|
+
ID mp_id = SYM2ID(vmasked_position);
|
|
326
|
+
if ( mp_id == sym_last ) masked_last = 1;
|
|
327
|
+
else if ( mp_id == sym_first ) masked_last = 0;
|
|
328
|
+
else {
|
|
329
|
+
rb_raise(rb_eArgError,
|
|
330
|
+
"partition_copy: unknown masked_position %s (expected :first or :last)",
|
|
331
|
+
rb_id2name(mp_id));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return rb_ca_partition_copy_c_mp(self, vkth, vaxis, masked_last);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/* partition(kth, axis: 0, masked_position: :last)
|
|
338
|
+
*
|
|
339
|
+
* Returns a CARemap view of +self+ partitioned along +axis+ such that
|
|
340
|
+
* the cell at the kth fiber-local position contains the kth-smallest
|
|
341
|
+
* value, with all cells before it <= and all cells after >=. Order
|
|
342
|
+
* within the < and > regions is unspecified. Average O(n) per fiber
|
|
343
|
+
* via the partition_addr_ki kernel (mkkernel `:sort` kind, algorithm:
|
|
344
|
+
* :partition).
|
|
345
|
+
*
|
|
346
|
+
* Signature mirrors rb_ca_sorted_view: positional kth + optional axis: /
|
|
347
|
+
* masked_position: kwargs (default 0 / :last). Mask handling mirrors
|
|
348
|
+
* {sort}: masked cells are an incomparable sentinel clustered at
|
|
349
|
+
* masked_position:, excluded from the kth-selection; a kth landing in
|
|
350
|
+
* the masked cluster needs no selection (unspecified order, same
|
|
351
|
+
* contract as the < / > regions). kth validation matches
|
|
352
|
+
* partition_addr_ki (-dim[axis] <= kth < dim[axis], negative counts
|
|
353
|
+
* from end).
|
|
354
|
+
*/
|
|
355
|
+
static VALUE
|
|
356
|
+
rb_ca_partitioned_view (int argc, VALUE *argv, VALUE self)
|
|
357
|
+
{
|
|
358
|
+
VALUE vkth, rkw = Qnil;
|
|
359
|
+
VALUE vaxis = INT2NUM(0);
|
|
360
|
+
VALUE vmasked_position = Qnil;
|
|
361
|
+
|
|
362
|
+
rb_scan_args(argc, argv, "1:", &vkth, &rkw);
|
|
363
|
+
rb_scan_options(rkw, "axis,masked_position", &vaxis, &vmasked_position);
|
|
364
|
+
|
|
365
|
+
int masked_last = 1;
|
|
366
|
+
if ( !NIL_P(vmasked_position) ) {
|
|
367
|
+
static ID sym_first = 0, sym_last = 0;
|
|
368
|
+
if ( !sym_first ) sym_first = rb_intern("first");
|
|
369
|
+
if ( !sym_last ) sym_last = rb_intern("last");
|
|
370
|
+
ID mp_id = SYM2ID(vmasked_position);
|
|
371
|
+
if ( mp_id == sym_last ) masked_last = 1;
|
|
372
|
+
else if ( mp_id == sym_first ) masked_last = 0;
|
|
373
|
+
else {
|
|
374
|
+
rb_raise(rb_eArgError,
|
|
375
|
+
"partition: unknown masked_position %s (expected :first or :last)",
|
|
376
|
+
rb_id2name(mp_id));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
CArray *ca;
|
|
381
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
382
|
+
|
|
383
|
+
/* CA_FIXLEN flows through the same partition_addr_ki fixlen dialect
|
|
384
|
+
as numeric; masked_position: applies uniformly across dtypes. */
|
|
385
|
+
VALUE target = self;
|
|
386
|
+
|
|
387
|
+
/* partition_addr_ki_mp validates axis + kth, splits masked cells to
|
|
388
|
+
masked_position:, and quickselects per fiber over the unmasked
|
|
389
|
+
sub-range. Returns CA_SIZE same-shape array of view-flat addresses
|
|
390
|
+
suitable for direct ca_remap_new wrap; the remap gather carries
|
|
391
|
+
target's mask bits through so masked cells stay masked at their
|
|
392
|
+
clustered position (no extra output-mask step needed here). */
|
|
393
|
+
volatile VALUE sigma_addr = rb_ca_partition_addr_ki_mp(target, vaxis, vkth, masked_last);
|
|
394
|
+
{
|
|
395
|
+
VALUE obj = rb_ca_remap_new(target, sigma_addr);
|
|
396
|
+
CA_FACE_LIFT_IF_FACE(obj, self, ca);
|
|
397
|
+
return obj;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/* ----------------------------------------------------------------------- */
|
|
402
|
+
|
|
403
|
+
void
|
|
404
|
+
Init_carray_partition (void)
|
|
405
|
+
{
|
|
406
|
+
/* `partition(kth, axis: k)` returns a CARemap view via the
|
|
407
|
+
quickselect kernel partition_addr_ki. The eager-position sibling
|
|
408
|
+
`partition_index` (lib/carray/ordering.rb) wraps partition_index_ki
|
|
409
|
+
under the same convention. */
|
|
410
|
+
rb_define_method(rb_cCArray, "partition", rb_ca_partitioned_view, -1);
|
|
411
|
+
|
|
412
|
+
/* `partition_copy` is the eager counterpart to `partition`: returns a
|
|
413
|
+
fresh entity array via per-fiber quickselect, bypassing the CARemap
|
|
414
|
+
scatter layer. Same mask / axis / kth semantics as the view form. */
|
|
415
|
+
rb_define_method(rb_cCArray, "partition_copy", rb_ca_partition_copy, -1);
|
|
416
|
+
}
|