carray 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +2 -1
- data/CHANGELOG.md +845 -3
- data/{NEWS.md → CHANGELOG.v1.md} +1 -1
- data/README.md +33 -33
- data/carray.gemspec +12 -8
- data/ext/ca_axis_dispatch.c +33 -4
- data/ext/ca_axis_group.c +256 -114
- data/ext/ca_binop_dispatch.c +5 -6
- data/ext/ca_binop_dispatch.h +0 -7
- data/ext/ca_categorical_iterator.c +121 -67
- data/ext/ca_for_each_element.h +6 -8
- data/ext/ca_group_iter.c +1 -1
- data/ext/ca_kernel_iterator.c +386 -74
- data/ext/ca_kernel_iterator.h +145 -45
- data/ext/ca_obj_array.c +62 -20
- data/ext/ca_obj_bincmp.c +57 -27
- data/ext/ca_obj_binop.c +86 -30
- data/ext/ca_obj_block.c +4 -4
- data/ext/ca_obj_const_string.c +88 -27
- data/ext/ca_obj_face.c +104 -0
- data/ext/ca_obj_face.h +48 -1
- data/ext/ca_obj_fake.c +11 -0
- data/ext/ca_obj_fixlen_string.c +21 -6
- data/ext/ca_obj_grid.c +11 -3
- data/ext/ca_obj_meld.c +125 -22
- data/ext/ca_obj_moncmp.c +33 -14
- data/ext/ca_obj_monop.c +19 -7
- data/ext/ca_obj_object.c +107 -4
- data/ext/ca_obj_record.c +3 -1
- data/ext/ca_obj_refer.c +30 -6
- data/ext/ca_obj_roll.c +13 -5
- data/ext/ca_obj_select.c +49 -34
- data/ext/ca_obj_select_axis.c +16 -6
- data/ext/ca_obj_shift.c +3 -3
- data/ext/ca_obj_stack.c +3 -8
- data/ext/ca_obj_stride.c +178 -24
- data/ext/ca_obj_string.c +11 -5
- data/ext/ca_obj_tile.c +13 -5
- data/ext/ca_obj_time.c +3 -1
- data/ext/ca_obj_timedelta.c +3 -1
- data/ext/ca_obj_transpose.c +1 -1
- data/ext/ca_obj_triop.c +62 -23
- data/ext/ca_obj_window.c +94 -19
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +1 -5
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +5 -5
- data/ext/ca_sweep_engine.c +362 -155
- data/ext/ca_sweep_engine.h +39 -9
- data/ext/ca_transform_common.c +7 -0
- data/ext/carray.h +148 -132
- data/ext/carray_access.c +83 -49
- data/ext/carray_address_basis.c +590 -0
- data/ext/carray_bincount.c +8 -8
- data/ext/carray_broadcast.c +102 -9
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +2010 -335
- data/ext/carray_call_cfunc.h +153 -0
- data/ext/carray_cast.c +184 -72
- data/ext/carray_conversion.c +22 -22
- data/ext/carray_copy.c +67 -32
- data/ext/carray_core.c +140 -13
- data/ext/carray_count.c +10 -11
- data/ext/carray_element.c +7 -7
- data/ext/carray_factorize.c +72 -51
- data/ext/carray_hold.c +1 -1
- data/ext/carray_index_classifier.c +7 -21
- data/ext/carray_internal.h +36 -3
- data/ext/carray_kernels_bincmp.c +1 -0
- data/ext/carray_kernels_binop.c +320 -298
- data/ext/carray_kernels_init.c +1095 -0
- data/ext/carray_kernels_map.c +1 -0
- data/ext/carray_kernels_moncmp.c +1 -0
- data/ext/carray_kernels_monop.c +412 -411
- data/ext/carray_kernels_reduce_aggregate.c +256 -87
- data/ext/carray_kernels_reduce_boolean.c +1 -0
- data/ext/carray_kernels_reduce_cumulative.c +324 -54
- data/ext/carray_kernels_reduce_extreme.c +605 -58
- data/ext/carray_kernels_reduce_variance.c +1 -0
- data/ext/carray_kernels_scan.c +5 -4
- data/ext/carray_kernels_search.c +187 -106
- data/ext/carray_kernels_sort.c +1 -0
- data/ext/carray_kernels_triop.c +1 -0
- data/ext/carray_lazy.c +175 -5
- data/ext/carray_loop.c +7 -1
- data/ext/carray_mask.c +29 -13
- data/ext/carray_median_percentile.c +56 -1
- data/ext/carray_memory_view.c +46 -21
- data/ext/carray_operator.c +50 -53
- data/ext/carray_order.c +1 -1
- data/ext/carray_partition.c +4 -4
- data/ext/carray_random.c +391 -47
- data/ext/carray_scatter.c +1 -1
- data/ext/carray_slab.c +13 -0
- data/ext/carray_sort.c +22 -24
- data/ext/carray_sort_kernel.c +10 -10
- data/ext/carray_test.c +1 -1
- data/ext/extconf.rb +18 -0
- data/ext/mk_call_cfunc.rb +323 -145
- data/ext/mkkernel.rb +651 -129
- data/ext/ruby_carray.c +28 -17
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +14 -1
- data/lib/carray/axis_group.rb +84 -7
- data/lib/carray/basics.rb +63 -59
- data/lib/carray/bincount_nd.rb +12 -12
- data/lib/carray/block_iterator.rb +111 -25
- data/lib/carray/categorical.rb +154 -37
- data/lib/carray/categorical_iterator.rb +300 -151
- data/lib/carray/conditional.rb +14 -14
- data/lib/carray/const_string.rb +131 -27
- data/lib/carray/construct.rb +61 -0
- data/lib/carray/core_extensions.rb +62 -5
- data/lib/carray/data_type_extension.rb +21 -1
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +3 -3
- data/lib/carray/frame/convert.rb +1 -1
- data/lib/carray/frame/csv_parser.rb +11 -4
- data/lib/carray/frame/frame.rb +85 -21
- data/lib/carray/frame/group.rb +36 -3
- data/lib/carray/frame/io.rb +224 -15
- data/lib/carray/frame/records.rb +18 -4
- data/lib/carray/frame/sort.rb +1 -1
- data/lib/carray/frame/verbs.rb +32 -12
- data/lib/carray/fuse_source.rb +123 -0
- data/lib/carray/fusion.rb +218 -0
- data/lib/carray/histogram.rb +16 -16
- data/lib/carray/inspect.rb +43 -16
- data/lib/carray/iterator.rb +147 -3
- data/lib/carray/lazy.rb +88 -73
- data/lib/carray/mask_gap_fill.rb +3 -1
- data/lib/carray/meld_reduce.rb +2 -2
- data/lib/carray/methods/align_addr.rb +1 -1
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/is_in.rb +25 -14
- data/lib/carray/methods/locate_addr.rb +81 -3
- data/lib/carray/methods/mask_duplicates.rb +36 -2
- data/lib/carray/methods/meshgrid.rb +4 -5
- data/lib/carray/methods/mode.rb +2 -2
- data/lib/carray/methods/nunique.rb +23 -2
- data/lib/carray/methods/repeat.rb +110 -0
- data/lib/carray/methods/snap.rb +7 -2
- data/lib/carray/methods/unique.rb +44 -4
- data/lib/carray/methods/value_counts.rb +2 -2
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +0 -19
- data/lib/carray/slab_iterator.rb +77 -19
- data/lib/carray/string_operation_extension.rb +10 -6
- data/lib/carray/time.rb +906 -491
- data/lib/carray/window_iterator.rb +421 -27
- data/lib/carray.rb +7 -5
- data/yard-stubs/ca_obj_array.rb +385 -0
- data/yard-stubs/ca_obj_bitarray.rb +38 -0
- data/yard-stubs/ca_obj_bitfield.rb +43 -0
- data/yard-stubs/ca_obj_block.rb +68 -0
- data/yard-stubs/ca_obj_byte_swap.rb +56 -0
- data/yard-stubs/ca_obj_fake.rb +31 -0
- data/yard-stubs/ca_obj_farray.rb +32 -0
- data/yard-stubs/ca_obj_field.rb +45 -0
- data/yard-stubs/ca_obj_grid.rb +35 -0
- data/yard-stubs/ca_obj_refer.rb +72 -0
- data/yard-stubs/ca_obj_roll.rb +45 -0
- data/yard-stubs/ca_obj_shift.rb +43 -0
- data/yard-stubs/ca_obj_stride.rb +181 -0
- data/yard-stubs/ca_obj_tile.rb +29 -0
- data/yard-stubs/ca_obj_transpose.rb +40 -0
- data/yard-stubs/ca_obj_window.rb +57 -0
- data/yard-stubs/carray_access.rb +131 -0
- data/yard-stubs/carray_attribute.rb +246 -0
- data/yard-stubs/carray_broadcast.rb +37 -0
- data/yard-stubs/carray_cast.rb +489 -0
- data/yard-stubs/carray_class.rb +65 -0
- data/yard-stubs/carray_conversion.rb +76 -0
- data/yard-stubs/carray_copy.rb +79 -0
- data/yard-stubs/carray_core.rb +34 -0
- data/yard-stubs/carray_count.rb +84 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +228 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +1615 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +103 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +252 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +59 -0
- data/yard-stubs/carray_sort.rb +165 -0
- data/yard-stubs/carray_test.rb +85 -0
- data/yard-stubs/carray_undef.rb +64 -0
- data/yard-stubs/carray_utils.rb +97 -0
- data/yard-stubs/ruby_carray.rb +193 -0
- metadata +67 -10
- data/ext/ca_obj_unbound_repeat.c +0 -496
data/ext/ca_binop_dispatch.c
CHANGED
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
operands arrive at the common type. Two ops break the uniform rule:
|
|
15
15
|
|
|
16
16
|
QUO -- only has a CA_OBJECT kernel; both operands promoted to
|
|
17
|
-
CA_OBJECT regardless of input
|
|
17
|
+
CA_OBJECT regardless of input data types
|
|
18
18
|
IPOWER -- heterogeneous (left: float/cmplx preserved, right: int64);
|
|
19
|
-
output preserves left
|
|
19
|
+
output preserves left data type. See ca_op_ipower.c.
|
|
20
20
|
|
|
21
21
|
---------------------------------------------------------------------------- */
|
|
22
22
|
|
|
@@ -58,7 +58,6 @@ ca_binop_kernel_lookup_vv (uint16_t op_id, int8_t common_dt)
|
|
|
58
58
|
case CA_BINOP_AND: return ca_binop_and [common_dt];
|
|
59
59
|
case CA_BINOP_OR: return ca_binop_or [common_dt];
|
|
60
60
|
case CA_BINOP_XOR: return ca_binop_xor [common_dt];
|
|
61
|
-
case CA_BINOP_REMINDER: return ca_binop_reminder [common_dt];
|
|
62
61
|
default: return NULL;
|
|
63
62
|
}
|
|
64
63
|
}
|
|
@@ -107,8 +106,8 @@ ca_binop_kernel_input_data_types (uint16_t op_id, int8_t l_dt, int8_t r_dt,
|
|
|
107
106
|
int
|
|
108
107
|
ca_binop_is_trapping (uint16_t op_id, int8_t common_dt)
|
|
109
108
|
{
|
|
110
|
-
/* Integer DIV / MOD / QUO can SIGFPE on a zero divisor. Float
|
|
111
|
-
returns NaN/Inf and does NOT trap, so it is not classified
|
|
109
|
+
/* Integer DIV / MOD / QUO / FMOD can SIGFPE on a zero divisor. Float
|
|
110
|
+
DIV returns NaN/Inf and does NOT trap, so it is not classified
|
|
112
111
|
trapping. */
|
|
113
112
|
int is_integer = ( common_dt >= CA_INT8 && common_dt <= CA_UINT64 );
|
|
114
113
|
if ( ! is_integer ) return 0;
|
|
@@ -117,7 +116,7 @@ ca_binop_is_trapping (uint16_t op_id, int8_t common_dt)
|
|
|
117
116
|
case CA_BINOP_DIV:
|
|
118
117
|
case CA_BINOP_MOD:
|
|
119
118
|
case CA_BINOP_QUO:
|
|
120
|
-
case
|
|
119
|
+
case CA_BINOP_FMOD:
|
|
121
120
|
return 1;
|
|
122
121
|
default:
|
|
123
122
|
return 0;
|
data/ext/ca_binop_dispatch.h
CHANGED
|
@@ -80,12 +80,6 @@ enum {
|
|
|
80
80
|
CA_BINOP_OR = 25,
|
|
81
81
|
CA_BINOP_XOR = 26,
|
|
82
82
|
|
|
83
|
-
/* IEEE 754 remainder (round-half-to-even, distinct from MOD which
|
|
84
|
-
truncates toward zero via C99 fmod on the float branch). Integer
|
|
85
|
-
branch is identical to MOD (`%`). All numeric + object. Traps on
|
|
86
|
-
integer zero divisor, like MOD. */
|
|
87
|
-
CA_BINOP_REMINDER = 27,
|
|
88
|
-
|
|
89
83
|
CA_BINOP_COUNT
|
|
90
84
|
};
|
|
91
85
|
|
|
@@ -127,7 +121,6 @@ extern ca_binop_func_t ca_binop_minimum [CA_NTYPE];
|
|
|
127
121
|
extern ca_binop_func_t ca_binop_and [CA_NTYPE];
|
|
128
122
|
extern ca_binop_func_t ca_binop_or [CA_NTYPE];
|
|
129
123
|
extern ca_binop_func_t ca_binop_xor [CA_NTYPE];
|
|
130
|
-
extern ca_binop_func_t ca_binop_reminder [CA_NTYPE];
|
|
131
124
|
|
|
132
125
|
/* ------------------------------------------------------------------- */
|
|
133
126
|
/* Dispatch API */
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
kernel_iterator macros do not model, so the flat inputs are materialised here:
|
|
22
22
|
ca_attach aliases a contiguous entity (codes / a contiguous value) and gathers
|
|
23
23
|
a view. Codes dispatch on their native integer type (no coercion); the value
|
|
24
|
-
move is a bytes-wide memcpy (grouped shares the value
|
|
24
|
+
move is a bytes-wide memcpy (grouped shares the value data type, so no value-type
|
|
25
25
|
dispatch is needed).
|
|
26
26
|
|
|
27
27
|
Surface (private): codes.__categorical_scatter__(value, cursor, grouped, k)
|
|
28
28
|
self = codes (integer, carries the exclusion mask), read flat
|
|
29
|
-
value = payload (any
|
|
29
|
+
value = payload (any data type, may carry a mask), read flat, same length
|
|
30
30
|
cursor = int64 length-k segment starts (mutated in place, consumed)
|
|
31
|
-
grouped = pre-allocated contiguous entity of the value
|
|
31
|
+
grouped = pre-allocated contiguous entity of the value data type, length nvalid
|
|
32
32
|
k = number of categories
|
|
33
33
|
Returns grouped.
|
|
34
34
|
|
|
@@ -79,7 +79,7 @@ rb_ca_categorical_scatter (VALUE self, VALUE rvalue, VALUE rcursor,
|
|
|
79
79
|
rb_raise(rb_eArgError, "__categorical_scatter__: cursor must be int64[k]");
|
|
80
80
|
}
|
|
81
81
|
if ( grouped->bytes != bytes ) {
|
|
82
|
-
rb_raise(rb_eArgError, "__categorical_scatter__: grouped/value
|
|
82
|
+
rb_raise(rb_eArgError, "__categorical_scatter__: grouped/value data type mismatch");
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
ca_attach(codes);
|
|
@@ -127,18 +127,31 @@ rb_ca_categorical_scatter (VALUE self, VALUE rvalue, VALUE rcursor,
|
|
|
127
127
|
(empty / all-masked -> sum 0 identity, count 0, min/max masked).
|
|
128
128
|
|
|
129
129
|
Surface (private): grouped.__reduceat_moments__(offsets, counts, sums, mins, maxs)
|
|
130
|
-
self = grouped (numeric value
|
|
130
|
+
self = grouped (numeric value data type, may carry a mask), contiguous entity
|
|
131
131
|
offsets = int64[k] segment STARTS; segment c = [offsets[c], offsets[c+1]),
|
|
132
132
|
the last ends at grouped.elements
|
|
133
133
|
counts = int64[k] output: present (non-masked) cells per segment
|
|
134
134
|
sums = float64[k] output: sum per segment (0 for empty, unmasked)
|
|
135
|
-
mins/maxs = value-
|
|
135
|
+
mins/maxs = value-type[k] output: min / max per segment; the kernel masks
|
|
136
136
|
the empty/all-masked segments (no value to report)
|
|
137
137
|
Derived on the Ruby side: mean = sum/count, count_masked = sizes - count, etc.
|
|
138
138
|
|
|
139
139
|
--------------------------------------------------------------------------- */
|
|
140
140
|
|
|
141
|
-
#
|
|
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
|
+
|
|
154
|
+
#define REDUCEAT_MOMENTS_BODY(T, ISNAN) \
|
|
142
155
|
do { \
|
|
143
156
|
const T *gp = (const T *) grouped->ptr; \
|
|
144
157
|
T *minv = (T *) minp, *maxv = (T *) maxp; \
|
|
@@ -147,13 +160,17 @@ rb_ca_categorical_scatter (VALUE self, VALUE rvalue, VALUE rcursor,
|
|
|
147
160
|
ca_size_t hi = (c + 1 < k) ? (ca_size_t) offs[c+1] : n; \
|
|
148
161
|
ca_size_t j, cnt = 0; \
|
|
149
162
|
double sacc = 0.0; \
|
|
150
|
-
T mn = 0, mx = 0; int seen = 0;
|
|
163
|
+
T mn = 0, mx = 0; int seen = 0, seen_num = 0; \
|
|
151
164
|
for ( j = lo; j < hi; j++ ) { \
|
|
152
165
|
if ( gm && gm[j] ) continue; /* masked value cell */ \
|
|
153
166
|
{ T v = gp[j]; \
|
|
154
167
|
sacc += (double) v; \
|
|
155
|
-
if ( !
|
|
156
|
-
|
|
168
|
+
if ( ! ISNAN(v) ) { \
|
|
169
|
+
if ( ! seen_num ) { mn = v; mx = v; seen_num = 1; } \
|
|
170
|
+
else { if ( v < mn ) mn = v; if ( v > mx ) mx = v; } \
|
|
171
|
+
} \
|
|
172
|
+
else if ( ! seen ) { mn = v; mx = v; } /* held until a number lands */\
|
|
173
|
+
seen = 1; \
|
|
157
174
|
cnt++; } \
|
|
158
175
|
} \
|
|
159
176
|
countp[c] = (int64_t) cnt; \
|
|
@@ -190,7 +207,7 @@ rb_ca_reduceat_moments (VALUE self, VALUE roffsets, VALUE rcounts,
|
|
|
190
207
|
if ( counts->elements != k || sums->elements != k ||
|
|
191
208
|
mins->elements != k || maxs->elements != k ||
|
|
192
209
|
mins->data_type != grouped->data_type || maxs->data_type != grouped->data_type ) {
|
|
193
|
-
rb_raise(rb_eArgError, "__reduceat_moments__: output shape/
|
|
210
|
+
rb_raise(rb_eArgError, "__reduceat_moments__: output shape/data type mismatch");
|
|
194
211
|
}
|
|
195
212
|
|
|
196
213
|
offs = (int64_t *) offsets->ptr;
|
|
@@ -205,16 +222,16 @@ rb_ca_reduceat_moments (VALUE self, VALUE roffsets, VALUE rcounts,
|
|
|
205
222
|
maxm = (boolean8_t *) maxs->mask->ptr;
|
|
206
223
|
|
|
207
224
|
switch ( grouped->data_type ) {
|
|
208
|
-
case CA_INT8: REDUCEAT_MOMENTS_BODY(int8_t); break;
|
|
209
|
-
case CA_UINT8: REDUCEAT_MOMENTS_BODY(uint8_t); break;
|
|
210
|
-
case CA_INT16: REDUCEAT_MOMENTS_BODY(int16_t); break;
|
|
211
|
-
case CA_UINT16: REDUCEAT_MOMENTS_BODY(uint16_t); break;
|
|
212
|
-
case CA_INT32: REDUCEAT_MOMENTS_BODY(int32_t); break;
|
|
213
|
-
case CA_UINT32: REDUCEAT_MOMENTS_BODY(uint32_t); break;
|
|
214
|
-
case CA_INT64: REDUCEAT_MOMENTS_BODY(int64_t); break;
|
|
215
|
-
case CA_UINT64: REDUCEAT_MOMENTS_BODY(uint64_t); break;
|
|
216
|
-
case CA_FLOAT32: REDUCEAT_MOMENTS_BODY(float32_t); break;
|
|
217
|
-
case CA_FLOAT64: REDUCEAT_MOMENTS_BODY(float64_t); break;
|
|
225
|
+
case CA_INT8: REDUCEAT_MOMENTS_BODY(int8_t, CAT_NAN_NEVER); break;
|
|
226
|
+
case CA_UINT8: REDUCEAT_MOMENTS_BODY(uint8_t, CAT_NAN_NEVER); break;
|
|
227
|
+
case CA_INT16: REDUCEAT_MOMENTS_BODY(int16_t, CAT_NAN_NEVER); break;
|
|
228
|
+
case CA_UINT16: REDUCEAT_MOMENTS_BODY(uint16_t, CAT_NAN_NEVER); break;
|
|
229
|
+
case CA_INT32: REDUCEAT_MOMENTS_BODY(int32_t, CAT_NAN_NEVER); break;
|
|
230
|
+
case CA_UINT32: REDUCEAT_MOMENTS_BODY(uint32_t, CAT_NAN_NEVER); break;
|
|
231
|
+
case CA_INT64: REDUCEAT_MOMENTS_BODY(int64_t, CAT_NAN_NEVER); break;
|
|
232
|
+
case CA_UINT64: REDUCEAT_MOMENTS_BODY(uint64_t, CAT_NAN_NEVER); break;
|
|
233
|
+
case CA_FLOAT32: REDUCEAT_MOMENTS_BODY(float32_t, CAT_NAN_CHECK); break;
|
|
234
|
+
case CA_FLOAT64: REDUCEAT_MOMENTS_BODY(float64_t, CAT_NAN_CHECK); break;
|
|
218
235
|
default:
|
|
219
236
|
rb_raise(rb_eCADataTypeError,
|
|
220
237
|
"__reduceat_moments__: numeric value required (got data_type %d)",
|
|
@@ -235,7 +252,7 @@ rb_ca_reduceat_moments (VALUE self, VALUE roffsets, VALUE rcounts,
|
|
|
235
252
|
(f = (m-1)*p/100, k = floor(f), lo + (f-k)*(hi-lo)). No per-segment view.
|
|
236
253
|
|
|
237
254
|
Surface (private): grouped.__reduceat_percentile__(offsets, p, out)
|
|
238
|
-
self = grouped (numeric value
|
|
255
|
+
self = grouped (numeric value data type, may carry a mask)
|
|
239
256
|
offsets = int64[k] segment STARTS (last ends at grouped.elements)
|
|
240
257
|
p = percentile in 0..100 (median = 50, quantile(q) = q*100)
|
|
241
258
|
out = float64[k] output; empty / all-masked segments are masked
|
|
@@ -278,11 +295,27 @@ ca_nth_element_double (double *a, ca_size_t n, ca_size_t kth)
|
|
|
278
295
|
{ double f = (double) (m - 1) * p / 100.0; \
|
|
279
296
|
ca_size_t ki = (ca_size_t) floor(f); \
|
|
280
297
|
double vlo, vhi; \
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
298
|
+
/* Push NaN to the tail, which is where CArray's sort puts it, so the \
|
|
299
|
+
ki-th element here is the ki-th of the sorted segment. Selection \
|
|
300
|
+
runs on the numeric prefix, since a comparison-based quickselect \
|
|
301
|
+
has nothing to say about a NaN, and a position landing in the tail \
|
|
302
|
+
answers NaN. The upper neighbour is clamped into the prefix too: a \
|
|
303
|
+
position whose neighbour would be a NaN interpolates against itself \
|
|
304
|
+
and answers vlo, which is why the median of [NaN, -9.0] is -9.0. */ \
|
|
305
|
+
ca_size_t nnum = m, t0 = 0; \
|
|
306
|
+
while ( t0 < nnum ) { \
|
|
307
|
+
if ( scratch[t0] != scratch[t0] ) { \
|
|
308
|
+
double tmp = scratch[--nnum]; \
|
|
309
|
+
scratch[nnum] = scratch[t0]; scratch[t0] = tmp; \
|
|
310
|
+
} else t0++; \
|
|
311
|
+
} \
|
|
312
|
+
if ( ki < nnum ) { \
|
|
313
|
+
ca_nth_element_double(scratch, nnum, ki); /* scratch[ki] = ki-th */ \
|
|
314
|
+
vlo = scratch[ki]; \
|
|
315
|
+
} else vlo = (double) NAN; \
|
|
316
|
+
if ( ki + 1 < nnum ) { /* (ki+1)-th = min of upper partition */ \
|
|
284
317
|
double mn = scratch[ki+1]; ca_size_t t; \
|
|
285
|
-
for ( t = ki + 2; t <
|
|
318
|
+
for ( t = ki + 2; t < nnum; t++ ) if ( scratch[t] < mn ) mn = scratch[t]; \
|
|
286
319
|
vhi = mn; \
|
|
287
320
|
} else vhi = vlo; \
|
|
288
321
|
outp[c] = vlo + (f - (double) ki) * (vhi - vlo); } \
|
|
@@ -354,7 +387,7 @@ rb_ca_reduceat_percentile (VALUE self, VALUE roffsets, VALUE rp, VALUE rout)
|
|
|
354
387
|
SS / (count-1).
|
|
355
388
|
|
|
356
389
|
Surface (private): grouped.__reduceat_variance__(offsets, means, counts, out)
|
|
357
|
-
self = grouped (numeric value
|
|
390
|
+
self = grouped (numeric value data type, may carry a mask)
|
|
358
391
|
offsets = int64[k] segment STARTS
|
|
359
392
|
means = float64[k] per-segment mean (ignored where count < 2)
|
|
360
393
|
counts = int64[k] per-segment present count
|
|
@@ -510,7 +543,7 @@ rb_ca_reduceat_prod (VALUE self, VALUE roffsets, VALUE rout)
|
|
|
510
543
|
/* __reduceat_argminmax__(offsets, min_idx, max_idx) — per-segment GROUP-LOCAL
|
|
511
544
|
index of the min / max (position within the segment, first occurrence on
|
|
512
545
|
ties). Empty / all-masked segments are masked. */
|
|
513
|
-
#define REDUCEAT_ARGMINMAX_BODY(T)
|
|
546
|
+
#define REDUCEAT_ARGMINMAX_BODY(T, ISNAN) \
|
|
514
547
|
do { \
|
|
515
548
|
const T *gp = (const T *) grouped->ptr; \
|
|
516
549
|
for ( c = 0; c < k; c++ ) { \
|
|
@@ -520,10 +553,13 @@ rb_ca_reduceat_prod (VALUE self, VALUE roffsets, VALUE rout)
|
|
|
520
553
|
for ( j = lo; j < hi; j++ ) { \
|
|
521
554
|
if ( gm && gm[j] ) continue; \
|
|
522
555
|
{ T v = gp[j]; ca_size_t li = j - lo; \
|
|
556
|
+
if ( ISNAN(v) ) continue; /* wins no contest, so marks no position */\
|
|
523
557
|
if ( ! seen ) { mn = mx = v; mni = mxi = li; seen = 1; } \
|
|
524
558
|
else { if ( v < mn ) { mn = v; mni = li; } \
|
|
525
559
|
if ( v > mx ) { mx = v; mxi = li; } } } \
|
|
526
560
|
} \
|
|
561
|
+
/* A segment of nothing but NaN has no position to report, the same as a \
|
|
562
|
+
segment with no present cell at all -- both are UNDEF, as in the core.*/\
|
|
527
563
|
if ( seen ) { minp[c] = (int64_t) mni; maxp[c] = (int64_t) mxi; } \
|
|
528
564
|
else { minp[c] = 0; maxp[c] = 0; minm[c] = 1; maxm[c] = 1; } \
|
|
529
565
|
} \
|
|
@@ -558,16 +594,16 @@ rb_ca_reduceat_argminmax (VALUE self, VALUE roffsets, VALUE rminidx, VALUE rmaxi
|
|
|
558
594
|
maxm = (boolean8_t *) maxidx->mask->ptr;
|
|
559
595
|
|
|
560
596
|
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;
|
|
597
|
+
case CA_INT8: REDUCEAT_ARGMINMAX_BODY(int8_t, CAT_NAN_NEVER); break;
|
|
598
|
+
case CA_UINT8: REDUCEAT_ARGMINMAX_BODY(uint8_t, CAT_NAN_NEVER); break;
|
|
599
|
+
case CA_INT16: REDUCEAT_ARGMINMAX_BODY(int16_t, CAT_NAN_NEVER); break;
|
|
600
|
+
case CA_UINT16: REDUCEAT_ARGMINMAX_BODY(uint16_t, CAT_NAN_NEVER); break;
|
|
601
|
+
case CA_INT32: REDUCEAT_ARGMINMAX_BODY(int32_t, CAT_NAN_NEVER); break;
|
|
602
|
+
case CA_UINT32: REDUCEAT_ARGMINMAX_BODY(uint32_t, CAT_NAN_NEVER); break;
|
|
603
|
+
case CA_INT64: REDUCEAT_ARGMINMAX_BODY(int64_t, CAT_NAN_NEVER); break;
|
|
604
|
+
case CA_UINT64: REDUCEAT_ARGMINMAX_BODY(uint64_t, CAT_NAN_NEVER); break;
|
|
605
|
+
case CA_FLOAT32: REDUCEAT_ARGMINMAX_BODY(float32_t, CAT_NAN_CHECK); break;
|
|
606
|
+
case CA_FLOAT64: REDUCEAT_ARGMINMAX_BODY(float64_t, CAT_NAN_CHECK); break;
|
|
571
607
|
default:
|
|
572
608
|
rb_raise(rb_eCADataTypeError,
|
|
573
609
|
"__reduceat_argminmax__: numeric value required (got data_type %d)",
|
|
@@ -577,7 +613,7 @@ rb_ca_reduceat_argminmax (VALUE self, VALUE roffsets, VALUE rminidx, VALUE rmaxi
|
|
|
577
613
|
}
|
|
578
614
|
|
|
579
615
|
/* __reduceat_all_any__(offsets, all_out, any_out) — per-segment boolean AND / OR
|
|
580
|
-
over present cells. Value
|
|
616
|
+
over present cells. Value data type must be boolean. Empty segment: all -> true,
|
|
581
617
|
any -> false. */
|
|
582
618
|
static VALUE
|
|
583
619
|
rb_ca_reduceat_all_any (VALUE self, VALUE roffsets, VALUE rall, VALUE rany)
|
|
@@ -631,6 +667,12 @@ static int
|
|
|
631
667
|
cmp_double (const void *a, const void *b)
|
|
632
668
|
{
|
|
633
669
|
double x = *(const double *) a, y = *(const double *) b;
|
|
670
|
+
/* NaN sorts last, which is where CArray's own sort puts it, so picking a
|
|
671
|
+
position out of the sorted segment gives the core's answer. A bare
|
|
672
|
+
< / > comparison returns 0 for every pair involving a NaN, which is not
|
|
673
|
+
a strict weak ordering and leaves qsort free to produce anything. */
|
|
674
|
+
if ( x != x ) return (y != y) ? 0 : 1;
|
|
675
|
+
if ( y != y ) return -1;
|
|
634
676
|
return (x < y) ? -1 : (x > y) ? 1 : 0;
|
|
635
677
|
}
|
|
636
678
|
|
|
@@ -648,13 +690,18 @@ cmp_double (const void *a, const void *b)
|
|
|
648
690
|
} \
|
|
649
691
|
if ( m == 0 ) { for ( t = 0; t < 5; t++ ) { outp[t][c] = 0.0; outm[t][c] = 1; } continue; } \
|
|
650
692
|
qsort(scratch, (size_t) m, sizeof(double), cmp_double); \
|
|
693
|
+
{ ca_size_t nnum = m; \
|
|
694
|
+
while ( nnum > 0 && scratch[nnum-1] != scratch[nnum-1] ) nnum--; \
|
|
651
695
|
for ( t = 0; t < 5; t++ ) { \
|
|
652
696
|
double f = (double) (m - 1) * P[t] / 100.0; \
|
|
653
697
|
ca_size_t ki = (ca_size_t) floor(f); \
|
|
654
698
|
double vlo = scratch[ki]; \
|
|
655
|
-
|
|
699
|
+
/* Clamp the upper neighbour into the numeric prefix: with NaN sorted \
|
|
700
|
+
last, a position whose neighbour is a NaN interpolates against \
|
|
701
|
+
itself, which is what the core answers. */ \
|
|
702
|
+
double vhi = (ki + 1 < nnum) ? scratch[ki+1] : vlo; \
|
|
656
703
|
outp[t][c] = vlo + (f - (double) ki) * (vhi - vlo); \
|
|
657
|
-
}
|
|
704
|
+
} } \
|
|
658
705
|
} \
|
|
659
706
|
} while (0)
|
|
660
707
|
|
|
@@ -817,12 +864,12 @@ rb_ca_reduceat_wsum_wmean (VALUE self, VALUE roffsets, VALUE rwg,
|
|
|
817
864
|
counts_out = int64, shape [K, ...H.band] (present cells per group)
|
|
818
865
|
sums_out = float64, shape [K, ...H.band] (per-group sum, 0 for empty)
|
|
819
866
|
|
|
820
|
-
Sums as float64 mirrors __reduceat_moments__; Ruby side casts to h
|
|
821
|
-
#sum (matches existing empty→0 identity contract). Mins/maxs are in h
|
|
867
|
+
Sums as float64 mirrors __reduceat_moments__; Ruby side casts to h data type in
|
|
868
|
+
#sum (matches existing empty→0 identity contract). Mins/maxs are in h data type
|
|
822
869
|
(empty group cell → 0 + masked, matching __reduceat_moments__).
|
|
823
870
|
--------------------------------------------------------------------------- */
|
|
824
871
|
|
|
825
|
-
#define FIBER_SCATTER_BODY(H_T, C_T)
|
|
872
|
+
#define FIBER_SCATTER_BODY(H_T, C_T, ISNAN) \
|
|
826
873
|
do { \
|
|
827
874
|
const H_T *hp = (const H_T *) h->ptr; \
|
|
828
875
|
const C_T *cp = (const C_T *) codes->ptr; \
|
|
@@ -844,11 +891,18 @@ rb_ca_reduceat_wsum_wmean (VALUE self, VALUE roffsets, VALUE rwg,
|
|
|
844
891
|
if ( c < 0 || c >= K ) continue; /* out-of-vocabulary */ \
|
|
845
892
|
out_off = c * band_size + out_outer + inn; \
|
|
846
893
|
v = hp[off]; \
|
|
894
|
+
/* NaN loses every contest, as in the flat twin and the core. min \
|
|
895
|
+
and max are seeded together and only ever move on a number, so a \
|
|
896
|
+
NaN sitting in min means this cell has met nothing but NaN yet. */\
|
|
847
897
|
if ( countp[out_off] == 0 ) { \
|
|
848
898
|
minv[out_off] = v; maxv[out_off] = v; \
|
|
849
|
-
} else {
|
|
850
|
-
if (
|
|
851
|
-
|
|
899
|
+
} else if ( ! ISNAN(v) ) { \
|
|
900
|
+
if ( ISNAN(minv[out_off]) ) { \
|
|
901
|
+
minv[out_off] = v; maxv[out_off] = v; \
|
|
902
|
+
} else { \
|
|
903
|
+
if ( v < minv[out_off] ) minv[out_off] = v; \
|
|
904
|
+
if ( v > maxv[out_off] ) maxv[out_off] = v; \
|
|
905
|
+
} \
|
|
852
906
|
} \
|
|
853
907
|
countp[out_off]++; \
|
|
854
908
|
sump[out_off] += (double) v; \
|
|
@@ -857,16 +911,16 @@ rb_ca_reduceat_wsum_wmean (VALUE self, VALUE roffsets, VALUE rwg,
|
|
|
857
911
|
} \
|
|
858
912
|
} while (0)
|
|
859
913
|
|
|
860
|
-
#define FIBER_SCATTER_DISPATCH_C(H_T)
|
|
914
|
+
#define FIBER_SCATTER_DISPATCH_C(H_T, ISNAN) \
|
|
861
915
|
switch ( codes->data_type ) { \
|
|
862
|
-
case CA_INT8: FIBER_SCATTER_BODY(H_T, int8_t); break; \
|
|
863
|
-
case CA_UINT8: FIBER_SCATTER_BODY(H_T, uint8_t); break; \
|
|
864
|
-
case CA_INT16: FIBER_SCATTER_BODY(H_T, int16_t); break; \
|
|
865
|
-
case CA_UINT16: FIBER_SCATTER_BODY(H_T, uint16_t); break; \
|
|
866
|
-
case CA_INT32: FIBER_SCATTER_BODY(H_T, int32_t); break; \
|
|
867
|
-
case CA_UINT32: FIBER_SCATTER_BODY(H_T, uint32_t); break; \
|
|
868
|
-
case CA_INT64: FIBER_SCATTER_BODY(H_T, int64_t); break; \
|
|
869
|
-
case CA_UINT64: FIBER_SCATTER_BODY(H_T, uint64_t); break; \
|
|
916
|
+
case CA_INT8: FIBER_SCATTER_BODY(H_T, int8_t, ISNAN); break; \
|
|
917
|
+
case CA_UINT8: FIBER_SCATTER_BODY(H_T, uint8_t, ISNAN); break; \
|
|
918
|
+
case CA_INT16: FIBER_SCATTER_BODY(H_T, int16_t, ISNAN); break; \
|
|
919
|
+
case CA_UINT16: FIBER_SCATTER_BODY(H_T, uint16_t, ISNAN); break; \
|
|
920
|
+
case CA_INT32: FIBER_SCATTER_BODY(H_T, int32_t, ISNAN); break; \
|
|
921
|
+
case CA_UINT32: FIBER_SCATTER_BODY(H_T, uint32_t, ISNAN); break; \
|
|
922
|
+
case CA_INT64: FIBER_SCATTER_BODY(H_T, int64_t, ISNAN); break; \
|
|
923
|
+
case CA_UINT64: FIBER_SCATTER_BODY(H_T, uint64_t, ISNAN); break; \
|
|
870
924
|
default: \
|
|
871
925
|
ca_detach(h); ca_detach(codes); \
|
|
872
926
|
rb_raise(rb_eCADataTypeError, \
|
|
@@ -921,7 +975,7 @@ rb_ca_fiber_scatter_moments (VALUE self, VALUE rcodes, VALUE raxis, VALUE rk,
|
|
|
921
975
|
}
|
|
922
976
|
if ( mins->data_type != h->data_type || maxs->data_type != h->data_type ) {
|
|
923
977
|
rb_raise(rb_eArgError,
|
|
924
|
-
"__fiber_scatter_moments__: mins/maxs must match h
|
|
978
|
+
"__fiber_scatter_moments__: mins/maxs must match h data type");
|
|
925
979
|
}
|
|
926
980
|
if ( counts->ndim != h->ndim || sums->ndim != h->ndim ||
|
|
927
981
|
mins->ndim != h->ndim || maxs->ndim != h->ndim ||
|
|
@@ -966,16 +1020,16 @@ rb_ca_fiber_scatter_moments (VALUE self, VALUE rcodes, VALUE raxis, VALUE rk,
|
|
|
966
1020
|
memset(maxp, 0, (size_t) total * (size_t) h->bytes);
|
|
967
1021
|
|
|
968
1022
|
switch ( h->data_type ) {
|
|
969
|
-
case CA_INT8: FIBER_SCATTER_DISPATCH_C(int8_t); break;
|
|
970
|
-
case CA_UINT8: FIBER_SCATTER_DISPATCH_C(uint8_t); break;
|
|
971
|
-
case CA_INT16: FIBER_SCATTER_DISPATCH_C(int16_t); break;
|
|
972
|
-
case CA_UINT16: FIBER_SCATTER_DISPATCH_C(uint16_t); break;
|
|
973
|
-
case CA_INT32: FIBER_SCATTER_DISPATCH_C(int32_t); break;
|
|
974
|
-
case CA_UINT32: FIBER_SCATTER_DISPATCH_C(uint32_t); break;
|
|
975
|
-
case CA_INT64: FIBER_SCATTER_DISPATCH_C(int64_t); break;
|
|
976
|
-
case CA_UINT64: FIBER_SCATTER_DISPATCH_C(uint64_t); break;
|
|
977
|
-
case CA_FLOAT32: FIBER_SCATTER_DISPATCH_C(float32_t); break;
|
|
978
|
-
case CA_FLOAT64: FIBER_SCATTER_DISPATCH_C(float64_t); break;
|
|
1023
|
+
case CA_INT8: FIBER_SCATTER_DISPATCH_C(int8_t, CAT_NAN_NEVER); break;
|
|
1024
|
+
case CA_UINT8: FIBER_SCATTER_DISPATCH_C(uint8_t, CAT_NAN_NEVER); break;
|
|
1025
|
+
case CA_INT16: FIBER_SCATTER_DISPATCH_C(int16_t, CAT_NAN_NEVER); break;
|
|
1026
|
+
case CA_UINT16: FIBER_SCATTER_DISPATCH_C(uint16_t, CAT_NAN_NEVER); break;
|
|
1027
|
+
case CA_INT32: FIBER_SCATTER_DISPATCH_C(int32_t, CAT_NAN_NEVER); break;
|
|
1028
|
+
case CA_UINT32: FIBER_SCATTER_DISPATCH_C(uint32_t, CAT_NAN_NEVER); break;
|
|
1029
|
+
case CA_INT64: FIBER_SCATTER_DISPATCH_C(int64_t, CAT_NAN_NEVER); break;
|
|
1030
|
+
case CA_UINT64: FIBER_SCATTER_DISPATCH_C(uint64_t, CAT_NAN_NEVER); break;
|
|
1031
|
+
case CA_FLOAT32: FIBER_SCATTER_DISPATCH_C(float32_t, CAT_NAN_CHECK); break;
|
|
1032
|
+
case CA_FLOAT64: FIBER_SCATTER_DISPATCH_C(float64_t, CAT_NAN_CHECK); break;
|
|
979
1033
|
default:
|
|
980
1034
|
ca_detach(h); ca_detach(codes);
|
|
981
1035
|
rb_raise(rb_eCADataTypeError,
|
data/ext/ca_for_each_element.h
CHANGED
|
@@ -125,8 +125,9 @@ typedef struct {
|
|
|
125
125
|
* inner : per-cell loop within chunk_n
|
|
126
126
|
*
|
|
127
127
|
* Memory peak per AC2: INPUT non-alias views materialise into a single
|
|
128
|
-
* chunk scratch (~32KB at f64). m0 (= masked form) is
|
|
129
|
-
*
|
|
128
|
+
* chunk scratch (~32KB at f64). m0 (= masked form) is chunk-sized too and
|
|
129
|
+
* re-gathered per chunk, so the macro reads at m0[k] -- indexed within the
|
|
130
|
+
* chunk, not by the flat cell index.
|
|
130
131
|
*
|
|
131
132
|
* For MASKED forms (m / m_in / m_out): when source has no mask, m0 is
|
|
132
133
|
* NULL and m / m_in == 0 always. m_out writes during INOUT_MASKED are
|
|
@@ -162,8 +163,7 @@ typedef struct {
|
|
|
162
163
|
&& (((x) = *(T *)((_st1).core.base[0] \
|
|
163
164
|
+ __cfem_k * (_st1).core.stride[0])), \
|
|
164
165
|
((m) = (_st1).core.m0 \
|
|
165
|
-
? (_st1).core.m0[
|
|
166
|
-
+ __cfem_k] \
|
|
166
|
+
? (_st1).core.m0[__cfem_k] \
|
|
167
167
|
: (boolean8_t)0), \
|
|
168
168
|
1); \
|
|
169
169
|
__cfem_k++ )
|
|
@@ -211,16 +211,14 @@ typedef struct {
|
|
|
211
211
|
&& (((in) = *(T_IN *)((_st2).core.base[0] \
|
|
212
212
|
+ __cfeim_k * (_st2).core.stride[0])), \
|
|
213
213
|
((m_in) = (_st2).core.m0 \
|
|
214
|
-
? (_st2).core.m0[
|
|
215
|
-
+ __cfeim_k] \
|
|
214
|
+
? (_st2).core.m0[__cfeim_k] \
|
|
216
215
|
: (boolean8_t)0), \
|
|
217
216
|
((m_out) = (m_in)), \
|
|
218
217
|
1); \
|
|
219
218
|
(*(T_OUT *)((_st2).core.base[1] \
|
|
220
219
|
+ __cfeim_k * (_st2).core.stride[1]) = (out)), \
|
|
221
220
|
(((_st2).core.m0) \
|
|
222
|
-
? ((_st2).core.m0[(
|
|
223
|
-
= (m_out)) \
|
|
221
|
+
? ((_st2).core.m0[__cfeim_k] = (m_out)) \
|
|
224
222
|
: (boolean8_t)0), \
|
|
225
223
|
__cfeim_k++ )
|
|
226
224
|
|
data/ext/ca_group_iter.c
CHANGED
|
@@ -292,7 +292,7 @@ Init_ca_group_iter (void)
|
|
|
292
292
|
address of the extremum (there is no group-local min_index for the group
|
|
293
293
|
iterator -- the order-preserving flat address is the meaningful position). */
|
|
294
294
|
{
|
|
295
|
-
const char *ops[] = { "sum", "prod", "mean", "min", "max",
|
|
295
|
+
const char *ops[] = { "sum", "accumulate", "prod", "mean", "min", "max",
|
|
296
296
|
"variance", "stddev", "variancep", "stddevp",
|
|
297
297
|
"count", "count_not_masked", "min_addr", "max_addr",
|
|
298
298
|
"all", "any", NULL };
|