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,3909 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
carray_kernels.c -- GENERATED by ext/mkkernel.rb -- DO NOT EDIT
|
|
4
|
+
|
|
5
|
+
Kernel definitions live in mkkernel.rb (search for `MkKernel.reduce`).
|
|
6
|
+
Regenerate by running:
|
|
7
|
+
|
|
8
|
+
cd ext && ruby mkkernel.rb > carray_kernels.c
|
|
9
|
+
|
|
10
|
+
extconf.rb regenerates automatically when mkkernel.rb is touched.
|
|
11
|
+
|
|
12
|
+
--------------------------------------------------------------------------- */
|
|
13
|
+
|
|
14
|
+
#include "carray.h"
|
|
15
|
+
#include "ca_kernel_iterator.h"
|
|
16
|
+
#include "ca_sort_kernels.h" /* sort kernels: internal, not via the carray.h umbrella */
|
|
17
|
+
#include "carray_internal.h" /* ca_lazy_arena_*, ca_is_lazy_view (streaming reduce) */
|
|
18
|
+
#include "ca_obj_face.h" /* rb_ca_strip_face_value (Face ordering gate) */
|
|
19
|
+
#include <math.h>
|
|
20
|
+
#include <stdint.h>
|
|
21
|
+
#include <stdlib.h> /* qsort, mergesort (HAVE_MERGESORT) -- for :sort kind */
|
|
22
|
+
|
|
23
|
+
/* MEMO_REDUCTION_FASTPATH_ENTITY_ONLY_GUARD Tier 2: CAStack identity is
|
|
24
|
+
probed by operation-table function pointer (obj_type is runtime-
|
|
25
|
+
assigned, so no CA_OBJ_STACK compile-time constant exists). */
|
|
26
|
+
extern ca_operation_function_t ca_stack_func;
|
|
27
|
+
/* BOOL2VAL: bool -> Ruby (Qtrue/Qfalse). Used as ruby_scalar wrapper
|
|
28
|
+
for the all/any flat-reduction Ruby surface so `a.all` / `a.any`
|
|
29
|
+
return real true/false, not Integer 0/1. (BOOL2OBJ already exists
|
|
30
|
+
but returns Integer per CArray's boolean-as-int convention.) */
|
|
31
|
+
#ifndef CARRAY_BOOL2VAL_DEFINED
|
|
32
|
+
#define CARRAY_BOOL2VAL_DEFINED
|
|
33
|
+
static inline VALUE BOOL2VAL (boolean8_t x) { return x ? Qtrue : Qfalse; }
|
|
34
|
+
#endif
|
|
35
|
+
|
|
36
|
+
#include "ca_op_powi.h"
|
|
37
|
+
|
|
38
|
+
/* ===== variancep_ki ============================================ */
|
|
39
|
+
|
|
40
|
+
#define __variancep_i8_P1EXPR(__x) ((double)(__x))
|
|
41
|
+
#define __variancep_i8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
42
|
+
static VALUE
|
|
43
|
+
variancep_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
44
|
+
{
|
|
45
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
46
|
+
CArray *co;
|
|
47
|
+
GetCArray(vout, co);
|
|
48
|
+
double *op = (double *) co->ptr;
|
|
49
|
+
ca_iter_state st;
|
|
50
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
51
|
+
slab_axes, naxes, 0);
|
|
52
|
+
if ( rc != CA_ITER_OK ) {
|
|
53
|
+
rb_raise(rb_eRuntimeError,
|
|
54
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
55
|
+
}
|
|
56
|
+
char *p;
|
|
57
|
+
boolean8_t *m;
|
|
58
|
+
ca_size_t out_i = 0;
|
|
59
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
60
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
61
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
62
|
+
double sum = 0.0;
|
|
63
|
+
ca_size_t masked_cnt = 0;
|
|
64
|
+
CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, sum, 0.0, __variancep_i8_P1EXPR, masked_cnt);
|
|
65
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
66
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
67
|
+
if ( __trigger ) {
|
|
68
|
+
if ( ! op_mask ) {
|
|
69
|
+
ca_create_mask(co);
|
|
70
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
71
|
+
}
|
|
72
|
+
op_mask[out_i] = 1;
|
|
73
|
+
op[out_i++] = (double) 0.0;
|
|
74
|
+
} else if ( n_valid < 1 ) {
|
|
75
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
76
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
77
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
78
|
+
op[out_i++] = (double) 0.0;
|
|
79
|
+
} else {
|
|
80
|
+
double mean = sum / (double) n_valid;
|
|
81
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
82
|
+
double M2 = 0.0;
|
|
83
|
+
ca_size_t __unused_mc = 0;
|
|
84
|
+
CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, M2, 0.0, __variancep_i8_P2EXPR, __unused_mc);
|
|
85
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
ca_iter_state_finish(&st);
|
|
89
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
90
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
91
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
92
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
93
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
94
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
95
|
+
return rb_float_new(op[0]);
|
|
96
|
+
}
|
|
97
|
+
return vout;
|
|
98
|
+
}
|
|
99
|
+
#undef __variancep_i8_P1EXPR
|
|
100
|
+
#undef __variancep_i8_P2EXPR
|
|
101
|
+
|
|
102
|
+
#define __variancep_u8_P1EXPR(__x) ((double)(__x))
|
|
103
|
+
#define __variancep_u8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
104
|
+
static VALUE
|
|
105
|
+
variancep_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
106
|
+
{
|
|
107
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
108
|
+
CArray *co;
|
|
109
|
+
GetCArray(vout, co);
|
|
110
|
+
double *op = (double *) co->ptr;
|
|
111
|
+
ca_iter_state st;
|
|
112
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
113
|
+
slab_axes, naxes, 0);
|
|
114
|
+
if ( rc != CA_ITER_OK ) {
|
|
115
|
+
rb_raise(rb_eRuntimeError,
|
|
116
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
117
|
+
}
|
|
118
|
+
char *p;
|
|
119
|
+
boolean8_t *m;
|
|
120
|
+
ca_size_t out_i = 0;
|
|
121
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
122
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
123
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
124
|
+
double sum = 0.0;
|
|
125
|
+
ca_size_t masked_cnt = 0;
|
|
126
|
+
CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, sum, 0.0, __variancep_u8_P1EXPR, masked_cnt);
|
|
127
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
128
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
129
|
+
if ( __trigger ) {
|
|
130
|
+
if ( ! op_mask ) {
|
|
131
|
+
ca_create_mask(co);
|
|
132
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
133
|
+
}
|
|
134
|
+
op_mask[out_i] = 1;
|
|
135
|
+
op[out_i++] = (double) 0.0;
|
|
136
|
+
} else if ( n_valid < 1 ) {
|
|
137
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
138
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
139
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
140
|
+
op[out_i++] = (double) 0.0;
|
|
141
|
+
} else {
|
|
142
|
+
double mean = sum / (double) n_valid;
|
|
143
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
144
|
+
double M2 = 0.0;
|
|
145
|
+
ca_size_t __unused_mc = 0;
|
|
146
|
+
CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, M2, 0.0, __variancep_u8_P2EXPR, __unused_mc);
|
|
147
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
ca_iter_state_finish(&st);
|
|
151
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
152
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
153
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
154
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
155
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
156
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
157
|
+
return rb_float_new(op[0]);
|
|
158
|
+
}
|
|
159
|
+
return vout;
|
|
160
|
+
}
|
|
161
|
+
#undef __variancep_u8_P1EXPR
|
|
162
|
+
#undef __variancep_u8_P2EXPR
|
|
163
|
+
|
|
164
|
+
#define __variancep_i16_P1EXPR(__x) ((double)(__x))
|
|
165
|
+
#define __variancep_i16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
166
|
+
static VALUE
|
|
167
|
+
variancep_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
168
|
+
{
|
|
169
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
170
|
+
CArray *co;
|
|
171
|
+
GetCArray(vout, co);
|
|
172
|
+
double *op = (double *) co->ptr;
|
|
173
|
+
ca_iter_state st;
|
|
174
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
175
|
+
slab_axes, naxes, 0);
|
|
176
|
+
if ( rc != CA_ITER_OK ) {
|
|
177
|
+
rb_raise(rb_eRuntimeError,
|
|
178
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
179
|
+
}
|
|
180
|
+
char *p;
|
|
181
|
+
boolean8_t *m;
|
|
182
|
+
ca_size_t out_i = 0;
|
|
183
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
184
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
185
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
186
|
+
double sum = 0.0;
|
|
187
|
+
ca_size_t masked_cnt = 0;
|
|
188
|
+
CA_SLAB_REDUCE_SUM8_EX(int16_t, double, st, p, m, sum, 0.0, __variancep_i16_P1EXPR, masked_cnt);
|
|
189
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
190
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
191
|
+
if ( __trigger ) {
|
|
192
|
+
if ( ! op_mask ) {
|
|
193
|
+
ca_create_mask(co);
|
|
194
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
195
|
+
}
|
|
196
|
+
op_mask[out_i] = 1;
|
|
197
|
+
op[out_i++] = (double) 0.0;
|
|
198
|
+
} else if ( n_valid < 1 ) {
|
|
199
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
200
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
201
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
202
|
+
op[out_i++] = (double) 0.0;
|
|
203
|
+
} else {
|
|
204
|
+
double mean = sum / (double) n_valid;
|
|
205
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
206
|
+
double M2 = 0.0;
|
|
207
|
+
ca_size_t __unused_mc = 0;
|
|
208
|
+
CA_SLAB_REDUCE_SUM8_EX(int16_t, double, st, p, m, M2, 0.0, __variancep_i16_P2EXPR, __unused_mc);
|
|
209
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
ca_iter_state_finish(&st);
|
|
213
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
214
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
215
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
216
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
217
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
218
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
219
|
+
return rb_float_new(op[0]);
|
|
220
|
+
}
|
|
221
|
+
return vout;
|
|
222
|
+
}
|
|
223
|
+
#undef __variancep_i16_P1EXPR
|
|
224
|
+
#undef __variancep_i16_P2EXPR
|
|
225
|
+
|
|
226
|
+
#define __variancep_u16_P1EXPR(__x) ((double)(__x))
|
|
227
|
+
#define __variancep_u16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
228
|
+
static VALUE
|
|
229
|
+
variancep_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
230
|
+
{
|
|
231
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
232
|
+
CArray *co;
|
|
233
|
+
GetCArray(vout, co);
|
|
234
|
+
double *op = (double *) co->ptr;
|
|
235
|
+
ca_iter_state st;
|
|
236
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
237
|
+
slab_axes, naxes, 0);
|
|
238
|
+
if ( rc != CA_ITER_OK ) {
|
|
239
|
+
rb_raise(rb_eRuntimeError,
|
|
240
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
241
|
+
}
|
|
242
|
+
char *p;
|
|
243
|
+
boolean8_t *m;
|
|
244
|
+
ca_size_t out_i = 0;
|
|
245
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
246
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
247
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
248
|
+
double sum = 0.0;
|
|
249
|
+
ca_size_t masked_cnt = 0;
|
|
250
|
+
CA_SLAB_REDUCE_SUM8_EX(uint16_t, double, st, p, m, sum, 0.0, __variancep_u16_P1EXPR, masked_cnt);
|
|
251
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
252
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
253
|
+
if ( __trigger ) {
|
|
254
|
+
if ( ! op_mask ) {
|
|
255
|
+
ca_create_mask(co);
|
|
256
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
257
|
+
}
|
|
258
|
+
op_mask[out_i] = 1;
|
|
259
|
+
op[out_i++] = (double) 0.0;
|
|
260
|
+
} else if ( n_valid < 1 ) {
|
|
261
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
262
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
263
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
264
|
+
op[out_i++] = (double) 0.0;
|
|
265
|
+
} else {
|
|
266
|
+
double mean = sum / (double) n_valid;
|
|
267
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
268
|
+
double M2 = 0.0;
|
|
269
|
+
ca_size_t __unused_mc = 0;
|
|
270
|
+
CA_SLAB_REDUCE_SUM8_EX(uint16_t, double, st, p, m, M2, 0.0, __variancep_u16_P2EXPR, __unused_mc);
|
|
271
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
ca_iter_state_finish(&st);
|
|
275
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
276
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
277
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
278
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
279
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
280
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
281
|
+
return rb_float_new(op[0]);
|
|
282
|
+
}
|
|
283
|
+
return vout;
|
|
284
|
+
}
|
|
285
|
+
#undef __variancep_u16_P1EXPR
|
|
286
|
+
#undef __variancep_u16_P2EXPR
|
|
287
|
+
|
|
288
|
+
#define __variancep_i32_P1EXPR(__x) ((double)(__x))
|
|
289
|
+
#define __variancep_i32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
290
|
+
static VALUE
|
|
291
|
+
variancep_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
292
|
+
{
|
|
293
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
294
|
+
CArray *co;
|
|
295
|
+
GetCArray(vout, co);
|
|
296
|
+
double *op = (double *) co->ptr;
|
|
297
|
+
ca_iter_state st;
|
|
298
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
299
|
+
slab_axes, naxes, 0);
|
|
300
|
+
if ( rc != CA_ITER_OK ) {
|
|
301
|
+
rb_raise(rb_eRuntimeError,
|
|
302
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
303
|
+
}
|
|
304
|
+
char *p;
|
|
305
|
+
boolean8_t *m;
|
|
306
|
+
ca_size_t out_i = 0;
|
|
307
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
308
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
309
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
310
|
+
double sum = 0.0;
|
|
311
|
+
ca_size_t masked_cnt = 0;
|
|
312
|
+
CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, sum, 0.0, __variancep_i32_P1EXPR, masked_cnt);
|
|
313
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
314
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
315
|
+
if ( __trigger ) {
|
|
316
|
+
if ( ! op_mask ) {
|
|
317
|
+
ca_create_mask(co);
|
|
318
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
319
|
+
}
|
|
320
|
+
op_mask[out_i] = 1;
|
|
321
|
+
op[out_i++] = (double) 0.0;
|
|
322
|
+
} else if ( n_valid < 1 ) {
|
|
323
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
324
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
325
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
326
|
+
op[out_i++] = (double) 0.0;
|
|
327
|
+
} else {
|
|
328
|
+
double mean = sum / (double) n_valid;
|
|
329
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
330
|
+
double M2 = 0.0;
|
|
331
|
+
ca_size_t __unused_mc = 0;
|
|
332
|
+
CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, M2, 0.0, __variancep_i32_P2EXPR, __unused_mc);
|
|
333
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
ca_iter_state_finish(&st);
|
|
337
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
338
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
339
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
340
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
341
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
342
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
343
|
+
return rb_float_new(op[0]);
|
|
344
|
+
}
|
|
345
|
+
return vout;
|
|
346
|
+
}
|
|
347
|
+
#undef __variancep_i32_P1EXPR
|
|
348
|
+
#undef __variancep_i32_P2EXPR
|
|
349
|
+
|
|
350
|
+
#define __variancep_u32_P1EXPR(__x) ((double)(__x))
|
|
351
|
+
#define __variancep_u32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
352
|
+
static VALUE
|
|
353
|
+
variancep_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
354
|
+
{
|
|
355
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
356
|
+
CArray *co;
|
|
357
|
+
GetCArray(vout, co);
|
|
358
|
+
double *op = (double *) co->ptr;
|
|
359
|
+
ca_iter_state st;
|
|
360
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
361
|
+
slab_axes, naxes, 0);
|
|
362
|
+
if ( rc != CA_ITER_OK ) {
|
|
363
|
+
rb_raise(rb_eRuntimeError,
|
|
364
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
365
|
+
}
|
|
366
|
+
char *p;
|
|
367
|
+
boolean8_t *m;
|
|
368
|
+
ca_size_t out_i = 0;
|
|
369
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
370
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
371
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
372
|
+
double sum = 0.0;
|
|
373
|
+
ca_size_t masked_cnt = 0;
|
|
374
|
+
CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, sum, 0.0, __variancep_u32_P1EXPR, masked_cnt);
|
|
375
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
376
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
377
|
+
if ( __trigger ) {
|
|
378
|
+
if ( ! op_mask ) {
|
|
379
|
+
ca_create_mask(co);
|
|
380
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
381
|
+
}
|
|
382
|
+
op_mask[out_i] = 1;
|
|
383
|
+
op[out_i++] = (double) 0.0;
|
|
384
|
+
} else if ( n_valid < 1 ) {
|
|
385
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
386
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
387
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
388
|
+
op[out_i++] = (double) 0.0;
|
|
389
|
+
} else {
|
|
390
|
+
double mean = sum / (double) n_valid;
|
|
391
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
392
|
+
double M2 = 0.0;
|
|
393
|
+
ca_size_t __unused_mc = 0;
|
|
394
|
+
CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, M2, 0.0, __variancep_u32_P2EXPR, __unused_mc);
|
|
395
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
ca_iter_state_finish(&st);
|
|
399
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
400
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
401
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
402
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
403
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
404
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
405
|
+
return rb_float_new(op[0]);
|
|
406
|
+
}
|
|
407
|
+
return vout;
|
|
408
|
+
}
|
|
409
|
+
#undef __variancep_u32_P1EXPR
|
|
410
|
+
#undef __variancep_u32_P2EXPR
|
|
411
|
+
|
|
412
|
+
#define __variancep_i64_P1EXPR(__x) ((double)(__x))
|
|
413
|
+
#define __variancep_i64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
414
|
+
static VALUE
|
|
415
|
+
variancep_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
416
|
+
{
|
|
417
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
418
|
+
CArray *co;
|
|
419
|
+
GetCArray(vout, co);
|
|
420
|
+
double *op = (double *) co->ptr;
|
|
421
|
+
ca_iter_state st;
|
|
422
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
423
|
+
slab_axes, naxes, 0);
|
|
424
|
+
if ( rc != CA_ITER_OK ) {
|
|
425
|
+
rb_raise(rb_eRuntimeError,
|
|
426
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
427
|
+
}
|
|
428
|
+
char *p;
|
|
429
|
+
boolean8_t *m;
|
|
430
|
+
ca_size_t out_i = 0;
|
|
431
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
432
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
433
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
434
|
+
double sum = 0.0;
|
|
435
|
+
ca_size_t masked_cnt = 0;
|
|
436
|
+
CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, sum, 0.0, __variancep_i64_P1EXPR, masked_cnt);
|
|
437
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
438
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
439
|
+
if ( __trigger ) {
|
|
440
|
+
if ( ! op_mask ) {
|
|
441
|
+
ca_create_mask(co);
|
|
442
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
443
|
+
}
|
|
444
|
+
op_mask[out_i] = 1;
|
|
445
|
+
op[out_i++] = (double) 0.0;
|
|
446
|
+
} else if ( n_valid < 1 ) {
|
|
447
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
448
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
449
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
450
|
+
op[out_i++] = (double) 0.0;
|
|
451
|
+
} else {
|
|
452
|
+
double mean = sum / (double) n_valid;
|
|
453
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
454
|
+
double M2 = 0.0;
|
|
455
|
+
ca_size_t __unused_mc = 0;
|
|
456
|
+
CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, M2, 0.0, __variancep_i64_P2EXPR, __unused_mc);
|
|
457
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
ca_iter_state_finish(&st);
|
|
461
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
462
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
463
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
464
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
465
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
466
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
467
|
+
return rb_float_new(op[0]);
|
|
468
|
+
}
|
|
469
|
+
return vout;
|
|
470
|
+
}
|
|
471
|
+
#undef __variancep_i64_P1EXPR
|
|
472
|
+
#undef __variancep_i64_P2EXPR
|
|
473
|
+
|
|
474
|
+
#define __variancep_u64_P1EXPR(__x) ((double)(__x))
|
|
475
|
+
#define __variancep_u64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
476
|
+
static VALUE
|
|
477
|
+
variancep_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
478
|
+
{
|
|
479
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
480
|
+
CArray *co;
|
|
481
|
+
GetCArray(vout, co);
|
|
482
|
+
double *op = (double *) co->ptr;
|
|
483
|
+
ca_iter_state st;
|
|
484
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
485
|
+
slab_axes, naxes, 0);
|
|
486
|
+
if ( rc != CA_ITER_OK ) {
|
|
487
|
+
rb_raise(rb_eRuntimeError,
|
|
488
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
489
|
+
}
|
|
490
|
+
char *p;
|
|
491
|
+
boolean8_t *m;
|
|
492
|
+
ca_size_t out_i = 0;
|
|
493
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
494
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
495
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
496
|
+
double sum = 0.0;
|
|
497
|
+
ca_size_t masked_cnt = 0;
|
|
498
|
+
CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, sum, 0.0, __variancep_u64_P1EXPR, masked_cnt);
|
|
499
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
500
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
501
|
+
if ( __trigger ) {
|
|
502
|
+
if ( ! op_mask ) {
|
|
503
|
+
ca_create_mask(co);
|
|
504
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
505
|
+
}
|
|
506
|
+
op_mask[out_i] = 1;
|
|
507
|
+
op[out_i++] = (double) 0.0;
|
|
508
|
+
} else if ( n_valid < 1 ) {
|
|
509
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
510
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
511
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
512
|
+
op[out_i++] = (double) 0.0;
|
|
513
|
+
} else {
|
|
514
|
+
double mean = sum / (double) n_valid;
|
|
515
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
516
|
+
double M2 = 0.0;
|
|
517
|
+
ca_size_t __unused_mc = 0;
|
|
518
|
+
CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, M2, 0.0, __variancep_u64_P2EXPR, __unused_mc);
|
|
519
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
ca_iter_state_finish(&st);
|
|
523
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
524
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
525
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
526
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
527
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
528
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
529
|
+
return rb_float_new(op[0]);
|
|
530
|
+
}
|
|
531
|
+
return vout;
|
|
532
|
+
}
|
|
533
|
+
#undef __variancep_u64_P1EXPR
|
|
534
|
+
#undef __variancep_u64_P2EXPR
|
|
535
|
+
|
|
536
|
+
#define __variancep_f32_P1EXPR(__x) ((double)(__x))
|
|
537
|
+
#define __variancep_f32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
538
|
+
static VALUE
|
|
539
|
+
variancep_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
540
|
+
{
|
|
541
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
542
|
+
CArray *co;
|
|
543
|
+
GetCArray(vout, co);
|
|
544
|
+
double *op = (double *) co->ptr;
|
|
545
|
+
ca_iter_state st;
|
|
546
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
547
|
+
slab_axes, naxes, 0);
|
|
548
|
+
if ( rc != CA_ITER_OK ) {
|
|
549
|
+
rb_raise(rb_eRuntimeError,
|
|
550
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
551
|
+
}
|
|
552
|
+
char *p;
|
|
553
|
+
boolean8_t *m;
|
|
554
|
+
ca_size_t out_i = 0;
|
|
555
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
556
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
557
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
558
|
+
double sum = 0.0;
|
|
559
|
+
ca_size_t masked_cnt = 0;
|
|
560
|
+
CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, sum, 0.0, __variancep_f32_P1EXPR, masked_cnt);
|
|
561
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
562
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
563
|
+
if ( __trigger ) {
|
|
564
|
+
if ( ! op_mask ) {
|
|
565
|
+
ca_create_mask(co);
|
|
566
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
567
|
+
}
|
|
568
|
+
op_mask[out_i] = 1;
|
|
569
|
+
op[out_i++] = (double) 0.0;
|
|
570
|
+
} else if ( n_valid < 1 ) {
|
|
571
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
572
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
573
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
574
|
+
op[out_i++] = (double) 0.0;
|
|
575
|
+
} else {
|
|
576
|
+
double mean = sum / (double) n_valid;
|
|
577
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
578
|
+
double M2 = 0.0;
|
|
579
|
+
ca_size_t __unused_mc = 0;
|
|
580
|
+
CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, M2, 0.0, __variancep_f32_P2EXPR, __unused_mc);
|
|
581
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
ca_iter_state_finish(&st);
|
|
585
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
586
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
587
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
588
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
589
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
590
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
591
|
+
return rb_float_new(op[0]);
|
|
592
|
+
}
|
|
593
|
+
return vout;
|
|
594
|
+
}
|
|
595
|
+
#undef __variancep_f32_P1EXPR
|
|
596
|
+
#undef __variancep_f32_P2EXPR
|
|
597
|
+
|
|
598
|
+
#define __variancep_f64_P1EXPR(__x) ((double)(__x))
|
|
599
|
+
#define __variancep_f64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
600
|
+
static VALUE
|
|
601
|
+
variancep_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
602
|
+
{
|
|
603
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
604
|
+
CArray *co;
|
|
605
|
+
GetCArray(vout, co);
|
|
606
|
+
double *op = (double *) co->ptr;
|
|
607
|
+
ca_iter_state st;
|
|
608
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
609
|
+
slab_axes, naxes, 0);
|
|
610
|
+
if ( rc != CA_ITER_OK ) {
|
|
611
|
+
rb_raise(rb_eRuntimeError,
|
|
612
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
613
|
+
}
|
|
614
|
+
char *p;
|
|
615
|
+
boolean8_t *m;
|
|
616
|
+
ca_size_t out_i = 0;
|
|
617
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
618
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
619
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
620
|
+
double sum = 0.0;
|
|
621
|
+
ca_size_t masked_cnt = 0;
|
|
622
|
+
CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, sum, 0.0, __variancep_f64_P1EXPR, masked_cnt);
|
|
623
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
624
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
625
|
+
if ( __trigger ) {
|
|
626
|
+
if ( ! op_mask ) {
|
|
627
|
+
ca_create_mask(co);
|
|
628
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
629
|
+
}
|
|
630
|
+
op_mask[out_i] = 1;
|
|
631
|
+
op[out_i++] = (double) 0.0;
|
|
632
|
+
} else if ( n_valid < 1 ) {
|
|
633
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
634
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
635
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
636
|
+
op[out_i++] = (double) 0.0;
|
|
637
|
+
} else {
|
|
638
|
+
double mean = sum / (double) n_valid;
|
|
639
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
640
|
+
double M2 = 0.0;
|
|
641
|
+
ca_size_t __unused_mc = 0;
|
|
642
|
+
CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, M2, 0.0, __variancep_f64_P2EXPR, __unused_mc);
|
|
643
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
ca_iter_state_finish(&st);
|
|
647
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
648
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
649
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
650
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
651
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
652
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
653
|
+
return rb_float_new(op[0]);
|
|
654
|
+
}
|
|
655
|
+
return vout;
|
|
656
|
+
}
|
|
657
|
+
#undef __variancep_f64_P1EXPR
|
|
658
|
+
#undef __variancep_f64_P2EXPR
|
|
659
|
+
|
|
660
|
+
#define __variancep_cmplx64_P1EXPR(__x) (__x)
|
|
661
|
+
#define __variancep_cmplx64_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
|
|
662
|
+
static VALUE
|
|
663
|
+
variancep_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
664
|
+
{
|
|
665
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
666
|
+
CArray *co;
|
|
667
|
+
GetCArray(vout, co);
|
|
668
|
+
double *op = (double *) co->ptr;
|
|
669
|
+
ca_iter_state st;
|
|
670
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
671
|
+
slab_axes, naxes, 0);
|
|
672
|
+
if ( rc != CA_ITER_OK ) {
|
|
673
|
+
rb_raise(rb_eRuntimeError,
|
|
674
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
675
|
+
}
|
|
676
|
+
char *p;
|
|
677
|
+
boolean8_t *m;
|
|
678
|
+
ca_size_t out_i = 0;
|
|
679
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
680
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
681
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
682
|
+
cmplx64_t sum = 0;
|
|
683
|
+
ca_size_t masked_cnt = 0;
|
|
684
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, cmplx64_t, st, p, m, sum, 0, __variancep_cmplx64_P1EXPR, masked_cnt);
|
|
685
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
686
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
687
|
+
if ( __trigger ) {
|
|
688
|
+
if ( ! op_mask ) {
|
|
689
|
+
ca_create_mask(co);
|
|
690
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
691
|
+
}
|
|
692
|
+
op_mask[out_i] = 1;
|
|
693
|
+
op[out_i++] = (double) 0.0;
|
|
694
|
+
} else if ( n_valid < 1 ) {
|
|
695
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
696
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
697
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
698
|
+
op[out_i++] = (double) 0.0;
|
|
699
|
+
} else {
|
|
700
|
+
cmplx64_t mean = sum / (cmplx64_t)(double) n_valid;
|
|
701
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
702
|
+
double M2 = 0.0;
|
|
703
|
+
ca_size_t __unused_mc = 0;
|
|
704
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, double, st, p, m, M2, 0.0, __variancep_cmplx64_P2EXPR, __unused_mc);
|
|
705
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
ca_iter_state_finish(&st);
|
|
709
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
710
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
711
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
712
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
713
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
714
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
715
|
+
return rb_float_new(op[0]);
|
|
716
|
+
}
|
|
717
|
+
return vout;
|
|
718
|
+
}
|
|
719
|
+
#undef __variancep_cmplx64_P1EXPR
|
|
720
|
+
#undef __variancep_cmplx64_P2EXPR
|
|
721
|
+
|
|
722
|
+
#define __variancep_cmplx128_P1EXPR(__x) (__x)
|
|
723
|
+
#define __variancep_cmplx128_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
|
|
724
|
+
static VALUE
|
|
725
|
+
variancep_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
726
|
+
{
|
|
727
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
728
|
+
CArray *co;
|
|
729
|
+
GetCArray(vout, co);
|
|
730
|
+
double *op = (double *) co->ptr;
|
|
731
|
+
ca_iter_state st;
|
|
732
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
733
|
+
slab_axes, naxes, 0);
|
|
734
|
+
if ( rc != CA_ITER_OK ) {
|
|
735
|
+
rb_raise(rb_eRuntimeError,
|
|
736
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
737
|
+
}
|
|
738
|
+
char *p;
|
|
739
|
+
boolean8_t *m;
|
|
740
|
+
ca_size_t out_i = 0;
|
|
741
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
742
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
743
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
744
|
+
cmplx128_t sum = 0;
|
|
745
|
+
ca_size_t masked_cnt = 0;
|
|
746
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, cmplx128_t, st, p, m, sum, 0, __variancep_cmplx128_P1EXPR, masked_cnt);
|
|
747
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
748
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
749
|
+
if ( __trigger ) {
|
|
750
|
+
if ( ! op_mask ) {
|
|
751
|
+
ca_create_mask(co);
|
|
752
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
753
|
+
}
|
|
754
|
+
op_mask[out_i] = 1;
|
|
755
|
+
op[out_i++] = (double) 0.0;
|
|
756
|
+
} else if ( n_valid < 1 ) {
|
|
757
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
758
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
759
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
760
|
+
op[out_i++] = (double) 0.0;
|
|
761
|
+
} else {
|
|
762
|
+
cmplx128_t mean = sum / (cmplx128_t)(double) n_valid;
|
|
763
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
764
|
+
double M2 = 0.0;
|
|
765
|
+
ca_size_t __unused_mc = 0;
|
|
766
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, double, st, p, m, M2, 0.0, __variancep_cmplx128_P2EXPR, __unused_mc);
|
|
767
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
ca_iter_state_finish(&st);
|
|
771
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
772
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
773
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
774
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
775
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
776
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
777
|
+
return rb_float_new(op[0]);
|
|
778
|
+
}
|
|
779
|
+
return vout;
|
|
780
|
+
}
|
|
781
|
+
#undef __variancep_cmplx128_P1EXPR
|
|
782
|
+
#undef __variancep_cmplx128_P2EXPR
|
|
783
|
+
|
|
784
|
+
#define __variancep_bool_P1EXPR(__x) ((double)(__x))
|
|
785
|
+
#define __variancep_bool_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
786
|
+
static VALUE
|
|
787
|
+
variancep_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
788
|
+
{
|
|
789
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
790
|
+
CArray *co;
|
|
791
|
+
GetCArray(vout, co);
|
|
792
|
+
double *op = (double *) co->ptr;
|
|
793
|
+
ca_iter_state st;
|
|
794
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
795
|
+
slab_axes, naxes, 0);
|
|
796
|
+
if ( rc != CA_ITER_OK ) {
|
|
797
|
+
rb_raise(rb_eRuntimeError,
|
|
798
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
799
|
+
}
|
|
800
|
+
char *p;
|
|
801
|
+
boolean8_t *m;
|
|
802
|
+
ca_size_t out_i = 0;
|
|
803
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
804
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
805
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
806
|
+
double sum = 0.0;
|
|
807
|
+
ca_size_t masked_cnt = 0;
|
|
808
|
+
CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, sum, 0.0, __variancep_bool_P1EXPR, masked_cnt);
|
|
809
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
810
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
811
|
+
if ( __trigger ) {
|
|
812
|
+
if ( ! op_mask ) {
|
|
813
|
+
ca_create_mask(co);
|
|
814
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
815
|
+
}
|
|
816
|
+
op_mask[out_i] = 1;
|
|
817
|
+
op[out_i++] = (double) 0.0;
|
|
818
|
+
} else if ( n_valid < 1 ) {
|
|
819
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
820
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
821
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
822
|
+
op[out_i++] = (double) 0.0;
|
|
823
|
+
} else {
|
|
824
|
+
double mean = sum / (double) n_valid;
|
|
825
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
826
|
+
double M2 = 0.0;
|
|
827
|
+
ca_size_t __unused_mc = 0;
|
|
828
|
+
CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, M2, 0.0, __variancep_bool_P2EXPR, __unused_mc);
|
|
829
|
+
op[out_i++] = (double)(M2 / (double)(n_valid));
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
ca_iter_state_finish(&st);
|
|
833
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
834
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
835
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
836
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
837
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
838
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
839
|
+
return rb_float_new(op[0]);
|
|
840
|
+
}
|
|
841
|
+
return vout;
|
|
842
|
+
}
|
|
843
|
+
#undef __variancep_bool_P1EXPR
|
|
844
|
+
#undef __variancep_bool_P2EXPR
|
|
845
|
+
|
|
846
|
+
static VALUE
|
|
847
|
+
variancep_ki_native_object (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
848
|
+
{
|
|
849
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_OBJECT, keep_axis);
|
|
850
|
+
CArray *co;
|
|
851
|
+
GetCArray(vout, co);
|
|
852
|
+
VALUE *op = (VALUE *) co->ptr;
|
|
853
|
+
ca_iter_state st;
|
|
854
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
855
|
+
slab_axes, naxes, 0);
|
|
856
|
+
if ( rc != CA_ITER_OK ) {
|
|
857
|
+
rb_raise(rb_eRuntimeError,
|
|
858
|
+
"variancep_ki: kernel_iterator init failed rc=%d", rc);
|
|
859
|
+
}
|
|
860
|
+
char *p;
|
|
861
|
+
boolean8_t *m;
|
|
862
|
+
ca_size_t out_i = 0;
|
|
863
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
864
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
865
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
866
|
+
VALUE sum = INT2FIX(0);
|
|
867
|
+
ca_size_t masked_cnt = 0;
|
|
868
|
+
CA_SLAB_REDUCE_T_EX(VALUE, st, p, m, sum, INT2FIX(0), sum = rb_funcall(sum, rb_intern("+"), 1, v), masked_cnt);
|
|
869
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
870
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
871
|
+
if ( __trigger ) {
|
|
872
|
+
if ( ! op_mask ) {
|
|
873
|
+
ca_create_mask(co);
|
|
874
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
875
|
+
}
|
|
876
|
+
op_mask[out_i] = 1;
|
|
877
|
+
op[out_i++] = (VALUE) INT2FIX(0);
|
|
878
|
+
} else if ( n_valid < 1 ) {
|
|
879
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
880
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
881
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
882
|
+
op[out_i++] = (VALUE) INT2FIX(0);
|
|
883
|
+
} else {
|
|
884
|
+
VALUE mean = rb_funcall(sum, rb_intern("/"), 1, LONG2NUM(n_valid));
|
|
885
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
886
|
+
VALUE M2 = INT2FIX(0);
|
|
887
|
+
ca_size_t __unused_mc = 0;
|
|
888
|
+
CA_SLAB_REDUCE_T_EX(VALUE, st, p, m, M2, INT2FIX(0), VALUE __d = rb_funcall(v, rb_intern("-"), 1, mean);
|
|
889
|
+
M2 = rb_funcall(M2, rb_intern("+"), 1, rb_funcall(__d, rb_intern("*"), 1, __d)), __unused_mc);
|
|
890
|
+
op[out_i++] = (VALUE)(rb_funcall(M2, rb_intern("/"), 1, LONG2NUM(n_valid)));
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
ca_iter_state_finish(&st);
|
|
894
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
895
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
896
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
897
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
898
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
899
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
900
|
+
return (VALUE)(op[0]);
|
|
901
|
+
}
|
|
902
|
+
return vout;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
VALUE
|
|
906
|
+
rb_ca_variancep_ki (int argc, VALUE *argv, VALUE self)
|
|
907
|
+
{
|
|
908
|
+
CArray *src;
|
|
909
|
+
GetCArray(self, src);
|
|
910
|
+
volatile VALUE ropt = rb_pop_options(&argc, &argv);
|
|
911
|
+
volatile VALUE raxis = Qnil, rkeep_axis = Qnil, rmin_count = Qnil, rfval = Qnil;
|
|
912
|
+
rb_scan_options(ropt, "axis,keep_axis,min_count,fill_value", &raxis, &rkeep_axis, &rmin_count, &rfval);
|
|
913
|
+
int keep_axis = RTEST(rkeep_axis);
|
|
914
|
+
int8_t slab_axes[CA_RANK_MAX];
|
|
915
|
+
int8_t naxes = rb_ca_parse_reduce_axes_kw(raxis, src, slab_axes);
|
|
916
|
+
ca_size_t min_count = -1;
|
|
917
|
+
if ( ! NIL_P(rmin_count) ) {
|
|
918
|
+
ca_size_t mc_user = NUM2SIZE(rmin_count);
|
|
919
|
+
if ( mc_user < 0 ) {
|
|
920
|
+
rb_raise(rb_eArgError, "variancep_ki: :min_count must be non-negative, got %lld", (long long) mc_user);
|
|
921
|
+
}
|
|
922
|
+
/* :min_count = 0 collapses to legacy default (any 1 valid). */
|
|
923
|
+
if ( mc_user > 0 ) min_count = mc_user;
|
|
924
|
+
}
|
|
925
|
+
VALUE result;
|
|
926
|
+
if ( argc > 0 ) {
|
|
927
|
+
rb_raise(rb_eArgError, "variancep_ki: positional axis arguments are no longer accepted (got %d); use axis: kwarg, e.g. a.variancep(axis: 0) or a.variancep(axis: [0, 1])", argc);
|
|
928
|
+
}
|
|
929
|
+
switch ( src->data_type ) {
|
|
930
|
+
case CA_INT8: {
|
|
931
|
+
result = variancep_ki_native_i8(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
932
|
+
break;
|
|
933
|
+
}
|
|
934
|
+
case CA_UINT8: {
|
|
935
|
+
result = variancep_ki_native_u8(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
936
|
+
break;
|
|
937
|
+
}
|
|
938
|
+
case CA_INT16: {
|
|
939
|
+
result = variancep_ki_native_i16(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
940
|
+
break;
|
|
941
|
+
}
|
|
942
|
+
case CA_UINT16: {
|
|
943
|
+
result = variancep_ki_native_u16(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
944
|
+
break;
|
|
945
|
+
}
|
|
946
|
+
case CA_INT32: {
|
|
947
|
+
result = variancep_ki_native_i32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
948
|
+
break;
|
|
949
|
+
}
|
|
950
|
+
case CA_UINT32: {
|
|
951
|
+
result = variancep_ki_native_u32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
952
|
+
break;
|
|
953
|
+
}
|
|
954
|
+
case CA_INT64: {
|
|
955
|
+
result = variancep_ki_native_i64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
956
|
+
break;
|
|
957
|
+
}
|
|
958
|
+
case CA_UINT64: {
|
|
959
|
+
result = variancep_ki_native_u64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
960
|
+
break;
|
|
961
|
+
}
|
|
962
|
+
case CA_FLOAT32: {
|
|
963
|
+
result = variancep_ki_native_f32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
964
|
+
break;
|
|
965
|
+
}
|
|
966
|
+
case CA_FLOAT64: {
|
|
967
|
+
result = variancep_ki_native_f64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
968
|
+
break;
|
|
969
|
+
}
|
|
970
|
+
case CA_CMPLX64: {
|
|
971
|
+
result = variancep_ki_native_cmplx64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
972
|
+
break;
|
|
973
|
+
}
|
|
974
|
+
case CA_CMPLX128: {
|
|
975
|
+
result = variancep_ki_native_cmplx128(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
976
|
+
break;
|
|
977
|
+
}
|
|
978
|
+
case CA_BOOLEAN: {
|
|
979
|
+
result = variancep_ki_native_bool(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
980
|
+
break;
|
|
981
|
+
}
|
|
982
|
+
case CA_OBJECT: {
|
|
983
|
+
result = variancep_ki_native_object(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
984
|
+
break;
|
|
985
|
+
}
|
|
986
|
+
default:
|
|
987
|
+
rb_raise(rb_eCADataTypeError, "variancep_ki: source data_type :%s not supported (expected one of: i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, cmplx64, cmplx128, bool, object)", ca_type_name[src->data_type]);
|
|
988
|
+
}
|
|
989
|
+
if ( ! NIL_P(rfval) ) {
|
|
990
|
+
if ( result == CA_UNDEF ) {
|
|
991
|
+
result = rfval;
|
|
992
|
+
} else if ( TYPE(result) != T_FLOAT && rb_obj_is_kind_of(result, rb_cCArray) ) {
|
|
993
|
+
CArray *cr;
|
|
994
|
+
GetCArray(result, cr);
|
|
995
|
+
if ( ca_has_mask(cr) ) {
|
|
996
|
+
result = rb_ca_mask_fill_copy(result, rfval);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return result;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/* ===== variance_ki ============================================ */
|
|
1004
|
+
|
|
1005
|
+
#define __variance_i8_P1EXPR(__x) ((double)(__x))
|
|
1006
|
+
#define __variance_i8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1007
|
+
static VALUE
|
|
1008
|
+
variance_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1009
|
+
{
|
|
1010
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1011
|
+
CArray *co;
|
|
1012
|
+
GetCArray(vout, co);
|
|
1013
|
+
double *op = (double *) co->ptr;
|
|
1014
|
+
ca_iter_state st;
|
|
1015
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1016
|
+
slab_axes, naxes, 0);
|
|
1017
|
+
if ( rc != CA_ITER_OK ) {
|
|
1018
|
+
rb_raise(rb_eRuntimeError,
|
|
1019
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1020
|
+
}
|
|
1021
|
+
char *p;
|
|
1022
|
+
boolean8_t *m;
|
|
1023
|
+
ca_size_t out_i = 0;
|
|
1024
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1025
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1026
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1027
|
+
double sum = 0.0;
|
|
1028
|
+
ca_size_t masked_cnt = 0;
|
|
1029
|
+
CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, sum, 0.0, __variance_i8_P1EXPR, masked_cnt);
|
|
1030
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1031
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1032
|
+
if ( __trigger ) {
|
|
1033
|
+
if ( ! op_mask ) {
|
|
1034
|
+
ca_create_mask(co);
|
|
1035
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1036
|
+
}
|
|
1037
|
+
op_mask[out_i] = 1;
|
|
1038
|
+
op[out_i++] = (double) 0.0;
|
|
1039
|
+
} else if ( n_valid < 2 ) {
|
|
1040
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1041
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1042
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1043
|
+
op[out_i++] = (double) 0.0;
|
|
1044
|
+
} else {
|
|
1045
|
+
double mean = sum / (double) n_valid;
|
|
1046
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1047
|
+
double M2 = 0.0;
|
|
1048
|
+
ca_size_t __unused_mc = 0;
|
|
1049
|
+
CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, M2, 0.0, __variance_i8_P2EXPR, __unused_mc);
|
|
1050
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
ca_iter_state_finish(&st);
|
|
1054
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1055
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1056
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1057
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1058
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1059
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1060
|
+
return rb_float_new(op[0]);
|
|
1061
|
+
}
|
|
1062
|
+
return vout;
|
|
1063
|
+
}
|
|
1064
|
+
#undef __variance_i8_P1EXPR
|
|
1065
|
+
#undef __variance_i8_P2EXPR
|
|
1066
|
+
|
|
1067
|
+
#define __variance_u8_P1EXPR(__x) ((double)(__x))
|
|
1068
|
+
#define __variance_u8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1069
|
+
static VALUE
|
|
1070
|
+
variance_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1071
|
+
{
|
|
1072
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1073
|
+
CArray *co;
|
|
1074
|
+
GetCArray(vout, co);
|
|
1075
|
+
double *op = (double *) co->ptr;
|
|
1076
|
+
ca_iter_state st;
|
|
1077
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1078
|
+
slab_axes, naxes, 0);
|
|
1079
|
+
if ( rc != CA_ITER_OK ) {
|
|
1080
|
+
rb_raise(rb_eRuntimeError,
|
|
1081
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1082
|
+
}
|
|
1083
|
+
char *p;
|
|
1084
|
+
boolean8_t *m;
|
|
1085
|
+
ca_size_t out_i = 0;
|
|
1086
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1087
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1088
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1089
|
+
double sum = 0.0;
|
|
1090
|
+
ca_size_t masked_cnt = 0;
|
|
1091
|
+
CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, sum, 0.0, __variance_u8_P1EXPR, masked_cnt);
|
|
1092
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1093
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1094
|
+
if ( __trigger ) {
|
|
1095
|
+
if ( ! op_mask ) {
|
|
1096
|
+
ca_create_mask(co);
|
|
1097
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1098
|
+
}
|
|
1099
|
+
op_mask[out_i] = 1;
|
|
1100
|
+
op[out_i++] = (double) 0.0;
|
|
1101
|
+
} else if ( n_valid < 2 ) {
|
|
1102
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1103
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1104
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1105
|
+
op[out_i++] = (double) 0.0;
|
|
1106
|
+
} else {
|
|
1107
|
+
double mean = sum / (double) n_valid;
|
|
1108
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1109
|
+
double M2 = 0.0;
|
|
1110
|
+
ca_size_t __unused_mc = 0;
|
|
1111
|
+
CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, M2, 0.0, __variance_u8_P2EXPR, __unused_mc);
|
|
1112
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
ca_iter_state_finish(&st);
|
|
1116
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1117
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1118
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1119
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1120
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1121
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1122
|
+
return rb_float_new(op[0]);
|
|
1123
|
+
}
|
|
1124
|
+
return vout;
|
|
1125
|
+
}
|
|
1126
|
+
#undef __variance_u8_P1EXPR
|
|
1127
|
+
#undef __variance_u8_P2EXPR
|
|
1128
|
+
|
|
1129
|
+
#define __variance_i16_P1EXPR(__x) ((double)(__x))
|
|
1130
|
+
#define __variance_i16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1131
|
+
static VALUE
|
|
1132
|
+
variance_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1133
|
+
{
|
|
1134
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1135
|
+
CArray *co;
|
|
1136
|
+
GetCArray(vout, co);
|
|
1137
|
+
double *op = (double *) co->ptr;
|
|
1138
|
+
ca_iter_state st;
|
|
1139
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1140
|
+
slab_axes, naxes, 0);
|
|
1141
|
+
if ( rc != CA_ITER_OK ) {
|
|
1142
|
+
rb_raise(rb_eRuntimeError,
|
|
1143
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1144
|
+
}
|
|
1145
|
+
char *p;
|
|
1146
|
+
boolean8_t *m;
|
|
1147
|
+
ca_size_t out_i = 0;
|
|
1148
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1149
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1150
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1151
|
+
double sum = 0.0;
|
|
1152
|
+
ca_size_t masked_cnt = 0;
|
|
1153
|
+
CA_SLAB_REDUCE_SUM8_EX(int16_t, double, st, p, m, sum, 0.0, __variance_i16_P1EXPR, masked_cnt);
|
|
1154
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1155
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1156
|
+
if ( __trigger ) {
|
|
1157
|
+
if ( ! op_mask ) {
|
|
1158
|
+
ca_create_mask(co);
|
|
1159
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1160
|
+
}
|
|
1161
|
+
op_mask[out_i] = 1;
|
|
1162
|
+
op[out_i++] = (double) 0.0;
|
|
1163
|
+
} else if ( n_valid < 2 ) {
|
|
1164
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1165
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1166
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1167
|
+
op[out_i++] = (double) 0.0;
|
|
1168
|
+
} else {
|
|
1169
|
+
double mean = sum / (double) n_valid;
|
|
1170
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1171
|
+
double M2 = 0.0;
|
|
1172
|
+
ca_size_t __unused_mc = 0;
|
|
1173
|
+
CA_SLAB_REDUCE_SUM8_EX(int16_t, double, st, p, m, M2, 0.0, __variance_i16_P2EXPR, __unused_mc);
|
|
1174
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
ca_iter_state_finish(&st);
|
|
1178
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1179
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1180
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1181
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1182
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1183
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1184
|
+
return rb_float_new(op[0]);
|
|
1185
|
+
}
|
|
1186
|
+
return vout;
|
|
1187
|
+
}
|
|
1188
|
+
#undef __variance_i16_P1EXPR
|
|
1189
|
+
#undef __variance_i16_P2EXPR
|
|
1190
|
+
|
|
1191
|
+
#define __variance_u16_P1EXPR(__x) ((double)(__x))
|
|
1192
|
+
#define __variance_u16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1193
|
+
static VALUE
|
|
1194
|
+
variance_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1195
|
+
{
|
|
1196
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1197
|
+
CArray *co;
|
|
1198
|
+
GetCArray(vout, co);
|
|
1199
|
+
double *op = (double *) co->ptr;
|
|
1200
|
+
ca_iter_state st;
|
|
1201
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1202
|
+
slab_axes, naxes, 0);
|
|
1203
|
+
if ( rc != CA_ITER_OK ) {
|
|
1204
|
+
rb_raise(rb_eRuntimeError,
|
|
1205
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1206
|
+
}
|
|
1207
|
+
char *p;
|
|
1208
|
+
boolean8_t *m;
|
|
1209
|
+
ca_size_t out_i = 0;
|
|
1210
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1211
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1212
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1213
|
+
double sum = 0.0;
|
|
1214
|
+
ca_size_t masked_cnt = 0;
|
|
1215
|
+
CA_SLAB_REDUCE_SUM8_EX(uint16_t, double, st, p, m, sum, 0.0, __variance_u16_P1EXPR, masked_cnt);
|
|
1216
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1217
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1218
|
+
if ( __trigger ) {
|
|
1219
|
+
if ( ! op_mask ) {
|
|
1220
|
+
ca_create_mask(co);
|
|
1221
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1222
|
+
}
|
|
1223
|
+
op_mask[out_i] = 1;
|
|
1224
|
+
op[out_i++] = (double) 0.0;
|
|
1225
|
+
} else if ( n_valid < 2 ) {
|
|
1226
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1227
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1228
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1229
|
+
op[out_i++] = (double) 0.0;
|
|
1230
|
+
} else {
|
|
1231
|
+
double mean = sum / (double) n_valid;
|
|
1232
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1233
|
+
double M2 = 0.0;
|
|
1234
|
+
ca_size_t __unused_mc = 0;
|
|
1235
|
+
CA_SLAB_REDUCE_SUM8_EX(uint16_t, double, st, p, m, M2, 0.0, __variance_u16_P2EXPR, __unused_mc);
|
|
1236
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
ca_iter_state_finish(&st);
|
|
1240
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1241
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1242
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1243
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1244
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1245
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1246
|
+
return rb_float_new(op[0]);
|
|
1247
|
+
}
|
|
1248
|
+
return vout;
|
|
1249
|
+
}
|
|
1250
|
+
#undef __variance_u16_P1EXPR
|
|
1251
|
+
#undef __variance_u16_P2EXPR
|
|
1252
|
+
|
|
1253
|
+
#define __variance_i32_P1EXPR(__x) ((double)(__x))
|
|
1254
|
+
#define __variance_i32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1255
|
+
static VALUE
|
|
1256
|
+
variance_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1257
|
+
{
|
|
1258
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1259
|
+
CArray *co;
|
|
1260
|
+
GetCArray(vout, co);
|
|
1261
|
+
double *op = (double *) co->ptr;
|
|
1262
|
+
ca_iter_state st;
|
|
1263
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1264
|
+
slab_axes, naxes, 0);
|
|
1265
|
+
if ( rc != CA_ITER_OK ) {
|
|
1266
|
+
rb_raise(rb_eRuntimeError,
|
|
1267
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1268
|
+
}
|
|
1269
|
+
char *p;
|
|
1270
|
+
boolean8_t *m;
|
|
1271
|
+
ca_size_t out_i = 0;
|
|
1272
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1273
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1274
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1275
|
+
double sum = 0.0;
|
|
1276
|
+
ca_size_t masked_cnt = 0;
|
|
1277
|
+
CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, sum, 0.0, __variance_i32_P1EXPR, masked_cnt);
|
|
1278
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1279
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1280
|
+
if ( __trigger ) {
|
|
1281
|
+
if ( ! op_mask ) {
|
|
1282
|
+
ca_create_mask(co);
|
|
1283
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1284
|
+
}
|
|
1285
|
+
op_mask[out_i] = 1;
|
|
1286
|
+
op[out_i++] = (double) 0.0;
|
|
1287
|
+
} else if ( n_valid < 2 ) {
|
|
1288
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1289
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1290
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1291
|
+
op[out_i++] = (double) 0.0;
|
|
1292
|
+
} else {
|
|
1293
|
+
double mean = sum / (double) n_valid;
|
|
1294
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1295
|
+
double M2 = 0.0;
|
|
1296
|
+
ca_size_t __unused_mc = 0;
|
|
1297
|
+
CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, M2, 0.0, __variance_i32_P2EXPR, __unused_mc);
|
|
1298
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
ca_iter_state_finish(&st);
|
|
1302
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1303
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1304
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1305
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1306
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1307
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1308
|
+
return rb_float_new(op[0]);
|
|
1309
|
+
}
|
|
1310
|
+
return vout;
|
|
1311
|
+
}
|
|
1312
|
+
#undef __variance_i32_P1EXPR
|
|
1313
|
+
#undef __variance_i32_P2EXPR
|
|
1314
|
+
|
|
1315
|
+
#define __variance_u32_P1EXPR(__x) ((double)(__x))
|
|
1316
|
+
#define __variance_u32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1317
|
+
static VALUE
|
|
1318
|
+
variance_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1319
|
+
{
|
|
1320
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1321
|
+
CArray *co;
|
|
1322
|
+
GetCArray(vout, co);
|
|
1323
|
+
double *op = (double *) co->ptr;
|
|
1324
|
+
ca_iter_state st;
|
|
1325
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1326
|
+
slab_axes, naxes, 0);
|
|
1327
|
+
if ( rc != CA_ITER_OK ) {
|
|
1328
|
+
rb_raise(rb_eRuntimeError,
|
|
1329
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1330
|
+
}
|
|
1331
|
+
char *p;
|
|
1332
|
+
boolean8_t *m;
|
|
1333
|
+
ca_size_t out_i = 0;
|
|
1334
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1335
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1336
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1337
|
+
double sum = 0.0;
|
|
1338
|
+
ca_size_t masked_cnt = 0;
|
|
1339
|
+
CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, sum, 0.0, __variance_u32_P1EXPR, masked_cnt);
|
|
1340
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1341
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1342
|
+
if ( __trigger ) {
|
|
1343
|
+
if ( ! op_mask ) {
|
|
1344
|
+
ca_create_mask(co);
|
|
1345
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1346
|
+
}
|
|
1347
|
+
op_mask[out_i] = 1;
|
|
1348
|
+
op[out_i++] = (double) 0.0;
|
|
1349
|
+
} else if ( n_valid < 2 ) {
|
|
1350
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1351
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1352
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1353
|
+
op[out_i++] = (double) 0.0;
|
|
1354
|
+
} else {
|
|
1355
|
+
double mean = sum / (double) n_valid;
|
|
1356
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1357
|
+
double M2 = 0.0;
|
|
1358
|
+
ca_size_t __unused_mc = 0;
|
|
1359
|
+
CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, M2, 0.0, __variance_u32_P2EXPR, __unused_mc);
|
|
1360
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
ca_iter_state_finish(&st);
|
|
1364
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1365
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1366
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1367
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1368
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1369
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1370
|
+
return rb_float_new(op[0]);
|
|
1371
|
+
}
|
|
1372
|
+
return vout;
|
|
1373
|
+
}
|
|
1374
|
+
#undef __variance_u32_P1EXPR
|
|
1375
|
+
#undef __variance_u32_P2EXPR
|
|
1376
|
+
|
|
1377
|
+
#define __variance_i64_P1EXPR(__x) ((double)(__x))
|
|
1378
|
+
#define __variance_i64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1379
|
+
static VALUE
|
|
1380
|
+
variance_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1381
|
+
{
|
|
1382
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1383
|
+
CArray *co;
|
|
1384
|
+
GetCArray(vout, co);
|
|
1385
|
+
double *op = (double *) co->ptr;
|
|
1386
|
+
ca_iter_state st;
|
|
1387
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1388
|
+
slab_axes, naxes, 0);
|
|
1389
|
+
if ( rc != CA_ITER_OK ) {
|
|
1390
|
+
rb_raise(rb_eRuntimeError,
|
|
1391
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1392
|
+
}
|
|
1393
|
+
char *p;
|
|
1394
|
+
boolean8_t *m;
|
|
1395
|
+
ca_size_t out_i = 0;
|
|
1396
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1397
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1398
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1399
|
+
double sum = 0.0;
|
|
1400
|
+
ca_size_t masked_cnt = 0;
|
|
1401
|
+
CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, sum, 0.0, __variance_i64_P1EXPR, masked_cnt);
|
|
1402
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1403
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1404
|
+
if ( __trigger ) {
|
|
1405
|
+
if ( ! op_mask ) {
|
|
1406
|
+
ca_create_mask(co);
|
|
1407
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1408
|
+
}
|
|
1409
|
+
op_mask[out_i] = 1;
|
|
1410
|
+
op[out_i++] = (double) 0.0;
|
|
1411
|
+
} else if ( n_valid < 2 ) {
|
|
1412
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1413
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1414
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1415
|
+
op[out_i++] = (double) 0.0;
|
|
1416
|
+
} else {
|
|
1417
|
+
double mean = sum / (double) n_valid;
|
|
1418
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1419
|
+
double M2 = 0.0;
|
|
1420
|
+
ca_size_t __unused_mc = 0;
|
|
1421
|
+
CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, M2, 0.0, __variance_i64_P2EXPR, __unused_mc);
|
|
1422
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
ca_iter_state_finish(&st);
|
|
1426
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1427
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1428
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1429
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1430
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1431
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1432
|
+
return rb_float_new(op[0]);
|
|
1433
|
+
}
|
|
1434
|
+
return vout;
|
|
1435
|
+
}
|
|
1436
|
+
#undef __variance_i64_P1EXPR
|
|
1437
|
+
#undef __variance_i64_P2EXPR
|
|
1438
|
+
|
|
1439
|
+
#define __variance_u64_P1EXPR(__x) ((double)(__x))
|
|
1440
|
+
#define __variance_u64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1441
|
+
static VALUE
|
|
1442
|
+
variance_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1443
|
+
{
|
|
1444
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1445
|
+
CArray *co;
|
|
1446
|
+
GetCArray(vout, co);
|
|
1447
|
+
double *op = (double *) co->ptr;
|
|
1448
|
+
ca_iter_state st;
|
|
1449
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1450
|
+
slab_axes, naxes, 0);
|
|
1451
|
+
if ( rc != CA_ITER_OK ) {
|
|
1452
|
+
rb_raise(rb_eRuntimeError,
|
|
1453
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1454
|
+
}
|
|
1455
|
+
char *p;
|
|
1456
|
+
boolean8_t *m;
|
|
1457
|
+
ca_size_t out_i = 0;
|
|
1458
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1459
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1460
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1461
|
+
double sum = 0.0;
|
|
1462
|
+
ca_size_t masked_cnt = 0;
|
|
1463
|
+
CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, sum, 0.0, __variance_u64_P1EXPR, masked_cnt);
|
|
1464
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1465
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1466
|
+
if ( __trigger ) {
|
|
1467
|
+
if ( ! op_mask ) {
|
|
1468
|
+
ca_create_mask(co);
|
|
1469
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1470
|
+
}
|
|
1471
|
+
op_mask[out_i] = 1;
|
|
1472
|
+
op[out_i++] = (double) 0.0;
|
|
1473
|
+
} else if ( n_valid < 2 ) {
|
|
1474
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1475
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1476
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1477
|
+
op[out_i++] = (double) 0.0;
|
|
1478
|
+
} else {
|
|
1479
|
+
double mean = sum / (double) n_valid;
|
|
1480
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1481
|
+
double M2 = 0.0;
|
|
1482
|
+
ca_size_t __unused_mc = 0;
|
|
1483
|
+
CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, M2, 0.0, __variance_u64_P2EXPR, __unused_mc);
|
|
1484
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
ca_iter_state_finish(&st);
|
|
1488
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1489
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1490
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1491
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1492
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1493
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1494
|
+
return rb_float_new(op[0]);
|
|
1495
|
+
}
|
|
1496
|
+
return vout;
|
|
1497
|
+
}
|
|
1498
|
+
#undef __variance_u64_P1EXPR
|
|
1499
|
+
#undef __variance_u64_P2EXPR
|
|
1500
|
+
|
|
1501
|
+
#define __variance_f32_P1EXPR(__x) ((double)(__x))
|
|
1502
|
+
#define __variance_f32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1503
|
+
static VALUE
|
|
1504
|
+
variance_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1505
|
+
{
|
|
1506
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1507
|
+
CArray *co;
|
|
1508
|
+
GetCArray(vout, co);
|
|
1509
|
+
double *op = (double *) co->ptr;
|
|
1510
|
+
ca_iter_state st;
|
|
1511
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1512
|
+
slab_axes, naxes, 0);
|
|
1513
|
+
if ( rc != CA_ITER_OK ) {
|
|
1514
|
+
rb_raise(rb_eRuntimeError,
|
|
1515
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1516
|
+
}
|
|
1517
|
+
char *p;
|
|
1518
|
+
boolean8_t *m;
|
|
1519
|
+
ca_size_t out_i = 0;
|
|
1520
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1521
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1522
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1523
|
+
double sum = 0.0;
|
|
1524
|
+
ca_size_t masked_cnt = 0;
|
|
1525
|
+
CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, sum, 0.0, __variance_f32_P1EXPR, masked_cnt);
|
|
1526
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1527
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1528
|
+
if ( __trigger ) {
|
|
1529
|
+
if ( ! op_mask ) {
|
|
1530
|
+
ca_create_mask(co);
|
|
1531
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1532
|
+
}
|
|
1533
|
+
op_mask[out_i] = 1;
|
|
1534
|
+
op[out_i++] = (double) 0.0;
|
|
1535
|
+
} else if ( n_valid < 2 ) {
|
|
1536
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1537
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1538
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1539
|
+
op[out_i++] = (double) 0.0;
|
|
1540
|
+
} else {
|
|
1541
|
+
double mean = sum / (double) n_valid;
|
|
1542
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1543
|
+
double M2 = 0.0;
|
|
1544
|
+
ca_size_t __unused_mc = 0;
|
|
1545
|
+
CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, M2, 0.0, __variance_f32_P2EXPR, __unused_mc);
|
|
1546
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
ca_iter_state_finish(&st);
|
|
1550
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1551
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1552
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1553
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1554
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1555
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1556
|
+
return rb_float_new(op[0]);
|
|
1557
|
+
}
|
|
1558
|
+
return vout;
|
|
1559
|
+
}
|
|
1560
|
+
#undef __variance_f32_P1EXPR
|
|
1561
|
+
#undef __variance_f32_P2EXPR
|
|
1562
|
+
|
|
1563
|
+
#define __variance_f64_P1EXPR(__x) ((double)(__x))
|
|
1564
|
+
#define __variance_f64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1565
|
+
static VALUE
|
|
1566
|
+
variance_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1567
|
+
{
|
|
1568
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1569
|
+
CArray *co;
|
|
1570
|
+
GetCArray(vout, co);
|
|
1571
|
+
double *op = (double *) co->ptr;
|
|
1572
|
+
ca_iter_state st;
|
|
1573
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1574
|
+
slab_axes, naxes, 0);
|
|
1575
|
+
if ( rc != CA_ITER_OK ) {
|
|
1576
|
+
rb_raise(rb_eRuntimeError,
|
|
1577
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1578
|
+
}
|
|
1579
|
+
char *p;
|
|
1580
|
+
boolean8_t *m;
|
|
1581
|
+
ca_size_t out_i = 0;
|
|
1582
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1583
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1584
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1585
|
+
double sum = 0.0;
|
|
1586
|
+
ca_size_t masked_cnt = 0;
|
|
1587
|
+
CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, sum, 0.0, __variance_f64_P1EXPR, masked_cnt);
|
|
1588
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1589
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1590
|
+
if ( __trigger ) {
|
|
1591
|
+
if ( ! op_mask ) {
|
|
1592
|
+
ca_create_mask(co);
|
|
1593
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1594
|
+
}
|
|
1595
|
+
op_mask[out_i] = 1;
|
|
1596
|
+
op[out_i++] = (double) 0.0;
|
|
1597
|
+
} else if ( n_valid < 2 ) {
|
|
1598
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1599
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1600
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1601
|
+
op[out_i++] = (double) 0.0;
|
|
1602
|
+
} else {
|
|
1603
|
+
double mean = sum / (double) n_valid;
|
|
1604
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1605
|
+
double M2 = 0.0;
|
|
1606
|
+
ca_size_t __unused_mc = 0;
|
|
1607
|
+
CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, M2, 0.0, __variance_f64_P2EXPR, __unused_mc);
|
|
1608
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
ca_iter_state_finish(&st);
|
|
1612
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1613
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1614
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1615
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1616
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1617
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1618
|
+
return rb_float_new(op[0]);
|
|
1619
|
+
}
|
|
1620
|
+
return vout;
|
|
1621
|
+
}
|
|
1622
|
+
#undef __variance_f64_P1EXPR
|
|
1623
|
+
#undef __variance_f64_P2EXPR
|
|
1624
|
+
|
|
1625
|
+
#define __variance_cmplx64_P1EXPR(__x) (__x)
|
|
1626
|
+
#define __variance_cmplx64_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
|
|
1627
|
+
static VALUE
|
|
1628
|
+
variance_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1629
|
+
{
|
|
1630
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1631
|
+
CArray *co;
|
|
1632
|
+
GetCArray(vout, co);
|
|
1633
|
+
double *op = (double *) co->ptr;
|
|
1634
|
+
ca_iter_state st;
|
|
1635
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1636
|
+
slab_axes, naxes, 0);
|
|
1637
|
+
if ( rc != CA_ITER_OK ) {
|
|
1638
|
+
rb_raise(rb_eRuntimeError,
|
|
1639
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1640
|
+
}
|
|
1641
|
+
char *p;
|
|
1642
|
+
boolean8_t *m;
|
|
1643
|
+
ca_size_t out_i = 0;
|
|
1644
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1645
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1646
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1647
|
+
cmplx64_t sum = 0;
|
|
1648
|
+
ca_size_t masked_cnt = 0;
|
|
1649
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, cmplx64_t, st, p, m, sum, 0, __variance_cmplx64_P1EXPR, masked_cnt);
|
|
1650
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1651
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1652
|
+
if ( __trigger ) {
|
|
1653
|
+
if ( ! op_mask ) {
|
|
1654
|
+
ca_create_mask(co);
|
|
1655
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1656
|
+
}
|
|
1657
|
+
op_mask[out_i] = 1;
|
|
1658
|
+
op[out_i++] = (double) 0.0;
|
|
1659
|
+
} else if ( n_valid < 2 ) {
|
|
1660
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1661
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1662
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1663
|
+
op[out_i++] = (double) 0.0;
|
|
1664
|
+
} else {
|
|
1665
|
+
cmplx64_t mean = sum / (cmplx64_t)(double) n_valid;
|
|
1666
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1667
|
+
double M2 = 0.0;
|
|
1668
|
+
ca_size_t __unused_mc = 0;
|
|
1669
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, double, st, p, m, M2, 0.0, __variance_cmplx64_P2EXPR, __unused_mc);
|
|
1670
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
ca_iter_state_finish(&st);
|
|
1674
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1675
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1676
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1677
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1678
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1679
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1680
|
+
return rb_float_new(op[0]);
|
|
1681
|
+
}
|
|
1682
|
+
return vout;
|
|
1683
|
+
}
|
|
1684
|
+
#undef __variance_cmplx64_P1EXPR
|
|
1685
|
+
#undef __variance_cmplx64_P2EXPR
|
|
1686
|
+
|
|
1687
|
+
#define __variance_cmplx128_P1EXPR(__x) (__x)
|
|
1688
|
+
#define __variance_cmplx128_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
|
|
1689
|
+
static VALUE
|
|
1690
|
+
variance_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1691
|
+
{
|
|
1692
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1693
|
+
CArray *co;
|
|
1694
|
+
GetCArray(vout, co);
|
|
1695
|
+
double *op = (double *) co->ptr;
|
|
1696
|
+
ca_iter_state st;
|
|
1697
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1698
|
+
slab_axes, naxes, 0);
|
|
1699
|
+
if ( rc != CA_ITER_OK ) {
|
|
1700
|
+
rb_raise(rb_eRuntimeError,
|
|
1701
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1702
|
+
}
|
|
1703
|
+
char *p;
|
|
1704
|
+
boolean8_t *m;
|
|
1705
|
+
ca_size_t out_i = 0;
|
|
1706
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1707
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1708
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1709
|
+
cmplx128_t sum = 0;
|
|
1710
|
+
ca_size_t masked_cnt = 0;
|
|
1711
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, cmplx128_t, st, p, m, sum, 0, __variance_cmplx128_P1EXPR, masked_cnt);
|
|
1712
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1713
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1714
|
+
if ( __trigger ) {
|
|
1715
|
+
if ( ! op_mask ) {
|
|
1716
|
+
ca_create_mask(co);
|
|
1717
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1718
|
+
}
|
|
1719
|
+
op_mask[out_i] = 1;
|
|
1720
|
+
op[out_i++] = (double) 0.0;
|
|
1721
|
+
} else if ( n_valid < 2 ) {
|
|
1722
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1723
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1724
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1725
|
+
op[out_i++] = (double) 0.0;
|
|
1726
|
+
} else {
|
|
1727
|
+
cmplx128_t mean = sum / (cmplx128_t)(double) n_valid;
|
|
1728
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1729
|
+
double M2 = 0.0;
|
|
1730
|
+
ca_size_t __unused_mc = 0;
|
|
1731
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, double, st, p, m, M2, 0.0, __variance_cmplx128_P2EXPR, __unused_mc);
|
|
1732
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
ca_iter_state_finish(&st);
|
|
1736
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1737
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1738
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1739
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1740
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1741
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1742
|
+
return rb_float_new(op[0]);
|
|
1743
|
+
}
|
|
1744
|
+
return vout;
|
|
1745
|
+
}
|
|
1746
|
+
#undef __variance_cmplx128_P1EXPR
|
|
1747
|
+
#undef __variance_cmplx128_P2EXPR
|
|
1748
|
+
|
|
1749
|
+
#define __variance_bool_P1EXPR(__x) ((double)(__x))
|
|
1750
|
+
#define __variance_bool_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1751
|
+
static VALUE
|
|
1752
|
+
variance_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1753
|
+
{
|
|
1754
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1755
|
+
CArray *co;
|
|
1756
|
+
GetCArray(vout, co);
|
|
1757
|
+
double *op = (double *) co->ptr;
|
|
1758
|
+
ca_iter_state st;
|
|
1759
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1760
|
+
slab_axes, naxes, 0);
|
|
1761
|
+
if ( rc != CA_ITER_OK ) {
|
|
1762
|
+
rb_raise(rb_eRuntimeError,
|
|
1763
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1764
|
+
}
|
|
1765
|
+
char *p;
|
|
1766
|
+
boolean8_t *m;
|
|
1767
|
+
ca_size_t out_i = 0;
|
|
1768
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1769
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1770
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1771
|
+
double sum = 0.0;
|
|
1772
|
+
ca_size_t masked_cnt = 0;
|
|
1773
|
+
CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, sum, 0.0, __variance_bool_P1EXPR, masked_cnt);
|
|
1774
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1775
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1776
|
+
if ( __trigger ) {
|
|
1777
|
+
if ( ! op_mask ) {
|
|
1778
|
+
ca_create_mask(co);
|
|
1779
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1780
|
+
}
|
|
1781
|
+
op_mask[out_i] = 1;
|
|
1782
|
+
op[out_i++] = (double) 0.0;
|
|
1783
|
+
} else if ( n_valid < 2 ) {
|
|
1784
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1785
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1786
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1787
|
+
op[out_i++] = (double) 0.0;
|
|
1788
|
+
} else {
|
|
1789
|
+
double mean = sum / (double) n_valid;
|
|
1790
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1791
|
+
double M2 = 0.0;
|
|
1792
|
+
ca_size_t __unused_mc = 0;
|
|
1793
|
+
CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, M2, 0.0, __variance_bool_P2EXPR, __unused_mc);
|
|
1794
|
+
op[out_i++] = (double)(M2 / (double)(n_valid - 1));
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
ca_iter_state_finish(&st);
|
|
1798
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1799
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1800
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1801
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1802
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1803
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1804
|
+
return rb_float_new(op[0]);
|
|
1805
|
+
}
|
|
1806
|
+
return vout;
|
|
1807
|
+
}
|
|
1808
|
+
#undef __variance_bool_P1EXPR
|
|
1809
|
+
#undef __variance_bool_P2EXPR
|
|
1810
|
+
|
|
1811
|
+
static VALUE
|
|
1812
|
+
variance_ki_native_object (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1813
|
+
{
|
|
1814
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_OBJECT, keep_axis);
|
|
1815
|
+
CArray *co;
|
|
1816
|
+
GetCArray(vout, co);
|
|
1817
|
+
VALUE *op = (VALUE *) co->ptr;
|
|
1818
|
+
ca_iter_state st;
|
|
1819
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1820
|
+
slab_axes, naxes, 0);
|
|
1821
|
+
if ( rc != CA_ITER_OK ) {
|
|
1822
|
+
rb_raise(rb_eRuntimeError,
|
|
1823
|
+
"variance_ki: kernel_iterator init failed rc=%d", rc);
|
|
1824
|
+
}
|
|
1825
|
+
char *p;
|
|
1826
|
+
boolean8_t *m;
|
|
1827
|
+
ca_size_t out_i = 0;
|
|
1828
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1829
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1830
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1831
|
+
VALUE sum = INT2FIX(0);
|
|
1832
|
+
ca_size_t masked_cnt = 0;
|
|
1833
|
+
CA_SLAB_REDUCE_T_EX(VALUE, st, p, m, sum, INT2FIX(0), sum = rb_funcall(sum, rb_intern("+"), 1, v), masked_cnt);
|
|
1834
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1835
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1836
|
+
if ( __trigger ) {
|
|
1837
|
+
if ( ! op_mask ) {
|
|
1838
|
+
ca_create_mask(co);
|
|
1839
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
1840
|
+
}
|
|
1841
|
+
op_mask[out_i] = 1;
|
|
1842
|
+
op[out_i++] = (VALUE) INT2FIX(0);
|
|
1843
|
+
} else if ( n_valid < 2 ) {
|
|
1844
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
1845
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
1846
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
1847
|
+
op[out_i++] = (VALUE) INT2FIX(0);
|
|
1848
|
+
} else {
|
|
1849
|
+
VALUE mean = rb_funcall(sum, rb_intern("/"), 1, LONG2NUM(n_valid));
|
|
1850
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
1851
|
+
VALUE M2 = INT2FIX(0);
|
|
1852
|
+
ca_size_t __unused_mc = 0;
|
|
1853
|
+
CA_SLAB_REDUCE_T_EX(VALUE, st, p, m, M2, INT2FIX(0), VALUE __d = rb_funcall(v, rb_intern("-"), 1, mean);
|
|
1854
|
+
M2 = rb_funcall(M2, rb_intern("+"), 1, rb_funcall(__d, rb_intern("*"), 1, __d)), __unused_mc);
|
|
1855
|
+
op[out_i++] = (VALUE)(rb_funcall(M2, rb_intern("/"), 1, LONG2NUM(n_valid - 1)));
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
ca_iter_state_finish(&st);
|
|
1859
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
1860
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
1861
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
1862
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
1863
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
1864
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
1865
|
+
return (VALUE)(op[0]);
|
|
1866
|
+
}
|
|
1867
|
+
return vout;
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
VALUE
|
|
1871
|
+
rb_ca_variance_ki (int argc, VALUE *argv, VALUE self)
|
|
1872
|
+
{
|
|
1873
|
+
CArray *src;
|
|
1874
|
+
GetCArray(self, src);
|
|
1875
|
+
volatile VALUE ropt = rb_pop_options(&argc, &argv);
|
|
1876
|
+
volatile VALUE raxis = Qnil, rkeep_axis = Qnil, rmin_count = Qnil, rfval = Qnil;
|
|
1877
|
+
rb_scan_options(ropt, "axis,keep_axis,min_count,fill_value", &raxis, &rkeep_axis, &rmin_count, &rfval);
|
|
1878
|
+
int keep_axis = RTEST(rkeep_axis);
|
|
1879
|
+
int8_t slab_axes[CA_RANK_MAX];
|
|
1880
|
+
int8_t naxes = rb_ca_parse_reduce_axes_kw(raxis, src, slab_axes);
|
|
1881
|
+
ca_size_t min_count = -1;
|
|
1882
|
+
if ( ! NIL_P(rmin_count) ) {
|
|
1883
|
+
ca_size_t mc_user = NUM2SIZE(rmin_count);
|
|
1884
|
+
if ( mc_user < 0 ) {
|
|
1885
|
+
rb_raise(rb_eArgError, "variance_ki: :min_count must be non-negative, got %lld", (long long) mc_user);
|
|
1886
|
+
}
|
|
1887
|
+
/* :min_count = 0 collapses to legacy default (any 1 valid). */
|
|
1888
|
+
if ( mc_user > 0 ) min_count = mc_user;
|
|
1889
|
+
}
|
|
1890
|
+
VALUE result;
|
|
1891
|
+
if ( argc > 0 ) {
|
|
1892
|
+
rb_raise(rb_eArgError, "variance_ki: positional axis arguments are no longer accepted (got %d); use axis: kwarg, e.g. a.variance(axis: 0) or a.variance(axis: [0, 1])", argc);
|
|
1893
|
+
}
|
|
1894
|
+
switch ( src->data_type ) {
|
|
1895
|
+
case CA_INT8: {
|
|
1896
|
+
result = variance_ki_native_i8(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1897
|
+
break;
|
|
1898
|
+
}
|
|
1899
|
+
case CA_UINT8: {
|
|
1900
|
+
result = variance_ki_native_u8(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1901
|
+
break;
|
|
1902
|
+
}
|
|
1903
|
+
case CA_INT16: {
|
|
1904
|
+
result = variance_ki_native_i16(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1905
|
+
break;
|
|
1906
|
+
}
|
|
1907
|
+
case CA_UINT16: {
|
|
1908
|
+
result = variance_ki_native_u16(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1909
|
+
break;
|
|
1910
|
+
}
|
|
1911
|
+
case CA_INT32: {
|
|
1912
|
+
result = variance_ki_native_i32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1913
|
+
break;
|
|
1914
|
+
}
|
|
1915
|
+
case CA_UINT32: {
|
|
1916
|
+
result = variance_ki_native_u32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1917
|
+
break;
|
|
1918
|
+
}
|
|
1919
|
+
case CA_INT64: {
|
|
1920
|
+
result = variance_ki_native_i64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1921
|
+
break;
|
|
1922
|
+
}
|
|
1923
|
+
case CA_UINT64: {
|
|
1924
|
+
result = variance_ki_native_u64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1925
|
+
break;
|
|
1926
|
+
}
|
|
1927
|
+
case CA_FLOAT32: {
|
|
1928
|
+
result = variance_ki_native_f32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1929
|
+
break;
|
|
1930
|
+
}
|
|
1931
|
+
case CA_FLOAT64: {
|
|
1932
|
+
result = variance_ki_native_f64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1933
|
+
break;
|
|
1934
|
+
}
|
|
1935
|
+
case CA_CMPLX64: {
|
|
1936
|
+
result = variance_ki_native_cmplx64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1937
|
+
break;
|
|
1938
|
+
}
|
|
1939
|
+
case CA_CMPLX128: {
|
|
1940
|
+
result = variance_ki_native_cmplx128(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1941
|
+
break;
|
|
1942
|
+
}
|
|
1943
|
+
case CA_BOOLEAN: {
|
|
1944
|
+
result = variance_ki_native_bool(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1945
|
+
break;
|
|
1946
|
+
}
|
|
1947
|
+
case CA_OBJECT: {
|
|
1948
|
+
result = variance_ki_native_object(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
1949
|
+
break;
|
|
1950
|
+
}
|
|
1951
|
+
default:
|
|
1952
|
+
rb_raise(rb_eCADataTypeError, "variance_ki: source data_type :%s not supported (expected one of: i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, cmplx64, cmplx128, bool, object)", ca_type_name[src->data_type]);
|
|
1953
|
+
}
|
|
1954
|
+
if ( ! NIL_P(rfval) ) {
|
|
1955
|
+
if ( result == CA_UNDEF ) {
|
|
1956
|
+
result = rfval;
|
|
1957
|
+
} else if ( TYPE(result) != T_FLOAT && rb_obj_is_kind_of(result, rb_cCArray) ) {
|
|
1958
|
+
CArray *cr;
|
|
1959
|
+
GetCArray(result, cr);
|
|
1960
|
+
if ( ca_has_mask(cr) ) {
|
|
1961
|
+
result = rb_ca_mask_fill_copy(result, rfval);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
return result;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
/* ===== stddevp_ki ============================================ */
|
|
1969
|
+
|
|
1970
|
+
#define __stddevp_i8_P1EXPR(__x) ((double)(__x))
|
|
1971
|
+
#define __stddevp_i8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
1972
|
+
static VALUE
|
|
1973
|
+
stddevp_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
1974
|
+
{
|
|
1975
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
1976
|
+
CArray *co;
|
|
1977
|
+
GetCArray(vout, co);
|
|
1978
|
+
double *op = (double *) co->ptr;
|
|
1979
|
+
ca_iter_state st;
|
|
1980
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
1981
|
+
slab_axes, naxes, 0);
|
|
1982
|
+
if ( rc != CA_ITER_OK ) {
|
|
1983
|
+
rb_raise(rb_eRuntimeError,
|
|
1984
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
1985
|
+
}
|
|
1986
|
+
char *p;
|
|
1987
|
+
boolean8_t *m;
|
|
1988
|
+
ca_size_t out_i = 0;
|
|
1989
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
1990
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
1991
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
1992
|
+
double sum = 0.0;
|
|
1993
|
+
ca_size_t masked_cnt = 0;
|
|
1994
|
+
CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, sum, 0.0, __stddevp_i8_P1EXPR, masked_cnt);
|
|
1995
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
1996
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
1997
|
+
if ( __trigger ) {
|
|
1998
|
+
if ( ! op_mask ) {
|
|
1999
|
+
ca_create_mask(co);
|
|
2000
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2001
|
+
}
|
|
2002
|
+
op_mask[out_i] = 1;
|
|
2003
|
+
op[out_i++] = (double) 0.0;
|
|
2004
|
+
} else if ( n_valid < 1 ) {
|
|
2005
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2006
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2007
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2008
|
+
op[out_i++] = (double) 0.0;
|
|
2009
|
+
} else {
|
|
2010
|
+
double mean = sum / (double) n_valid;
|
|
2011
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2012
|
+
double M2 = 0.0;
|
|
2013
|
+
ca_size_t __unused_mc = 0;
|
|
2014
|
+
CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, M2, 0.0, __stddevp_i8_P2EXPR, __unused_mc);
|
|
2015
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
ca_iter_state_finish(&st);
|
|
2019
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2020
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2021
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2022
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2023
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2024
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2025
|
+
return rb_float_new(op[0]);
|
|
2026
|
+
}
|
|
2027
|
+
return vout;
|
|
2028
|
+
}
|
|
2029
|
+
#undef __stddevp_i8_P1EXPR
|
|
2030
|
+
#undef __stddevp_i8_P2EXPR
|
|
2031
|
+
|
|
2032
|
+
#define __stddevp_u8_P1EXPR(__x) ((double)(__x))
|
|
2033
|
+
#define __stddevp_u8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2034
|
+
static VALUE
|
|
2035
|
+
stddevp_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2036
|
+
{
|
|
2037
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2038
|
+
CArray *co;
|
|
2039
|
+
GetCArray(vout, co);
|
|
2040
|
+
double *op = (double *) co->ptr;
|
|
2041
|
+
ca_iter_state st;
|
|
2042
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2043
|
+
slab_axes, naxes, 0);
|
|
2044
|
+
if ( rc != CA_ITER_OK ) {
|
|
2045
|
+
rb_raise(rb_eRuntimeError,
|
|
2046
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2047
|
+
}
|
|
2048
|
+
char *p;
|
|
2049
|
+
boolean8_t *m;
|
|
2050
|
+
ca_size_t out_i = 0;
|
|
2051
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2052
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2053
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2054
|
+
double sum = 0.0;
|
|
2055
|
+
ca_size_t masked_cnt = 0;
|
|
2056
|
+
CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, sum, 0.0, __stddevp_u8_P1EXPR, masked_cnt);
|
|
2057
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2058
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2059
|
+
if ( __trigger ) {
|
|
2060
|
+
if ( ! op_mask ) {
|
|
2061
|
+
ca_create_mask(co);
|
|
2062
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2063
|
+
}
|
|
2064
|
+
op_mask[out_i] = 1;
|
|
2065
|
+
op[out_i++] = (double) 0.0;
|
|
2066
|
+
} else if ( n_valid < 1 ) {
|
|
2067
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2068
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2069
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2070
|
+
op[out_i++] = (double) 0.0;
|
|
2071
|
+
} else {
|
|
2072
|
+
double mean = sum / (double) n_valid;
|
|
2073
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2074
|
+
double M2 = 0.0;
|
|
2075
|
+
ca_size_t __unused_mc = 0;
|
|
2076
|
+
CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, M2, 0.0, __stddevp_u8_P2EXPR, __unused_mc);
|
|
2077
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
ca_iter_state_finish(&st);
|
|
2081
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2082
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2083
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2084
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2085
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2086
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2087
|
+
return rb_float_new(op[0]);
|
|
2088
|
+
}
|
|
2089
|
+
return vout;
|
|
2090
|
+
}
|
|
2091
|
+
#undef __stddevp_u8_P1EXPR
|
|
2092
|
+
#undef __stddevp_u8_P2EXPR
|
|
2093
|
+
|
|
2094
|
+
#define __stddevp_i16_P1EXPR(__x) ((double)(__x))
|
|
2095
|
+
#define __stddevp_i16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2096
|
+
static VALUE
|
|
2097
|
+
stddevp_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2098
|
+
{
|
|
2099
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2100
|
+
CArray *co;
|
|
2101
|
+
GetCArray(vout, co);
|
|
2102
|
+
double *op = (double *) co->ptr;
|
|
2103
|
+
ca_iter_state st;
|
|
2104
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2105
|
+
slab_axes, naxes, 0);
|
|
2106
|
+
if ( rc != CA_ITER_OK ) {
|
|
2107
|
+
rb_raise(rb_eRuntimeError,
|
|
2108
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2109
|
+
}
|
|
2110
|
+
char *p;
|
|
2111
|
+
boolean8_t *m;
|
|
2112
|
+
ca_size_t out_i = 0;
|
|
2113
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2114
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2115
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2116
|
+
double sum = 0.0;
|
|
2117
|
+
ca_size_t masked_cnt = 0;
|
|
2118
|
+
CA_SLAB_REDUCE_SUM8_EX(int16_t, double, st, p, m, sum, 0.0, __stddevp_i16_P1EXPR, masked_cnt);
|
|
2119
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2120
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2121
|
+
if ( __trigger ) {
|
|
2122
|
+
if ( ! op_mask ) {
|
|
2123
|
+
ca_create_mask(co);
|
|
2124
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2125
|
+
}
|
|
2126
|
+
op_mask[out_i] = 1;
|
|
2127
|
+
op[out_i++] = (double) 0.0;
|
|
2128
|
+
} else if ( n_valid < 1 ) {
|
|
2129
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2130
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2131
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2132
|
+
op[out_i++] = (double) 0.0;
|
|
2133
|
+
} else {
|
|
2134
|
+
double mean = sum / (double) n_valid;
|
|
2135
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2136
|
+
double M2 = 0.0;
|
|
2137
|
+
ca_size_t __unused_mc = 0;
|
|
2138
|
+
CA_SLAB_REDUCE_SUM8_EX(int16_t, double, st, p, m, M2, 0.0, __stddevp_i16_P2EXPR, __unused_mc);
|
|
2139
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
ca_iter_state_finish(&st);
|
|
2143
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2144
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2145
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2146
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2147
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2148
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2149
|
+
return rb_float_new(op[0]);
|
|
2150
|
+
}
|
|
2151
|
+
return vout;
|
|
2152
|
+
}
|
|
2153
|
+
#undef __stddevp_i16_P1EXPR
|
|
2154
|
+
#undef __stddevp_i16_P2EXPR
|
|
2155
|
+
|
|
2156
|
+
#define __stddevp_u16_P1EXPR(__x) ((double)(__x))
|
|
2157
|
+
#define __stddevp_u16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2158
|
+
static VALUE
|
|
2159
|
+
stddevp_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2160
|
+
{
|
|
2161
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2162
|
+
CArray *co;
|
|
2163
|
+
GetCArray(vout, co);
|
|
2164
|
+
double *op = (double *) co->ptr;
|
|
2165
|
+
ca_iter_state st;
|
|
2166
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2167
|
+
slab_axes, naxes, 0);
|
|
2168
|
+
if ( rc != CA_ITER_OK ) {
|
|
2169
|
+
rb_raise(rb_eRuntimeError,
|
|
2170
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2171
|
+
}
|
|
2172
|
+
char *p;
|
|
2173
|
+
boolean8_t *m;
|
|
2174
|
+
ca_size_t out_i = 0;
|
|
2175
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2176
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2177
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2178
|
+
double sum = 0.0;
|
|
2179
|
+
ca_size_t masked_cnt = 0;
|
|
2180
|
+
CA_SLAB_REDUCE_SUM8_EX(uint16_t, double, st, p, m, sum, 0.0, __stddevp_u16_P1EXPR, masked_cnt);
|
|
2181
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2182
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2183
|
+
if ( __trigger ) {
|
|
2184
|
+
if ( ! op_mask ) {
|
|
2185
|
+
ca_create_mask(co);
|
|
2186
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2187
|
+
}
|
|
2188
|
+
op_mask[out_i] = 1;
|
|
2189
|
+
op[out_i++] = (double) 0.0;
|
|
2190
|
+
} else if ( n_valid < 1 ) {
|
|
2191
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2192
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2193
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2194
|
+
op[out_i++] = (double) 0.0;
|
|
2195
|
+
} else {
|
|
2196
|
+
double mean = sum / (double) n_valid;
|
|
2197
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2198
|
+
double M2 = 0.0;
|
|
2199
|
+
ca_size_t __unused_mc = 0;
|
|
2200
|
+
CA_SLAB_REDUCE_SUM8_EX(uint16_t, double, st, p, m, M2, 0.0, __stddevp_u16_P2EXPR, __unused_mc);
|
|
2201
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
ca_iter_state_finish(&st);
|
|
2205
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2206
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2207
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2208
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2209
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2210
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2211
|
+
return rb_float_new(op[0]);
|
|
2212
|
+
}
|
|
2213
|
+
return vout;
|
|
2214
|
+
}
|
|
2215
|
+
#undef __stddevp_u16_P1EXPR
|
|
2216
|
+
#undef __stddevp_u16_P2EXPR
|
|
2217
|
+
|
|
2218
|
+
#define __stddevp_i32_P1EXPR(__x) ((double)(__x))
|
|
2219
|
+
#define __stddevp_i32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2220
|
+
static VALUE
|
|
2221
|
+
stddevp_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2222
|
+
{
|
|
2223
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2224
|
+
CArray *co;
|
|
2225
|
+
GetCArray(vout, co);
|
|
2226
|
+
double *op = (double *) co->ptr;
|
|
2227
|
+
ca_iter_state st;
|
|
2228
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2229
|
+
slab_axes, naxes, 0);
|
|
2230
|
+
if ( rc != CA_ITER_OK ) {
|
|
2231
|
+
rb_raise(rb_eRuntimeError,
|
|
2232
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2233
|
+
}
|
|
2234
|
+
char *p;
|
|
2235
|
+
boolean8_t *m;
|
|
2236
|
+
ca_size_t out_i = 0;
|
|
2237
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2238
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2239
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2240
|
+
double sum = 0.0;
|
|
2241
|
+
ca_size_t masked_cnt = 0;
|
|
2242
|
+
CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, sum, 0.0, __stddevp_i32_P1EXPR, masked_cnt);
|
|
2243
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2244
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2245
|
+
if ( __trigger ) {
|
|
2246
|
+
if ( ! op_mask ) {
|
|
2247
|
+
ca_create_mask(co);
|
|
2248
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2249
|
+
}
|
|
2250
|
+
op_mask[out_i] = 1;
|
|
2251
|
+
op[out_i++] = (double) 0.0;
|
|
2252
|
+
} else if ( n_valid < 1 ) {
|
|
2253
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2254
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2255
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2256
|
+
op[out_i++] = (double) 0.0;
|
|
2257
|
+
} else {
|
|
2258
|
+
double mean = sum / (double) n_valid;
|
|
2259
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2260
|
+
double M2 = 0.0;
|
|
2261
|
+
ca_size_t __unused_mc = 0;
|
|
2262
|
+
CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, M2, 0.0, __stddevp_i32_P2EXPR, __unused_mc);
|
|
2263
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
ca_iter_state_finish(&st);
|
|
2267
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2268
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2269
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2270
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2271
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2272
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2273
|
+
return rb_float_new(op[0]);
|
|
2274
|
+
}
|
|
2275
|
+
return vout;
|
|
2276
|
+
}
|
|
2277
|
+
#undef __stddevp_i32_P1EXPR
|
|
2278
|
+
#undef __stddevp_i32_P2EXPR
|
|
2279
|
+
|
|
2280
|
+
#define __stddevp_u32_P1EXPR(__x) ((double)(__x))
|
|
2281
|
+
#define __stddevp_u32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2282
|
+
static VALUE
|
|
2283
|
+
stddevp_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2284
|
+
{
|
|
2285
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2286
|
+
CArray *co;
|
|
2287
|
+
GetCArray(vout, co);
|
|
2288
|
+
double *op = (double *) co->ptr;
|
|
2289
|
+
ca_iter_state st;
|
|
2290
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2291
|
+
slab_axes, naxes, 0);
|
|
2292
|
+
if ( rc != CA_ITER_OK ) {
|
|
2293
|
+
rb_raise(rb_eRuntimeError,
|
|
2294
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2295
|
+
}
|
|
2296
|
+
char *p;
|
|
2297
|
+
boolean8_t *m;
|
|
2298
|
+
ca_size_t out_i = 0;
|
|
2299
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2300
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2301
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2302
|
+
double sum = 0.0;
|
|
2303
|
+
ca_size_t masked_cnt = 0;
|
|
2304
|
+
CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, sum, 0.0, __stddevp_u32_P1EXPR, masked_cnt);
|
|
2305
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2306
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2307
|
+
if ( __trigger ) {
|
|
2308
|
+
if ( ! op_mask ) {
|
|
2309
|
+
ca_create_mask(co);
|
|
2310
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2311
|
+
}
|
|
2312
|
+
op_mask[out_i] = 1;
|
|
2313
|
+
op[out_i++] = (double) 0.0;
|
|
2314
|
+
} else if ( n_valid < 1 ) {
|
|
2315
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2316
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2317
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2318
|
+
op[out_i++] = (double) 0.0;
|
|
2319
|
+
} else {
|
|
2320
|
+
double mean = sum / (double) n_valid;
|
|
2321
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2322
|
+
double M2 = 0.0;
|
|
2323
|
+
ca_size_t __unused_mc = 0;
|
|
2324
|
+
CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, M2, 0.0, __stddevp_u32_P2EXPR, __unused_mc);
|
|
2325
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
ca_iter_state_finish(&st);
|
|
2329
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2330
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2331
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2332
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2333
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2334
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2335
|
+
return rb_float_new(op[0]);
|
|
2336
|
+
}
|
|
2337
|
+
return vout;
|
|
2338
|
+
}
|
|
2339
|
+
#undef __stddevp_u32_P1EXPR
|
|
2340
|
+
#undef __stddevp_u32_P2EXPR
|
|
2341
|
+
|
|
2342
|
+
#define __stddevp_i64_P1EXPR(__x) ((double)(__x))
|
|
2343
|
+
#define __stddevp_i64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2344
|
+
static VALUE
|
|
2345
|
+
stddevp_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2346
|
+
{
|
|
2347
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2348
|
+
CArray *co;
|
|
2349
|
+
GetCArray(vout, co);
|
|
2350
|
+
double *op = (double *) co->ptr;
|
|
2351
|
+
ca_iter_state st;
|
|
2352
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2353
|
+
slab_axes, naxes, 0);
|
|
2354
|
+
if ( rc != CA_ITER_OK ) {
|
|
2355
|
+
rb_raise(rb_eRuntimeError,
|
|
2356
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2357
|
+
}
|
|
2358
|
+
char *p;
|
|
2359
|
+
boolean8_t *m;
|
|
2360
|
+
ca_size_t out_i = 0;
|
|
2361
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2362
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2363
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2364
|
+
double sum = 0.0;
|
|
2365
|
+
ca_size_t masked_cnt = 0;
|
|
2366
|
+
CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, sum, 0.0, __stddevp_i64_P1EXPR, masked_cnt);
|
|
2367
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2368
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2369
|
+
if ( __trigger ) {
|
|
2370
|
+
if ( ! op_mask ) {
|
|
2371
|
+
ca_create_mask(co);
|
|
2372
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2373
|
+
}
|
|
2374
|
+
op_mask[out_i] = 1;
|
|
2375
|
+
op[out_i++] = (double) 0.0;
|
|
2376
|
+
} else if ( n_valid < 1 ) {
|
|
2377
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2378
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2379
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2380
|
+
op[out_i++] = (double) 0.0;
|
|
2381
|
+
} else {
|
|
2382
|
+
double mean = sum / (double) n_valid;
|
|
2383
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2384
|
+
double M2 = 0.0;
|
|
2385
|
+
ca_size_t __unused_mc = 0;
|
|
2386
|
+
CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, M2, 0.0, __stddevp_i64_P2EXPR, __unused_mc);
|
|
2387
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
ca_iter_state_finish(&st);
|
|
2391
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2392
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2393
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2394
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2395
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2396
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2397
|
+
return rb_float_new(op[0]);
|
|
2398
|
+
}
|
|
2399
|
+
return vout;
|
|
2400
|
+
}
|
|
2401
|
+
#undef __stddevp_i64_P1EXPR
|
|
2402
|
+
#undef __stddevp_i64_P2EXPR
|
|
2403
|
+
|
|
2404
|
+
#define __stddevp_u64_P1EXPR(__x) ((double)(__x))
|
|
2405
|
+
#define __stddevp_u64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2406
|
+
static VALUE
|
|
2407
|
+
stddevp_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2408
|
+
{
|
|
2409
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2410
|
+
CArray *co;
|
|
2411
|
+
GetCArray(vout, co);
|
|
2412
|
+
double *op = (double *) co->ptr;
|
|
2413
|
+
ca_iter_state st;
|
|
2414
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2415
|
+
slab_axes, naxes, 0);
|
|
2416
|
+
if ( rc != CA_ITER_OK ) {
|
|
2417
|
+
rb_raise(rb_eRuntimeError,
|
|
2418
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2419
|
+
}
|
|
2420
|
+
char *p;
|
|
2421
|
+
boolean8_t *m;
|
|
2422
|
+
ca_size_t out_i = 0;
|
|
2423
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2424
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2425
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2426
|
+
double sum = 0.0;
|
|
2427
|
+
ca_size_t masked_cnt = 0;
|
|
2428
|
+
CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, sum, 0.0, __stddevp_u64_P1EXPR, masked_cnt);
|
|
2429
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2430
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2431
|
+
if ( __trigger ) {
|
|
2432
|
+
if ( ! op_mask ) {
|
|
2433
|
+
ca_create_mask(co);
|
|
2434
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2435
|
+
}
|
|
2436
|
+
op_mask[out_i] = 1;
|
|
2437
|
+
op[out_i++] = (double) 0.0;
|
|
2438
|
+
} else if ( n_valid < 1 ) {
|
|
2439
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2440
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2441
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2442
|
+
op[out_i++] = (double) 0.0;
|
|
2443
|
+
} else {
|
|
2444
|
+
double mean = sum / (double) n_valid;
|
|
2445
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2446
|
+
double M2 = 0.0;
|
|
2447
|
+
ca_size_t __unused_mc = 0;
|
|
2448
|
+
CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, M2, 0.0, __stddevp_u64_P2EXPR, __unused_mc);
|
|
2449
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
ca_iter_state_finish(&st);
|
|
2453
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2454
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2455
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2456
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2457
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2458
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2459
|
+
return rb_float_new(op[0]);
|
|
2460
|
+
}
|
|
2461
|
+
return vout;
|
|
2462
|
+
}
|
|
2463
|
+
#undef __stddevp_u64_P1EXPR
|
|
2464
|
+
#undef __stddevp_u64_P2EXPR
|
|
2465
|
+
|
|
2466
|
+
#define __stddevp_f32_P1EXPR(__x) ((double)(__x))
|
|
2467
|
+
#define __stddevp_f32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2468
|
+
static VALUE
|
|
2469
|
+
stddevp_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2470
|
+
{
|
|
2471
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2472
|
+
CArray *co;
|
|
2473
|
+
GetCArray(vout, co);
|
|
2474
|
+
double *op = (double *) co->ptr;
|
|
2475
|
+
ca_iter_state st;
|
|
2476
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2477
|
+
slab_axes, naxes, 0);
|
|
2478
|
+
if ( rc != CA_ITER_OK ) {
|
|
2479
|
+
rb_raise(rb_eRuntimeError,
|
|
2480
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2481
|
+
}
|
|
2482
|
+
char *p;
|
|
2483
|
+
boolean8_t *m;
|
|
2484
|
+
ca_size_t out_i = 0;
|
|
2485
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2486
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2487
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2488
|
+
double sum = 0.0;
|
|
2489
|
+
ca_size_t masked_cnt = 0;
|
|
2490
|
+
CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, sum, 0.0, __stddevp_f32_P1EXPR, masked_cnt);
|
|
2491
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2492
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2493
|
+
if ( __trigger ) {
|
|
2494
|
+
if ( ! op_mask ) {
|
|
2495
|
+
ca_create_mask(co);
|
|
2496
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2497
|
+
}
|
|
2498
|
+
op_mask[out_i] = 1;
|
|
2499
|
+
op[out_i++] = (double) 0.0;
|
|
2500
|
+
} else if ( n_valid < 1 ) {
|
|
2501
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2502
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2503
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2504
|
+
op[out_i++] = (double) 0.0;
|
|
2505
|
+
} else {
|
|
2506
|
+
double mean = sum / (double) n_valid;
|
|
2507
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2508
|
+
double M2 = 0.0;
|
|
2509
|
+
ca_size_t __unused_mc = 0;
|
|
2510
|
+
CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, M2, 0.0, __stddevp_f32_P2EXPR, __unused_mc);
|
|
2511
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
ca_iter_state_finish(&st);
|
|
2515
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2516
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2517
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2518
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2519
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2520
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2521
|
+
return rb_float_new(op[0]);
|
|
2522
|
+
}
|
|
2523
|
+
return vout;
|
|
2524
|
+
}
|
|
2525
|
+
#undef __stddevp_f32_P1EXPR
|
|
2526
|
+
#undef __stddevp_f32_P2EXPR
|
|
2527
|
+
|
|
2528
|
+
#define __stddevp_f64_P1EXPR(__x) ((double)(__x))
|
|
2529
|
+
#define __stddevp_f64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2530
|
+
static VALUE
|
|
2531
|
+
stddevp_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2532
|
+
{
|
|
2533
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2534
|
+
CArray *co;
|
|
2535
|
+
GetCArray(vout, co);
|
|
2536
|
+
double *op = (double *) co->ptr;
|
|
2537
|
+
ca_iter_state st;
|
|
2538
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2539
|
+
slab_axes, naxes, 0);
|
|
2540
|
+
if ( rc != CA_ITER_OK ) {
|
|
2541
|
+
rb_raise(rb_eRuntimeError,
|
|
2542
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2543
|
+
}
|
|
2544
|
+
char *p;
|
|
2545
|
+
boolean8_t *m;
|
|
2546
|
+
ca_size_t out_i = 0;
|
|
2547
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2548
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2549
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2550
|
+
double sum = 0.0;
|
|
2551
|
+
ca_size_t masked_cnt = 0;
|
|
2552
|
+
CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, sum, 0.0, __stddevp_f64_P1EXPR, masked_cnt);
|
|
2553
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2554
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2555
|
+
if ( __trigger ) {
|
|
2556
|
+
if ( ! op_mask ) {
|
|
2557
|
+
ca_create_mask(co);
|
|
2558
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2559
|
+
}
|
|
2560
|
+
op_mask[out_i] = 1;
|
|
2561
|
+
op[out_i++] = (double) 0.0;
|
|
2562
|
+
} else if ( n_valid < 1 ) {
|
|
2563
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2564
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2565
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2566
|
+
op[out_i++] = (double) 0.0;
|
|
2567
|
+
} else {
|
|
2568
|
+
double mean = sum / (double) n_valid;
|
|
2569
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2570
|
+
double M2 = 0.0;
|
|
2571
|
+
ca_size_t __unused_mc = 0;
|
|
2572
|
+
CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, M2, 0.0, __stddevp_f64_P2EXPR, __unused_mc);
|
|
2573
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
ca_iter_state_finish(&st);
|
|
2577
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2578
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2579
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2580
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2581
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2582
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2583
|
+
return rb_float_new(op[0]);
|
|
2584
|
+
}
|
|
2585
|
+
return vout;
|
|
2586
|
+
}
|
|
2587
|
+
#undef __stddevp_f64_P1EXPR
|
|
2588
|
+
#undef __stddevp_f64_P2EXPR
|
|
2589
|
+
|
|
2590
|
+
#define __stddevp_cmplx64_P1EXPR(__x) (__x)
|
|
2591
|
+
#define __stddevp_cmplx64_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
|
|
2592
|
+
static VALUE
|
|
2593
|
+
stddevp_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2594
|
+
{
|
|
2595
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2596
|
+
CArray *co;
|
|
2597
|
+
GetCArray(vout, co);
|
|
2598
|
+
double *op = (double *) co->ptr;
|
|
2599
|
+
ca_iter_state st;
|
|
2600
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2601
|
+
slab_axes, naxes, 0);
|
|
2602
|
+
if ( rc != CA_ITER_OK ) {
|
|
2603
|
+
rb_raise(rb_eRuntimeError,
|
|
2604
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2605
|
+
}
|
|
2606
|
+
char *p;
|
|
2607
|
+
boolean8_t *m;
|
|
2608
|
+
ca_size_t out_i = 0;
|
|
2609
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2610
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2611
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2612
|
+
cmplx64_t sum = 0;
|
|
2613
|
+
ca_size_t masked_cnt = 0;
|
|
2614
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, cmplx64_t, st, p, m, sum, 0, __stddevp_cmplx64_P1EXPR, masked_cnt);
|
|
2615
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2616
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2617
|
+
if ( __trigger ) {
|
|
2618
|
+
if ( ! op_mask ) {
|
|
2619
|
+
ca_create_mask(co);
|
|
2620
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2621
|
+
}
|
|
2622
|
+
op_mask[out_i] = 1;
|
|
2623
|
+
op[out_i++] = (double) 0.0;
|
|
2624
|
+
} else if ( n_valid < 1 ) {
|
|
2625
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2626
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2627
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2628
|
+
op[out_i++] = (double) 0.0;
|
|
2629
|
+
} else {
|
|
2630
|
+
cmplx64_t mean = sum / (cmplx64_t)(double) n_valid;
|
|
2631
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2632
|
+
double M2 = 0.0;
|
|
2633
|
+
ca_size_t __unused_mc = 0;
|
|
2634
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, double, st, p, m, M2, 0.0, __stddevp_cmplx64_P2EXPR, __unused_mc);
|
|
2635
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
ca_iter_state_finish(&st);
|
|
2639
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2640
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2641
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2642
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2643
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2644
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2645
|
+
return rb_float_new(op[0]);
|
|
2646
|
+
}
|
|
2647
|
+
return vout;
|
|
2648
|
+
}
|
|
2649
|
+
#undef __stddevp_cmplx64_P1EXPR
|
|
2650
|
+
#undef __stddevp_cmplx64_P2EXPR
|
|
2651
|
+
|
|
2652
|
+
#define __stddevp_cmplx128_P1EXPR(__x) (__x)
|
|
2653
|
+
#define __stddevp_cmplx128_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
|
|
2654
|
+
static VALUE
|
|
2655
|
+
stddevp_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2656
|
+
{
|
|
2657
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2658
|
+
CArray *co;
|
|
2659
|
+
GetCArray(vout, co);
|
|
2660
|
+
double *op = (double *) co->ptr;
|
|
2661
|
+
ca_iter_state st;
|
|
2662
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2663
|
+
slab_axes, naxes, 0);
|
|
2664
|
+
if ( rc != CA_ITER_OK ) {
|
|
2665
|
+
rb_raise(rb_eRuntimeError,
|
|
2666
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2667
|
+
}
|
|
2668
|
+
char *p;
|
|
2669
|
+
boolean8_t *m;
|
|
2670
|
+
ca_size_t out_i = 0;
|
|
2671
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2672
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2673
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2674
|
+
cmplx128_t sum = 0;
|
|
2675
|
+
ca_size_t masked_cnt = 0;
|
|
2676
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, cmplx128_t, st, p, m, sum, 0, __stddevp_cmplx128_P1EXPR, masked_cnt);
|
|
2677
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2678
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2679
|
+
if ( __trigger ) {
|
|
2680
|
+
if ( ! op_mask ) {
|
|
2681
|
+
ca_create_mask(co);
|
|
2682
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2683
|
+
}
|
|
2684
|
+
op_mask[out_i] = 1;
|
|
2685
|
+
op[out_i++] = (double) 0.0;
|
|
2686
|
+
} else if ( n_valid < 1 ) {
|
|
2687
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2688
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2689
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2690
|
+
op[out_i++] = (double) 0.0;
|
|
2691
|
+
} else {
|
|
2692
|
+
cmplx128_t mean = sum / (cmplx128_t)(double) n_valid;
|
|
2693
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2694
|
+
double M2 = 0.0;
|
|
2695
|
+
ca_size_t __unused_mc = 0;
|
|
2696
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, double, st, p, m, M2, 0.0, __stddevp_cmplx128_P2EXPR, __unused_mc);
|
|
2697
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
ca_iter_state_finish(&st);
|
|
2701
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2702
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2703
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2704
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2705
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2706
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2707
|
+
return rb_float_new(op[0]);
|
|
2708
|
+
}
|
|
2709
|
+
return vout;
|
|
2710
|
+
}
|
|
2711
|
+
#undef __stddevp_cmplx128_P1EXPR
|
|
2712
|
+
#undef __stddevp_cmplx128_P2EXPR
|
|
2713
|
+
|
|
2714
|
+
#define __stddevp_bool_P1EXPR(__x) ((double)(__x))
|
|
2715
|
+
#define __stddevp_bool_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2716
|
+
static VALUE
|
|
2717
|
+
stddevp_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2718
|
+
{
|
|
2719
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2720
|
+
CArray *co;
|
|
2721
|
+
GetCArray(vout, co);
|
|
2722
|
+
double *op = (double *) co->ptr;
|
|
2723
|
+
ca_iter_state st;
|
|
2724
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2725
|
+
slab_axes, naxes, 0);
|
|
2726
|
+
if ( rc != CA_ITER_OK ) {
|
|
2727
|
+
rb_raise(rb_eRuntimeError,
|
|
2728
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2729
|
+
}
|
|
2730
|
+
char *p;
|
|
2731
|
+
boolean8_t *m;
|
|
2732
|
+
ca_size_t out_i = 0;
|
|
2733
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2734
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2735
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2736
|
+
double sum = 0.0;
|
|
2737
|
+
ca_size_t masked_cnt = 0;
|
|
2738
|
+
CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, sum, 0.0, __stddevp_bool_P1EXPR, masked_cnt);
|
|
2739
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2740
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2741
|
+
if ( __trigger ) {
|
|
2742
|
+
if ( ! op_mask ) {
|
|
2743
|
+
ca_create_mask(co);
|
|
2744
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2745
|
+
}
|
|
2746
|
+
op_mask[out_i] = 1;
|
|
2747
|
+
op[out_i++] = (double) 0.0;
|
|
2748
|
+
} else if ( n_valid < 1 ) {
|
|
2749
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2750
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2751
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2752
|
+
op[out_i++] = (double) 0.0;
|
|
2753
|
+
} else {
|
|
2754
|
+
double mean = sum / (double) n_valid;
|
|
2755
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2756
|
+
double M2 = 0.0;
|
|
2757
|
+
ca_size_t __unused_mc = 0;
|
|
2758
|
+
CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, M2, 0.0, __stddevp_bool_P2EXPR, __unused_mc);
|
|
2759
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid), 0.0)));
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
ca_iter_state_finish(&st);
|
|
2763
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2764
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2765
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2766
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2767
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2768
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2769
|
+
return rb_float_new(op[0]);
|
|
2770
|
+
}
|
|
2771
|
+
return vout;
|
|
2772
|
+
}
|
|
2773
|
+
#undef __stddevp_bool_P1EXPR
|
|
2774
|
+
#undef __stddevp_bool_P2EXPR
|
|
2775
|
+
|
|
2776
|
+
static VALUE
|
|
2777
|
+
stddevp_ki_native_object (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2778
|
+
{
|
|
2779
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2780
|
+
CArray *co;
|
|
2781
|
+
GetCArray(vout, co);
|
|
2782
|
+
double *op = (double *) co->ptr;
|
|
2783
|
+
ca_iter_state st;
|
|
2784
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2785
|
+
slab_axes, naxes, 0);
|
|
2786
|
+
if ( rc != CA_ITER_OK ) {
|
|
2787
|
+
rb_raise(rb_eRuntimeError,
|
|
2788
|
+
"stddevp_ki: kernel_iterator init failed rc=%d", rc);
|
|
2789
|
+
}
|
|
2790
|
+
char *p;
|
|
2791
|
+
boolean8_t *m;
|
|
2792
|
+
ca_size_t out_i = 0;
|
|
2793
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2794
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2795
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2796
|
+
VALUE sum = INT2FIX(0);
|
|
2797
|
+
ca_size_t masked_cnt = 0;
|
|
2798
|
+
CA_SLAB_REDUCE_T_EX(VALUE, st, p, m, sum, INT2FIX(0), sum = rb_funcall(sum, rb_intern("+"), 1, v), masked_cnt);
|
|
2799
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2800
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2801
|
+
if ( __trigger ) {
|
|
2802
|
+
if ( ! op_mask ) {
|
|
2803
|
+
ca_create_mask(co);
|
|
2804
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2805
|
+
}
|
|
2806
|
+
op_mask[out_i] = 1;
|
|
2807
|
+
op[out_i++] = (double) 0.0;
|
|
2808
|
+
} else if ( n_valid < 1 ) {
|
|
2809
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2810
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2811
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2812
|
+
op[out_i++] = (double) 0.0;
|
|
2813
|
+
} else {
|
|
2814
|
+
VALUE mean = rb_funcall(sum, rb_intern("/"), 1, LONG2NUM(n_valid));
|
|
2815
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2816
|
+
VALUE M2 = INT2FIX(0);
|
|
2817
|
+
ca_size_t __unused_mc = 0;
|
|
2818
|
+
CA_SLAB_REDUCE_T_EX(VALUE, st, p, m, M2, INT2FIX(0), VALUE __d = rb_funcall(v, rb_intern("-"), 1, mean);
|
|
2819
|
+
M2 = rb_funcall(M2, rb_intern("+"), 1, rb_funcall(__d, rb_intern("*"), 1, __d)), __unused_mc);
|
|
2820
|
+
op[out_i++] = (double)(sqrt(fmax(NUM2DBL(rb_funcall(M2, rb_intern("/"), 1, LONG2NUM(n_valid))), 0.0)));
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
ca_iter_state_finish(&st);
|
|
2824
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2825
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2826
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2827
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2828
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2829
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2830
|
+
return rb_float_new(op[0]);
|
|
2831
|
+
}
|
|
2832
|
+
return vout;
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
VALUE
|
|
2836
|
+
rb_ca_stddevp_ki (int argc, VALUE *argv, VALUE self)
|
|
2837
|
+
{
|
|
2838
|
+
CArray *src;
|
|
2839
|
+
GetCArray(self, src);
|
|
2840
|
+
volatile VALUE ropt = rb_pop_options(&argc, &argv);
|
|
2841
|
+
volatile VALUE raxis = Qnil, rkeep_axis = Qnil, rmin_count = Qnil, rfval = Qnil;
|
|
2842
|
+
rb_scan_options(ropt, "axis,keep_axis,min_count,fill_value", &raxis, &rkeep_axis, &rmin_count, &rfval);
|
|
2843
|
+
int keep_axis = RTEST(rkeep_axis);
|
|
2844
|
+
int8_t slab_axes[CA_RANK_MAX];
|
|
2845
|
+
int8_t naxes = rb_ca_parse_reduce_axes_kw(raxis, src, slab_axes);
|
|
2846
|
+
ca_size_t min_count = -1;
|
|
2847
|
+
if ( ! NIL_P(rmin_count) ) {
|
|
2848
|
+
ca_size_t mc_user = NUM2SIZE(rmin_count);
|
|
2849
|
+
if ( mc_user < 0 ) {
|
|
2850
|
+
rb_raise(rb_eArgError, "stddevp_ki: :min_count must be non-negative, got %lld", (long long) mc_user);
|
|
2851
|
+
}
|
|
2852
|
+
/* :min_count = 0 collapses to legacy default (any 1 valid). */
|
|
2853
|
+
if ( mc_user > 0 ) min_count = mc_user;
|
|
2854
|
+
}
|
|
2855
|
+
VALUE result;
|
|
2856
|
+
if ( argc > 0 ) {
|
|
2857
|
+
rb_raise(rb_eArgError, "stddevp_ki: positional axis arguments are no longer accepted (got %d); use axis: kwarg, e.g. a.stddevp(axis: 0) or a.stddevp(axis: [0, 1])", argc);
|
|
2858
|
+
}
|
|
2859
|
+
switch ( src->data_type ) {
|
|
2860
|
+
case CA_INT8: {
|
|
2861
|
+
result = stddevp_ki_native_i8(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2862
|
+
break;
|
|
2863
|
+
}
|
|
2864
|
+
case CA_UINT8: {
|
|
2865
|
+
result = stddevp_ki_native_u8(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2866
|
+
break;
|
|
2867
|
+
}
|
|
2868
|
+
case CA_INT16: {
|
|
2869
|
+
result = stddevp_ki_native_i16(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2870
|
+
break;
|
|
2871
|
+
}
|
|
2872
|
+
case CA_UINT16: {
|
|
2873
|
+
result = stddevp_ki_native_u16(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2874
|
+
break;
|
|
2875
|
+
}
|
|
2876
|
+
case CA_INT32: {
|
|
2877
|
+
result = stddevp_ki_native_i32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2878
|
+
break;
|
|
2879
|
+
}
|
|
2880
|
+
case CA_UINT32: {
|
|
2881
|
+
result = stddevp_ki_native_u32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2882
|
+
break;
|
|
2883
|
+
}
|
|
2884
|
+
case CA_INT64: {
|
|
2885
|
+
result = stddevp_ki_native_i64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2886
|
+
break;
|
|
2887
|
+
}
|
|
2888
|
+
case CA_UINT64: {
|
|
2889
|
+
result = stddevp_ki_native_u64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2890
|
+
break;
|
|
2891
|
+
}
|
|
2892
|
+
case CA_FLOAT32: {
|
|
2893
|
+
result = stddevp_ki_native_f32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2894
|
+
break;
|
|
2895
|
+
}
|
|
2896
|
+
case CA_FLOAT64: {
|
|
2897
|
+
result = stddevp_ki_native_f64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2898
|
+
break;
|
|
2899
|
+
}
|
|
2900
|
+
case CA_CMPLX64: {
|
|
2901
|
+
result = stddevp_ki_native_cmplx64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2902
|
+
break;
|
|
2903
|
+
}
|
|
2904
|
+
case CA_CMPLX128: {
|
|
2905
|
+
result = stddevp_ki_native_cmplx128(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2906
|
+
break;
|
|
2907
|
+
}
|
|
2908
|
+
case CA_BOOLEAN: {
|
|
2909
|
+
result = stddevp_ki_native_bool(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2910
|
+
break;
|
|
2911
|
+
}
|
|
2912
|
+
case CA_OBJECT: {
|
|
2913
|
+
result = stddevp_ki_native_object(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
2914
|
+
break;
|
|
2915
|
+
}
|
|
2916
|
+
default:
|
|
2917
|
+
rb_raise(rb_eCADataTypeError, "stddevp_ki: source data_type :%s not supported (expected one of: i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, cmplx64, cmplx128, bool, object)", ca_type_name[src->data_type]);
|
|
2918
|
+
}
|
|
2919
|
+
if ( ! NIL_P(rfval) ) {
|
|
2920
|
+
if ( result == CA_UNDEF ) {
|
|
2921
|
+
result = rfval;
|
|
2922
|
+
} else if ( TYPE(result) != T_FLOAT && rb_obj_is_kind_of(result, rb_cCArray) ) {
|
|
2923
|
+
CArray *cr;
|
|
2924
|
+
GetCArray(result, cr);
|
|
2925
|
+
if ( ca_has_mask(cr) ) {
|
|
2926
|
+
result = rb_ca_mask_fill_copy(result, rfval);
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
return result;
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2933
|
+
/* ===== stddev_ki ============================================ */
|
|
2934
|
+
|
|
2935
|
+
#define __stddev_i8_P1EXPR(__x) ((double)(__x))
|
|
2936
|
+
#define __stddev_i8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2937
|
+
static VALUE
|
|
2938
|
+
stddev_ki_native_i8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
2939
|
+
{
|
|
2940
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
2941
|
+
CArray *co;
|
|
2942
|
+
GetCArray(vout, co);
|
|
2943
|
+
double *op = (double *) co->ptr;
|
|
2944
|
+
ca_iter_state st;
|
|
2945
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
2946
|
+
slab_axes, naxes, 0);
|
|
2947
|
+
if ( rc != CA_ITER_OK ) {
|
|
2948
|
+
rb_raise(rb_eRuntimeError,
|
|
2949
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
2950
|
+
}
|
|
2951
|
+
char *p;
|
|
2952
|
+
boolean8_t *m;
|
|
2953
|
+
ca_size_t out_i = 0;
|
|
2954
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
2955
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
2956
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
2957
|
+
double sum = 0.0;
|
|
2958
|
+
ca_size_t masked_cnt = 0;
|
|
2959
|
+
CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, sum, 0.0, __stddev_i8_P1EXPR, masked_cnt);
|
|
2960
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
2961
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
2962
|
+
if ( __trigger ) {
|
|
2963
|
+
if ( ! op_mask ) {
|
|
2964
|
+
ca_create_mask(co);
|
|
2965
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
2966
|
+
}
|
|
2967
|
+
op_mask[out_i] = 1;
|
|
2968
|
+
op[out_i++] = (double) 0.0;
|
|
2969
|
+
} else if ( n_valid < 2 ) {
|
|
2970
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
2971
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
2972
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
2973
|
+
op[out_i++] = (double) 0.0;
|
|
2974
|
+
} else {
|
|
2975
|
+
double mean = sum / (double) n_valid;
|
|
2976
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
2977
|
+
double M2 = 0.0;
|
|
2978
|
+
ca_size_t __unused_mc = 0;
|
|
2979
|
+
CA_SLAB_REDUCE_SUM8_EX(int8_t, double, st, p, m, M2, 0.0, __stddev_i8_P2EXPR, __unused_mc);
|
|
2980
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
ca_iter_state_finish(&st);
|
|
2984
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
2985
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
2986
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
2987
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
2988
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
2989
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
2990
|
+
return rb_float_new(op[0]);
|
|
2991
|
+
}
|
|
2992
|
+
return vout;
|
|
2993
|
+
}
|
|
2994
|
+
#undef __stddev_i8_P1EXPR
|
|
2995
|
+
#undef __stddev_i8_P2EXPR
|
|
2996
|
+
|
|
2997
|
+
#define __stddev_u8_P1EXPR(__x) ((double)(__x))
|
|
2998
|
+
#define __stddev_u8_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
2999
|
+
static VALUE
|
|
3000
|
+
stddev_ki_native_u8 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3001
|
+
{
|
|
3002
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3003
|
+
CArray *co;
|
|
3004
|
+
GetCArray(vout, co);
|
|
3005
|
+
double *op = (double *) co->ptr;
|
|
3006
|
+
ca_iter_state st;
|
|
3007
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3008
|
+
slab_axes, naxes, 0);
|
|
3009
|
+
if ( rc != CA_ITER_OK ) {
|
|
3010
|
+
rb_raise(rb_eRuntimeError,
|
|
3011
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3012
|
+
}
|
|
3013
|
+
char *p;
|
|
3014
|
+
boolean8_t *m;
|
|
3015
|
+
ca_size_t out_i = 0;
|
|
3016
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3017
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3018
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3019
|
+
double sum = 0.0;
|
|
3020
|
+
ca_size_t masked_cnt = 0;
|
|
3021
|
+
CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, sum, 0.0, __stddev_u8_P1EXPR, masked_cnt);
|
|
3022
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3023
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3024
|
+
if ( __trigger ) {
|
|
3025
|
+
if ( ! op_mask ) {
|
|
3026
|
+
ca_create_mask(co);
|
|
3027
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3028
|
+
}
|
|
3029
|
+
op_mask[out_i] = 1;
|
|
3030
|
+
op[out_i++] = (double) 0.0;
|
|
3031
|
+
} else if ( n_valid < 2 ) {
|
|
3032
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3033
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3034
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3035
|
+
op[out_i++] = (double) 0.0;
|
|
3036
|
+
} else {
|
|
3037
|
+
double mean = sum / (double) n_valid;
|
|
3038
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3039
|
+
double M2 = 0.0;
|
|
3040
|
+
ca_size_t __unused_mc = 0;
|
|
3041
|
+
CA_SLAB_REDUCE_SUM8_EX(uint8_t, double, st, p, m, M2, 0.0, __stddev_u8_P2EXPR, __unused_mc);
|
|
3042
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
ca_iter_state_finish(&st);
|
|
3046
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3047
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3048
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3049
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3050
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3051
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3052
|
+
return rb_float_new(op[0]);
|
|
3053
|
+
}
|
|
3054
|
+
return vout;
|
|
3055
|
+
}
|
|
3056
|
+
#undef __stddev_u8_P1EXPR
|
|
3057
|
+
#undef __stddev_u8_P2EXPR
|
|
3058
|
+
|
|
3059
|
+
#define __stddev_i16_P1EXPR(__x) ((double)(__x))
|
|
3060
|
+
#define __stddev_i16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
3061
|
+
static VALUE
|
|
3062
|
+
stddev_ki_native_i16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3063
|
+
{
|
|
3064
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3065
|
+
CArray *co;
|
|
3066
|
+
GetCArray(vout, co);
|
|
3067
|
+
double *op = (double *) co->ptr;
|
|
3068
|
+
ca_iter_state st;
|
|
3069
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3070
|
+
slab_axes, naxes, 0);
|
|
3071
|
+
if ( rc != CA_ITER_OK ) {
|
|
3072
|
+
rb_raise(rb_eRuntimeError,
|
|
3073
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3074
|
+
}
|
|
3075
|
+
char *p;
|
|
3076
|
+
boolean8_t *m;
|
|
3077
|
+
ca_size_t out_i = 0;
|
|
3078
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3079
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3080
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3081
|
+
double sum = 0.0;
|
|
3082
|
+
ca_size_t masked_cnt = 0;
|
|
3083
|
+
CA_SLAB_REDUCE_SUM8_EX(int16_t, double, st, p, m, sum, 0.0, __stddev_i16_P1EXPR, masked_cnt);
|
|
3084
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3085
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3086
|
+
if ( __trigger ) {
|
|
3087
|
+
if ( ! op_mask ) {
|
|
3088
|
+
ca_create_mask(co);
|
|
3089
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3090
|
+
}
|
|
3091
|
+
op_mask[out_i] = 1;
|
|
3092
|
+
op[out_i++] = (double) 0.0;
|
|
3093
|
+
} else if ( n_valid < 2 ) {
|
|
3094
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3095
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3096
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3097
|
+
op[out_i++] = (double) 0.0;
|
|
3098
|
+
} else {
|
|
3099
|
+
double mean = sum / (double) n_valid;
|
|
3100
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3101
|
+
double M2 = 0.0;
|
|
3102
|
+
ca_size_t __unused_mc = 0;
|
|
3103
|
+
CA_SLAB_REDUCE_SUM8_EX(int16_t, double, st, p, m, M2, 0.0, __stddev_i16_P2EXPR, __unused_mc);
|
|
3104
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
ca_iter_state_finish(&st);
|
|
3108
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3109
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3110
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3111
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3112
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3113
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3114
|
+
return rb_float_new(op[0]);
|
|
3115
|
+
}
|
|
3116
|
+
return vout;
|
|
3117
|
+
}
|
|
3118
|
+
#undef __stddev_i16_P1EXPR
|
|
3119
|
+
#undef __stddev_i16_P2EXPR
|
|
3120
|
+
|
|
3121
|
+
#define __stddev_u16_P1EXPR(__x) ((double)(__x))
|
|
3122
|
+
#define __stddev_u16_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
3123
|
+
static VALUE
|
|
3124
|
+
stddev_ki_native_u16 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3125
|
+
{
|
|
3126
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3127
|
+
CArray *co;
|
|
3128
|
+
GetCArray(vout, co);
|
|
3129
|
+
double *op = (double *) co->ptr;
|
|
3130
|
+
ca_iter_state st;
|
|
3131
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3132
|
+
slab_axes, naxes, 0);
|
|
3133
|
+
if ( rc != CA_ITER_OK ) {
|
|
3134
|
+
rb_raise(rb_eRuntimeError,
|
|
3135
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3136
|
+
}
|
|
3137
|
+
char *p;
|
|
3138
|
+
boolean8_t *m;
|
|
3139
|
+
ca_size_t out_i = 0;
|
|
3140
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3141
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3142
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3143
|
+
double sum = 0.0;
|
|
3144
|
+
ca_size_t masked_cnt = 0;
|
|
3145
|
+
CA_SLAB_REDUCE_SUM8_EX(uint16_t, double, st, p, m, sum, 0.0, __stddev_u16_P1EXPR, masked_cnt);
|
|
3146
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3147
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3148
|
+
if ( __trigger ) {
|
|
3149
|
+
if ( ! op_mask ) {
|
|
3150
|
+
ca_create_mask(co);
|
|
3151
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3152
|
+
}
|
|
3153
|
+
op_mask[out_i] = 1;
|
|
3154
|
+
op[out_i++] = (double) 0.0;
|
|
3155
|
+
} else if ( n_valid < 2 ) {
|
|
3156
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3157
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3158
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3159
|
+
op[out_i++] = (double) 0.0;
|
|
3160
|
+
} else {
|
|
3161
|
+
double mean = sum / (double) n_valid;
|
|
3162
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3163
|
+
double M2 = 0.0;
|
|
3164
|
+
ca_size_t __unused_mc = 0;
|
|
3165
|
+
CA_SLAB_REDUCE_SUM8_EX(uint16_t, double, st, p, m, M2, 0.0, __stddev_u16_P2EXPR, __unused_mc);
|
|
3166
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
3169
|
+
ca_iter_state_finish(&st);
|
|
3170
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3171
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3172
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3173
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3174
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3175
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3176
|
+
return rb_float_new(op[0]);
|
|
3177
|
+
}
|
|
3178
|
+
return vout;
|
|
3179
|
+
}
|
|
3180
|
+
#undef __stddev_u16_P1EXPR
|
|
3181
|
+
#undef __stddev_u16_P2EXPR
|
|
3182
|
+
|
|
3183
|
+
#define __stddev_i32_P1EXPR(__x) ((double)(__x))
|
|
3184
|
+
#define __stddev_i32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
3185
|
+
static VALUE
|
|
3186
|
+
stddev_ki_native_i32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3187
|
+
{
|
|
3188
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3189
|
+
CArray *co;
|
|
3190
|
+
GetCArray(vout, co);
|
|
3191
|
+
double *op = (double *) co->ptr;
|
|
3192
|
+
ca_iter_state st;
|
|
3193
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3194
|
+
slab_axes, naxes, 0);
|
|
3195
|
+
if ( rc != CA_ITER_OK ) {
|
|
3196
|
+
rb_raise(rb_eRuntimeError,
|
|
3197
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3198
|
+
}
|
|
3199
|
+
char *p;
|
|
3200
|
+
boolean8_t *m;
|
|
3201
|
+
ca_size_t out_i = 0;
|
|
3202
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3203
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3204
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3205
|
+
double sum = 0.0;
|
|
3206
|
+
ca_size_t masked_cnt = 0;
|
|
3207
|
+
CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, sum, 0.0, __stddev_i32_P1EXPR, masked_cnt);
|
|
3208
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3209
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3210
|
+
if ( __trigger ) {
|
|
3211
|
+
if ( ! op_mask ) {
|
|
3212
|
+
ca_create_mask(co);
|
|
3213
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3214
|
+
}
|
|
3215
|
+
op_mask[out_i] = 1;
|
|
3216
|
+
op[out_i++] = (double) 0.0;
|
|
3217
|
+
} else if ( n_valid < 2 ) {
|
|
3218
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3219
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3220
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3221
|
+
op[out_i++] = (double) 0.0;
|
|
3222
|
+
} else {
|
|
3223
|
+
double mean = sum / (double) n_valid;
|
|
3224
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3225
|
+
double M2 = 0.0;
|
|
3226
|
+
ca_size_t __unused_mc = 0;
|
|
3227
|
+
CA_SLAB_REDUCE_SUM8_EX(int32_t, double, st, p, m, M2, 0.0, __stddev_i32_P2EXPR, __unused_mc);
|
|
3228
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
ca_iter_state_finish(&st);
|
|
3232
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3233
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3234
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3235
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3236
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3237
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3238
|
+
return rb_float_new(op[0]);
|
|
3239
|
+
}
|
|
3240
|
+
return vout;
|
|
3241
|
+
}
|
|
3242
|
+
#undef __stddev_i32_P1EXPR
|
|
3243
|
+
#undef __stddev_i32_P2EXPR
|
|
3244
|
+
|
|
3245
|
+
#define __stddev_u32_P1EXPR(__x) ((double)(__x))
|
|
3246
|
+
#define __stddev_u32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
3247
|
+
static VALUE
|
|
3248
|
+
stddev_ki_native_u32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3249
|
+
{
|
|
3250
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3251
|
+
CArray *co;
|
|
3252
|
+
GetCArray(vout, co);
|
|
3253
|
+
double *op = (double *) co->ptr;
|
|
3254
|
+
ca_iter_state st;
|
|
3255
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3256
|
+
slab_axes, naxes, 0);
|
|
3257
|
+
if ( rc != CA_ITER_OK ) {
|
|
3258
|
+
rb_raise(rb_eRuntimeError,
|
|
3259
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3260
|
+
}
|
|
3261
|
+
char *p;
|
|
3262
|
+
boolean8_t *m;
|
|
3263
|
+
ca_size_t out_i = 0;
|
|
3264
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3265
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3266
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3267
|
+
double sum = 0.0;
|
|
3268
|
+
ca_size_t masked_cnt = 0;
|
|
3269
|
+
CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, sum, 0.0, __stddev_u32_P1EXPR, masked_cnt);
|
|
3270
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3271
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3272
|
+
if ( __trigger ) {
|
|
3273
|
+
if ( ! op_mask ) {
|
|
3274
|
+
ca_create_mask(co);
|
|
3275
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3276
|
+
}
|
|
3277
|
+
op_mask[out_i] = 1;
|
|
3278
|
+
op[out_i++] = (double) 0.0;
|
|
3279
|
+
} else if ( n_valid < 2 ) {
|
|
3280
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3281
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3282
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3283
|
+
op[out_i++] = (double) 0.0;
|
|
3284
|
+
} else {
|
|
3285
|
+
double mean = sum / (double) n_valid;
|
|
3286
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3287
|
+
double M2 = 0.0;
|
|
3288
|
+
ca_size_t __unused_mc = 0;
|
|
3289
|
+
CA_SLAB_REDUCE_SUM8_EX(uint32_t, double, st, p, m, M2, 0.0, __stddev_u32_P2EXPR, __unused_mc);
|
|
3290
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
ca_iter_state_finish(&st);
|
|
3294
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3295
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3296
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3297
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3298
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3299
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3300
|
+
return rb_float_new(op[0]);
|
|
3301
|
+
}
|
|
3302
|
+
return vout;
|
|
3303
|
+
}
|
|
3304
|
+
#undef __stddev_u32_P1EXPR
|
|
3305
|
+
#undef __stddev_u32_P2EXPR
|
|
3306
|
+
|
|
3307
|
+
#define __stddev_i64_P1EXPR(__x) ((double)(__x))
|
|
3308
|
+
#define __stddev_i64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
3309
|
+
static VALUE
|
|
3310
|
+
stddev_ki_native_i64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3311
|
+
{
|
|
3312
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3313
|
+
CArray *co;
|
|
3314
|
+
GetCArray(vout, co);
|
|
3315
|
+
double *op = (double *) co->ptr;
|
|
3316
|
+
ca_iter_state st;
|
|
3317
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3318
|
+
slab_axes, naxes, 0);
|
|
3319
|
+
if ( rc != CA_ITER_OK ) {
|
|
3320
|
+
rb_raise(rb_eRuntimeError,
|
|
3321
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3322
|
+
}
|
|
3323
|
+
char *p;
|
|
3324
|
+
boolean8_t *m;
|
|
3325
|
+
ca_size_t out_i = 0;
|
|
3326
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3327
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3328
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3329
|
+
double sum = 0.0;
|
|
3330
|
+
ca_size_t masked_cnt = 0;
|
|
3331
|
+
CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, sum, 0.0, __stddev_i64_P1EXPR, masked_cnt);
|
|
3332
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3333
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3334
|
+
if ( __trigger ) {
|
|
3335
|
+
if ( ! op_mask ) {
|
|
3336
|
+
ca_create_mask(co);
|
|
3337
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3338
|
+
}
|
|
3339
|
+
op_mask[out_i] = 1;
|
|
3340
|
+
op[out_i++] = (double) 0.0;
|
|
3341
|
+
} else if ( n_valid < 2 ) {
|
|
3342
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3343
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3344
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3345
|
+
op[out_i++] = (double) 0.0;
|
|
3346
|
+
} else {
|
|
3347
|
+
double mean = sum / (double) n_valid;
|
|
3348
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3349
|
+
double M2 = 0.0;
|
|
3350
|
+
ca_size_t __unused_mc = 0;
|
|
3351
|
+
CA_SLAB_REDUCE_SUM8_EX(int64_t, double, st, p, m, M2, 0.0, __stddev_i64_P2EXPR, __unused_mc);
|
|
3352
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
ca_iter_state_finish(&st);
|
|
3356
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3357
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3358
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3359
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3360
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3361
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3362
|
+
return rb_float_new(op[0]);
|
|
3363
|
+
}
|
|
3364
|
+
return vout;
|
|
3365
|
+
}
|
|
3366
|
+
#undef __stddev_i64_P1EXPR
|
|
3367
|
+
#undef __stddev_i64_P2EXPR
|
|
3368
|
+
|
|
3369
|
+
#define __stddev_u64_P1EXPR(__x) ((double)(__x))
|
|
3370
|
+
#define __stddev_u64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
3371
|
+
static VALUE
|
|
3372
|
+
stddev_ki_native_u64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3373
|
+
{
|
|
3374
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3375
|
+
CArray *co;
|
|
3376
|
+
GetCArray(vout, co);
|
|
3377
|
+
double *op = (double *) co->ptr;
|
|
3378
|
+
ca_iter_state st;
|
|
3379
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3380
|
+
slab_axes, naxes, 0);
|
|
3381
|
+
if ( rc != CA_ITER_OK ) {
|
|
3382
|
+
rb_raise(rb_eRuntimeError,
|
|
3383
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3384
|
+
}
|
|
3385
|
+
char *p;
|
|
3386
|
+
boolean8_t *m;
|
|
3387
|
+
ca_size_t out_i = 0;
|
|
3388
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3389
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3390
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3391
|
+
double sum = 0.0;
|
|
3392
|
+
ca_size_t masked_cnt = 0;
|
|
3393
|
+
CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, sum, 0.0, __stddev_u64_P1EXPR, masked_cnt);
|
|
3394
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3395
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3396
|
+
if ( __trigger ) {
|
|
3397
|
+
if ( ! op_mask ) {
|
|
3398
|
+
ca_create_mask(co);
|
|
3399
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3400
|
+
}
|
|
3401
|
+
op_mask[out_i] = 1;
|
|
3402
|
+
op[out_i++] = (double) 0.0;
|
|
3403
|
+
} else if ( n_valid < 2 ) {
|
|
3404
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3405
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3406
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3407
|
+
op[out_i++] = (double) 0.0;
|
|
3408
|
+
} else {
|
|
3409
|
+
double mean = sum / (double) n_valid;
|
|
3410
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3411
|
+
double M2 = 0.0;
|
|
3412
|
+
ca_size_t __unused_mc = 0;
|
|
3413
|
+
CA_SLAB_REDUCE_SUM8_EX(uint64_t, double, st, p, m, M2, 0.0, __stddev_u64_P2EXPR, __unused_mc);
|
|
3414
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
ca_iter_state_finish(&st);
|
|
3418
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3419
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3420
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3421
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3422
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3423
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3424
|
+
return rb_float_new(op[0]);
|
|
3425
|
+
}
|
|
3426
|
+
return vout;
|
|
3427
|
+
}
|
|
3428
|
+
#undef __stddev_u64_P1EXPR
|
|
3429
|
+
#undef __stddev_u64_P2EXPR
|
|
3430
|
+
|
|
3431
|
+
#define __stddev_f32_P1EXPR(__x) ((double)(__x))
|
|
3432
|
+
#define __stddev_f32_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
3433
|
+
static VALUE
|
|
3434
|
+
stddev_ki_native_f32 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3435
|
+
{
|
|
3436
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3437
|
+
CArray *co;
|
|
3438
|
+
GetCArray(vout, co);
|
|
3439
|
+
double *op = (double *) co->ptr;
|
|
3440
|
+
ca_iter_state st;
|
|
3441
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3442
|
+
slab_axes, naxes, 0);
|
|
3443
|
+
if ( rc != CA_ITER_OK ) {
|
|
3444
|
+
rb_raise(rb_eRuntimeError,
|
|
3445
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3446
|
+
}
|
|
3447
|
+
char *p;
|
|
3448
|
+
boolean8_t *m;
|
|
3449
|
+
ca_size_t out_i = 0;
|
|
3450
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3451
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3452
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3453
|
+
double sum = 0.0;
|
|
3454
|
+
ca_size_t masked_cnt = 0;
|
|
3455
|
+
CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, sum, 0.0, __stddev_f32_P1EXPR, masked_cnt);
|
|
3456
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3457
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3458
|
+
if ( __trigger ) {
|
|
3459
|
+
if ( ! op_mask ) {
|
|
3460
|
+
ca_create_mask(co);
|
|
3461
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3462
|
+
}
|
|
3463
|
+
op_mask[out_i] = 1;
|
|
3464
|
+
op[out_i++] = (double) 0.0;
|
|
3465
|
+
} else if ( n_valid < 2 ) {
|
|
3466
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3467
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3468
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3469
|
+
op[out_i++] = (double) 0.0;
|
|
3470
|
+
} else {
|
|
3471
|
+
double mean = sum / (double) n_valid;
|
|
3472
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3473
|
+
double M2 = 0.0;
|
|
3474
|
+
ca_size_t __unused_mc = 0;
|
|
3475
|
+
CA_SLAB_REDUCE_SUM8_EX(float, double, st, p, m, M2, 0.0, __stddev_f32_P2EXPR, __unused_mc);
|
|
3476
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
ca_iter_state_finish(&st);
|
|
3480
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3481
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3482
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3483
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3484
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3485
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3486
|
+
return rb_float_new(op[0]);
|
|
3487
|
+
}
|
|
3488
|
+
return vout;
|
|
3489
|
+
}
|
|
3490
|
+
#undef __stddev_f32_P1EXPR
|
|
3491
|
+
#undef __stddev_f32_P2EXPR
|
|
3492
|
+
|
|
3493
|
+
#define __stddev_f64_P1EXPR(__x) ((double)(__x))
|
|
3494
|
+
#define __stddev_f64_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
3495
|
+
static VALUE
|
|
3496
|
+
stddev_ki_native_f64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3497
|
+
{
|
|
3498
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3499
|
+
CArray *co;
|
|
3500
|
+
GetCArray(vout, co);
|
|
3501
|
+
double *op = (double *) co->ptr;
|
|
3502
|
+
ca_iter_state st;
|
|
3503
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3504
|
+
slab_axes, naxes, 0);
|
|
3505
|
+
if ( rc != CA_ITER_OK ) {
|
|
3506
|
+
rb_raise(rb_eRuntimeError,
|
|
3507
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3508
|
+
}
|
|
3509
|
+
char *p;
|
|
3510
|
+
boolean8_t *m;
|
|
3511
|
+
ca_size_t out_i = 0;
|
|
3512
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3513
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3514
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3515
|
+
double sum = 0.0;
|
|
3516
|
+
ca_size_t masked_cnt = 0;
|
|
3517
|
+
CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, sum, 0.0, __stddev_f64_P1EXPR, masked_cnt);
|
|
3518
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3519
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3520
|
+
if ( __trigger ) {
|
|
3521
|
+
if ( ! op_mask ) {
|
|
3522
|
+
ca_create_mask(co);
|
|
3523
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3524
|
+
}
|
|
3525
|
+
op_mask[out_i] = 1;
|
|
3526
|
+
op[out_i++] = (double) 0.0;
|
|
3527
|
+
} else if ( n_valid < 2 ) {
|
|
3528
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3529
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3530
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3531
|
+
op[out_i++] = (double) 0.0;
|
|
3532
|
+
} else {
|
|
3533
|
+
double mean = sum / (double) n_valid;
|
|
3534
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3535
|
+
double M2 = 0.0;
|
|
3536
|
+
ca_size_t __unused_mc = 0;
|
|
3537
|
+
CA_SLAB_REDUCE_SUM8_EX(double, double, st, p, m, M2, 0.0, __stddev_f64_P2EXPR, __unused_mc);
|
|
3538
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
ca_iter_state_finish(&st);
|
|
3542
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3543
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3544
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3545
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3546
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3547
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3548
|
+
return rb_float_new(op[0]);
|
|
3549
|
+
}
|
|
3550
|
+
return vout;
|
|
3551
|
+
}
|
|
3552
|
+
#undef __stddev_f64_P1EXPR
|
|
3553
|
+
#undef __stddev_f64_P2EXPR
|
|
3554
|
+
|
|
3555
|
+
#define __stddev_cmplx64_P1EXPR(__x) (__x)
|
|
3556
|
+
#define __stddev_cmplx64_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
|
|
3557
|
+
static VALUE
|
|
3558
|
+
stddev_ki_native_cmplx64 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3559
|
+
{
|
|
3560
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3561
|
+
CArray *co;
|
|
3562
|
+
GetCArray(vout, co);
|
|
3563
|
+
double *op = (double *) co->ptr;
|
|
3564
|
+
ca_iter_state st;
|
|
3565
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3566
|
+
slab_axes, naxes, 0);
|
|
3567
|
+
if ( rc != CA_ITER_OK ) {
|
|
3568
|
+
rb_raise(rb_eRuntimeError,
|
|
3569
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3570
|
+
}
|
|
3571
|
+
char *p;
|
|
3572
|
+
boolean8_t *m;
|
|
3573
|
+
ca_size_t out_i = 0;
|
|
3574
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3575
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3576
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3577
|
+
cmplx64_t sum = 0;
|
|
3578
|
+
ca_size_t masked_cnt = 0;
|
|
3579
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, cmplx64_t, st, p, m, sum, 0, __stddev_cmplx64_P1EXPR, masked_cnt);
|
|
3580
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3581
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3582
|
+
if ( __trigger ) {
|
|
3583
|
+
if ( ! op_mask ) {
|
|
3584
|
+
ca_create_mask(co);
|
|
3585
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3586
|
+
}
|
|
3587
|
+
op_mask[out_i] = 1;
|
|
3588
|
+
op[out_i++] = (double) 0.0;
|
|
3589
|
+
} else if ( n_valid < 2 ) {
|
|
3590
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3591
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3592
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3593
|
+
op[out_i++] = (double) 0.0;
|
|
3594
|
+
} else {
|
|
3595
|
+
cmplx64_t mean = sum / (cmplx64_t)(double) n_valid;
|
|
3596
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3597
|
+
double M2 = 0.0;
|
|
3598
|
+
ca_size_t __unused_mc = 0;
|
|
3599
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx64_t, double, st, p, m, M2, 0.0, __stddev_cmplx64_P2EXPR, __unused_mc);
|
|
3600
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
ca_iter_state_finish(&st);
|
|
3604
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3605
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3606
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3607
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3608
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3609
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3610
|
+
return rb_float_new(op[0]);
|
|
3611
|
+
}
|
|
3612
|
+
return vout;
|
|
3613
|
+
}
|
|
3614
|
+
#undef __stddev_cmplx64_P1EXPR
|
|
3615
|
+
#undef __stddev_cmplx64_P2EXPR
|
|
3616
|
+
|
|
3617
|
+
#define __stddev_cmplx128_P1EXPR(__x) (__x)
|
|
3618
|
+
#define __stddev_cmplx128_P2EXPR(__x) (creal((__x) - mean) * creal((__x) - mean) + cimag((__x) - mean) * cimag((__x) - mean))
|
|
3619
|
+
static VALUE
|
|
3620
|
+
stddev_ki_native_cmplx128 (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3621
|
+
{
|
|
3622
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3623
|
+
CArray *co;
|
|
3624
|
+
GetCArray(vout, co);
|
|
3625
|
+
double *op = (double *) co->ptr;
|
|
3626
|
+
ca_iter_state st;
|
|
3627
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3628
|
+
slab_axes, naxes, 0);
|
|
3629
|
+
if ( rc != CA_ITER_OK ) {
|
|
3630
|
+
rb_raise(rb_eRuntimeError,
|
|
3631
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3632
|
+
}
|
|
3633
|
+
char *p;
|
|
3634
|
+
boolean8_t *m;
|
|
3635
|
+
ca_size_t out_i = 0;
|
|
3636
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3637
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3638
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3639
|
+
cmplx128_t sum = 0;
|
|
3640
|
+
ca_size_t masked_cnt = 0;
|
|
3641
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, cmplx128_t, st, p, m, sum, 0, __stddev_cmplx128_P1EXPR, masked_cnt);
|
|
3642
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3643
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3644
|
+
if ( __trigger ) {
|
|
3645
|
+
if ( ! op_mask ) {
|
|
3646
|
+
ca_create_mask(co);
|
|
3647
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3648
|
+
}
|
|
3649
|
+
op_mask[out_i] = 1;
|
|
3650
|
+
op[out_i++] = (double) 0.0;
|
|
3651
|
+
} else if ( n_valid < 2 ) {
|
|
3652
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3653
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3654
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3655
|
+
op[out_i++] = (double) 0.0;
|
|
3656
|
+
} else {
|
|
3657
|
+
cmplx128_t mean = sum / (cmplx128_t)(double) n_valid;
|
|
3658
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3659
|
+
double M2 = 0.0;
|
|
3660
|
+
ca_size_t __unused_mc = 0;
|
|
3661
|
+
CA_SLAB_REDUCE_SUM8_EX(cmplx128_t, double, st, p, m, M2, 0.0, __stddev_cmplx128_P2EXPR, __unused_mc);
|
|
3662
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
ca_iter_state_finish(&st);
|
|
3666
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3667
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3668
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3669
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3670
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3671
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3672
|
+
return rb_float_new(op[0]);
|
|
3673
|
+
}
|
|
3674
|
+
return vout;
|
|
3675
|
+
}
|
|
3676
|
+
#undef __stddev_cmplx128_P1EXPR
|
|
3677
|
+
#undef __stddev_cmplx128_P2EXPR
|
|
3678
|
+
|
|
3679
|
+
#define __stddev_bool_P1EXPR(__x) ((double)(__x))
|
|
3680
|
+
#define __stddev_bool_P2EXPR(__x) (((double)(__x) - mean) * ((double)(__x) - mean))
|
|
3681
|
+
static VALUE
|
|
3682
|
+
stddev_ki_native_bool (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3683
|
+
{
|
|
3684
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3685
|
+
CArray *co;
|
|
3686
|
+
GetCArray(vout, co);
|
|
3687
|
+
double *op = (double *) co->ptr;
|
|
3688
|
+
ca_iter_state st;
|
|
3689
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3690
|
+
slab_axes, naxes, 0);
|
|
3691
|
+
if ( rc != CA_ITER_OK ) {
|
|
3692
|
+
rb_raise(rb_eRuntimeError,
|
|
3693
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3694
|
+
}
|
|
3695
|
+
char *p;
|
|
3696
|
+
boolean8_t *m;
|
|
3697
|
+
ca_size_t out_i = 0;
|
|
3698
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3699
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3700
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3701
|
+
double sum = 0.0;
|
|
3702
|
+
ca_size_t masked_cnt = 0;
|
|
3703
|
+
CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, sum, 0.0, __stddev_bool_P1EXPR, masked_cnt);
|
|
3704
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3705
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3706
|
+
if ( __trigger ) {
|
|
3707
|
+
if ( ! op_mask ) {
|
|
3708
|
+
ca_create_mask(co);
|
|
3709
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3710
|
+
}
|
|
3711
|
+
op_mask[out_i] = 1;
|
|
3712
|
+
op[out_i++] = (double) 0.0;
|
|
3713
|
+
} else if ( n_valid < 2 ) {
|
|
3714
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3715
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3716
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3717
|
+
op[out_i++] = (double) 0.0;
|
|
3718
|
+
} else {
|
|
3719
|
+
double mean = sum / (double) n_valid;
|
|
3720
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3721
|
+
double M2 = 0.0;
|
|
3722
|
+
ca_size_t __unused_mc = 0;
|
|
3723
|
+
CA_SLAB_REDUCE_SUM8_EX(boolean8_t, double, st, p, m, M2, 0.0, __stddev_bool_P2EXPR, __unused_mc);
|
|
3724
|
+
op[out_i++] = (double)(sqrt(fmax(M2 / (double)(n_valid - 1), 0.0)));
|
|
3725
|
+
}
|
|
3726
|
+
}
|
|
3727
|
+
ca_iter_state_finish(&st);
|
|
3728
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3729
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3730
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3731
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3732
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3733
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3734
|
+
return rb_float_new(op[0]);
|
|
3735
|
+
}
|
|
3736
|
+
return vout;
|
|
3737
|
+
}
|
|
3738
|
+
#undef __stddev_bool_P1EXPR
|
|
3739
|
+
#undef __stddev_bool_P2EXPR
|
|
3740
|
+
|
|
3741
|
+
static VALUE
|
|
3742
|
+
stddev_ki_native_object (VALUE self, CArray *ca, int8_t *slab_axes, int8_t naxes, int keep_axis, ca_size_t min_count)
|
|
3743
|
+
{
|
|
3744
|
+
VALUE vout = rb_ca_new_reduced(self, slab_axes, naxes, CA_FLOAT64, keep_axis);
|
|
3745
|
+
CArray *co;
|
|
3746
|
+
GetCArray(vout, co);
|
|
3747
|
+
double *op = (double *) co->ptr;
|
|
3748
|
+
ca_iter_state st;
|
|
3749
|
+
int rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES,
|
|
3750
|
+
slab_axes, naxes, 0);
|
|
3751
|
+
if ( rc != CA_ITER_OK ) {
|
|
3752
|
+
rb_raise(rb_eRuntimeError,
|
|
3753
|
+
"stddev_ki: kernel_iterator init failed rc=%d", rc);
|
|
3754
|
+
}
|
|
3755
|
+
char *p;
|
|
3756
|
+
boolean8_t *m;
|
|
3757
|
+
ca_size_t out_i = 0;
|
|
3758
|
+
boolean8_t *op_mask = NULL; /* lazily allocated on first UNDEF */
|
|
3759
|
+
while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
|
|
3760
|
+
/* Pass 1: sum = Σx (+ masked_cnt) */
|
|
3761
|
+
VALUE sum = INT2FIX(0);
|
|
3762
|
+
ca_size_t masked_cnt = 0;
|
|
3763
|
+
CA_SLAB_REDUCE_T_EX(VALUE, st, p, m, sum, INT2FIX(0), sum = rb_funcall(sum, rb_intern("+"), 1, v), masked_cnt);
|
|
3764
|
+
ca_size_t n_valid = st.slab_elements - masked_cnt;
|
|
3765
|
+
int __trigger = (min_count < 0 ? masked_cnt == st.slab_elements : n_valid < min_count);
|
|
3766
|
+
if ( __trigger ) {
|
|
3767
|
+
if ( ! op_mask ) {
|
|
3768
|
+
ca_create_mask(co);
|
|
3769
|
+
op_mask = (boolean8_t *) co->mask->ptr;
|
|
3770
|
+
}
|
|
3771
|
+
op_mask[out_i] = 1;
|
|
3772
|
+
op[out_i++] = (double) 0.0;
|
|
3773
|
+
} else if ( n_valid < 2 ) {
|
|
3774
|
+
/* Legacy degenerate case (e.g. sample variance with 1 unmasked
|
|
3775
|
+
cell): return zero rather than UNDEF, matching pre-migration
|
|
3776
|
+
behaviour of `cnt > 1 ? formula : 0`. */
|
|
3777
|
+
op[out_i++] = (double) 0.0;
|
|
3778
|
+
} else {
|
|
3779
|
+
VALUE mean = rb_funcall(sum, rb_intern("/"), 1, LONG2NUM(n_valid));
|
|
3780
|
+
/* Pass 2: M2 = Σ (x - mean)² */
|
|
3781
|
+
VALUE M2 = INT2FIX(0);
|
|
3782
|
+
ca_size_t __unused_mc = 0;
|
|
3783
|
+
CA_SLAB_REDUCE_T_EX(VALUE, st, p, m, M2, INT2FIX(0), VALUE __d = rb_funcall(v, rb_intern("-"), 1, mean);
|
|
3784
|
+
M2 = rb_funcall(M2, rb_intern("+"), 1, rb_funcall(__d, rb_intern("*"), 1, __d)), __unused_mc);
|
|
3785
|
+
op[out_i++] = (double)(sqrt(fmax(NUM2DBL(rb_funcall(M2, rb_intern("/"), 1, LONG2NUM(n_valid - 1))), 0.0)));
|
|
3786
|
+
}
|
|
3787
|
+
}
|
|
3788
|
+
ca_iter_state_finish(&st);
|
|
3789
|
+
/* Full-reduction scalar shortcut: naxes == ca->ndim and no
|
|
3790
|
+
keep_axis means the output is a 1-element CArray; unwrap it to
|
|
3791
|
+
the ruby scalar (matches the standard reduce emit path lines
|
|
3792
|
+
1811-1817). Full reduction with all-masked returns CA_UNDEF. */
|
|
3793
|
+
if ( naxes == ca->ndim && !keep_axis ) {
|
|
3794
|
+
if ( op_mask && op_mask[0] ) return CA_UNDEF;
|
|
3795
|
+
return rb_float_new(op[0]);
|
|
3796
|
+
}
|
|
3797
|
+
return vout;
|
|
3798
|
+
}
|
|
3799
|
+
|
|
3800
|
+
VALUE
|
|
3801
|
+
rb_ca_stddev_ki (int argc, VALUE *argv, VALUE self)
|
|
3802
|
+
{
|
|
3803
|
+
CArray *src;
|
|
3804
|
+
GetCArray(self, src);
|
|
3805
|
+
volatile VALUE ropt = rb_pop_options(&argc, &argv);
|
|
3806
|
+
volatile VALUE raxis = Qnil, rkeep_axis = Qnil, rmin_count = Qnil, rfval = Qnil;
|
|
3807
|
+
rb_scan_options(ropt, "axis,keep_axis,min_count,fill_value", &raxis, &rkeep_axis, &rmin_count, &rfval);
|
|
3808
|
+
int keep_axis = RTEST(rkeep_axis);
|
|
3809
|
+
int8_t slab_axes[CA_RANK_MAX];
|
|
3810
|
+
int8_t naxes = rb_ca_parse_reduce_axes_kw(raxis, src, slab_axes);
|
|
3811
|
+
ca_size_t min_count = -1;
|
|
3812
|
+
if ( ! NIL_P(rmin_count) ) {
|
|
3813
|
+
ca_size_t mc_user = NUM2SIZE(rmin_count);
|
|
3814
|
+
if ( mc_user < 0 ) {
|
|
3815
|
+
rb_raise(rb_eArgError, "stddev_ki: :min_count must be non-negative, got %lld", (long long) mc_user);
|
|
3816
|
+
}
|
|
3817
|
+
/* :min_count = 0 collapses to legacy default (any 1 valid). */
|
|
3818
|
+
if ( mc_user > 0 ) min_count = mc_user;
|
|
3819
|
+
}
|
|
3820
|
+
VALUE result;
|
|
3821
|
+
if ( argc > 0 ) {
|
|
3822
|
+
rb_raise(rb_eArgError, "stddev_ki: positional axis arguments are no longer accepted (got %d); use axis: kwarg, e.g. a.stddev(axis: 0) or a.stddev(axis: [0, 1])", argc);
|
|
3823
|
+
}
|
|
3824
|
+
switch ( src->data_type ) {
|
|
3825
|
+
case CA_INT8: {
|
|
3826
|
+
result = stddev_ki_native_i8(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3827
|
+
break;
|
|
3828
|
+
}
|
|
3829
|
+
case CA_UINT8: {
|
|
3830
|
+
result = stddev_ki_native_u8(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3831
|
+
break;
|
|
3832
|
+
}
|
|
3833
|
+
case CA_INT16: {
|
|
3834
|
+
result = stddev_ki_native_i16(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3835
|
+
break;
|
|
3836
|
+
}
|
|
3837
|
+
case CA_UINT16: {
|
|
3838
|
+
result = stddev_ki_native_u16(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3839
|
+
break;
|
|
3840
|
+
}
|
|
3841
|
+
case CA_INT32: {
|
|
3842
|
+
result = stddev_ki_native_i32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3843
|
+
break;
|
|
3844
|
+
}
|
|
3845
|
+
case CA_UINT32: {
|
|
3846
|
+
result = stddev_ki_native_u32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3847
|
+
break;
|
|
3848
|
+
}
|
|
3849
|
+
case CA_INT64: {
|
|
3850
|
+
result = stddev_ki_native_i64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3851
|
+
break;
|
|
3852
|
+
}
|
|
3853
|
+
case CA_UINT64: {
|
|
3854
|
+
result = stddev_ki_native_u64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3855
|
+
break;
|
|
3856
|
+
}
|
|
3857
|
+
case CA_FLOAT32: {
|
|
3858
|
+
result = stddev_ki_native_f32(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3859
|
+
break;
|
|
3860
|
+
}
|
|
3861
|
+
case CA_FLOAT64: {
|
|
3862
|
+
result = stddev_ki_native_f64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3863
|
+
break;
|
|
3864
|
+
}
|
|
3865
|
+
case CA_CMPLX64: {
|
|
3866
|
+
result = stddev_ki_native_cmplx64(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3867
|
+
break;
|
|
3868
|
+
}
|
|
3869
|
+
case CA_CMPLX128: {
|
|
3870
|
+
result = stddev_ki_native_cmplx128(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3871
|
+
break;
|
|
3872
|
+
}
|
|
3873
|
+
case CA_BOOLEAN: {
|
|
3874
|
+
result = stddev_ki_native_bool(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3875
|
+
break;
|
|
3876
|
+
}
|
|
3877
|
+
case CA_OBJECT: {
|
|
3878
|
+
result = stddev_ki_native_object(self, src, slab_axes, naxes, keep_axis, min_count);
|
|
3879
|
+
break;
|
|
3880
|
+
}
|
|
3881
|
+
default:
|
|
3882
|
+
rb_raise(rb_eCADataTypeError, "stddev_ki: source data_type :%s not supported (expected one of: i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, cmplx64, cmplx128, bool, object)", ca_type_name[src->data_type]);
|
|
3883
|
+
}
|
|
3884
|
+
if ( ! NIL_P(rfval) ) {
|
|
3885
|
+
if ( result == CA_UNDEF ) {
|
|
3886
|
+
result = rfval;
|
|
3887
|
+
} else if ( TYPE(result) != T_FLOAT && rb_obj_is_kind_of(result, rb_cCArray) ) {
|
|
3888
|
+
CArray *cr;
|
|
3889
|
+
GetCArray(result, cr);
|
|
3890
|
+
if ( ca_has_mask(cr) ) {
|
|
3891
|
+
result = rb_ca_mask_fill_copy(result, rfval);
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
return result;
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3898
|
+
void
|
|
3899
|
+
Init_carray_kernels_reduce_variance (void)
|
|
3900
|
+
{
|
|
3901
|
+
/* Phase E rewire: legacy 'variancep' now dispatches via variancep_ki */
|
|
3902
|
+
rb_define_method(rb_cCArray, "variancep", rb_ca_variancep_ki, -1);
|
|
3903
|
+
/* Phase E rewire: legacy 'variance' now dispatches via variance_ki */
|
|
3904
|
+
rb_define_method(rb_cCArray, "variance", rb_ca_variance_ki, -1);
|
|
3905
|
+
/* Phase E rewire: legacy 'stddevp' now dispatches via stddevp_ki */
|
|
3906
|
+
rb_define_method(rb_cCArray, "stddevp", rb_ca_stddevp_ki, -1);
|
|
3907
|
+
/* Phase E rewire: legacy 'stddev' now dispatches via stddev_ki */
|
|
3908
|
+
rb_define_method(rb_cCArray, "stddev", rb_ca_stddev_ki, -1);
|
|
3909
|
+
}
|