carray 3.0.1 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +824 -0
- data/README.md +5 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +258 -4
- data/ext/ca_axis_group.c +368 -184
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +90 -41
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +960 -245
- data/ext/ca_kernel_iterator.h +352 -181
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +194 -42
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +5 -4
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +180 -50
- data/ext/ca_obj_face.c +428 -62
- data/ext/ca_obj_face.h +107 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +39 -26
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +235 -55
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +551 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +88 -75
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -123
- data/ext/ca_obj_stride.c +267 -35
- data/ext/ca_obj_string.c +25 -22
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +157 -29
- data/ext/ca_op_ipower.c +25 -13
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +385 -198
- data/ext/ca_sweep_engine.h +31 -23
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +463 -0
- data/ext/carray.h +90 -28
- data/ext/carray_access.c +487 -231
- data/ext/carray_address_basis.c +731 -0
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +49 -17
- data/ext/carray_call_cfunc.c +667 -511
- data/ext/carray_cast.c +1556 -247
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +84 -38
- data/ext/carray_core.c +591 -119
- data/ext/carray_count.c +148 -96
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +604 -291
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +400 -1
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +88 -66
- data/ext/carray_mask.c +705 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +263 -63
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1093 -363
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +582 -204
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +183 -70
- data/ext/carray_sort.c +235 -240
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +103 -118
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1349 -851
- data/ext/ruby_carray.c +17 -2
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +18 -0
- data/lib/carray/axis_group.rb +245 -20
- data/lib/carray/basics.rb +95 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +200 -54
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +244 -59
- data/lib/carray/categorical_iterator.rb +391 -757
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +177 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +590 -76
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +205 -35
- data/lib/carray/frame/group.rb +199 -40
- data/lib/carray/frame/io.rb +452 -60
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +54 -19
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +726 -56
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +71 -20
- data/lib/carray/iterator.rb +157 -2
- data/lib/carray/lazy.rb +54 -67
- data/lib/carray/mask_gap_fill.rb +66 -50
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +130 -6
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +235 -21
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +91 -0
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +52 -3
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +109 -40
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +9 -4
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +535 -105
- data/lib/carray/window_iterator.rb +259 -82
- data/lib/carray.rb +4 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +11 -4
- data/yard-stubs/carray_access.rb +6 -5
- data/yard-stubs/carray_broadcast.rb +2 -2
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -83
- data/yard-stubs/carray_count.rb +16 -2
- data/yard-stubs/carray_lazy.rb +210 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +1499 -4
- data/yard-stubs/carray_median_percentile.rb +26 -8
- data/yard-stubs/carray_order.rb +43 -82
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +11 -8
- data/yard-stubs/carray_sort.rb +50 -8
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -25837
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14593
- data/ext/carray_kernels_reduce_extreme.c +0 -16948
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32138
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/ca_binop_dispatch.c
CHANGED
|
@@ -27,39 +27,56 @@
|
|
|
27
27
|
/* vv kernel lookup */
|
|
28
28
|
/* ------------------------------------------------------------------- */
|
|
29
29
|
|
|
30
|
+
/* The kernel table of each op id. The eager operators hold the tables
|
|
31
|
+
themselves; ca_binop_op_id_of_table maps one back to its op id, so that
|
|
32
|
+
both ask ca_binop_is_trapping the same question. */
|
|
33
|
+
static ca_binop_func_t * const ca_binop_tables[CA_BINOP_COUNT] = {
|
|
34
|
+
[CA_BINOP_ADD] = ca_binop_add,
|
|
35
|
+
[CA_BINOP_SUB] = ca_binop_sub,
|
|
36
|
+
[CA_BINOP_MUL] = ca_binop_mul,
|
|
37
|
+
[CA_BINOP_DIV] = ca_binop_div,
|
|
38
|
+
[CA_BINOP_POW] = ca_binop_power,
|
|
39
|
+
[CA_BINOP_BIT_AND] = ca_binop_bit_and_i,
|
|
40
|
+
[CA_BINOP_BIT_OR] = ca_binop_bit_or_i,
|
|
41
|
+
[CA_BINOP_BIT_XOR] = ca_binop_bit_xor_i,
|
|
42
|
+
[CA_BINOP_BIT_LSHIFT]= ca_binop_bit_lshift,
|
|
43
|
+
[CA_BINOP_BIT_RSHIFT]= ca_binop_bit_rshift,
|
|
44
|
+
[CA_BINOP_MOD] = ca_binop_mod,
|
|
45
|
+
[CA_BINOP_QUO] = ca_binop_quo_i,
|
|
46
|
+
[CA_BINOP_RCP_MUL] = ca_binop_rcp_mul,
|
|
47
|
+
[CA_BINOP_IPOWER] = ca_binop_ipower,
|
|
48
|
+
[CA_BINOP_COPYSIGN] = ca_binop_copysign,
|
|
49
|
+
[CA_BINOP_LOGADDEXP] = ca_binop_logaddexp,
|
|
50
|
+
[CA_BINOP_NEXTAFTER] = ca_binop_nextafter,
|
|
51
|
+
[CA_BINOP_FMOD] = ca_binop_fmod,
|
|
52
|
+
[CA_BINOP_ATAN2] = ca_binop_atan2,
|
|
53
|
+
[CA_BINOP_HYPOT] = ca_binop_hypot,
|
|
54
|
+
[CA_BINOP_PMAX] = ca_binop_pmax,
|
|
55
|
+
[CA_BINOP_PMIN] = ca_binop_pmin,
|
|
56
|
+
[CA_BINOP_MAXIMUM] = ca_binop_maximum,
|
|
57
|
+
[CA_BINOP_MINIMUM] = ca_binop_minimum,
|
|
58
|
+
[CA_BINOP_AND] = ca_binop_and,
|
|
59
|
+
[CA_BINOP_OR] = ca_binop_or,
|
|
60
|
+
[CA_BINOP_XOR] = ca_binop_xor,
|
|
61
|
+
};
|
|
62
|
+
|
|
30
63
|
ca_binop_func_t
|
|
31
64
|
ca_binop_kernel_lookup_vv (uint16_t op_id, int8_t common_dt)
|
|
32
65
|
{
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
case CA_BINOP_QUO: return ca_binop_quo_i [common_dt];
|
|
46
|
-
case CA_BINOP_RCP_MUL: return ca_binop_rcp_mul [common_dt];
|
|
47
|
-
case CA_BINOP_IPOWER: return ca_binop_ipower [common_dt];
|
|
48
|
-
case CA_BINOP_COPYSIGN: return ca_binop_copysign [common_dt];
|
|
49
|
-
case CA_BINOP_LOGADDEXP: return ca_binop_logaddexp [common_dt];
|
|
50
|
-
case CA_BINOP_NEXTAFTER: return ca_binop_nextafter [common_dt];
|
|
51
|
-
case CA_BINOP_FMOD: return ca_binop_fmod [common_dt];
|
|
52
|
-
case CA_BINOP_ATAN2: return ca_binop_atan2 [common_dt];
|
|
53
|
-
case CA_BINOP_HYPOT: return ca_binop_hypot [common_dt];
|
|
54
|
-
case CA_BINOP_PMAX: return ca_binop_pmax [common_dt];
|
|
55
|
-
case CA_BINOP_PMIN: return ca_binop_pmin [common_dt];
|
|
56
|
-
case CA_BINOP_MAXIMUM: return ca_binop_maximum [common_dt];
|
|
57
|
-
case CA_BINOP_MINIMUM: return ca_binop_minimum [common_dt];
|
|
58
|
-
case CA_BINOP_AND: return ca_binop_and [common_dt];
|
|
59
|
-
case CA_BINOP_OR: return ca_binop_or [common_dt];
|
|
60
|
-
case CA_BINOP_XOR: return ca_binop_xor [common_dt];
|
|
61
|
-
default: return NULL;
|
|
66
|
+
if ( op_id >= CA_BINOP_COUNT || ! ca_binop_tables[op_id] ) return NULL;
|
|
67
|
+
return ca_binop_tables[op_id][common_dt];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* The op id whose kernel table is `table`, or -1 for a table no op id
|
|
71
|
+
names. */
|
|
72
|
+
int
|
|
73
|
+
ca_binop_op_id_of_table (ca_binop_func_t table[])
|
|
74
|
+
{
|
|
75
|
+
int op_id;
|
|
76
|
+
for ( op_id = 0; op_id < CA_BINOP_COUNT; op_id++ ) {
|
|
77
|
+
if ( ca_binop_tables[op_id] == table ) return op_id;
|
|
62
78
|
}
|
|
79
|
+
return -1;
|
|
63
80
|
}
|
|
64
81
|
|
|
65
82
|
/* ------------------------------------------------------------------- */
|
|
@@ -106,10 +123,12 @@ ca_binop_kernel_input_data_types (uint16_t op_id, int8_t l_dt, int8_t r_dt,
|
|
|
106
123
|
int
|
|
107
124
|
ca_binop_is_trapping (uint16_t op_id, int8_t common_dt)
|
|
108
125
|
{
|
|
109
|
-
/*
|
|
110
|
-
DIV
|
|
111
|
-
|
|
126
|
+
/* An object cell calls Ruby, which can raise for any op. Integer
|
|
127
|
+
DIV / MOD / QUO / FMOD / RCP_MUL raise on a zero divisor, and POW /
|
|
128
|
+
IPOWER on zero to a negative power. Float division returns NaN/Inf
|
|
129
|
+
and does not trap. */
|
|
112
130
|
int is_integer = ( common_dt >= CA_INT8 && common_dt <= CA_UINT64 );
|
|
131
|
+
if ( common_dt == CA_OBJECT ) return 1;
|
|
113
132
|
if ( ! is_integer ) return 0;
|
|
114
133
|
|
|
115
134
|
switch (op_id) {
|
|
@@ -117,6 +136,9 @@ ca_binop_is_trapping (uint16_t op_id, int8_t common_dt)
|
|
|
117
136
|
case CA_BINOP_MOD:
|
|
118
137
|
case CA_BINOP_QUO:
|
|
119
138
|
case CA_BINOP_FMOD:
|
|
139
|
+
case CA_BINOP_RCP_MUL:
|
|
140
|
+
case CA_BINOP_POW:
|
|
141
|
+
case CA_BINOP_IPOWER:
|
|
120
142
|
return 1;
|
|
121
143
|
default:
|
|
122
144
|
return 0;
|
data/ext/ca_binop_dispatch.h
CHANGED
|
@@ -148,5 +148,6 @@ void ca_binop_kernel_input_data_types (uint16_t op_id, int8_t l_dt, int8_t r_dt,
|
|
|
148
148
|
a slab mask to the kernel so masked cells are skipped (otherwise
|
|
149
149
|
masked-zero divisors crash with SIGFPE). See §3.4 rev3. */
|
|
150
150
|
int ca_binop_is_trapping (uint16_t op_id, int8_t common_dt);
|
|
151
|
+
int ca_binop_op_id_of_table (ca_binop_func_t table[]);
|
|
151
152
|
|
|
152
153
|
#endif /* CA_BINOP_DISPATCH_H */
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
--------------------------------------------------------------------------- */
|
|
36
36
|
|
|
37
37
|
#include "carray.h"
|
|
38
|
+
#include "carray_internal.h" /* CA_EXTREMUM_REPLACES */
|
|
38
39
|
#include <stdlib.h> /* qsort */
|
|
39
40
|
#include <math.h> /* floor */
|
|
40
41
|
|
|
@@ -82,8 +83,7 @@ rb_ca_categorical_scatter (VALUE self, VALUE rvalue, VALUE rcursor,
|
|
|
82
83
|
rb_raise(rb_eArgError, "__categorical_scatter__: grouped/value data type mismatch");
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
ca_attach(value);
|
|
86
|
+
ca_attach_n(2, codes, value); /* window: detached before each raise inside */
|
|
87
87
|
cmask = ca_mask_ptr(codes);
|
|
88
88
|
vmask = ca_mask_ptr(value);
|
|
89
89
|
cur = (int64_t *) cursor->ptr;
|
|
@@ -138,6 +138,19 @@ rb_ca_categorical_scatter (VALUE self, VALUE rvalue, VALUE rcursor,
|
|
|
138
138
|
|
|
139
139
|
--------------------------------------------------------------------------- */
|
|
140
140
|
|
|
141
|
+
/* NaN loses every contest, which is what CArray#min / #max do (mkkernel
|
|
142
|
+
declares it as `all_nan_result: :nan`): a NaN never displaces a number, the
|
|
143
|
+
first number displaces a NaN that seeded the accumulator, and a segment
|
|
144
|
+
holding nothing but NaN answers NaN. Without this the answer depends on
|
|
145
|
+
where in the segment the NaN sits, and a reduction that is order-free
|
|
146
|
+
stopped being order-free.
|
|
147
|
+
|
|
148
|
+
The predicate is passed per instantiation rather than written inline so an
|
|
149
|
+
integer body never compares a value with itself, which is a tautology the
|
|
150
|
+
compiler is right to warn about. */
|
|
151
|
+
#define CAT_NAN_NEVER(v) (0)
|
|
152
|
+
#define CAT_NAN_CHECK(v) ((v) != (v))
|
|
153
|
+
|
|
141
154
|
#define REDUCEAT_MOMENTS_BODY(T) \
|
|
142
155
|
do { \
|
|
143
156
|
const T *gp = (const T *) grouped->ptr; \
|
|
@@ -152,8 +165,11 @@ rb_ca_categorical_scatter (VALUE self, VALUE rvalue, VALUE rcursor,
|
|
|
152
165
|
if ( gm && gm[j] ) continue; /* masked value cell */ \
|
|
153
166
|
{ T v = gp[j]; \
|
|
154
167
|
sacc += (double) v; \
|
|
155
|
-
if ( ! seen ) { mn = v; mx = v; seen = 1; }
|
|
156
|
-
else {
|
|
168
|
+
if ( ! seen ) { mn = v; mx = v; seen = 1; } \
|
|
169
|
+
else { \
|
|
170
|
+
if ( CA_EXTREMUM_REPLACES(v, mn, <) ) mn = v; \
|
|
171
|
+
if ( CA_EXTREMUM_REPLACES(v, mx, >) ) mx = v; \
|
|
172
|
+
} \
|
|
157
173
|
cnt++; } \
|
|
158
174
|
} \
|
|
159
175
|
countp[c] = (int64_t) cnt; \
|
|
@@ -278,14 +294,31 @@ ca_nth_element_double (double *a, ca_size_t n, ca_size_t kth)
|
|
|
278
294
|
{ double f = (double) (m - 1) * p / 100.0; \
|
|
279
295
|
ca_size_t ki = (ca_size_t) floor(f); \
|
|
280
296
|
double vlo, vhi; \
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
297
|
+
/* Push NaN to the tail, which is where CArray's sort puts it, so the \
|
|
298
|
+
ki-th element here is the ki-th of the sorted segment. Selection \
|
|
299
|
+
runs on the numeric prefix, since a comparison-based quickselect \
|
|
300
|
+
has nothing to say about a NaN; a position or an upper neighbour \
|
|
301
|
+
landing in the tail is NaN. The blend is CArray#percentile's, so \
|
|
302
|
+
both answer alike for NaN and infinities. */ \
|
|
303
|
+
ca_size_t nnum = m, t0 = 0; \
|
|
304
|
+
while ( t0 < nnum ) { \
|
|
305
|
+
if ( scratch[t0] != scratch[t0] ) { \
|
|
306
|
+
double tmp = scratch[--nnum]; \
|
|
307
|
+
scratch[nnum] = scratch[t0]; scratch[t0] = tmp; \
|
|
308
|
+
} else t0++; \
|
|
309
|
+
} \
|
|
310
|
+
if ( ki < nnum ) { \
|
|
311
|
+
ca_nth_element_double(scratch, nnum, ki); /* scratch[ki] = ki-th */ \
|
|
312
|
+
vlo = scratch[ki]; \
|
|
313
|
+
} else vlo = (double) NAN; \
|
|
314
|
+
if ( ki + 1 < nnum ) { /* (ki+1)-th = min of upper partition */ \
|
|
284
315
|
double mn = scratch[ki+1]; ca_size_t t; \
|
|
285
|
-
for ( t = ki + 2; t <
|
|
316
|
+
for ( t = ki + 2; t < nnum; t++ ) if ( scratch[t] < mn ) mn = scratch[t]; \
|
|
286
317
|
vhi = mn; \
|
|
287
|
-
} else vhi =
|
|
288
|
-
|
|
318
|
+
} else vhi = (double) NAN; \
|
|
319
|
+
{ double r = f - (double) ki; \
|
|
320
|
+
outp[c] = ( r == 0.0 || ki + 1 >= m ) ? vlo \
|
|
321
|
+
: vlo * (1.0 - r) + vhi * r; } } \
|
|
289
322
|
} \
|
|
290
323
|
} while (0)
|
|
291
324
|
|
|
@@ -302,6 +335,11 @@ rb_ca_reduceat_percentile (VALUE self, VALUE roffsets, VALUE rp, VALUE rout)
|
|
|
302
335
|
GetCArray(roffsets, offsets);
|
|
303
336
|
GetCArray(rout, out);
|
|
304
337
|
p = NUM2DBL(rp);
|
|
338
|
+
if ( !(p >= 0.0 && p <= 100.0) ) {
|
|
339
|
+
rb_raise(rb_eArgError,
|
|
340
|
+
"percentile: p must be Numeric in [0,100] (got %"PRIsVALUE")",
|
|
341
|
+
rb_inspect(rp));
|
|
342
|
+
}
|
|
305
343
|
k = (int64_t) offsets->elements;
|
|
306
344
|
n = grouped->elements;
|
|
307
345
|
if ( offsets->data_type != CA_INT64 || out->data_type != CA_FLOAT64 ||
|
|
@@ -350,7 +388,7 @@ rb_ca_reduceat_percentile (VALUE self, VALUE roffsets, VALUE rp, VALUE rout)
|
|
|
350
388
|
accumulates the per-segment centred sum of squares; variance = SS / (n-1).
|
|
351
389
|
Centred (not the one-pass sum-of-squares) so the ε-close contract holds — a
|
|
352
390
|
one-pass formula cancels catastrophically. Matches CArray#variance per group:
|
|
353
|
-
count 0
|
|
391
|
+
count 0 or 1 -> masked (the sample variance is undefined), count >= 2 ->
|
|
354
392
|
SS / (count-1).
|
|
355
393
|
|
|
356
394
|
Surface (private): grouped.__reduceat_variance__(offsets, means, counts, out)
|
|
@@ -358,7 +396,7 @@ rb_ca_reduceat_percentile (VALUE self, VALUE roffsets, VALUE rp, VALUE rout)
|
|
|
358
396
|
offsets = int64[k] segment STARTS
|
|
359
397
|
means = float64[k] per-segment mean (ignored where count < 2)
|
|
360
398
|
counts = int64[k] per-segment present count
|
|
361
|
-
out = float64[k] output: variance; count 0
|
|
399
|
+
out = float64[k] output: variance; count 0 or 1 masked
|
|
362
400
|
|
|
363
401
|
--------------------------------------------------------------------------- */
|
|
364
402
|
|
|
@@ -367,8 +405,7 @@ rb_ca_reduceat_percentile (VALUE self, VALUE roffsets, VALUE rp, VALUE rout)
|
|
|
367
405
|
const T *gp = (const T *) grouped->ptr; \
|
|
368
406
|
for ( c = 0; c < k; c++ ) { \
|
|
369
407
|
int64_t cnt = countp[c]; \
|
|
370
|
-
if ( cnt
|
|
371
|
-
if ( cnt == 1 ) { outp[c] = 0.0; continue; } /* n=1 contract: 0.0 */ \
|
|
408
|
+
if ( cnt < 2 ) { outp[c] = 0.0; outm[c] = 1; continue; } /* undefined */ \
|
|
372
409
|
{ double mean = meanp[c], ss = 0.0; \
|
|
373
410
|
ca_size_t lo = (ca_size_t) offs[c]; \
|
|
374
411
|
ca_size_t hi = (c + 1 < k) ? (ca_size_t) offs[c+1] : n, j; \
|
|
@@ -510,7 +547,7 @@ rb_ca_reduceat_prod (VALUE self, VALUE roffsets, VALUE rout)
|
|
|
510
547
|
/* __reduceat_argminmax__(offsets, min_idx, max_idx) — per-segment GROUP-LOCAL
|
|
511
548
|
index of the min / max (position within the segment, first occurrence on
|
|
512
549
|
ties). Empty / all-masked segments are masked. */
|
|
513
|
-
#define REDUCEAT_ARGMINMAX_BODY(T)
|
|
550
|
+
#define REDUCEAT_ARGMINMAX_BODY(T, ISNAN) \
|
|
514
551
|
do { \
|
|
515
552
|
const T *gp = (const T *) grouped->ptr; \
|
|
516
553
|
for ( c = 0; c < k; c++ ) { \
|
|
@@ -520,10 +557,13 @@ rb_ca_reduceat_prod (VALUE self, VALUE roffsets, VALUE rout)
|
|
|
520
557
|
for ( j = lo; j < hi; j++ ) { \
|
|
521
558
|
if ( gm && gm[j] ) continue; \
|
|
522
559
|
{ T v = gp[j]; ca_size_t li = j - lo; \
|
|
560
|
+
if ( ISNAN(v) ) continue; /* wins no contest, so marks no position */\
|
|
523
561
|
if ( ! seen ) { mn = mx = v; mni = mxi = li; seen = 1; } \
|
|
524
562
|
else { if ( v < mn ) { mn = v; mni = li; } \
|
|
525
563
|
if ( v > mx ) { mx = v; mxi = li; } } } \
|
|
526
564
|
} \
|
|
565
|
+
/* A segment of nothing but NaN has no position to report, the same as a \
|
|
566
|
+
segment with no present cell at all -- both are UNDEF, as in the core.*/\
|
|
527
567
|
if ( seen ) { minp[c] = (int64_t) mni; maxp[c] = (int64_t) mxi; } \
|
|
528
568
|
else { minp[c] = 0; maxp[c] = 0; minm[c] = 1; maxm[c] = 1; } \
|
|
529
569
|
} \
|
|
@@ -558,16 +598,16 @@ rb_ca_reduceat_argminmax (VALUE self, VALUE roffsets, VALUE rminidx, VALUE rmaxi
|
|
|
558
598
|
maxm = (boolean8_t *) maxidx->mask->ptr;
|
|
559
599
|
|
|
560
600
|
switch ( grouped->data_type ) {
|
|
561
|
-
case CA_INT8: REDUCEAT_ARGMINMAX_BODY(int8_t); break;
|
|
562
|
-
case CA_UINT8: REDUCEAT_ARGMINMAX_BODY(uint8_t); break;
|
|
563
|
-
case CA_INT16: REDUCEAT_ARGMINMAX_BODY(int16_t); break;
|
|
564
|
-
case CA_UINT16: REDUCEAT_ARGMINMAX_BODY(uint16_t); break;
|
|
565
|
-
case CA_INT32: REDUCEAT_ARGMINMAX_BODY(int32_t); break;
|
|
566
|
-
case CA_UINT32: REDUCEAT_ARGMINMAX_BODY(uint32_t); break;
|
|
567
|
-
case CA_INT64: REDUCEAT_ARGMINMAX_BODY(int64_t); break;
|
|
568
|
-
case CA_UINT64: REDUCEAT_ARGMINMAX_BODY(uint64_t); break;
|
|
569
|
-
case CA_FLOAT32: REDUCEAT_ARGMINMAX_BODY(float32_t); break;
|
|
570
|
-
case CA_FLOAT64: REDUCEAT_ARGMINMAX_BODY(float64_t); break;
|
|
601
|
+
case CA_INT8: REDUCEAT_ARGMINMAX_BODY(int8_t, CAT_NAN_NEVER); break;
|
|
602
|
+
case CA_UINT8: REDUCEAT_ARGMINMAX_BODY(uint8_t, CAT_NAN_NEVER); break;
|
|
603
|
+
case CA_INT16: REDUCEAT_ARGMINMAX_BODY(int16_t, CAT_NAN_NEVER); break;
|
|
604
|
+
case CA_UINT16: REDUCEAT_ARGMINMAX_BODY(uint16_t, CAT_NAN_NEVER); break;
|
|
605
|
+
case CA_INT32: REDUCEAT_ARGMINMAX_BODY(int32_t, CAT_NAN_NEVER); break;
|
|
606
|
+
case CA_UINT32: REDUCEAT_ARGMINMAX_BODY(uint32_t, CAT_NAN_NEVER); break;
|
|
607
|
+
case CA_INT64: REDUCEAT_ARGMINMAX_BODY(int64_t, CAT_NAN_NEVER); break;
|
|
608
|
+
case CA_UINT64: REDUCEAT_ARGMINMAX_BODY(uint64_t, CAT_NAN_NEVER); break;
|
|
609
|
+
case CA_FLOAT32: REDUCEAT_ARGMINMAX_BODY(float32_t, CAT_NAN_CHECK); break;
|
|
610
|
+
case CA_FLOAT64: REDUCEAT_ARGMINMAX_BODY(float64_t, CAT_NAN_CHECK); break;
|
|
571
611
|
default:
|
|
572
612
|
rb_raise(rb_eCADataTypeError,
|
|
573
613
|
"__reduceat_argminmax__: numeric value required (got data_type %d)",
|
|
@@ -631,6 +671,12 @@ static int
|
|
|
631
671
|
cmp_double (const void *a, const void *b)
|
|
632
672
|
{
|
|
633
673
|
double x = *(const double *) a, y = *(const double *) b;
|
|
674
|
+
/* NaN sorts last, which is where CArray's own sort puts it, so picking a
|
|
675
|
+
position out of the sorted segment gives the core's answer. A bare
|
|
676
|
+
< / > comparison returns 0 for every pair involving a NaN, which is not
|
|
677
|
+
a strict weak ordering and leaves qsort free to produce anything. */
|
|
678
|
+
if ( x != x ) return (y != y) ? 0 : 1;
|
|
679
|
+
if ( y != y ) return -1;
|
|
634
680
|
return (x < y) ? -1 : (x > y) ? 1 : 0;
|
|
635
681
|
}
|
|
636
682
|
|
|
@@ -648,13 +694,18 @@ cmp_double (const void *a, const void *b)
|
|
|
648
694
|
} \
|
|
649
695
|
if ( m == 0 ) { for ( t = 0; t < 5; t++ ) { outp[t][c] = 0.0; outm[t][c] = 1; } continue; } \
|
|
650
696
|
qsort(scratch, (size_t) m, sizeof(double), cmp_double); \
|
|
697
|
+
{ ca_size_t nnum = m; \
|
|
698
|
+
while ( nnum > 0 && scratch[nnum-1] != scratch[nnum-1] ) nnum--; \
|
|
651
699
|
for ( t = 0; t < 5; t++ ) { \
|
|
652
700
|
double f = (double) (m - 1) * P[t] / 100.0; \
|
|
653
701
|
ca_size_t ki = (ca_size_t) floor(f); \
|
|
654
702
|
double vlo = scratch[ki]; \
|
|
655
|
-
|
|
703
|
+
/* Clamp the upper neighbour into the numeric prefix: with NaN sorted \
|
|
704
|
+
last, a position whose neighbour is a NaN interpolates against \
|
|
705
|
+
itself, which is what the core answers. */ \
|
|
706
|
+
double vhi = (ki + 1 < nnum) ? scratch[ki+1] : vlo; \
|
|
656
707
|
outp[t][c] = vlo + (f - (double) ki) * (vhi - vlo); \
|
|
657
|
-
}
|
|
708
|
+
} } \
|
|
658
709
|
} \
|
|
659
710
|
} while (0)
|
|
660
711
|
|
|
@@ -847,8 +898,8 @@ rb_ca_reduceat_wsum_wmean (VALUE self, VALUE roffsets, VALUE rwg,
|
|
|
847
898
|
if ( countp[out_off] == 0 ) { \
|
|
848
899
|
minv[out_off] = v; maxv[out_off] = v; \
|
|
849
900
|
} else { \
|
|
850
|
-
if ( v
|
|
851
|
-
if ( v
|
|
901
|
+
if ( CA_EXTREMUM_REPLACES(v, minv[out_off], <) ) minv[out_off] = v;\
|
|
902
|
+
if ( CA_EXTREMUM_REPLACES(v, maxv[out_off], >) ) maxv[out_off] = v;\
|
|
852
903
|
} \
|
|
853
904
|
countp[out_off]++; \
|
|
854
905
|
sump[out_off] += (double) v; \
|
|
@@ -951,8 +1002,7 @@ rb_ca_fiber_scatter_moments (VALUE self, VALUE rcodes, VALUE raxis, VALUE rk,
|
|
|
951
1002
|
band_size = outer_prod * inner_prod;
|
|
952
1003
|
total = (ca_size_t)(K * band_size);
|
|
953
1004
|
|
|
954
|
-
|
|
955
|
-
ca_attach(codes);
|
|
1005
|
+
ca_attach_n(2, h, codes); /* window: detached before each raise inside */
|
|
956
1006
|
hm = ca_mask_ptr(h);
|
|
957
1007
|
cm = ca_mask_ptr(codes);
|
|
958
1008
|
countp = (int64_t *) counts->ptr;
|
|
@@ -1118,8 +1168,7 @@ rb_ca_fiber_scatter_prod (VALUE self, VALUE rcodes, VALUE raxis,
|
|
|
1118
1168
|
band_size = outer_prod * inner_prod;
|
|
1119
1169
|
total = (ca_size_t)(K * band_size);
|
|
1120
1170
|
|
|
1121
|
-
|
|
1122
|
-
ca_attach(codes);
|
|
1171
|
+
ca_attach_n(2, h, codes); /* window: detached before each raise inside */
|
|
1123
1172
|
hm = ca_mask_ptr(h);
|
|
1124
1173
|
cm = ca_mask_ptr(codes);
|
|
1125
1174
|
outp = (double *) out->ptr;
|
|
@@ -1227,6 +1276,7 @@ rb_ca_fiber_scatter_wsum_wmean (VALUE self, VALUE rcodes, VALUE rweights,
|
|
|
1227
1276
|
ca_size_t ax, inn, outer, cell;
|
|
1228
1277
|
ca_size_t axis_size, inner_prod, outer_prod, band_size, total;
|
|
1229
1278
|
double *wp, *wsp, *wsw, *wmp;
|
|
1279
|
+
volatile VALUE hwsw = 0, hcnt = 0;
|
|
1230
1280
|
boolean8_t *hm, *cm, *wm, *wmm;
|
|
1231
1281
|
int8_t i, j;
|
|
1232
1282
|
int64_t *cnt_scratch = NULL;
|
|
@@ -1287,9 +1337,7 @@ rb_ca_fiber_scatter_wsum_wmean (VALUE self, VALUE rcodes, VALUE rweights,
|
|
|
1287
1337
|
band_size = outer_prod * inner_prod;
|
|
1288
1338
|
total = (ca_size_t)(K * band_size);
|
|
1289
1339
|
|
|
1290
|
-
|
|
1291
|
-
ca_attach(codes);
|
|
1292
|
-
ca_attach(weights);
|
|
1340
|
+
ca_attach_n(3, h, codes, weights); /* window: detached before each raise inside */
|
|
1293
1341
|
hm = ca_mask_ptr(h);
|
|
1294
1342
|
cm = ca_mask_ptr(codes);
|
|
1295
1343
|
wm = ca_mask_ptr(weights);
|
|
@@ -1298,8 +1346,9 @@ rb_ca_fiber_scatter_wsum_wmean (VALUE self, VALUE rcodes, VALUE rweights,
|
|
|
1298
1346
|
wmp = (double *) wmean->ptr; /* wmean output (temp = sum-of-weights, then divide) */
|
|
1299
1347
|
|
|
1300
1348
|
/* Two auxiliary scratches: sum-of-weights (per cell) and present-pair count. */
|
|
1301
|
-
|
|
1302
|
-
|
|
1349
|
+
/* ALLOCV, so a raise below (codes of the wrong type) leaves nothing. */
|
|
1350
|
+
wsw = ALLOCV_N(double, hwsw, total);
|
|
1351
|
+
cnt_scratch = ALLOCV_N(int64_t, hcnt, total);
|
|
1303
1352
|
|
|
1304
1353
|
memset(wsp, 0, (size_t) total * sizeof(double));
|
|
1305
1354
|
memset(wsw, 0, (size_t) total * sizeof(double));
|
|
@@ -1318,7 +1367,7 @@ rb_ca_fiber_scatter_wsum_wmean (VALUE self, VALUE rcodes, VALUE rweights,
|
|
|
1318
1367
|
case CA_FLOAT32: FIBER_SCATTER_WSUM_DISPATCH_C(float32_t); break;
|
|
1319
1368
|
case CA_FLOAT64: FIBER_SCATTER_WSUM_DISPATCH_C(float64_t); break;
|
|
1320
1369
|
default:
|
|
1321
|
-
|
|
1370
|
+
ALLOCV_END(hwsw); ALLOCV_END(hcnt);
|
|
1322
1371
|
ca_detach(h); ca_detach(codes); ca_detach(weights);
|
|
1323
1372
|
rb_raise(rb_eCADataTypeError,
|
|
1324
1373
|
"__fiber_scatter_wsum_wmean__: numeric value required (got %d)",
|
|
@@ -1337,8 +1386,8 @@ rb_ca_fiber_scatter_wsum_wmean (VALUE self, VALUE rcodes, VALUE rweights,
|
|
|
1337
1386
|
}
|
|
1338
1387
|
}
|
|
1339
1388
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1389
|
+
ALLOCV_END(hwsw);
|
|
1390
|
+
ALLOCV_END(hcnt);
|
|
1342
1391
|
ca_detach(h);
|
|
1343
1392
|
ca_detach(codes);
|
|
1344
1393
|
ca_detach(weights);
|
data/ext/ca_compare.c
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
#include "ruby.h"
|
|
15
15
|
#include "carray.h"
|
|
16
16
|
#include "ca_compare.h"
|
|
17
|
+
#include "carray_internal.h" /* ca_obj_cmp, CA_OBJ_ISNAN */
|
|
17
18
|
#include <math.h>
|
|
18
19
|
|
|
19
20
|
#define DEFINE_ELEM_CMP(type) \
|
|
@@ -53,13 +54,18 @@ DEFINE_ELEM_CMP(uint64_t)
|
|
|
53
54
|
DEFINE_ELEM_CMP_FLOAT(float32_t)
|
|
54
55
|
DEFINE_ELEM_CMP_FLOAT(float64_t)
|
|
55
56
|
|
|
56
|
-
/* CA_OBJECT: compare
|
|
57
|
+
/* CA_OBJECT: compare by `<=>`, as sort orders object cells: a Float NaN
|
|
58
|
+
after every other value, and a pair `<=>` cannot order raises
|
|
59
|
+
"comparison of A with B failed". */
|
|
57
60
|
static int
|
|
58
61
|
elem_cmp_VALUE (const void *va, const void *vb)
|
|
59
62
|
{
|
|
60
63
|
const VALUE *a = (const VALUE *) va;
|
|
61
64
|
const VALUE *b = (const VALUE *) vb;
|
|
62
|
-
|
|
65
|
+
int nan_a = CA_OBJ_ISNAN(*a);
|
|
66
|
+
int nan_b = CA_OBJ_ISNAN(*b);
|
|
67
|
+
if ( nan_a || nan_b ) return nan_a - nan_b;
|
|
68
|
+
return ca_obj_cmp(*a, *b);
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
/* FIXLEN / retired / otherwise unorderable data_types: callers must handle
|
data/ext/ca_for_buffer.h
CHANGED
|
@@ -1,43 +1,33 @@
|
|
|
1
1
|
/* ---------------------------------------------------------------------------
|
|
2
2
|
*
|
|
3
|
-
* ca_for_buffer.h --
|
|
4
|
-
*
|
|
3
|
+
* ca_for_buffer.h -- whole contig buffer handed to author / third-party
|
|
4
|
+
* library
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* C-side counterpart of Ruby's `ca.attach! { |a| ... }` block: the
|
|
7
|
+
* attach / sync / detach lifecycle is scoped to a body function, which
|
|
8
|
+
* receives a contig buffer ptr and element count and may do whatever
|
|
9
|
+
* (typically pass the ptr to a third-party library: FFTW, akima init,
|
|
10
|
+
* fitpack surf1, ...).
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* The buffer aliases ca->ptr when the array is a contig entity and is a
|
|
13
|
+
* materialised scratch otherwise. A writable call syncs the buffer back
|
|
14
|
+
* to the array's storage when the body returns.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* CA_WITH_BUFFER_WRITABLE(ca, T, ptr, n)
|
|
21
|
-
* Writable; same ptr/n semantics, plus ca_sync on block exit so
|
|
22
|
-
* author writes propagate back to the view's storage.
|
|
16
|
+
* The body may raise. The view is closed however the body is left: a
|
|
17
|
+
* writable view is synced first, so what the body wrote before raising
|
|
18
|
+
* reaches the view's storage, and the view is detached even if that sync
|
|
19
|
+
* raises. The body's exception is the one that propagates.
|
|
23
20
|
*
|
|
24
21
|
* Author pattern:
|
|
25
22
|
*
|
|
26
|
-
*
|
|
27
|
-
* ca_size_t n
|
|
28
|
-
*
|
|
23
|
+
* static void
|
|
24
|
+
* fft_body (void *user_data, void *ptr, ca_size_t n)
|
|
25
|
+
* {
|
|
26
|
+
* fftw_plan plan = (fftw_plan) user_data;
|
|
29
27
|
* fftw_execute_dft(plan, ptr, ptr);
|
|
30
28
|
* }
|
|
31
29
|
*
|
|
32
|
-
*
|
|
33
|
-
* - `break;` from body exits cleanly (= outer for's advance clause
|
|
34
|
-
* runs ca_sync / ca_detach).
|
|
35
|
-
* - `return;` from body LEAKS the attach; restructure to break.
|
|
36
|
-
* - Macros are NOT statement-equivalent (= nested for); no trailing
|
|
37
|
-
* `else`.
|
|
38
|
-
* - For Ruby-exception-safe lifecycle (e.g. when calling Ruby code or
|
|
39
|
-
* anything that may raise from inside the body), use the function
|
|
40
|
-
* form `rb_ca_call_with_buffer` instead (= rb_ensure-protected).
|
|
30
|
+
* rb_ca_call_with_buffer(rca, 1, fft_body, plan);
|
|
41
31
|
*
|
|
42
32
|
* --------------------------------------------------------------------------- */
|
|
43
33
|
|
|
@@ -47,46 +37,9 @@
|
|
|
47
37
|
#include "carray.h"
|
|
48
38
|
#include "ca_sweep_engine.h"
|
|
49
39
|
|
|
50
|
-
/*
|
|
51
|
-
|
|
52
|
-
/* Read-only: ca_attach (alias-when-possible) + author body + ca_detach. */
|
|
53
|
-
#define CA_WITH_BUFFER(_ca, T, _ptr, _n) \
|
|
54
|
-
for ( CArray *__cwv_ca = (CArray *)(_ca); \
|
|
55
|
-
__cwv_ca; \
|
|
56
|
-
ca_detach(__cwv_ca), __cwv_ca = NULL ) \
|
|
57
|
-
for ( int __cwv_once = (ca_attach(__cwv_ca), \
|
|
58
|
-
(_ptr) = (T *)__cwv_ca->ptr, \
|
|
59
|
-
(_n) = __cwv_ca->elements, \
|
|
60
|
-
1); \
|
|
61
|
-
__cwv_once; \
|
|
62
|
-
__cwv_once = 0 )
|
|
63
|
-
|
|
64
|
-
/* Writable: same as above + ca_sync on block exit. */
|
|
65
|
-
#define CA_WITH_BUFFER_WRITABLE(_ca, T, _ptr, _n) \
|
|
66
|
-
for ( CArray *__cwvw_ca = (CArray *)(_ca); \
|
|
67
|
-
__cwvw_ca; \
|
|
68
|
-
ca_sync(__cwvw_ca), ca_detach(__cwvw_ca), __cwvw_ca = NULL ) \
|
|
69
|
-
for ( int __cwvw_once = (ca_attach(__cwvw_ca), \
|
|
70
|
-
(_ptr) = (T *)__cwvw_ca->ptr, \
|
|
71
|
-
(_n) = __cwvw_ca->elements, \
|
|
72
|
-
1); \
|
|
73
|
-
__cwvw_once; \
|
|
74
|
-
__cwvw_once = 0 )
|
|
75
|
-
|
|
76
|
-
/* ---------- function form (rb_ensure-protected, AC8) ----------
|
|
77
|
-
*
|
|
78
|
-
* Use this when the body may raise a Ruby exception (= calling rb_funcall,
|
|
79
|
-
* type-checking with rb_check_type, indirect Ruby code, etc.). The
|
|
80
|
-
* engine ca_attach's the view, runs body via rb_ensure, then guarantees
|
|
81
|
-
* ca_sync (if writable) and ca_detach run before the exception
|
|
82
|
-
* propagates.
|
|
83
|
-
*
|
|
84
|
-
* body_fn(user_data, ptr, n_elements) -> may raise
|
|
40
|
+
/* body_fn(user_data, ptr, n_elements) -> may raise
|
|
85
41
|
*
|
|
86
|
-
* Returns
|
|
87
|
-
* function itself returns Qnil since rb_ensure body must be VALUE).
|
|
88
|
-
* For richer return semantics, box your result in user_data.
|
|
89
|
-
*/
|
|
42
|
+
* Returns nothing; box a result in user_data. */
|
|
90
43
|
typedef void (*ca_with_buffer_body_fn) (void *user_data, void *ptr,
|
|
91
44
|
ca_size_t n_elements);
|
|
92
45
|
|
data/ext/ca_group_iter.c
CHANGED
|
@@ -40,10 +40,14 @@ static ID id_axis_group_reduce, id_reshape, id_transpose, id_labels;
|
|
|
40
40
|
static VALUE
|
|
41
41
|
rb_ca_register_axis_group_classes (VALUE klass, VALUE cat, VALUE ag)
|
|
42
42
|
{
|
|
43
|
+
static int registered = 0;
|
|
43
44
|
rb_cCategorical = cat;
|
|
44
45
|
rb_cAxisGroup = ag;
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
if ( ! registered ) { /* one GC root per address, not per call */
|
|
47
|
+
rb_gc_register_address(&rb_cCategorical);
|
|
48
|
+
rb_gc_register_address(&rb_cAxisGroup);
|
|
49
|
+
registered = 1;
|
|
50
|
+
}
|
|
47
51
|
return Qnil;
|
|
48
52
|
}
|
|
49
53
|
|
|
@@ -172,7 +176,7 @@ group_iter_shape_output (VALUE result, VALUE group_dims, VALUE perm, VALUE squee
|
|
|
172
176
|
nband = cr->ndim - 1;
|
|
173
177
|
nd = ng + nband;
|
|
174
178
|
if ( nd > CA_RANK_MAX ) {
|
|
175
|
-
rb_raise(
|
|
179
|
+
rb_raise(rb_eArgError, "axis_group: output ndim %ld too large", nd);
|
|
176
180
|
}
|
|
177
181
|
for ( i = 0; i < ng; i++ ) {
|
|
178
182
|
dims[i] = RARRAY_AREF(group_dims, i);
|
|
@@ -233,17 +237,19 @@ group_iter_reduce (int argc, VALUE *argv, VALUE self)
|
|
|
233
237
|
parsed = rb_funcall(rb_cAxisGroup, id_parse_axis,
|
|
234
238
|
1, (vaxis == Qundef) ? Qnil : vaxis);
|
|
235
239
|
if ( RTEST(RARRAY_AREF(parsed, 0)) == 0 ) {
|
|
236
|
-
/* no :group -> plain reduction on the value (grouping not engaged)
|
|
237
|
-
|
|
240
|
+
/* no :group -> plain reduction on the value (grouping not engaged),
|
|
241
|
+
with every keyword the caller gave */
|
|
242
|
+
if ( NIL_P(kw) ) {
|
|
238
243
|
return rb_funcall(value, op_id, 0);
|
|
239
244
|
}
|
|
240
|
-
|
|
241
|
-
VALUE h = rb_hash_new();
|
|
242
|
-
rb_hash_aset(h, ID2SYM(rb_intern("axis")), vaxis);
|
|
243
|
-
return rb_funcallv_kw(value, op_id, 1, &h, RB_PASS_KEYWORDS);
|
|
244
|
-
}
|
|
245
|
+
return rb_funcallv_kw(value, op_id, 1, &kw, RB_PASS_KEYWORDS);
|
|
245
246
|
}
|
|
246
247
|
|
|
248
|
+
/* min_count: / fill_value: are applied to the grouped result; any other
|
|
249
|
+
keyword is refused before the work is done. */
|
|
250
|
+
rb_funcall(rb_cAxisGroup, rb_intern("__check_reduce_keywords__"), 2,
|
|
251
|
+
op_sym, NIL_P(kw) ? rb_hash_new() : kw);
|
|
252
|
+
|
|
247
253
|
/* group reduction */
|
|
248
254
|
fused = RARRAY_AREF(parsed, 1);
|
|
249
255
|
plan = rb_funcall(spec, id_reduce_plan, 1, fused);
|
|
@@ -253,9 +259,19 @@ group_iter_reduce (int argc, VALUE *argv, VALUE self)
|
|
|
253
259
|
perm = RARRAY_AREF(plan, 3);
|
|
254
260
|
squeeze = RARRAY_AREF(plan, 4);
|
|
255
261
|
|
|
262
|
+
/* a count reads only the mask, so a payload the kernel cannot read
|
|
263
|
+
(object, fixlen, ...) is counted through a boolean stand-in */
|
|
264
|
+
if ( op_id == rb_intern("count") || op_id == rb_intern("count_not_masked") ) {
|
|
265
|
+
value = rb_funcall(rb_cAxisGroup, rb_intern("__count_stand_in__"), 1, value);
|
|
266
|
+
}
|
|
256
267
|
result = rb_funcall(value, id_axis_group_reduce, 3,
|
|
257
268
|
group_axes, bundles, op_sym);
|
|
258
|
-
|
|
269
|
+
result = group_iter_shape_output(result, group_dims, perm, squeeze);
|
|
270
|
+
if ( ! NIL_P(kw) ) {
|
|
271
|
+
result = rb_funcall(rb_cAxisGroup, rb_intern("__finish_reduction__"), 4,
|
|
272
|
+
self, op_sym, kw, result);
|
|
273
|
+
}
|
|
274
|
+
return result;
|
|
259
275
|
}
|
|
260
276
|
|
|
261
277
|
void
|