carray 3.0.3 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +264 -0
- data/README.md +3 -2
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +1 -6
- data/ext/ca_axis_group.c +27 -27
- data/ext/ca_binop_dispatch.c +1 -29
- data/ext/ca_binop_dispatch.h +0 -1
- data/ext/ca_categorical_iterator.c +205 -134
- data/ext/ca_compare.c +7 -18
- data/ext/ca_group_iter.c +16 -17
- data/ext/ca_kernel_iterator.c +1234 -1994
- data/ext/ca_kernel_iterator.h +391 -437
- data/ext/ca_monop_dispatch.c +82 -59
- data/ext/ca_monop_dispatch.h +1 -0
- data/ext/ca_obj_array.c +96 -39
- data/ext/ca_obj_bincmp.c +24 -21
- data/ext/ca_obj_binop.c +15 -26
- data/ext/ca_obj_bitarray.c +3 -2
- data/ext/ca_obj_bitfield.c +5 -6
- data/ext/ca_obj_block.c +18 -9
- data/ext/ca_obj_byte_swap.c +5 -6
- data/ext/ca_obj_const_string.c +173 -19
- data/ext/ca_obj_face.c +238 -57
- data/ext/ca_obj_face.h +19 -0
- data/ext/ca_obj_fake.c +15 -29
- data/ext/ca_obj_farray.c +6 -3
- data/ext/ca_obj_field.c +17 -5
- data/ext/ca_obj_fixlen_string.c +2 -3
- data/ext/ca_obj_grid.c +406 -132
- data/ext/ca_obj_meld.c +172 -34
- data/ext/ca_obj_moncmp.c +23 -8
- data/ext/ca_obj_monop.c +67 -57
- data/ext/ca_obj_object.c +157 -51
- data/ext/ca_obj_record.c +12 -7
- data/ext/ca_obj_reduce.c +13 -8
- data/ext/ca_obj_refer.c +25 -27
- data/ext/ca_obj_remap.c +30 -9
- data/ext/ca_obj_repeat.c +9 -10
- data/ext/ca_obj_roll.c +6 -5
- data/ext/ca_obj_select.c +14 -9
- data/ext/ca_obj_select_axis.c +15 -47
- data/ext/ca_obj_shift.c +11 -1
- data/ext/ca_obj_stack.c +179 -34
- data/ext/ca_obj_stride.c +162 -115
- data/ext/ca_obj_string.c +71 -4
- data/ext/ca_obj_tile.c +6 -5
- data/ext/ca_obj_time.c +22 -6
- data/ext/ca_obj_timedelta.c +22 -6
- data/ext/ca_obj_transpose.c +5 -3
- data/ext/ca_obj_triop.c +23 -32
- data/ext/ca_obj_window.c +190 -26
- data/ext/ca_sweep_engine.c +2 -2
- data/ext/caframe_csv_reader.c +80 -1
- data/ext/carray.h +181 -75
- data/ext/carray_access.c +184 -96
- data/ext/carray_address_basis.c +343 -87
- data/ext/carray_attribute.c +89 -6
- data/ext/carray_bincount.c +10 -8
- data/ext/carray_broadcast.c +13 -8
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +108 -0
- data/ext/carray_cast.c +142 -24
- data/ext/carray_cast_func.rb +46 -6
- data/ext/carray_class.c +4 -3
- data/ext/carray_config.h +28 -0
- data/ext/carray_conversion.c +16 -7
- data/ext/carray_copy.c +51 -14
- data/ext/carray_core.c +147 -55
- data/ext/carray_count.c +50 -20
- data/ext/carray_element.c +76 -33
- data/ext/carray_factorize.c +118 -64
- data/ext/carray_generate.c +191 -50
- data/ext/carray_histogram.c +62 -17
- data/ext/carray_hold.c +12 -15
- data/ext/carray_index_classifier.c +388 -176
- data/ext/carray_internal.h +336 -29
- data/ext/carray_kernels_bincmp.c +4453 -0
- data/ext/carray_kernels_binop.c +11368 -0
- data/ext/carray_kernels_init.c +1734 -0
- data/ext/carray_kernels_moncmp.c +2104 -0
- data/ext/carray_kernels_monop.c +18369 -0
- data/ext/carray_kernels_reduce_aggregate.c +23818 -0
- data/ext/carray_kernels_reduce_boolean.c +406 -0
- data/ext/carray_kernels_reduce_cumulative.c +10086 -0
- data/ext/carray_kernels_reduce_extreme.c +17634 -0
- data/ext/carray_kernels_reduce_variance.c +3849 -0
- data/ext/carray_kernels_scan.c +4302 -0
- data/ext/carray_kernels_search.c +33829 -0
- data/ext/carray_kernels_sort.c +10906 -0
- data/ext/carray_kernels_triop.c +1864 -0
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +170 -111
- data/ext/carray_mask.c +292 -72
- data/ext/carray_median_percentile.c +82 -28
- data/ext/carray_memory_view.c +669 -561
- data/ext/carray_operator.c +124 -47
- data/ext/carray_order.c +384 -76
- data/ext/carray_partition.c +28 -27
- data/ext/carray_random.c +67 -13
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +63 -38
- data/ext/carray_segment.c +3 -3
- data/ext/carray_slab.c +91 -28
- data/ext/carray_sort.c +35 -35
- data/ext/carray_struct.c +19 -18
- data/ext/carray_test.c +26 -5
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +246 -45
- data/ext/mk_call_cfunc.rb +19 -2
- data/ext/mkkernel.rb +198 -240
- data/ext/ruby_carray.c +10 -4
- data/ext/version.h +4 -4
- data/lib/carray/attribute.rb +126 -22
- data/lib/carray/autoload_carray.rb +8 -31
- data/lib/carray/autoload_method_extension.rb +14 -5
- data/lib/carray/axis_group.rb +255 -106
- data/lib/carray/basics.rb +78 -10
- data/lib/carray/bincount_nd.rb +12 -2
- data/lib/carray/block_iterator.rb +126 -23
- data/lib/carray/boolean_reduce.rb +17 -17
- data/lib/carray/categorical.rb +165 -43
- data/lib/carray/categorical_iterator.rb +130 -27
- data/lib/carray/complex.rb +5 -5
- data/lib/carray/conditional.rb +67 -18
- data/lib/carray/const_string.rb +14 -5
- data/lib/carray/construct.rb +15 -11
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/distance_limit.rb +77 -0
- data/lib/carray/fixlen_string.rb +7 -1
- data/lib/carray/frame/column_verbs.rb +70 -0
- data/lib/carray/frame/convert.rb +69 -0
- data/lib/carray/frame/csv_parser.rb +111 -17
- data/lib/carray/frame/describe.rb +3 -2
- data/lib/carray/frame/frame.rb +246 -21
- data/lib/carray/frame/group.rb +510 -95
- data/lib/carray/frame/io.rb +115 -28
- data/lib/carray/frame/join.rb +312 -51
- data/lib/carray/frame/records.rb +83 -7
- data/lib/carray/frame/reshape.rb +42 -35
- data/lib/carray/frame/sort.rb +7 -19
- data/lib/carray/frame/verbs.rb +188 -48
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +11 -4
- data/lib/carray/fusion.rb +40 -16
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +31 -8
- data/lib/carray/iterator.rb +85 -7
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +182 -183
- data/lib/carray/mask_gap_fill.rb +63 -57
- data/lib/carray/meld_reduce.rb +12 -14
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +16 -0
- data/lib/carray/methods/bit_string.rb +1 -1
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +3 -1
- data/lib/carray/methods/gather_nd.rb +14 -5
- data/lib/carray/methods/insert_block.rb +2 -2
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +53 -36
- data/lib/carray/methods/join.rb +1 -6
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +47 -51
- data/lib/carray/methods/mode.rb +1 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/resize.rb +3 -3
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +3 -3
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +53 -8
- data/lib/carray/segment_iterator.rb +313 -82
- data/lib/carray/serialize.rb +24 -10
- data/lib/carray/slab_iterator.rb +50 -0
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +8 -1
- data/lib/carray/struct.rb +9 -21
- data/lib/carray/struct_builder.rb +19 -8
- data/lib/carray/time.rb +726 -104
- data/lib/carray/window_iterator.rb +122 -16
- data/lib/carray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +4 -0
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +2 -1
- data/yard-stubs/ca_obj_roll.rb +2 -2
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +8 -3
- data/yard-stubs/carray_access.rb +6 -1
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_cast.rb +10 -0
- data/yard-stubs/carray_conversion.rb +2 -1
- data/yard-stubs/carray_copy.rb +4 -2
- data/yard-stubs/carray_count.rb +4 -4
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_mask.rb +26 -2
- data/yard-stubs/carray_math.rb +27 -1
- data/yard-stubs/carray_median_percentile.rb +5 -2
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +29 -18
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +14 -9
- data/yard-stubs/carray_slab.rb +9 -2
- data/yard-stubs/carray_sort.rb +6 -5
- data/yard-stubs/carray_test.rb +5 -3
- metadata +25 -3
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_order.c
CHANGED
|
@@ -116,19 +116,23 @@ ca_project_loop (CArray *co, CArray *ca, CArray *ci, char *lfill, char *ufill)
|
|
|
116
116
|
xfree(ma);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
/* The result is wrapped before anything is copied into it: for an object
|
|
120
|
+
array the gathered cells are VALUEs that only the result's mark keeps
|
|
121
|
+
alive once the source is detached. */
|
|
122
|
+
static VALUE
|
|
120
123
|
ca_project (CArray *ca, CArray *ci, char *lfill, char *ufill)
|
|
121
124
|
{
|
|
125
|
+
volatile VALUE obj;
|
|
122
126
|
CArray *co;
|
|
123
127
|
|
|
124
|
-
|
|
128
|
+
obj = rb_carray_new(ca->data_type, ci->ndim, ci->dim, ca->bytes, NULL);
|
|
129
|
+
GetCArray(obj, co);
|
|
125
130
|
|
|
126
|
-
|
|
131
|
+
ca_attach_n(2, ca, ci); /* window: nothing raises inside */
|
|
127
132
|
ca_project_loop(co, ca, ci, lfill, ufill);
|
|
128
|
-
|
|
129
133
|
ca_detach_n(2, ca, ci); /* DETACH */
|
|
130
134
|
|
|
131
|
-
return
|
|
135
|
+
return obj;
|
|
132
136
|
}
|
|
133
137
|
|
|
134
138
|
/* rk.__count_below__(q, inclusive) -- for each cell of q, how many values
|
|
@@ -254,12 +258,12 @@ rb_ca_project (int argc, VALUE *argv, VALUE self)
|
|
|
254
258
|
lfval = ALLOCV_N(char, hlfval, ca->bytes); /* converting a fill value */
|
|
255
259
|
ufval = ALLOCV_N(char, hufval, ca->bytes); /* can raise; the unwind frees */
|
|
256
260
|
|
|
257
|
-
if ( ! NIL_P(vlfval) ) {
|
|
261
|
+
if ( ! NIL_P(vlfval) && vlfval != CA_UNDEF ) {
|
|
258
262
|
rb_ca_obj2ptr(self, vlfval, lfval);
|
|
259
263
|
rb_ca_obj2ptr(self, vlfval, ufval);
|
|
260
264
|
}
|
|
261
265
|
|
|
262
|
-
if ( ! NIL_P(vufval) ) {
|
|
266
|
+
if ( ! NIL_P(vufval) && vufval != CA_UNDEF ) {
|
|
263
267
|
rb_ca_obj2ptr(self, vufval, ufval);
|
|
264
268
|
}
|
|
265
269
|
|
|
@@ -274,15 +278,19 @@ rb_ca_project (int argc, VALUE *argv, VALUE self)
|
|
|
274
278
|
TypedData_Get_Struct(vstorage, CArray, &carray_data_type, ca);
|
|
275
279
|
}
|
|
276
280
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
281
|
+
/* A fill of UNDEF is no fill: the cell is masked, as it is with none. */
|
|
282
|
+
{
|
|
283
|
+
VALUE vlower = vlfval;
|
|
284
|
+
VALUE vupper = NIL_P(vufval) ? vlfval : vufval;
|
|
285
|
+
obj = ca_project(ca, ci,
|
|
286
|
+
( NIL_P(vlower) || vlower == CA_UNDEF ) ? NULL : lfval,
|
|
287
|
+
( NIL_P(vupper) || vupper == CA_UNDEF ) ? NULL : ufval);
|
|
288
|
+
}
|
|
289
|
+
GetCArray(obj, co);
|
|
280
290
|
|
|
281
291
|
ALLOCV_END(hlfval);
|
|
282
292
|
ALLOCV_END(hufval);
|
|
283
293
|
|
|
284
|
-
obj = ca_wrap_struct(co);
|
|
285
|
-
|
|
286
294
|
if ( ! ca_is_any_masked(co) ) {
|
|
287
295
|
obj = rb_ca_unmask_copy(obj);
|
|
288
296
|
}
|
|
@@ -291,6 +299,7 @@ rb_ca_project (int argc, VALUE *argv, VALUE self)
|
|
|
291
299
|
obj = ca_face_lift(obj, self);
|
|
292
300
|
}
|
|
293
301
|
|
|
302
|
+
rb_ca_inherit_attr(obj, self);
|
|
294
303
|
return obj;
|
|
295
304
|
}
|
|
296
305
|
|
|
@@ -532,6 +541,41 @@ rb_ca_search_nearest_addr_kw (int argc, VALUE *argv, VALUE self)
|
|
|
532
541
|
|
|
533
542
|
/* ---- sort_by_key family ---------------------------------------------- */
|
|
534
543
|
|
|
544
|
+
/* The key orders self's cells one for one, so it has self's shape. */
|
|
545
|
+
static void
|
|
546
|
+
ca_by_key_check_shape (VALUE self, VALUE rkey, const char *name)
|
|
547
|
+
{
|
|
548
|
+
CArray *ca, *ck;
|
|
549
|
+
int8_t i;
|
|
550
|
+
rb_check_carray_object(rkey);
|
|
551
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
552
|
+
TypedData_Get_Struct(rkey, CArray, &carray_data_type, ck);
|
|
553
|
+
if ( ca->ndim == ck->ndim ) {
|
|
554
|
+
for (i = 0; i < ca->ndim; i++) {
|
|
555
|
+
if ( ca->dim[i] != ck->dim[i] ) break;
|
|
556
|
+
}
|
|
557
|
+
if ( i == ca->ndim ) return;
|
|
558
|
+
}
|
|
559
|
+
rb_raise(rb_eArgError, "%s: the key's shape %"PRIsVALUE" differs from "
|
|
560
|
+
"the array's %"PRIsVALUE, name,
|
|
561
|
+
rb_funcall(rkey, rb_intern("shape"), 0),
|
|
562
|
+
rb_funcall(self, rb_intern("shape"), 0));
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/* self at the addresses an extremum by key found. A fiber with no cell to
|
|
566
|
+
compare has a masked (or UNDEF) address and answers UNDEF. */
|
|
567
|
+
static VALUE
|
|
568
|
+
ca_by_key_fetch (VALUE self, VALUE addrs)
|
|
569
|
+
{
|
|
570
|
+
if ( addrs == CA_UNDEF ) {
|
|
571
|
+
return CA_UNDEF;
|
|
572
|
+
}
|
|
573
|
+
if ( rb_obj_is_carray(addrs) && RTEST(rb_ca_has_mask(addrs)) ) {
|
|
574
|
+
return rb_funcall(self, rb_intern("project"), 1, addrs);
|
|
575
|
+
}
|
|
576
|
+
return rb_ca_fetch(self, addrs);
|
|
577
|
+
}
|
|
578
|
+
|
|
535
579
|
/* sort_by_key(key, axis: 0) -- gather self at key.sort_addr(axis:). */
|
|
536
580
|
static VALUE
|
|
537
581
|
rb_ca_sort_by_key (int argc, VALUE *argv, VALUE self)
|
|
@@ -542,6 +586,7 @@ rb_ca_sort_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
542
586
|
if ( NIL_P(raxis) ) {
|
|
543
587
|
raxis = INT2FIX(0);
|
|
544
588
|
}
|
|
589
|
+
ca_by_key_check_shape(self, rkey, "sort_by_key");
|
|
545
590
|
VALUE addrs = rb_ca_sort_addr_c(rkey, raxis, 0, 1); /* masked_last=1 (:last), unchanged default */
|
|
546
591
|
return rb_ca_fetch(self, addrs);
|
|
547
592
|
}
|
|
@@ -553,9 +598,11 @@ rb_ca_max_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
553
598
|
VALUE rkey, rkw = Qnil, raxis = Qnil;
|
|
554
599
|
rb_scan_args(argc, argv, "1:", &rkey, &rkw);
|
|
555
600
|
rb_scan_options(rkw, "axis", &raxis);
|
|
556
|
-
|
|
557
|
-
|
|
601
|
+
ca_by_key_check_shape(self, rkey, "max_by_key");
|
|
602
|
+
if ( NIL_P(raxis) && RTEST(rb_ca_is_empty(self)) ) {
|
|
603
|
+
return CA_UNDEF;
|
|
558
604
|
}
|
|
605
|
+
rkey = ca_order_key(rkey, "max_by_key");
|
|
559
606
|
|
|
560
607
|
VALUE addrs;
|
|
561
608
|
|
|
@@ -568,7 +615,7 @@ rb_ca_max_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
568
615
|
rb_hash_aset(kw, ID2SYM(id_axis), raxis);
|
|
569
616
|
addrs = rb_funcallv_kw(rkey, rb_intern("max_addr"), 1, &kw, RB_PASS_KEYWORDS);
|
|
570
617
|
}
|
|
571
|
-
return
|
|
618
|
+
return ca_by_key_fetch(self, addrs);
|
|
572
619
|
}
|
|
573
620
|
|
|
574
621
|
/* min_by_key(key, axis: nil) -- self[key.min_addr(axis:)] (or UNDEF if empty). */
|
|
@@ -578,9 +625,11 @@ rb_ca_min_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
578
625
|
VALUE rkey, rkw = Qnil, raxis = Qnil;
|
|
579
626
|
rb_scan_args(argc, argv, "1:", &rkey, &rkw);
|
|
580
627
|
rb_scan_options(rkw, "axis", &raxis);
|
|
581
|
-
|
|
582
|
-
|
|
628
|
+
ca_by_key_check_shape(self, rkey, "min_by_key");
|
|
629
|
+
if ( NIL_P(raxis) && RTEST(rb_ca_is_empty(self)) ) {
|
|
630
|
+
return CA_UNDEF;
|
|
583
631
|
}
|
|
632
|
+
rkey = ca_order_key(rkey, "min_by_key");
|
|
584
633
|
|
|
585
634
|
VALUE addrs;
|
|
586
635
|
|
|
@@ -593,7 +642,7 @@ rb_ca_min_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
593
642
|
rb_hash_aset(kw, ID2SYM(id_axis), raxis);
|
|
594
643
|
addrs = rb_funcallv_kw(rkey, rb_intern("min_addr"), 1, &kw, RB_PASS_KEYWORDS);
|
|
595
644
|
}
|
|
596
|
-
return
|
|
645
|
+
return ca_by_key_fetch(self, addrs);
|
|
597
646
|
}
|
|
598
647
|
|
|
599
648
|
/* ---- take_along_axis / put_along_axis -------------------------------- */
|
|
@@ -637,10 +686,16 @@ rb_ca_put_along_axis (int argc, VALUE *argv, VALUE self)
|
|
|
637
686
|
raxis = INT2FIX(0);
|
|
638
687
|
}
|
|
639
688
|
VALUE addrs = rb_ca_axis2addr_c(self, argv[0], raxis);
|
|
640
|
-
/* A masked index writes nothing
|
|
641
|
-
|
|
689
|
+
/* A masked index writes nothing. The values are first laid out over the
|
|
690
|
+
indices by the store itself (an array of the indices' shape, so a
|
|
691
|
+
broadcast, UNDEF or a Face value means what it means unmasked), and
|
|
692
|
+
only the cells at unmasked indices are written. */
|
|
642
693
|
if ( RTEST(rb_ca_has_mask(addrs)) ) {
|
|
643
|
-
rb_funcall(
|
|
694
|
+
VALUE sel = rb_funcall(addrs, rb_intern("is_not_masked"), 0);
|
|
695
|
+
VALUE vals = rb_funcall(self, rb_intern("project"), 1, addrs);
|
|
696
|
+
rb_funcall(vals, rb_intern("[]="), 1, argv[1]);
|
|
697
|
+
rb_ca_store(self, rb_funcall(addrs, rb_intern("[]"), 1, sel),
|
|
698
|
+
rb_funcall(vals, rb_intern("[]"), 1, sel));
|
|
644
699
|
return self;
|
|
645
700
|
}
|
|
646
701
|
rb_ca_store(self, addrs, argv[1]);
|
|
@@ -653,7 +708,12 @@ static VALUE
|
|
|
653
708
|
rb_ca_range_method (VALUE self)
|
|
654
709
|
{
|
|
655
710
|
VALUE mm_argv[1] = { Qnil };
|
|
656
|
-
|
|
711
|
+
CArray *ca;
|
|
712
|
+
VALUE pair;
|
|
713
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
714
|
+
/* A Face answers its own minmax (in its order, with its elements). */
|
|
715
|
+
pair = ca_is_face(ca) ? rb_funcall(self, rb_intern("minmax"), 0)
|
|
716
|
+
: rb_ca_minmax_ki(0, mm_argv, self);
|
|
657
717
|
VALUE lo = rb_ary_entry(pair, 0);
|
|
658
718
|
VALUE hi = rb_ary_entry(pair, 1);
|
|
659
719
|
return rb_range_new(lo, hi, 0);
|
|
@@ -661,6 +721,221 @@ rb_ca_range_method (VALUE self)
|
|
|
661
721
|
|
|
662
722
|
/* ---- nlargest / nsmallest family ------------------------------------- */
|
|
663
723
|
|
|
724
|
+
/* The partition picks the right values but, among cells that tie with the
|
|
725
|
+
last one picked, any of them. The answer is the cells first in the
|
|
726
|
+
order (value, then NaN, then masked; the values descending for the
|
|
727
|
+
largest) with ties broken by position, as `order` breaks them. So the
|
|
728
|
+
tied candidates are replaced by the earliest cells that tie, and the
|
|
729
|
+
candidates are sorted by (order, position): O(n) per fiber besides the
|
|
730
|
+
sort of the candidates. */
|
|
731
|
+
|
|
732
|
+
typedef struct {
|
|
733
|
+
const char *v; /* the fiber's values, contiguous */
|
|
734
|
+
const boolean8_t *m; /* its mask, or NULL */
|
|
735
|
+
int8_t type;
|
|
736
|
+
ca_size_t bytes;
|
|
737
|
+
int desc;
|
|
738
|
+
} ca_topk_fiber_t;
|
|
739
|
+
|
|
740
|
+
/* 0 a value, 1 NaN, 2 masked: the classes come in that order. */
|
|
741
|
+
static int
|
|
742
|
+
ca_topk_class (const ca_topk_fiber_t *f, ca_size_t i)
|
|
743
|
+
{
|
|
744
|
+
if ( f->m && f->m[i] ) return 2;
|
|
745
|
+
if ( f->type == CA_FLOAT64 && isnan(((const double *) f->v)[i]) ) return 1;
|
|
746
|
+
if ( f->type == CA_FLOAT32 && isnan(((const float *) f->v)[i]) ) return 1;
|
|
747
|
+
return 0;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
#define CA_TOPK_CMP(T) \
|
|
751
|
+
{ T a_ = ((const T *) f->v)[i], b_ = ((const T *) f->v)[j]; \
|
|
752
|
+
r = (a_ < b_) ? -1 : (a_ > b_) ? 1 : 0; } \
|
|
753
|
+
break
|
|
754
|
+
|
|
755
|
+
/* The order of cells i and j, ties not broken. */
|
|
756
|
+
static int
|
|
757
|
+
ca_topk_cmp (const ca_topk_fiber_t *f, ca_size_t i, ca_size_t j)
|
|
758
|
+
{
|
|
759
|
+
int ci = ca_topk_class(f, i), cj = ca_topk_class(f, j), r = 0;
|
|
760
|
+
if ( ci != cj ) return ( ci < cj ) ? -1 : 1;
|
|
761
|
+
if ( ci != 0 ) return 0;
|
|
762
|
+
switch ( f->type ) {
|
|
763
|
+
case CA_BOOLEAN:
|
|
764
|
+
case CA_UINT8: CA_TOPK_CMP(uint8_t);
|
|
765
|
+
case CA_INT8: CA_TOPK_CMP(int8_t);
|
|
766
|
+
case CA_INT16: CA_TOPK_CMP(int16_t);
|
|
767
|
+
case CA_UINT16: CA_TOPK_CMP(uint16_t);
|
|
768
|
+
case CA_INT32: CA_TOPK_CMP(int32_t);
|
|
769
|
+
case CA_UINT32: CA_TOPK_CMP(uint32_t);
|
|
770
|
+
case CA_INT64: CA_TOPK_CMP(int64_t);
|
|
771
|
+
case CA_UINT64: CA_TOPK_CMP(uint64_t);
|
|
772
|
+
case CA_FLOAT32: CA_TOPK_CMP(float);
|
|
773
|
+
case CA_FLOAT64: CA_TOPK_CMP(double);
|
|
774
|
+
case CA_FIXLEN:
|
|
775
|
+
r = memcmp(f->v + i * f->bytes, f->v + j * f->bytes, (size_t) f->bytes);
|
|
776
|
+
r = ( r > 0 ) - ( r < 0 );
|
|
777
|
+
break;
|
|
778
|
+
default:
|
|
779
|
+
r = 0;
|
|
780
|
+
}
|
|
781
|
+
return f->desc ? -r : r;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
#undef CA_TOPK_CMP
|
|
785
|
+
|
|
786
|
+
/* Merge sort of positions by (order, position). */
|
|
787
|
+
static void
|
|
788
|
+
ca_topk_sort (const ca_topk_fiber_t *f, ca_size_t *p, ca_size_t *tmp, ca_size_t n)
|
|
789
|
+
{
|
|
790
|
+
ca_size_t h, i, j, k;
|
|
791
|
+
if ( n < 2 ) return;
|
|
792
|
+
h = n / 2;
|
|
793
|
+
ca_topk_sort(f, p, tmp, h);
|
|
794
|
+
ca_topk_sort(f, p + h, tmp, n - h);
|
|
795
|
+
i = 0; j = h; k = 0;
|
|
796
|
+
while ( i < h && j < n ) {
|
|
797
|
+
int r = ca_topk_cmp(f, p[i], p[j]);
|
|
798
|
+
if ( r < 0 || ( r == 0 && p[i] < p[j] ) ) tmp[k++] = p[i++];
|
|
799
|
+
else tmp[k++] = p[j++];
|
|
800
|
+
}
|
|
801
|
+
while ( i < h ) tmp[k++] = p[i++];
|
|
802
|
+
while ( j < n ) tmp[k++] = p[j++];
|
|
803
|
+
memcpy(p, tmp, (size_t) n * sizeof(ca_size_t));
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
#define CA_TOPK_SCAN_VALUE(T) \
|
|
807
|
+
{ const T *v_ = (const T *) f->v; T w_ = v_[worst]; \
|
|
808
|
+
for (j = 0; j <= end && ties > 0; j++) { \
|
|
809
|
+
if ( v_[j] == w_ && ! ( f->m && f->m[j] ) ) { c[n++] = j; ties--; } \
|
|
810
|
+
} } \
|
|
811
|
+
break
|
|
812
|
+
|
|
813
|
+
/* The earliest cells, up to `end`, that tie with cell `worst`, appended to
|
|
814
|
+
c[n..] until `ties` are found. A value compares by ==, which leaves out
|
|
815
|
+
NaN and the masked cells; those classes tie within themselves. */
|
|
816
|
+
static ca_size_t
|
|
817
|
+
ca_topk_scan_ties (const ca_topk_fiber_t *f, ca_size_t worst, ca_size_t end,
|
|
818
|
+
ca_size_t *c, ca_size_t n, ca_size_t ties)
|
|
819
|
+
{
|
|
820
|
+
ca_size_t j;
|
|
821
|
+
int cls = ca_topk_class(f, worst);
|
|
822
|
+
if ( cls != 0 || f->type == CA_FIXLEN ) {
|
|
823
|
+
for (j = 0; j <= end && ties > 0; j++) {
|
|
824
|
+
if ( ca_topk_cmp(f, j, worst) == 0 ) { c[n++] = j; ties--; }
|
|
825
|
+
}
|
|
826
|
+
return n;
|
|
827
|
+
}
|
|
828
|
+
switch ( f->type ) {
|
|
829
|
+
case CA_BOOLEAN:
|
|
830
|
+
case CA_UINT8: CA_TOPK_SCAN_VALUE(uint8_t);
|
|
831
|
+
case CA_INT8: CA_TOPK_SCAN_VALUE(int8_t);
|
|
832
|
+
case CA_INT16: CA_TOPK_SCAN_VALUE(int16_t);
|
|
833
|
+
case CA_UINT16: CA_TOPK_SCAN_VALUE(uint16_t);
|
|
834
|
+
case CA_INT32: CA_TOPK_SCAN_VALUE(int32_t);
|
|
835
|
+
case CA_UINT32: CA_TOPK_SCAN_VALUE(uint32_t);
|
|
836
|
+
case CA_INT64: CA_TOPK_SCAN_VALUE(int64_t);
|
|
837
|
+
case CA_UINT64: CA_TOPK_SCAN_VALUE(uint64_t);
|
|
838
|
+
case CA_FLOAT32: CA_TOPK_SCAN_VALUE(float);
|
|
839
|
+
case CA_FLOAT64: CA_TOPK_SCAN_VALUE(double);
|
|
840
|
+
}
|
|
841
|
+
return n;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
#undef CA_TOPK_SCAN_VALUE
|
|
845
|
+
|
|
846
|
+
static void
|
|
847
|
+
ca_topk_fix_fiber (const ca_topk_fiber_t *f, ca_size_t len,
|
|
848
|
+
ca_size_t *c, ca_size_t cap, ca_size_t *tmp)
|
|
849
|
+
{
|
|
850
|
+
ca_size_t worst = c[0], ties = 0, n = 0, end = 0, k;
|
|
851
|
+
for (k = 1; k < cap; k++) {
|
|
852
|
+
if ( ca_topk_cmp(f, c[k], worst) > 0 ) worst = c[k];
|
|
853
|
+
}
|
|
854
|
+
/* Keep the candidates before the worst; the ones tied with it are
|
|
855
|
+
replaced by the earliest cells that tie, which lie no later than the
|
|
856
|
+
last tied candidate. */
|
|
857
|
+
for (k = 0; k < cap; k++) {
|
|
858
|
+
if ( ca_topk_cmp(f, c[k], worst) < 0 ) {
|
|
859
|
+
c[n++] = c[k];
|
|
860
|
+
}
|
|
861
|
+
else {
|
|
862
|
+
ties++;
|
|
863
|
+
if ( c[k] > end ) end = c[k];
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
(void) len;
|
|
867
|
+
n = ca_topk_scan_ties(f, worst, end, c, n, ties);
|
|
868
|
+
ca_topk_sort(f, c, tmp, cap);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
/* `picked` holds cap candidate positions per fiber along axis; returns the
|
|
872
|
+
stable answer of the same shape. The fibers are read with the axis
|
|
873
|
+
moved last, from a contiguous copy. */
|
|
874
|
+
static VALUE
|
|
875
|
+
ca_topk_stable (VALUE self, VALUE picked, long axis, int desc)
|
|
876
|
+
{
|
|
877
|
+
volatile VALUE key = ca_order_key(self, desc ? "nlargest" : "nsmallest");
|
|
878
|
+
volatile VALUE vals, pk, holder = 0;
|
|
879
|
+
VALUE perm[CA_RANK_MAX], inv[CA_RANK_MAX];
|
|
880
|
+
CArray *cv, *cp;
|
|
881
|
+
ca_topk_fiber_t f;
|
|
882
|
+
ca_size_t len, cap, outer, o, *tmp;
|
|
883
|
+
int ndim, k, last;
|
|
884
|
+
|
|
885
|
+
GetCArray(key, cv);
|
|
886
|
+
ndim = cv->ndim;
|
|
887
|
+
last = ( axis == ndim - 1 );
|
|
888
|
+
if ( ! last ) {
|
|
889
|
+
int n = 0;
|
|
890
|
+
for (k = 0; k < ndim; k++) if ( k != axis ) perm[n++] = INT2FIX(k);
|
|
891
|
+
perm[n] = LONG2NUM(axis);
|
|
892
|
+
for (k = 0; k < ndim; k++) inv[NUM2INT(perm[k])] = INT2FIX(k);
|
|
893
|
+
}
|
|
894
|
+
/* An entity whose fibers already lie along its last axis is read in
|
|
895
|
+
place; anything else is copied into that layout. */
|
|
896
|
+
if ( last && ca_is_entity(cv) ) {
|
|
897
|
+
vals = key;
|
|
898
|
+
ca_update_mask(cv);
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
vals = rb_ca_copy(last ? key : rb_funcallv(key, rb_intern("transpose"), ndim, perm));
|
|
902
|
+
}
|
|
903
|
+
pk = rb_ca_copy(last ? picked : rb_funcallv(picked, rb_intern("transpose"), ndim, perm));
|
|
904
|
+
GetCArray(vals, cv);
|
|
905
|
+
GetCArray(pk, cp);
|
|
906
|
+
|
|
907
|
+
len = cv->dim[ndim - 1];
|
|
908
|
+
cap = cp->dim[ndim - 1];
|
|
909
|
+
if ( len == 0 || cap == 0 ) return picked;
|
|
910
|
+
outer = cv->elements / len;
|
|
911
|
+
f.type = cv->data_type;
|
|
912
|
+
f.bytes = cv->bytes;
|
|
913
|
+
f.desc = desc;
|
|
914
|
+
tmp = ALLOCV_N(ca_size_t, holder, cap);
|
|
915
|
+
for (o = 0; o < outer; o++) {
|
|
916
|
+
f.v = cv->ptr + o * len * cv->bytes;
|
|
917
|
+
f.m = cv->mask ? (boolean8_t *) cv->mask->ptr + o * len : NULL;
|
|
918
|
+
ca_topk_fix_fiber(&f, len, (ca_size_t *) cp->ptr + o * cap, cap, tmp);
|
|
919
|
+
}
|
|
920
|
+
ALLOCV_END(holder);
|
|
921
|
+
return last ? pk : rb_ca_copy(rb_funcallv(pk, rb_intern("transpose"), ndim, inv));
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/* Whether self holds a cell the order puts after the numbers: a masked
|
|
925
|
+
cell, or a NaN. */
|
|
926
|
+
static int
|
|
927
|
+
ca_topk_has_cells_after_numbers (VALUE self, CArray *ca)
|
|
928
|
+
{
|
|
929
|
+
if ( ca_has_mask(ca) && ca_count_masked(ca) > 0 ) {
|
|
930
|
+
return 1;
|
|
931
|
+
}
|
|
932
|
+
if ( ca_is_float_type(ca) ) {
|
|
933
|
+
VALUE nan = rb_funcall(self, rb_intern("is_nan"), 0);
|
|
934
|
+
return RTEST(rb_funcall(nan, rb_intern("any"), 0));
|
|
935
|
+
}
|
|
936
|
+
return 0;
|
|
937
|
+
}
|
|
938
|
+
|
|
664
939
|
/* Per-axis top-k positions (cap clamped, axis normalized).
|
|
665
940
|
* Called by rb_ca_topk_index below. */
|
|
666
941
|
static VALUE
|
|
@@ -671,12 +946,32 @@ rb_ca_topk_positions (VALUE self, long cap, long axis_norm, int desc)
|
|
|
671
946
|
long dim_axis = (long) ca->dim[axis_norm];
|
|
672
947
|
VALUE raxis_norm = LONG2NUM(axis_norm);
|
|
673
948
|
|
|
949
|
+
/* The largest: reversing the ascending order would put the NaN and the
|
|
950
|
+
masked cells first, so rank them descending (NaN, then the masked
|
|
951
|
+
cells, last) when there are any. An object array is ranked by
|
|
952
|
+
`order` both ways (its cells compare in Ruby). */
|
|
953
|
+
if ( ca->data_type == CA_OBJECT ||
|
|
954
|
+
( desc && ca_topk_has_cells_after_numbers(self, ca) ) ) {
|
|
955
|
+
VALUE kw = rb_hash_new();
|
|
956
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("axis")), raxis_norm);
|
|
957
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("descending")), desc ? Qtrue : Qfalse);
|
|
958
|
+
VALUE rank = rb_funcallv_kw(self, rb_intern("order"), 1, &kw, RB_PASS_KEYWORDS);
|
|
959
|
+
VALUE full = rb_ca_sort_index_ki_quick(rank, raxis_norm);
|
|
960
|
+
if ( cap >= dim_axis ) {
|
|
961
|
+
return rb_ca_copy(full);
|
|
962
|
+
}
|
|
963
|
+
int ndim = (int) ca->ndim;
|
|
964
|
+
VALUE spec[CA_RANK_MAX];
|
|
965
|
+
for ( int k = 0; k < ndim; k++ ) {
|
|
966
|
+
spec[k] = Qnil;
|
|
967
|
+
}
|
|
968
|
+
spec[axis_norm] = rb_range_new(INT2FIX(0), LONG2NUM(cap), 1);
|
|
969
|
+
return rb_ca_copy(rb_ca_fetch2(full, ndim, spec));
|
|
970
|
+
}
|
|
971
|
+
|
|
674
972
|
if ( cap >= dim_axis ) {
|
|
675
973
|
VALUE full = rb_ca_sort_index_ki_quick(self, raxis_norm);
|
|
676
|
-
|
|
677
|
-
full = rb_ca_flip_axis(full, NUM2LONG(raxis_norm));
|
|
678
|
-
}
|
|
679
|
-
return rb_ca_copy(full);
|
|
974
|
+
return ca_topk_stable(self, full, axis_norm, desc);
|
|
680
975
|
}
|
|
681
976
|
|
|
682
977
|
long pivot = desc ? (dim_axis - cap) : (cap - 1);
|
|
@@ -703,7 +998,7 @@ rb_ca_topk_positions (VALUE self, long cap, long axis_norm, int desc)
|
|
|
703
998
|
order = rb_ca_flip_axis(order, NUM2LONG(raxis_norm));
|
|
704
999
|
}
|
|
705
1000
|
VALUE picked = rb_ca_take_along_axis_c(partidx_top, order, raxis_norm);
|
|
706
|
-
return
|
|
1001
|
+
return ca_topk_stable(self, picked, axis_norm, desc);
|
|
707
1002
|
}
|
|
708
1003
|
|
|
709
1004
|
/* Dispatcher: normalize axis, clamp cap, empty-cap corner.
|
|
@@ -807,11 +1102,10 @@ rb_ca_nsmallest (int argc, VALUE *argv, VALUE self)
|
|
|
807
1102
|
* ever compare equal), so a later sort_addr key never gets consulted;
|
|
808
1103
|
* dense ranks preserve ties, so it does.
|
|
809
1104
|
*
|
|
810
|
-
* descending:
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
* order still reverses correctly. */
|
|
1105
|
+
* descending: ranks the largest value 0, with NaN after the numbers as
|
|
1106
|
+
* ascending. The kernel gives the descending dense rank; the ordinal rank
|
|
1107
|
+
* is the ascending ordinal rank of it, so tied cells keep their original
|
|
1108
|
+
* order in both directions. */
|
|
815
1109
|
|
|
816
1110
|
static VALUE
|
|
817
1111
|
rb_ca_order (int argc, VALUE *argv, VALUE self)
|
|
@@ -826,11 +1120,24 @@ rb_ca_order (int argc, VALUE *argv, VALUE self)
|
|
|
826
1120
|
int do_stable = NIL_P(rkind) ? 0
|
|
827
1121
|
: ca_symbol_choice(rkind, "kind", "quick", "stable", NULL);
|
|
828
1122
|
|
|
829
|
-
|
|
1123
|
+
if ( RTEST(rdesc) && ! dense ) {
|
|
1124
|
+
VALUE kw = rb_hash_new();
|
|
1125
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("axis")), raxis);
|
|
1126
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("descending")), Qtrue);
|
|
1127
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("method")), ID2SYM(rb_intern("dense")));
|
|
1128
|
+
rb_hash_aset(kw, ID2SYM(rb_intern("kind")), do_stable ? ID2SYM(rb_intern("stable")) : ID2SYM(rb_intern("quick")));
|
|
1129
|
+
VALUE ranked = rb_funcallv_kw(self, rb_intern("order"), 1, &kw, RB_PASS_KEYWORDS);
|
|
1130
|
+
rb_hash_delete(kw, ID2SYM(rb_intern("descending")));
|
|
1131
|
+
rb_hash_delete(kw, ID2SYM(rb_intern("method")));
|
|
1132
|
+
return rb_funcallv_kw(ranked, rb_intern("order"), 1, &kw, RB_PASS_KEYWORDS);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/* The kernel's dense == 2 is the descending dense rank. */
|
|
1136
|
+
int kmode = ( dense && RTEST(rdesc) ) ? 2 : dense;
|
|
830
1137
|
if ( NIL_P(raxis) ) {
|
|
831
1138
|
VALUE flat = rb_ca_flatten(self);
|
|
832
1139
|
/* Direct C-level dispatch via c_callable: true extern (mkkernel). */
|
|
833
|
-
VALUE ranked = rb_ca_rank_index_ki_kind_dense(flat, INT2FIX(0), do_stable,
|
|
1140
|
+
VALUE ranked = rb_ca_rank_index_ki_kind_dense(flat, INT2FIX(0), do_stable, kmode);
|
|
834
1141
|
/* reshape(*shape) */
|
|
835
1142
|
CArray *ca;
|
|
836
1143
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
@@ -838,43 +1145,12 @@ rb_ca_order (int argc, VALUE *argv, VALUE self)
|
|
|
838
1145
|
for ( long k = 0; k < (long) ca->ndim; k++ ) {
|
|
839
1146
|
shape_argv[k] = LONG2NUM((long) ca->dim[k]);
|
|
840
1147
|
}
|
|
841
|
-
|
|
842
|
-
n = RTEST(rb_ca_has_mask(self))
|
|
843
|
-
? SIZE2NUM(ca_count_not_masked(ca)) /* = elements - count_masked */
|
|
844
|
-
: rb_ca_elements(self);
|
|
845
|
-
} else {
|
|
846
|
-
long axis_norm = rb_ca_normalize_axis_value(self, raxis, "order");
|
|
847
|
-
VALUE raxis_norm = LONG2NUM(axis_norm);
|
|
848
|
-
asc = rb_ca_rank_index_ki_kind_dense(self, raxis_norm, do_stable, dense);
|
|
849
|
-
if ( RTEST(rb_ca_has_mask(self)) ) {
|
|
850
|
-
n = rb_ca_count_not_masked_c(self, raxis_norm);
|
|
851
|
-
} else {
|
|
852
|
-
CArray *ca;
|
|
853
|
-
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
854
|
-
n = LONG2NUM((long) ca->dim[axis_norm]);
|
|
855
|
-
}
|
|
856
|
-
if ( RTEST(rb_obj_is_kind_of(n, rb_cCArray)) ) {
|
|
857
|
-
VALUE ia_argv[1] = { raxis_norm };
|
|
858
|
-
n = rb_ca_insert_axis(1, ia_argv, n);
|
|
859
|
-
}
|
|
1148
|
+
return rb_ca_reshape((int) ca->ndim, shape_argv, ranked);
|
|
860
1149
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
CArray/Integer mixed receivers uniformly via Ruby's operator
|
|
866
|
-
dispatch. No single C entry covers both. */
|
|
867
|
-
VALUE n_minus_1 = rb_funcall(n, id_sub, 1, INT2FIX(1));
|
|
868
|
-
diff = rb_funcall(n_minus_1, id_sub, 1, asc);
|
|
869
|
-
} else {
|
|
870
|
-
diff = asc;
|
|
871
|
-
}
|
|
872
|
-
/* Output data_type: CA_SIZE (= ca_size_t, int64 on 64-bit builds),
|
|
873
|
-
matching the rest of the *_index family (sort_index / partition_index
|
|
874
|
-
/ rank_index) that order is built on. No explicit cast needed here:
|
|
875
|
-
asc (rank_index_ki's output) is already CA_SIZE, and Integer - CArray
|
|
876
|
-
promotion in the descending branch preserves it. */
|
|
877
|
-
return diff;
|
|
1150
|
+
long axis_norm = rb_ca_normalize_axis_value(self, raxis, "order");
|
|
1151
|
+
/* Output data_type: CA_SIZE (int64 on 64-bit builds), as the rest of the
|
|
1152
|
+
*_index family. */
|
|
1153
|
+
return rb_ca_rank_index_ki_kind_dense(self, LONG2NUM(axis_norm), do_stable, kmode);
|
|
878
1154
|
}
|
|
879
1155
|
|
|
880
1156
|
/* ---- linear_section / linear_fetch ----------------------------------- */
|
|
@@ -896,9 +1172,7 @@ ca_linear_prep (VALUE self, VALUE raxis, const char *name, long *axis_out)
|
|
|
896
1172
|
Face) is caught by the rb_ca_to_float64 cast below, so no separate
|
|
897
1173
|
float-numeric flag is needed. */
|
|
898
1174
|
if ( ca_is_face(ca) ) {
|
|
899
|
-
|
|
900
|
-
ca_face_refuse_order(name, self, "order");
|
|
901
|
-
}
|
|
1175
|
+
ca_face_require_orderable(self, name, "order");
|
|
902
1176
|
self = rb_ca_strip_face_value(self);
|
|
903
1177
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
904
1178
|
}
|
|
@@ -925,13 +1199,26 @@ rb_ca_linear_section_m (int argc, VALUE *argv, VALUE self)
|
|
|
925
1199
|
rb_check_arity(argc, 1, 1);
|
|
926
1200
|
VALUE val = argv[0];
|
|
927
1201
|
|
|
928
|
-
/* Query gate: the reference axis, still a Face here,
|
|
929
|
-
into
|
|
1202
|
+
/* Query gate: the reference axis, still a Face here, and the query are
|
|
1203
|
+
brought into one space (ca_face_reconcile_pair). */
|
|
930
1204
|
if ( rb_obj_is_carray(self) ) {
|
|
931
1205
|
CArray *sca;
|
|
932
1206
|
TypedData_Get_Struct(self, CArray, &carray_data_type, sca);
|
|
933
1207
|
if ( ca_is_face(sca) ) {
|
|
934
|
-
|
|
1208
|
+
volatile VALUE ref = self, query = val;
|
|
1209
|
+
ca_face_reconcile_pair(&ref, &query, "linear_section");
|
|
1210
|
+
self = ref;
|
|
1211
|
+
val = query;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
{
|
|
1216
|
+
CArray *ca;
|
|
1217
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1218
|
+
if ( ca_is_complex_type(ca) ) {
|
|
1219
|
+
rb_raise(rb_eCADataTypeError,
|
|
1220
|
+
"linear_section: a %s array has no order (complex numbers are "
|
|
1221
|
+
"not ordered)", ca_type_name[ca->data_type]);
|
|
935
1222
|
}
|
|
936
1223
|
}
|
|
937
1224
|
|
|
@@ -960,6 +1247,27 @@ rb_ca_linear_fetch_m (int argc, VALUE *argv, VALUE self)
|
|
|
960
1247
|
rb_check_arity(argc, 1, 1);
|
|
961
1248
|
VALUE addr = argv[0];
|
|
962
1249
|
|
|
1250
|
+
/* A complex array interpolates its real and imaginary parts: the
|
|
1251
|
+
weights are real, so each part is a real interpolation. */
|
|
1252
|
+
{
|
|
1253
|
+
CArray *ca;
|
|
1254
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
1255
|
+
if ( ca_is_complex_type(ca) ) {
|
|
1256
|
+
VALUE args[2], re, im;
|
|
1257
|
+
int n = 1;
|
|
1258
|
+
args[0] = addr;
|
|
1259
|
+
if ( ! NIL_P(ropt) ) args[n++] = ropt;
|
|
1260
|
+
re = rb_funcallv_kw(rb_funcall(self, rb_intern("real"), 0),
|
|
1261
|
+
rb_intern("linear_fetch"), n, args,
|
|
1262
|
+
NIL_P(ropt) ? RB_NO_KEYWORDS : RB_PASS_KEYWORDS);
|
|
1263
|
+
im = rb_funcallv_kw(rb_funcall(self, rb_intern("imag"), 0),
|
|
1264
|
+
rb_intern("linear_fetch"), n, args,
|
|
1265
|
+
NIL_P(ropt) ? RB_NO_KEYWORDS : RB_PASS_KEYWORDS);
|
|
1266
|
+
return rb_funcall(re, '+', 1,
|
|
1267
|
+
rb_funcall(im, '*', 1, rb_Complex(INT2FIX(0), INT2FIX(1))));
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
963
1271
|
long axis_norm = 0;
|
|
964
1272
|
VALUE sc = ca_linear_prep(self, raxis, "linear_fetch", &axis_norm);
|
|
965
1273
|
return rb_ca_linear_fetch_ki(sc, addr, LONG2NUM(axis_norm));
|