carray 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +2 -1
- data/CHANGELOG.md +845 -3
- data/{NEWS.md → CHANGELOG.v1.md} +1 -1
- data/README.md +33 -33
- data/carray.gemspec +12 -8
- data/ext/ca_axis_dispatch.c +33 -4
- data/ext/ca_axis_group.c +256 -114
- data/ext/ca_binop_dispatch.c +5 -6
- data/ext/ca_binop_dispatch.h +0 -7
- data/ext/ca_categorical_iterator.c +121 -67
- data/ext/ca_for_each_element.h +6 -8
- data/ext/ca_group_iter.c +1 -1
- data/ext/ca_kernel_iterator.c +386 -74
- data/ext/ca_kernel_iterator.h +145 -45
- data/ext/ca_obj_array.c +62 -20
- data/ext/ca_obj_bincmp.c +57 -27
- data/ext/ca_obj_binop.c +86 -30
- data/ext/ca_obj_block.c +4 -4
- data/ext/ca_obj_const_string.c +88 -27
- data/ext/ca_obj_face.c +104 -0
- data/ext/ca_obj_face.h +48 -1
- data/ext/ca_obj_fake.c +11 -0
- data/ext/ca_obj_fixlen_string.c +21 -6
- data/ext/ca_obj_grid.c +11 -3
- data/ext/ca_obj_meld.c +125 -22
- data/ext/ca_obj_moncmp.c +33 -14
- data/ext/ca_obj_monop.c +19 -7
- data/ext/ca_obj_object.c +107 -4
- data/ext/ca_obj_record.c +3 -1
- data/ext/ca_obj_refer.c +30 -6
- data/ext/ca_obj_roll.c +13 -5
- data/ext/ca_obj_select.c +49 -34
- data/ext/ca_obj_select_axis.c +16 -6
- data/ext/ca_obj_shift.c +3 -3
- data/ext/ca_obj_stack.c +3 -8
- data/ext/ca_obj_stride.c +178 -24
- data/ext/ca_obj_string.c +11 -5
- data/ext/ca_obj_tile.c +13 -5
- data/ext/ca_obj_time.c +3 -1
- data/ext/ca_obj_timedelta.c +3 -1
- data/ext/ca_obj_transpose.c +1 -1
- data/ext/ca_obj_triop.c +62 -23
- data/ext/ca_obj_window.c +94 -19
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +1 -5
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +5 -5
- data/ext/ca_sweep_engine.c +362 -155
- data/ext/ca_sweep_engine.h +39 -9
- data/ext/ca_transform_common.c +7 -0
- data/ext/carray.h +148 -132
- data/ext/carray_access.c +83 -49
- data/ext/carray_address_basis.c +590 -0
- data/ext/carray_bincount.c +8 -8
- data/ext/carray_broadcast.c +102 -9
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +2010 -335
- data/ext/carray_call_cfunc.h +153 -0
- data/ext/carray_cast.c +184 -72
- data/ext/carray_conversion.c +22 -22
- data/ext/carray_copy.c +67 -32
- data/ext/carray_core.c +140 -13
- data/ext/carray_count.c +10 -11
- data/ext/carray_element.c +7 -7
- data/ext/carray_factorize.c +72 -51
- data/ext/carray_hold.c +1 -1
- data/ext/carray_index_classifier.c +7 -21
- data/ext/carray_internal.h +36 -3
- data/ext/carray_kernels_bincmp.c +1 -0
- data/ext/carray_kernels_binop.c +320 -298
- data/ext/carray_kernels_init.c +1095 -0
- data/ext/carray_kernels_map.c +1 -0
- data/ext/carray_kernels_moncmp.c +1 -0
- data/ext/carray_kernels_monop.c +412 -411
- data/ext/carray_kernels_reduce_aggregate.c +256 -87
- data/ext/carray_kernels_reduce_boolean.c +1 -0
- data/ext/carray_kernels_reduce_cumulative.c +324 -54
- data/ext/carray_kernels_reduce_extreme.c +605 -58
- data/ext/carray_kernels_reduce_variance.c +1 -0
- data/ext/carray_kernels_scan.c +5 -4
- data/ext/carray_kernels_search.c +187 -106
- data/ext/carray_kernels_sort.c +1 -0
- data/ext/carray_kernels_triop.c +1 -0
- data/ext/carray_lazy.c +175 -5
- data/ext/carray_loop.c +7 -1
- data/ext/carray_mask.c +29 -13
- data/ext/carray_median_percentile.c +56 -1
- data/ext/carray_memory_view.c +46 -21
- data/ext/carray_operator.c +50 -53
- data/ext/carray_order.c +1 -1
- data/ext/carray_partition.c +4 -4
- data/ext/carray_random.c +391 -47
- data/ext/carray_scatter.c +1 -1
- data/ext/carray_slab.c +13 -0
- data/ext/carray_sort.c +22 -24
- data/ext/carray_sort_kernel.c +10 -10
- data/ext/carray_test.c +1 -1
- data/ext/extconf.rb +18 -0
- data/ext/mk_call_cfunc.rb +323 -145
- data/ext/mkkernel.rb +651 -129
- data/ext/ruby_carray.c +28 -17
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +14 -1
- data/lib/carray/axis_group.rb +84 -7
- data/lib/carray/basics.rb +63 -59
- data/lib/carray/bincount_nd.rb +12 -12
- data/lib/carray/block_iterator.rb +111 -25
- data/lib/carray/categorical.rb +154 -37
- data/lib/carray/categorical_iterator.rb +300 -151
- data/lib/carray/conditional.rb +14 -14
- data/lib/carray/const_string.rb +131 -27
- data/lib/carray/construct.rb +61 -0
- data/lib/carray/core_extensions.rb +62 -5
- data/lib/carray/data_type_extension.rb +21 -1
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +3 -3
- data/lib/carray/frame/convert.rb +1 -1
- data/lib/carray/frame/csv_parser.rb +11 -4
- data/lib/carray/frame/frame.rb +85 -21
- data/lib/carray/frame/group.rb +36 -3
- data/lib/carray/frame/io.rb +224 -15
- data/lib/carray/frame/records.rb +18 -4
- data/lib/carray/frame/sort.rb +1 -1
- data/lib/carray/frame/verbs.rb +32 -12
- data/lib/carray/fuse_source.rb +123 -0
- data/lib/carray/fusion.rb +218 -0
- data/lib/carray/histogram.rb +16 -16
- data/lib/carray/inspect.rb +43 -16
- data/lib/carray/iterator.rb +147 -3
- data/lib/carray/lazy.rb +88 -73
- data/lib/carray/mask_gap_fill.rb +3 -1
- data/lib/carray/meld_reduce.rb +2 -2
- data/lib/carray/methods/align_addr.rb +1 -1
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/is_in.rb +25 -14
- data/lib/carray/methods/locate_addr.rb +81 -3
- data/lib/carray/methods/mask_duplicates.rb +36 -2
- data/lib/carray/methods/meshgrid.rb +4 -5
- data/lib/carray/methods/mode.rb +2 -2
- data/lib/carray/methods/nunique.rb +23 -2
- data/lib/carray/methods/repeat.rb +110 -0
- data/lib/carray/methods/snap.rb +7 -2
- data/lib/carray/methods/unique.rb +44 -4
- data/lib/carray/methods/value_counts.rb +2 -2
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +0 -19
- data/lib/carray/slab_iterator.rb +77 -19
- data/lib/carray/string_operation_extension.rb +10 -6
- data/lib/carray/time.rb +906 -491
- data/lib/carray/window_iterator.rb +421 -27
- data/lib/carray.rb +7 -5
- data/yard-stubs/ca_obj_array.rb +385 -0
- data/yard-stubs/ca_obj_bitarray.rb +38 -0
- data/yard-stubs/ca_obj_bitfield.rb +43 -0
- data/yard-stubs/ca_obj_block.rb +68 -0
- data/yard-stubs/ca_obj_byte_swap.rb +56 -0
- data/yard-stubs/ca_obj_fake.rb +31 -0
- data/yard-stubs/ca_obj_farray.rb +32 -0
- data/yard-stubs/ca_obj_field.rb +45 -0
- data/yard-stubs/ca_obj_grid.rb +35 -0
- data/yard-stubs/ca_obj_refer.rb +72 -0
- data/yard-stubs/ca_obj_roll.rb +45 -0
- data/yard-stubs/ca_obj_shift.rb +43 -0
- data/yard-stubs/ca_obj_stride.rb +181 -0
- data/yard-stubs/ca_obj_tile.rb +29 -0
- data/yard-stubs/ca_obj_transpose.rb +40 -0
- data/yard-stubs/ca_obj_window.rb +57 -0
- data/yard-stubs/carray_access.rb +131 -0
- data/yard-stubs/carray_attribute.rb +246 -0
- data/yard-stubs/carray_broadcast.rb +37 -0
- data/yard-stubs/carray_cast.rb +489 -0
- data/yard-stubs/carray_class.rb +65 -0
- data/yard-stubs/carray_conversion.rb +76 -0
- data/yard-stubs/carray_copy.rb +79 -0
- data/yard-stubs/carray_core.rb +34 -0
- data/yard-stubs/carray_count.rb +84 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +228 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +1615 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +103 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +252 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +59 -0
- data/yard-stubs/carray_sort.rb +165 -0
- data/yard-stubs/carray_test.rb +85 -0
- data/yard-stubs/carray_undef.rb +64 -0
- data/yard-stubs/carray_utils.rb +97 -0
- data/yard-stubs/ruby_carray.rb +193 -0
- metadata +67 -10
- data/ext/ca_obj_unbound_repeat.c +0 -496
data/ext/ruby_carray.c
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Single entry point Init_carray_ext: declares the CArray class
|
|
4
4
|
hierarchy + exception class + CA module, populates top-level
|
|
5
|
-
constants (CA_RANK_MAX /
|
|
5
|
+
constants (CA_RANK_MAX / CA_* data_type Symbols / alignment
|
|
6
6
|
values), then drives the per-module Init_* sequence in load order.
|
|
7
7
|
|
|
8
8
|
CAREFUL: the Init_* call order below carries real ordering
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
---------------------------------------------------------------------------- */
|
|
15
15
|
|
|
16
16
|
#include "carray.h"
|
|
17
|
+
#include "carray_build_flags.h"
|
|
17
18
|
#include "version.h"
|
|
18
19
|
|
|
19
20
|
#ifdef HAVE_RB_ARITHMETIC_SEQUENCE_EXTRACT
|
|
@@ -26,7 +27,7 @@ VALUE rb_cCAIterator;
|
|
|
26
27
|
VALUE rb_eCADataTypeError;
|
|
27
28
|
VALUE rb_mCA;
|
|
28
29
|
|
|
29
|
-
VALUE
|
|
30
|
+
VALUE CA_UNSPECIFIED;
|
|
30
31
|
|
|
31
32
|
void Init_carray_core ();
|
|
32
33
|
void Init_carray_undef ();
|
|
@@ -81,7 +82,6 @@ void Init_ca_obj_stack (); /* multi-parent outer-axis stack */
|
|
|
81
82
|
void Init_ca_obj_meld (); /* multi-parent ragged concat along existing axis */
|
|
82
83
|
void Init_ca_obj_transpose ();
|
|
83
84
|
void Init_ca_obj_repeat ();
|
|
84
|
-
void Init_ca_obj_unbound_repeat ();
|
|
85
85
|
void Init_ca_obj_reduce ();
|
|
86
86
|
void Init_ca_obj_field ();
|
|
87
87
|
void Init_ca_obj_fake ();
|
|
@@ -107,7 +107,7 @@ void Init_ca_obj_moncmp (); /* CAMonCmp + lazy elementwise predicate dispatch *
|
|
|
107
107
|
|
|
108
108
|
/* Init_carray_iterator retired; CAIterator is a form-only base defined inline
|
|
109
109
|
in Init_carray_ext (accessors in lib/carray/iterator.rb). The 2.0 C engines
|
|
110
|
-
(dimension / window / block iterators)
|
|
110
|
+
(dimension / window / block iterators) were retired in 3.0. */
|
|
111
111
|
|
|
112
112
|
void Init_carray_mathfunc ();
|
|
113
113
|
|
|
@@ -121,6 +121,13 @@ void Init_ca_kernel_iterator ();
|
|
|
121
121
|
|
|
122
122
|
void Init_carray_slab ();
|
|
123
123
|
|
|
124
|
+
void Init_carray_address_basis (); /* CArray::AddressBasis: pointer + byte
|
|
125
|
+
strides lent for the length of a block,
|
|
126
|
+
for code that addresses cells itself.
|
|
127
|
+
A runtime facility at the ca_attach
|
|
128
|
+
layer, not a user surface; see
|
|
129
|
+
guides/devel/21_address_basis.md */
|
|
130
|
+
|
|
124
131
|
void
|
|
125
132
|
Init_carray_ext (void)
|
|
126
133
|
{
|
|
@@ -142,7 +149,7 @@ Init_carray_ext (void)
|
|
|
142
149
|
rb_cCScalar = rb_define_class("CScalar", rb_cCArray);
|
|
143
150
|
rb_cCAView = rb_define_class("CAView", rb_cCArray);
|
|
144
151
|
/* CAREFUL: CAStride must exist before its subclasses (CARefer /
|
|
145
|
-
CABlock / CAField / CARepeat /
|
|
152
|
+
CABlock / CAField / CARepeat / CATranspose /
|
|
146
153
|
CAFarray) are defined or registered. See devel/CAStride.md. */
|
|
147
154
|
rb_cCAStride = rb_define_class("CAStride", rb_cCAView);
|
|
148
155
|
rb_cCARefer = rb_define_class("CARefer", rb_cCAStride);
|
|
@@ -151,10 +158,6 @@ Init_carray_ext (void)
|
|
|
151
158
|
rb_cCASelect = rb_define_class("CASelect", rb_cCAView);
|
|
152
159
|
rb_cCAObject = rb_define_class("CAObject", rb_cCAView);
|
|
153
160
|
rb_cCARepeat = rb_define_class("CARepeat", rb_cCAStride);
|
|
154
|
-
/* CAUnboundRepeat: a CAStride with stride-0 axes on each `*` position
|
|
155
|
-
and sized (matching parent) on each nil position. */
|
|
156
|
-
rb_cCAUnboundRepeat = rb_define_class("CAUnboundRepeat", rb_cCAStride);
|
|
157
|
-
|
|
158
161
|
rb_cCArrayMask = rb_define_class("CArrayMask", rb_cCArray);
|
|
159
162
|
rb_cCAStrideMask = rb_define_class("CAStrideMask", rb_cCAStride);
|
|
160
163
|
rb_cCAReferMask = rb_define_class("CAReferMask", rb_cCARefer);
|
|
@@ -162,7 +165,6 @@ Init_carray_ext (void)
|
|
|
162
165
|
rb_cCAFieldMask = rb_define_class("CAFieldMask", rb_cCAField);
|
|
163
166
|
rb_cCASelectMask = rb_define_class("CASelectMask", rb_cCASelect);
|
|
164
167
|
rb_cCARepeatMask = rb_define_class("CARepeatMask", rb_cCARepeat);
|
|
165
|
-
rb_cCAUnboundRepeatMask = rb_define_class("CAUnboundRepeatMask", rb_cCAUnboundRepeat);
|
|
166
168
|
|
|
167
169
|
/* -- Exception class -- */
|
|
168
170
|
|
|
@@ -175,6 +177,10 @@ Init_carray_ext (void)
|
|
|
175
177
|
|
|
176
178
|
/* -- version -- */
|
|
177
179
|
|
|
180
|
+
/* The flags this build's arithmetic was compiled with. Anything that
|
|
181
|
+
computes what these kernels compute, somewhere other than in them, has
|
|
182
|
+
to be built the same way to arrive at the same answer. */
|
|
183
|
+
rb_define_const(rb_cCArray, "BUILD_FLAGS", rb_str_new2(CA_BUILD_FLAGS));
|
|
178
184
|
rb_define_const(rb_cCArray, "VERSION", rb_str_new2(CA_VERSION));
|
|
179
185
|
rb_define_const(rb_cCArray, "VERSION_CODE", INT2NUM(CA_VERSION_CODE));
|
|
180
186
|
rb_define_const(rb_cCArray, "VERSION_MAJOR", INT2NUM(CA_VERSION_MAJOR));
|
|
@@ -184,8 +190,14 @@ Init_carray_ext (void)
|
|
|
184
190
|
|
|
185
191
|
/* -- system -- */
|
|
186
192
|
rb_define_const(rb_cObject, "CA_RANK_MAX", INT2NUM(CA_RANK_MAX));
|
|
187
|
-
|
|
188
|
-
|
|
193
|
+
/* Sentinel meaning "the caller did not give this argument". It is
|
|
194
|
+
distinct from nil because nil is itself a legal fill value (a
|
|
195
|
+
CA_OBJECT array can be filled with nil), so nil cannot mark
|
|
196
|
+
absence. C code only ever compares against it; the value is never
|
|
197
|
+
read and must never be passed in from Ruby. The constant exists to
|
|
198
|
+
anchor the object against the GC. */
|
|
199
|
+
CA_UNSPECIFIED = rb_funcall(rb_cObject, rb_intern("new"), 0);
|
|
200
|
+
rb_define_const(rb_cCArray, "UNSPECIFIED", CA_UNSPECIFIED);
|
|
189
201
|
|
|
190
202
|
#ifdef HAVE_COMPLEX_H
|
|
191
203
|
/* @private */
|
|
@@ -305,7 +317,7 @@ Init_carray_ext (void)
|
|
|
305
317
|
Init_ca_obj_refer();
|
|
306
318
|
Init_ca_obj_stride(); /* CAREFUL: must precede CAStride subclasses
|
|
307
319
|
(farray / block / transpose / repeat /
|
|
308
|
-
|
|
320
|
+
field). */
|
|
309
321
|
Init_ca_obj_farray();
|
|
310
322
|
Init_ca_obj_block();
|
|
311
323
|
Init_ca_obj_select();
|
|
@@ -320,7 +332,6 @@ Init_carray_ext (void)
|
|
|
320
332
|
Init_ca_obj_meld();
|
|
321
333
|
Init_ca_obj_transpose();
|
|
322
334
|
Init_ca_obj_repeat();
|
|
323
|
-
Init_ca_obj_unbound_repeat();
|
|
324
335
|
Init_ca_obj_reduce();
|
|
325
336
|
Init_ca_obj_field();
|
|
326
337
|
Init_ca_obj_fake();
|
|
@@ -351,9 +362,7 @@ Init_carray_ext (void)
|
|
|
351
362
|
/* CAIterator is the form-only base of the 3.0 iterator family; its shared
|
|
352
363
|
accessors are plain Ruby attr_readers (lib/carray/iterator.rb). The C
|
|
353
364
|
reduction iterators subclass it and carray_access.c constructs
|
|
354
|
-
CASlabIterator by name, so the class object must exist here.
|
|
355
|
-
2.0 dispatch engines (dimension / window / block C iterators + the
|
|
356
|
-
kernel_at_addr base) are preserved at samples/caiterator/. */
|
|
365
|
+
CASlabIterator by name, so the class object must exist here. */
|
|
357
366
|
rb_cCAIterator = rb_define_class("CAIterator", rb_cObject);
|
|
358
367
|
|
|
359
368
|
Init_ca_group_iter(); /* devel/MEMO_AXIS_GROUP.md — axis-group [] surface
|
|
@@ -371,5 +380,7 @@ Init_carray_ext (void)
|
|
|
371
380
|
Init_ca_kernel_iterator();
|
|
372
381
|
|
|
373
382
|
Init_carray_slab();
|
|
383
|
+
|
|
384
|
+
Init_carray_address_basis();
|
|
374
385
|
}
|
|
375
386
|
|
data/ext/version.h
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#define CA_VERSION "3.0.
|
|
2
|
-
#define CA_VERSION_CODE
|
|
1
|
+
#define CA_VERSION "3.0.2"
|
|
2
|
+
#define CA_VERSION_CODE 302
|
|
3
3
|
#define CA_VERSION_MAJOR 3
|
|
4
4
|
#define CA_VERSION_MINOR 0
|
|
5
|
-
#define CA_VERSION_TEENY
|
|
6
|
-
#define CA_VERSION_DATE "2026/
|
|
5
|
+
#define CA_VERSION_TEENY 2
|
|
6
|
+
#define CA_VERSION_DATE "2026/09/24"
|
|
@@ -30,8 +30,9 @@
|
|
|
30
30
|
|
|
31
31
|
class CArray
|
|
32
32
|
inspect_rb = "carray/inspect"
|
|
33
|
-
autoload_method "inspect",
|
|
34
|
-
autoload_method "
|
|
33
|
+
autoload_method "inspect", inspect_rb
|
|
34
|
+
autoload_method "inspect_full", inspect_rb
|
|
35
|
+
autoload_method "source_code", inspect_rb
|
|
35
36
|
end
|
|
36
37
|
|
|
37
38
|
# ---- Serializer / Marshal / dump / load ------------------------------------
|
|
@@ -42,7 +43,6 @@ class CArray
|
|
|
42
43
|
autoload_method "self.save", serialize_rb
|
|
43
44
|
autoload_method "self.load", serialize_rb
|
|
44
45
|
autoload_method "self.dump", serialize_rb
|
|
45
|
-
autoload_method "self.load_from_file", serialize_rb
|
|
46
46
|
autoload_method "marshal_dump", serialize_rb
|
|
47
47
|
autoload_method "marshal_load", serialize_rb
|
|
48
48
|
end
|
|
@@ -62,6 +62,24 @@ class CArray
|
|
|
62
62
|
autoload :TableMethods, "carray/table"
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
+
# ---- Fusion (reading a lazy expression as a plan) --------------------------
|
|
66
|
+
#
|
|
67
|
+
# Nothing in the core asks for a plan -- CArray can always walk the view --
|
|
68
|
+
# so this loads only when something that compiles one asks.
|
|
69
|
+
|
|
70
|
+
class CArray
|
|
71
|
+
autoload :Fusion, "carray/fusion"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# ---- Reading a block as an expression (CArray.fuse) -------------------------
|
|
75
|
+
#
|
|
76
|
+
# Only `fuse` needs this, and only when it is called, so the parser it uses
|
|
77
|
+
# is not loaded by `require "carray"`.
|
|
78
|
+
|
|
79
|
+
class CArray
|
|
80
|
+
autoload :FuseSource, "carray/fuse_source"
|
|
81
|
+
end
|
|
82
|
+
|
|
65
83
|
# ---- Iterators (class / slab) ----------------------------------------------
|
|
66
84
|
|
|
67
85
|
autoload :CASlabIterator, "carray/slab_iterator"
|
|
@@ -172,6 +190,7 @@ end
|
|
|
172
190
|
# (2) Single-feature method files under carray/methods/
|
|
173
191
|
# ============================================================================
|
|
174
192
|
|
|
193
|
+
|
|
175
194
|
class CArray
|
|
176
195
|
# composition family (eager ragged list -> one array)
|
|
177
196
|
autoload_method "self.concatenate", "carray/methods/composition"
|
|
@@ -182,11 +201,13 @@ class CArray
|
|
|
182
201
|
autoload_method "self.meshgrid", "carray/methods/meshgrid"
|
|
183
202
|
|
|
184
203
|
autoload_method "bincount", "carray/methods/bincount"
|
|
204
|
+
autoload_method "repeat", "carray/methods/repeat"
|
|
185
205
|
autoload_method "self.broadcast", "carray/methods/broadcast"
|
|
186
206
|
autoload_method "gather_nd", "carray/methods/gather_nd"
|
|
187
207
|
autoload_method "put_nd", "carray/methods/gather_nd"
|
|
188
208
|
autoload_method "mask_duplicates", "carray/methods/mask_duplicates"
|
|
189
209
|
autoload_method "unique", "carray/methods/unique"
|
|
210
|
+
autoload_method "factorize", "carray/methods/factorize"
|
|
190
211
|
autoload_method "is_in", "carray/methods/is_in"
|
|
191
212
|
autoload_method "intersection", "carray/methods/is_in"
|
|
192
213
|
autoload_method "difference", "carray/methods/is_in"
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
# monkey patching is avoided -- only classes that explicitly `extend
|
|
16
16
|
# AutoloadMethodExtension` gain the method.
|
|
17
17
|
|
|
18
|
+
# @private
|
|
18
19
|
module AutoloadMethodExtension
|
|
19
20
|
# @!visibility private
|
|
20
21
|
def autoload_method (method, library)
|
|
@@ -31,14 +32,26 @@ module AutoloadMethodExtension
|
|
|
31
32
|
private
|
|
32
33
|
|
|
33
34
|
def autoload_define (target, name, library, original_spec)
|
|
34
|
-
|
|
35
|
+
stub = nil
|
|
36
|
+
target.define_method(name) do |*args, **kwargs, &block|
|
|
35
37
|
begin
|
|
36
38
|
require library
|
|
37
39
|
rescue LoadError
|
|
38
40
|
raise "error in autoloading '#{library}' hooked by method " \
|
|
39
41
|
"'#{original_spec}', check gem installation."
|
|
40
42
|
end
|
|
43
|
+
# The require is supposed to have replaced this stub with the real
|
|
44
|
+
# definition. If it has not, the method does not exist anywhere, and
|
|
45
|
+
# forwarding would land straight back here and keep doing so until the
|
|
46
|
+
# stack gave out -- naming neither the method nor the library. Say
|
|
47
|
+
# which, once.
|
|
48
|
+
if target.instance_method(name) == stub
|
|
49
|
+
raise NoMethodError,
|
|
50
|
+
"'#{original_spec}' is registered for autoload from " \
|
|
51
|
+
"'#{library}', but that library defines no such method"
|
|
52
|
+
end
|
|
41
53
|
send(name, *args, **kwargs, &block)
|
|
42
54
|
end
|
|
55
|
+
stub = target.instance_method(name)
|
|
43
56
|
end
|
|
44
57
|
end
|
data/lib/carray/axis_group.rb
CHANGED
|
@@ -308,7 +308,72 @@ end
|
|
|
308
308
|
# / min / max / variance / stddev / variancep / stddevp / count /
|
|
309
309
|
# count_not_masked / all / any) bind in C to one driver; the rest of the common
|
|
310
310
|
# iterator surface that composes cheaply from those is added here.
|
|
311
|
+
# CAGroupIterator subclasses CAIterator, but the class itself is created in
|
|
312
|
+
# C, so the reopening below carries no superclass for YARD to read.
|
|
313
|
+
# @!parse class CAGroupIterator < CAIterator; end
|
|
311
314
|
class CAGroupIterator
|
|
315
|
+
# The shape one value per piece comes back in: a group slot contributes its
|
|
316
|
+
# category count, a band slot its length, in slot order. The base declares
|
|
317
|
+
# these and every other member answers them; this one inherited the readers
|
|
318
|
+
# without anything ever setting the ivars, so it answered nil -- which the
|
|
319
|
+
# base's own rule calls out as the one thing a member must not do ("a clean
|
|
320
|
+
# NotImplementedError, never a wrong answer").
|
|
321
|
+
def shape
|
|
322
|
+
spec.slot_meta.map { |m| m[:kind] == :group ? m[:k] : m[:len] }
|
|
323
|
+
end
|
|
324
|
+
alias dim shape
|
|
325
|
+
|
|
326
|
+
def ndim
|
|
327
|
+
spec.nslots
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# The C dispatcher every reduction shares takes keywords only, so the
|
|
331
|
+
# value-equality and masked forms the base declares -- count(v), count(UNDEF)
|
|
332
|
+
# -- arrived as "wrong number of arguments", which reads as a method that
|
|
333
|
+
# does not take one rather than one whose engine has no such fold. Both are
|
|
334
|
+
# composed here instead, out of folds the engine does have.
|
|
335
|
+
alias __count_present__ count
|
|
336
|
+
|
|
337
|
+
# @overload count
|
|
338
|
+
# Per-group count of present (non-masked) cells.
|
|
339
|
+
# @overload count(UNDEF)
|
|
340
|
+
# Per-group count of masked cells, as {#count_masked}.
|
|
341
|
+
# @overload count(v)
|
|
342
|
+
# Per-group count of cells equal to `v`.
|
|
343
|
+
# @return [CArray]
|
|
344
|
+
def count (*args, **kw)
|
|
345
|
+
return __count_present__(**kw) if args.empty?
|
|
346
|
+
if args.size > 1
|
|
347
|
+
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0..1)"
|
|
348
|
+
end
|
|
349
|
+
v = args.first
|
|
350
|
+
return count_masked(**kw) if v.equal?(UNDEF)
|
|
351
|
+
# a masked cell equals nothing, and eq marks it UNDEF; drop that to false
|
|
352
|
+
# so it is simply not counted
|
|
353
|
+
hit = value.eq(v)
|
|
354
|
+
hit = hit.strip_mask(false) if hit.has_mask?
|
|
355
|
+
self.class.__build__(hit.int64, spec).sum(**kw).int64
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
alias __all_folded__ all
|
|
359
|
+
alias __any_folded__ any
|
|
360
|
+
|
|
361
|
+
# @overload all
|
|
362
|
+
# Per-group `all` over a boolean payload.
|
|
363
|
+
# @return [CArray]
|
|
364
|
+
def all (**kw)
|
|
365
|
+
boolean_payload!(:all)
|
|
366
|
+
__all_folded__(**kw)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# @overload any
|
|
370
|
+
# Per-group `any` over a boolean payload.
|
|
371
|
+
# @return [CArray]
|
|
372
|
+
def any (**kw)
|
|
373
|
+
boolean_payload!(:any)
|
|
374
|
+
__any_folded__(**kw)
|
|
375
|
+
end
|
|
376
|
+
|
|
312
377
|
# Per-group classified cell count (mask-independent) = count on the
|
|
313
378
|
# mask-stripped value, so every classified cell is counted regardless of the
|
|
314
379
|
# value mask (unlike count / count_not_masked, which count present cells).
|
|
@@ -401,8 +466,8 @@ class CAGroupIterator
|
|
|
401
466
|
end
|
|
402
467
|
|
|
403
468
|
# @overload cummax(axis: :group)
|
|
404
|
-
# Per-group inclusive running maximum, source-shaped, in the source
|
|
405
|
-
# (extrema do not grow magnitude, so the
|
|
469
|
+
# Per-group inclusive running maximum, source-shaped, in the source data type
|
|
470
|
+
# (extrema do not grow magnitude, so the data type is preserved). The first
|
|
406
471
|
# member of a group emits its own value. Without :group delegates to value
|
|
407
472
|
# cummax.
|
|
408
473
|
# @return [CArray]
|
|
@@ -411,7 +476,7 @@ class CAGroupIterator
|
|
|
411
476
|
end
|
|
412
477
|
|
|
413
478
|
# @overload cummin(axis: :group)
|
|
414
|
-
# Per-group inclusive running minimum, source-shaped, in the source
|
|
479
|
+
# Per-group inclusive running minimum, source-shaped, in the source data type.
|
|
415
480
|
# Without :group delegates to value cummin.
|
|
416
481
|
# @return [CArray]
|
|
417
482
|
def cummin (**kw)
|
|
@@ -549,6 +614,18 @@ class CAGroupIterator
|
|
|
549
614
|
# (the shape a length-K result reshapes to). This is the classification the C
|
|
550
615
|
# scatter kernel computes on the fly, materialised once so the order
|
|
551
616
|
# statistics / iterate / sort_addr can hold each group's members together.
|
|
617
|
+
# Whether a payload folds with all / any is the core's call, not this
|
|
618
|
+
# engine's. The engine counts any non-zero numeric cell as true, which made
|
|
619
|
+
# the group the one member of the family that answered where CArray#all and
|
|
620
|
+
# every sibling refuse -- so `data.all` and `data[g].all(axis: :group)` on
|
|
621
|
+
# the same float array disagreed about whether the question was even
|
|
622
|
+
# askable. Asking a one-cell array of the same data type lets the core's own
|
|
623
|
+
# refusal through, unworded by us.
|
|
624
|
+
def boolean_payload! (op)
|
|
625
|
+
CArray.new(value.data_type, [1]).public_send(op)
|
|
626
|
+
nil
|
|
627
|
+
end
|
|
628
|
+
|
|
552
629
|
def composite_layout
|
|
553
630
|
gslots = spec.slot_meta.select { |m| m[:kind] == :group }
|
|
554
631
|
bslots = spec.slot_meta.select { |m| m[:kind] == :band }
|
|
@@ -612,7 +689,7 @@ class CAGroupIterator
|
|
|
612
689
|
unless value.respond_to?(op)
|
|
613
690
|
raise NotImplementedError, "axis_group scan: value has no ##{op}"
|
|
614
691
|
end
|
|
615
|
-
return value.
|
|
692
|
+
return value.public_send(op)
|
|
616
693
|
end
|
|
617
694
|
unless fused.empty?
|
|
618
695
|
raise ArgumentError,
|
|
@@ -630,7 +707,7 @@ class CAGroupIterator
|
|
|
630
707
|
# operation, and remains a follow-up.
|
|
631
708
|
def order_stat (op, args, kw)
|
|
632
709
|
has_group, fused = AxisGroup.parse_axis(kw[:axis])
|
|
633
|
-
return value.
|
|
710
|
+
return value.public_send(op, *args) unless has_group
|
|
634
711
|
unless fused.empty?
|
|
635
712
|
raise NotImplementedError,
|
|
636
713
|
"axis_group: folding a band into an order statistic (axis: [:group, k]) " \
|
|
@@ -651,13 +728,13 @@ class CAGroupIterator
|
|
|
651
728
|
ccat, kdims, gslots, bslots, gaxes = composite_layout
|
|
652
729
|
nout = (op == :quantile) ? 5 : 1
|
|
653
730
|
if bslots.empty?
|
|
654
|
-
res = value.group_by_category(ccat).
|
|
731
|
+
res = value.group_by_category(ccat).public_send(op, *args)
|
|
655
732
|
return nout == 1 ? res.reshape(*kdims) : res.map { |r| r.reshape(*kdims) }
|
|
656
733
|
end
|
|
657
734
|
out_shape = spec.slot_meta.map { |m| m[:kind] == :group ? m[:k] : m[:len] }
|
|
658
735
|
outs = Array.new(nout) { CArray.float64(*out_shape) }
|
|
659
736
|
each_band_block(ccat, gslots, bslots, gaxes) do |_vi, out_idx, _co, gi|
|
|
660
|
-
result = gi.
|
|
737
|
+
result = gi.public_send(op, *args)
|
|
661
738
|
if nout == 1
|
|
662
739
|
outs[0][*out_idx] = result.reshape(*kdims)
|
|
663
740
|
else
|
data/lib/carray/basics.rb
CHANGED
|
@@ -30,27 +30,26 @@ class CArray
|
|
|
30
30
|
# shift as other axes are inserted (e.g. `insert_axis(0, 1, 2)`
|
|
31
31
|
# puts one axis before each of the first three source axes).
|
|
32
32
|
#
|
|
33
|
-
# Each inserted axis takes one of
|
|
34
|
-
# `repeat` value: `1` (or `nil`) for a plain size-1 axis, an
|
|
35
|
-
# Integer `N > 1` for a read-only bound repeat view
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# giving one value per position.
|
|
33
|
+
# Each inserted axis takes one of two forms, chosen by its
|
|
34
|
+
# `repeat` value: `1` (or `nil`) for a plain size-1 axis, or an
|
|
35
|
+
# Integer `N > 1` for a read-only bound repeat view. `repeat` is
|
|
36
|
+
# either a single value applied to every inserted axis, or an
|
|
37
|
+
# Array giving one value per position.
|
|
39
38
|
#
|
|
40
|
-
# The everyday way to add an axis is the `:_`
|
|
41
|
-
#
|
|
42
|
-
#
|
|
39
|
+
# The everyday way to add an axis is the `:_` indexer when the
|
|
40
|
+
# shape is known at the call site; `insert_axis` is for library
|
|
41
|
+
# code that builds the axis list programmatically.
|
|
43
42
|
#
|
|
44
43
|
# @param positions [Array<Integer>] source-frame positions of the
|
|
45
44
|
# new axes.
|
|
46
|
-
# @param repeat [Integer,
|
|
47
|
-
#
|
|
45
|
+
# @param repeat [Integer, Array, nil] repeat spec applied to each
|
|
46
|
+
# inserted axis.
|
|
48
47
|
# @return [CArray] view with the new axes inserted.
|
|
49
48
|
# @example
|
|
50
49
|
# a = CArray.int32(3, 4).seq
|
|
51
50
|
# a.insert_axis(0) # shape (1, 3, 4)
|
|
52
51
|
# a.insert_axis(1, repeat: 5) # shape (3, 5, 4)
|
|
53
|
-
# a.insert_axis(0, 1, repeat: [
|
|
52
|
+
# a.insert_axis(0, 1, repeat: [1, 3]) # size-1 then bound
|
|
54
53
|
def insert_axis (*positions, repeat: nil)
|
|
55
54
|
flat = positions.flatten
|
|
56
55
|
if flat.empty?
|
|
@@ -81,57 +80,31 @@ class CArray
|
|
|
81
80
|
Array.new(flat.length, repeat)
|
|
82
81
|
end
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
when :*
|
|
91
|
-
# ok
|
|
92
|
-
else
|
|
93
|
-
raise ArgumentError,
|
|
94
|
-
"insert_axis: repeat must be a positive Integer or :*, got #{r.inspect}"
|
|
95
|
-
end
|
|
83
|
+
# Validate each value. A positive Integer only; nil is not a valid
|
|
84
|
+
# per-axis repeat.
|
|
85
|
+
reps.each do |r|
|
|
86
|
+
unless r.is_a?(Integer)
|
|
87
|
+
raise ArgumentError,
|
|
88
|
+
"insert_axis: repeat must be a positive Integer, got #{r.inspect}"
|
|
96
89
|
end
|
|
90
|
+
raise ArgumentError, "insert_axis: repeat count must be >= 1" if r < 1
|
|
91
|
+
end
|
|
97
92
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
order.each_with_index { |i, k| final[i] = gaps[i] + k }
|
|
106
|
-
|
|
107
|
-
unbound_args = order.select { |i| reps[i] == :* }
|
|
108
|
-
concrete_args = order.reject { |i| reps[i] == :* } # in output order
|
|
109
|
-
|
|
110
|
-
# Stage 1: insert the concrete (size-1 / bound) axes by their source
|
|
111
|
-
# gaps, then grow the bound ones with broadcast_to.
|
|
112
|
-
inter = self
|
|
113
|
-
unless concrete_args.empty?
|
|
114
|
-
inter = __insert_axis_size1__(*concrete_args.map { |i| gaps[i] })
|
|
115
|
-
if concrete_args.any? { |i| reps[i].is_a?(Integer) && reps[i] > 1 }
|
|
116
|
-
shp = inter.shape
|
|
117
|
-
concrete_args.each do |i|
|
|
118
|
-
r = reps[i]
|
|
119
|
-
next unless r.is_a?(Integer) && r > 1
|
|
120
|
-
# intermediate position = final position minus unbound axes before it
|
|
121
|
-
shp[final[i] - unbound_args.count { |u| final[u] < final[i] }] = r
|
|
122
|
-
end
|
|
123
|
-
inter = inter.broadcast_to(*shp)
|
|
124
|
-
end
|
|
125
|
-
end
|
|
93
|
+
# Final output layout: stable order by (gap, argument index) keeps
|
|
94
|
+
# same-gap axes in argument order; the k-th inserted axis lands at output
|
|
95
|
+
# position gap + k. This output position only drives broadcast_to; the
|
|
96
|
+
# insertion itself always goes through the source-frame primitive.
|
|
97
|
+
order = (0...flat.length).sort_by { |i| [gaps[i], i] }
|
|
98
|
+
final = {}
|
|
99
|
+
order.each_with_index { |i, k| final[i] = gaps[i] + k }
|
|
126
100
|
|
|
127
|
-
|
|
101
|
+
inter = __insert_axis_size1__(*order.map { |i| gaps[i] })
|
|
102
|
+
return inter unless order.any? { |i| reps[i] > 1 }
|
|
128
103
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
inter.unbound_repeat(*pattern)
|
|
134
|
-
end
|
|
104
|
+
shp = inter.shape
|
|
105
|
+
order.each { |i| shp[final[i]] = reps[i] if reps[i] > 1 }
|
|
106
|
+
inter.broadcast_to(*shp)
|
|
107
|
+
end
|
|
135
108
|
|
|
136
109
|
# @overload drop_axis
|
|
137
110
|
# Returns a view of `self` with every size-1 axis dropped.
|
|
@@ -186,6 +159,10 @@ class CArray
|
|
|
186
159
|
# @raise [ArgumentError] when `offset.length != self.ndim`.
|
|
187
160
|
def paste (offset, src)
|
|
188
161
|
raise ArgumentError, "offset length must equal ndim" if offset.length != ndim
|
|
162
|
+
# A zero-length source covers no cell, so there is nothing to write --
|
|
163
|
+
# and the empty range it would ask for is not a window CAWindow can
|
|
164
|
+
# build. This is what lets concatenate / mosaic take an empty piece.
|
|
165
|
+
return self if src.elements.zero?
|
|
189
166
|
ranges = offset.each_with_index.map { |o, i| o...(o + src.shape[i]) }
|
|
190
167
|
self.window(*ranges)[] = src
|
|
191
168
|
self
|
|
@@ -246,6 +223,33 @@ class CArray
|
|
|
246
223
|
|
|
247
224
|
alias cmp <=>
|
|
248
225
|
|
|
226
|
+
# @!group Elementwise math
|
|
227
|
+
|
|
228
|
+
# Returns `[quotient, remainder]` element-wise.
|
|
229
|
+
#
|
|
230
|
+
# The quotient is floored toward -inf, so `q * other + r == self` holds
|
|
231
|
+
# for every sign combination -- the pair Ruby's `Integer#divmod` and
|
|
232
|
+
# `Float#divmod` return. For integers that is `self / other` unchanged;
|
|
233
|
+
# for floats `/` is true division, so the quotient is floored here.
|
|
234
|
+
#
|
|
235
|
+
# @param other [CArray, Numeric] divisor.
|
|
236
|
+
# @return [Array<CArray>] the floored quotient and the remainder.
|
|
237
|
+
# @raise [ArgumentError] for complex arrays, which have no ordering to
|
|
238
|
+
# floor toward.
|
|
239
|
+
# @example
|
|
240
|
+
# CA_INT32([-7]).divmod(3) # => [-3, 2]
|
|
241
|
+
# CA_DOUBLE([-7.0]).divmod(3.0) # => [-3.0, 2.0]
|
|
242
|
+
def divmod(other)
|
|
243
|
+
if complex?
|
|
244
|
+
raise ArgumentError, "divmod is not defined for complex arrays"
|
|
245
|
+
end
|
|
246
|
+
q = self / other
|
|
247
|
+
q = q.floor unless q.integer?
|
|
248
|
+
[q, self % other]
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# @!endgroup
|
|
252
|
+
|
|
249
253
|
# @overload clip(min, max = nil, fill_value = nil, lfill: nil, ufill: nil)
|
|
250
254
|
# Returns `self` with every element clamped to `[min, max]`.
|
|
251
255
|
#
|
data/lib/carray/bincount_nd.rb
CHANGED
|
@@ -68,16 +68,16 @@ class CArray
|
|
|
68
68
|
# use `CArray#histogram`.
|
|
69
69
|
class BincountND
|
|
70
70
|
|
|
71
|
-
# @overload initialize(lengths:, fiber_shape: [],
|
|
71
|
+
# @overload initialize(lengths:, fiber_shape: [], weights_data_type: nil)
|
|
72
72
|
# Allocates a new N-D discrete bincount accumulator.
|
|
73
73
|
# @param lengths [Array<Integer>] per-dimension label ranges;
|
|
74
74
|
# each must be `>= 1`.
|
|
75
75
|
# @param fiber_shape [Array<Integer>] shape of the leading
|
|
76
76
|
# axes.
|
|
77
|
-
# @param
|
|
77
|
+
# @param weights_data_type [Symbol, nil] `data_type` for weighted
|
|
78
78
|
# accumulators; `nil` for pure counts (int64).
|
|
79
79
|
# @return [BincountND]
|
|
80
|
-
def initialize (lengths:, fiber_shape: [],
|
|
80
|
+
def initialize (lengths:, fiber_shape: [], weights_data_type: nil)
|
|
81
81
|
@lengths = lengths.map(&:to_i)
|
|
82
82
|
raise ArgumentError, "lengths must be a non-empty list" if @lengths.empty?
|
|
83
83
|
@lengths.each_with_index do |l, k|
|
|
@@ -85,11 +85,11 @@ class CArray
|
|
|
85
85
|
end
|
|
86
86
|
@m = @lengths.size
|
|
87
87
|
@fiber_shape = fiber_shape.map(&:to_i).freeze
|
|
88
|
-
@weighted = !
|
|
89
|
-
@
|
|
88
|
+
@weighted = !weights_data_type.nil?
|
|
89
|
+
@counts_data_type = @weighted ? weights_data_type : :int64
|
|
90
90
|
ext_dims = @lengths.map { |l| l + 1 } # +1: upper overflow cell
|
|
91
91
|
ext_shape = @fiber_shape + ext_dims
|
|
92
|
-
@full_counts = CArray.public_send(@
|
|
92
|
+
@full_counts = CArray.public_send(@counts_data_type, *ext_shape).fill(0)
|
|
93
93
|
@sample_axis = nil
|
|
94
94
|
@channel_axis = nil
|
|
95
95
|
end
|
|
@@ -209,7 +209,7 @@ class CArray
|
|
|
209
209
|
|
|
210
210
|
if weights
|
|
211
211
|
raise ArgumentError, "weights given but accumulator is unweighted" unless @weighted
|
|
212
|
-
weights = CArray.wrap_readonly(weights, @
|
|
212
|
+
weights = CArray.wrap_readonly(weights, @counts_data_type)
|
|
213
213
|
expected_w_shape = chunk.shape.dup
|
|
214
214
|
expected_w_shape.delete_at(channel_ax)
|
|
215
215
|
unless weights.shape == expected_w_shape
|
|
@@ -297,7 +297,7 @@ class CArray
|
|
|
297
297
|
result = self.class.send(:new,
|
|
298
298
|
lengths: @lengths,
|
|
299
299
|
fiber_shape: @fiber_shape,
|
|
300
|
-
|
|
300
|
+
weights_data_type: @weighted ? @counts_data_type : nil)
|
|
301
301
|
rf = result.instance_variable_get(:@full_counts)
|
|
302
302
|
rf[] = @full_counts + other.full_counts
|
|
303
303
|
result.instance_variable_set(:@sample_axis, @sample_axis)
|
|
@@ -344,14 +344,14 @@ class CArray
|
|
|
344
344
|
[sample_ax, channel_ax].sort.reverse.each { |p| fiber_shape.delete_at(p) }
|
|
345
345
|
|
|
346
346
|
# Weighted counts are float64-only (the FLAT bincount coerces weights to the
|
|
347
|
-
# counts
|
|
348
|
-
#
|
|
349
|
-
|
|
347
|
+
# counts data type and the FIBER kernel requires float64 weights/counts), so
|
|
348
|
+
# the type is fixed here rather than derived from the weights' own type.
|
|
349
|
+
weights_data_type = (:float64 if weights)
|
|
350
350
|
|
|
351
351
|
h = BincountND.send(:new,
|
|
352
352
|
lengths: lengths,
|
|
353
353
|
fiber_shape: fiber_shape,
|
|
354
|
-
|
|
354
|
+
weights_data_type: weights_data_type)
|
|
355
355
|
h.add(self, axis: axis, weights: weights)
|
|
356
356
|
h
|
|
357
357
|
end
|