carray 3.0.2 → 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 +568 -0
- data/README.md +6 -6
- data/carray.gemspec +1 -1
- data/ext/ca_axis_descriptor.h +27 -24
- data/ext/ca_axis_dispatch.c +220 -0
- data/ext/ca_axis_group.c +201 -123
- data/ext/ca_binop_dispatch.c +46 -52
- data/ext/ca_binop_dispatch.h +1 -1
- data/ext/ca_categorical_iterator.c +249 -183
- data/ext/ca_compare.c +7 -12
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +38 -23
- data/ext/ca_kernel_iterator.c +1765 -2076
- data/ext/ca_kernel_iterator.h +584 -566
- data/ext/ca_monop_dispatch.c +86 -63
- data/ext/ca_monop_dispatch.h +5 -0
- data/ext/ca_obj_array.c +223 -56
- data/ext/ca_obj_bincmp.c +172 -138
- data/ext/ca_obj_binop.c +116 -230
- data/ext/ca_obj_bitarray.c +40 -26
- data/ext/ca_obj_bitfield.c +100 -68
- data/ext/ca_obj_block.c +19 -9
- data/ext/ca_obj_byte_swap.c +45 -46
- data/ext/ca_obj_const_string.c +269 -44
- data/ext/ca_obj_face.c +612 -89
- data/ext/ca_obj_face.h +111 -47
- data/ext/ca_obj_fake.c +36 -79
- data/ext/ca_obj_farray.c +7 -3
- data/ext/ca_obj_field.c +33 -8
- data/ext/ca_obj_fixlen_string.c +23 -24
- data/ext/ca_obj_grid.c +541 -210
- data/ext/ca_obj_meld.c +331 -111
- data/ext/ca_obj_moncmp.c +80 -65
- data/ext/ca_obj_monop.c +177 -149
- data/ext/ca_obj_object.c +664 -248
- data/ext/ca_obj_record.c +63 -23
- data/ext/ca_obj_reduce.c +18 -16
- data/ext/ca_obj_refer.c +140 -58
- data/ext/ca_obj_remap.c +85 -24
- data/ext/ca_obj_repeat.c +24 -9
- data/ext/ca_obj_roll.c +121 -16
- data/ext/ca_obj_select.c +61 -58
- data/ext/ca_obj_select_axis.c +73 -107
- data/ext/ca_obj_shift.c +32 -102
- data/ext/ca_obj_stack.c +372 -122
- data/ext/ca_obj_stride.c +348 -140
- data/ext/ca_obj_string.c +88 -22
- data/ext/ca_obj_tile.c +38 -21
- data/ext/ca_obj_time.c +45 -31
- data/ext/ca_obj_timedelta.c +43 -29
- data/ext/ca_obj_transpose.c +17 -6
- data/ext/ca_obj_triop.c +125 -141
- data/ext/ca_obj_window.c +330 -44
- data/ext/ca_op_ipower.c +24 -11
- data/ext/ca_op_powi.h +57 -30
- data/ext/ca_pow5_table.h +656 -0
- data/ext/ca_sort_kernels.h +70 -0
- data/ext/ca_sweep_engine.c +104 -81
- data/ext/ca_sweep_engine.h +7 -20
- data/ext/ca_triop_dispatch.c +4 -1
- data/ext/ca_triop_dispatch.h +5 -2
- data/ext/caframe_csv_reader.c +542 -0
- data/ext/carray.h +241 -92
- data/ext/carray_access.c +608 -276
- data/ext/carray_address_basis.c +494 -97
- data/ext/carray_attribute.c +129 -4
- data/ext/carray_bincount.c +39 -7
- data/ext/carray_broadcast.c +56 -19
- data/ext/carray_build_flags.h +1 -1
- data/ext/carray_call_cfunc.c +108 -28
- data/ext/carray_cast.c +1576 -223
- data/ext/carray_cast_func.rb +77 -24
- data/ext/carray_class.c +4 -3
- data/ext/carray_conversion.c +208 -75
- data/ext/carray_copy.c +82 -24
- data/ext/carray_core.c +646 -162
- data/ext/carray_count.c +171 -88
- data/ext/carray_element.c +94 -60
- data/ext/carray_factorize.c +670 -324
- data/ext/carray_generate.c +260 -83
- data/ext/carray_histogram.c +209 -106
- data/ext/carray_hold.c +14 -16
- data/ext/carray_index_classifier.c +422 -243
- data/ext/carray_internal.h +692 -3
- data/ext/carray_kernels_bincmp.c +7 -0
- data/ext/carray_kernels_binop.c +487 -120
- data/ext/carray_kernels_init.c +653 -50
- data/ext/carray_kernels_moncmp.c +15 -8
- data/ext/carray_kernels_monop.c +99 -43
- data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
- data/ext/carray_kernels_reduce_boolean.c +112 -36
- data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
- data/ext/carray_kernels_reduce_extreme.c +3032 -2892
- data/ext/carray_kernels_reduce_variance.c +439 -500
- data/ext/carray_kernels_scan.c +1097 -488
- data/ext/carray_kernels_search.c +3787 -2176
- data/ext/carray_kernels_sort.c +1200 -920
- data/ext/carray_kernels_triop.c +479 -7
- data/ext/carray_key_windows.c +216 -0
- data/ext/carray_lazy.c +967 -153
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +910 -324
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +299 -100
- data/ext/carray_memory_view.c +872 -758
- data/ext/carray_operator.c +1171 -364
- data/ext/carray_order.c +505 -133
- data/ext/carray_partition.c +112 -65
- data/ext/carray_random.c +327 -239
- data/ext/carray_round.c +273 -0
- data/ext/carray_scatter.c +346 -78
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +249 -86
- data/ext/carray_sort.c +224 -227
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +118 -39
- data/ext/carray_test.c +193 -69
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_undef.c +4 -0
- data/ext/carray_utils.c +579 -113
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +19 -4
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1202 -1014
- data/ext/ruby_carray.c +17 -5
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +160 -17
- data/lib/carray/autoload_carray.rb +23 -27
- data/lib/carray/autoload_method_extension.rb +20 -5
- data/lib/carray/axis_group.rb +360 -63
- data/lib/carray/basics.rb +162 -28
- data/lib/carray/bincount_nd.rb +18 -2
- data/lib/carray/block_iterator.rb +231 -58
- data/lib/carray/boolean_reduce.rb +34 -42
- data/lib/carray/categorical.rb +242 -52
- data/lib/carray/categorical_iterator.rb +437 -827
- data/lib/carray/complex.rb +41 -34
- data/lib/carray/conditional.rb +150 -14
- data/lib/carray/const_string.rb +59 -4
- 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/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +82 -7
- data/lib/carray/frame/csv_parser.rb +688 -87
- data/lib/carray/frame/describe.rb +80 -0
- data/lib/carray/frame/frame.rb +369 -45
- data/lib/carray/frame/group.rb +631 -90
- data/lib/carray/frame/io.rb +506 -79
- data/lib/carray/frame/join.rb +411 -62
- data/lib/carray/frame/records.rb +116 -19
- data/lib/carray/frame/reshape.rb +455 -0
- data/lib/carray/frame/sort.rb +30 -18
- data/lib/carray/frame/verbs.rb +868 -61
- data/lib/carray/frame/windows.rb +117 -0
- data/lib/carray/frame.rb +4 -0
- data/lib/carray/fuse_source.rb +118 -2
- data/lib/carray/fusion.rb +257 -42
- data/lib/carray/histogram.rb +6 -1
- data/lib/carray/inspect.rb +54 -13
- data/lib/carray/iterator.rb +99 -9
- data/lib/carray/key_windows.rb +620 -0
- data/lib/carray/lazy.rb +216 -193
- data/lib/carray/mask_gap_fill.rb +112 -92
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +52 -21
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bin.rb +26 -18
- data/lib/carray/methods/bincount.rb +18 -2
- data/lib/carray/methods/bit_string.rb +15 -4
- data/lib/carray/methods/choose.rb +16 -3
- data/lib/carray/methods/composition.rb +18 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +25 -5
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_between.rb +59 -0
- data/lib/carray/methods/is_in.rb +140 -10
- data/lib/carray/methods/join.rb +2 -7
- data/lib/carray/methods/lag.rb +49 -0
- data/lib/carray/methods/locate_addr.rb +182 -45
- data/lib/carray/methods/mode.rb +18 -1
- data/lib/carray/methods/nunique.rb +11 -6
- data/lib/carray/methods/repeat.rb +1 -20
- data/lib/carray/methods/resize.rb +21 -23
- data/lib/carray/methods/snap.rb +34 -12
- data/lib/carray/methods/unique.rb +11 -2
- data/lib/carray/methods/value_counts.rb +4 -11
- data/lib/carray/record_order.rb +208 -0
- data/lib/carray/rng.rb +3 -0
- data/lib/carray/runtime.rb +65 -17
- data/lib/carray/segment_iterator.rb +1221 -0
- data/lib/carray/serialize.rb +214 -30
- data/lib/carray/slab_iterator.rb +101 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string.rb +105 -5
- data/lib/carray/string_operation_extension.rb +12 -4
- data/lib/carray/struct.rb +137 -58
- data/lib/carray/struct_builder.rb +124 -17
- data/lib/carray/time.rb +1222 -186
- data/lib/carray/window_iterator.rb +242 -81
- data/lib/carray.rb +9 -2
- data/yard-stubs/ca_obj_array.rb +4 -4
- data/yard-stubs/ca_obj_bitarray.rb +7 -0
- data/yard-stubs/ca_obj_bitfield.rb +23 -12
- data/yard-stubs/ca_obj_fake.rb +1 -1
- data/yard-stubs/ca_obj_field.rb +5 -1
- data/yard-stubs/ca_obj_grid.rb +21 -10
- data/yard-stubs/ca_obj_refer.rb +5 -4
- data/yard-stubs/ca_obj_roll.rb +2 -3
- data/yard-stubs/ca_obj_shift.rb +5 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_tile.rb +1 -1
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +9 -5
- data/yard-stubs/carray_access.rb +11 -5
- data/yard-stubs/carray_attribute.rb +0 -5
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +88 -43
- data/yard-stubs/carray_conversion.rb +15 -2
- data/yard-stubs/carray_copy.rb +12 -5
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_element.rb +10 -4
- data/yard-stubs/carray_generate.rb +21 -1
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +60 -12
- data/yard-stubs/carray_math.rb +52 -14
- data/yard-stubs/carray_median_percentile.rb +15 -8
- data/yard-stubs/carray_memory_view.rb +40 -23
- data/yard-stubs/carray_order.rb +61 -29
- data/yard-stubs/carray_random.rb +13 -4
- data/yard-stubs/carray_scatter.rb +21 -9
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +10 -2
- data/yard-stubs/carray_sort.rb +49 -8
- data/yard-stubs/carray_test.rb +15 -3
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +19 -5
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_kernels_map.c +0 -3467
- data/lib/carray/arrow_tensor.rb +0 -401
- data/lib/carray/table.rb +0 -108
data/ext/carray_order.c
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include "ruby.h"
|
|
2
2
|
#include "carray.h"
|
|
3
|
+
#include "carray_internal.h" /* ca_integer_arg */
|
|
3
4
|
#include "ca_kernel_iterator.h"
|
|
4
5
|
#include "ca_obj_face.h"
|
|
5
6
|
#include <math.h>
|
|
@@ -115,21 +116,115 @@ ca_project_loop (CArray *co, CArray *ca, CArray *ci, char *lfill, char *ufill)
|
|
|
115
116
|
xfree(ma);
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
|
|
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
|
|
119
123
|
ca_project (CArray *ca, CArray *ci, char *lfill, char *ufill)
|
|
120
124
|
{
|
|
125
|
+
volatile VALUE obj;
|
|
121
126
|
CArray *co;
|
|
122
127
|
|
|
123
|
-
|
|
128
|
+
obj = rb_carray_new(ca->data_type, ci->ndim, ci->dim, ca->bytes, NULL);
|
|
129
|
+
GetCArray(obj, co);
|
|
124
130
|
|
|
125
|
-
|
|
131
|
+
ca_attach_n(2, ca, ci); /* window: nothing raises inside */
|
|
126
132
|
ca_project_loop(co, ca, ci, lfill, ufill);
|
|
127
|
-
|
|
128
133
|
ca_detach_n(2, ca, ci); /* DETACH */
|
|
129
134
|
|
|
130
|
-
return
|
|
135
|
+
return obj;
|
|
131
136
|
}
|
|
132
137
|
|
|
138
|
+
/* rk.__count_below__(q, inclusive) -- for each cell of q, how many values
|
|
139
|
+
* of the sorted array rk are below it (at or below it when inclusive).
|
|
140
|
+
* rk is 1-D, ascending, with no masked or NaN value; q has rk's data type
|
|
141
|
+
* (any shape, read in address order). The count is the insertion position
|
|
142
|
+
* of the cell among rk's values, found by binary search; a masked or NaN
|
|
143
|
+
* cell gets an arbitrary count, for the caller to mask. Returns an int64
|
|
144
|
+
* array of q's shape. Numeric and boolean types only. */
|
|
145
|
+
|
|
146
|
+
/* The search keeps a base and a length and moves the base by a comparison
|
|
147
|
+
rather than branching on it, which keeps the loop free of mispredicted
|
|
148
|
+
branches; the last comparison adds the cell at the base. */
|
|
149
|
+
#define CA_COUNT_BELOW_LOOP(T, CMP) \
|
|
150
|
+
{ \
|
|
151
|
+
const T *r = (const T *) cr->ptr; \
|
|
152
|
+
const T *x = (const T *) cq->ptr; \
|
|
153
|
+
for ( i = 0; i < m; i++ ) { \
|
|
154
|
+
T v = x[i]; \
|
|
155
|
+
const T *base = r; \
|
|
156
|
+
ca_size_t len = n; \
|
|
157
|
+
if ( len == 0 ) { out[i] = 0; continue; } \
|
|
158
|
+
while ( len > 1 ) { \
|
|
159
|
+
ca_size_t half = len / 2; \
|
|
160
|
+
base = (base[half] CMP v) ? base + half : base; \
|
|
161
|
+
len -= half; \
|
|
162
|
+
} \
|
|
163
|
+
out[i] = (int64_t) (base - r) + ((*base CMP v) ? 1 : 0); \
|
|
164
|
+
} \
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
#define CA_COUNT_BELOW(T) \
|
|
168
|
+
if ( inclusive ) CA_COUNT_BELOW_LOOP(T, <=) \
|
|
169
|
+
else CA_COUNT_BELOW_LOOP(T, <)
|
|
170
|
+
|
|
171
|
+
static VALUE
|
|
172
|
+
rb_ca_count_below (VALUE self, VALUE vq, VALUE vinclusive)
|
|
173
|
+
{
|
|
174
|
+
volatile VALUE vout;
|
|
175
|
+
CArray *cr, *cq, *co;
|
|
176
|
+
ca_size_t n, m, i;
|
|
177
|
+
int64_t *out;
|
|
178
|
+
int inclusive = RTEST(vinclusive);
|
|
179
|
+
|
|
180
|
+
GetCArray(self, cr);
|
|
181
|
+
rb_check_carray_object(vq);
|
|
182
|
+
GetCArray(vq, cq);
|
|
183
|
+
if ( cr->ndim != 1 ) {
|
|
184
|
+
rb_raise(rb_eArgError, "__count_below__: the reference must be 1-D");
|
|
185
|
+
}
|
|
186
|
+
if ( cr->data_type != cq->data_type ) {
|
|
187
|
+
rb_raise(rb_eCADataTypeError,
|
|
188
|
+
"__count_below__: the reference and the query must have one data type");
|
|
189
|
+
}
|
|
190
|
+
switch ( cr->data_type ) {
|
|
191
|
+
case CA_BOOLEAN: case CA_INT8: case CA_UINT8: case CA_INT16: case CA_UINT16:
|
|
192
|
+
case CA_INT32: case CA_UINT32: case CA_INT64: case CA_UINT64:
|
|
193
|
+
case CA_FLOAT32: case CA_FLOAT64:
|
|
194
|
+
break;
|
|
195
|
+
default:
|
|
196
|
+
rb_raise(rb_eCADataTypeError, "__count_below__: no order for %s",
|
|
197
|
+
ca_type_name[cr->data_type]);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
n = cr->elements;
|
|
201
|
+
m = cq->elements;
|
|
202
|
+
vout = rb_carray_new(CA_INT64, cq->ndim, cq->dim, 0, NULL);
|
|
203
|
+
GetCArray(vout, co);
|
|
204
|
+
out = (int64_t *) co->ptr;
|
|
205
|
+
|
|
206
|
+
ca_attach_n(2, cr, cq); /* window: nothing raises inside */
|
|
207
|
+
switch ( cr->data_type ) {
|
|
208
|
+
case CA_BOOLEAN:
|
|
209
|
+
case CA_UINT8: CA_COUNT_BELOW(uint8_t); break;
|
|
210
|
+
case CA_INT8: CA_COUNT_BELOW(int8_t); break;
|
|
211
|
+
case CA_INT16: CA_COUNT_BELOW(int16_t); break;
|
|
212
|
+
case CA_UINT16: CA_COUNT_BELOW(uint16_t); break;
|
|
213
|
+
case CA_INT32: CA_COUNT_BELOW(int32_t); break;
|
|
214
|
+
case CA_UINT32: CA_COUNT_BELOW(uint32_t); break;
|
|
215
|
+
case CA_INT64: CA_COUNT_BELOW(int64_t); break;
|
|
216
|
+
case CA_UINT64: CA_COUNT_BELOW(uint64_t); break;
|
|
217
|
+
case CA_FLOAT32: CA_COUNT_BELOW(float); break;
|
|
218
|
+
case CA_FLOAT64: CA_COUNT_BELOW(double); break;
|
|
219
|
+
}
|
|
220
|
+
ca_detach_n(2, cr, cq);
|
|
221
|
+
|
|
222
|
+
return vout;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
#undef CA_COUNT_BELOW
|
|
226
|
+
#undef CA_COUNT_BELOW_LOOP
|
|
227
|
+
|
|
133
228
|
/* project(idx, lval=nil, uval=nil) — gather: for each element of `idx`,
|
|
134
229
|
* pick `self[idx[i]]`. Returns an entity CArray shaped like `idx`.
|
|
135
230
|
*
|
|
@@ -142,6 +237,7 @@ VALUE
|
|
|
142
237
|
rb_ca_project (int argc, VALUE *argv, VALUE self)
|
|
143
238
|
{
|
|
144
239
|
volatile VALUE obj, ridx, vlfval, vufval, vstorage;
|
|
240
|
+
volatile VALUE hlfval = 0, hufval = 0;
|
|
145
241
|
CArray *ca, *ci, *co;
|
|
146
242
|
char *lfval, *ufval;
|
|
147
243
|
int self_is_face;
|
|
@@ -152,21 +248,22 @@ rb_ca_project (int argc, VALUE *argv, VALUE self)
|
|
|
152
248
|
self_is_face = ca_is_face(ca);
|
|
153
249
|
|
|
154
250
|
rb_check_carray_object(ridx);
|
|
251
|
+
ca_check_index_array(ridx);
|
|
155
252
|
ci = ca_wrap_readonly(ridx, CA_SIZE);
|
|
156
253
|
|
|
157
254
|
/* The fill args arrive as surface values. rb_ca_obj2ptr owns the
|
|
158
|
-
surface->storage conversion: for a Face self it fires the
|
|
255
|
+
surface->storage conversion: for a Face self it fires the element_to_storage
|
|
159
256
|
write hook (a datetime scalar / Time is reconciled to the Face's unit),
|
|
160
257
|
for a plain array it writes the storage bytes directly. */
|
|
161
|
-
lfval =
|
|
162
|
-
ufval =
|
|
258
|
+
lfval = ALLOCV_N(char, hlfval, ca->bytes); /* converting a fill value */
|
|
259
|
+
ufval = ALLOCV_N(char, hufval, ca->bytes); /* can raise; the unwind frees */
|
|
163
260
|
|
|
164
|
-
if ( ! NIL_P(vlfval) ) {
|
|
261
|
+
if ( ! NIL_P(vlfval) && vlfval != CA_UNDEF ) {
|
|
165
262
|
rb_ca_obj2ptr(self, vlfval, lfval);
|
|
166
263
|
rb_ca_obj2ptr(self, vlfval, ufval);
|
|
167
264
|
}
|
|
168
265
|
|
|
169
|
-
if ( ! NIL_P(vufval) ) {
|
|
266
|
+
if ( ! NIL_P(vufval) && vufval != CA_UNDEF ) {
|
|
170
267
|
rb_ca_obj2ptr(self, vufval, ufval);
|
|
171
268
|
}
|
|
172
269
|
|
|
@@ -181,14 +278,18 @@ rb_ca_project (int argc, VALUE *argv, VALUE self)
|
|
|
181
278
|
TypedData_Get_Struct(vstorage, CArray, &carray_data_type, ca);
|
|
182
279
|
}
|
|
183
280
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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);
|
|
190
290
|
|
|
191
|
-
|
|
291
|
+
ALLOCV_END(hlfval);
|
|
292
|
+
ALLOCV_END(hufval);
|
|
192
293
|
|
|
193
294
|
if ( ! ca_is_any_masked(co) ) {
|
|
194
295
|
obj = rb_ca_unmask_copy(obj);
|
|
@@ -198,6 +299,7 @@ rb_ca_project (int argc, VALUE *argv, VALUE self)
|
|
|
198
299
|
obj = ca_face_lift(obj, self);
|
|
199
300
|
}
|
|
200
301
|
|
|
302
|
+
rb_ca_inherit_attr(obj, self);
|
|
201
303
|
return obj;
|
|
202
304
|
}
|
|
203
305
|
|
|
@@ -255,7 +357,7 @@ extern VALUE rb_ca_reshape (int argc, VALUE *argv, VALUE self)
|
|
|
255
357
|
* through rb_funcall + kwarg hash construction. */
|
|
256
358
|
extern VALUE rb_ca_sort_index_ki_quick (VALUE self, VALUE vaxis);
|
|
257
359
|
extern VALUE rb_ca_partition_index_ki (VALUE self, VALUE vaxis, VALUE vkth);
|
|
258
|
-
extern VALUE
|
|
360
|
+
extern VALUE rb_ca_rank_index_ki_kind_dense (VALUE self, VALUE vaxis, int stable, int dense);
|
|
259
361
|
|
|
260
362
|
/* ---- no-axis (flat) search helper -----------------------------------
|
|
261
363
|
*
|
|
@@ -439,6 +541,41 @@ rb_ca_search_nearest_addr_kw (int argc, VALUE *argv, VALUE self)
|
|
|
439
541
|
|
|
440
542
|
/* ---- sort_by_key family ---------------------------------------------- */
|
|
441
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
|
+
|
|
442
579
|
/* sort_by_key(key, axis: 0) -- gather self at key.sort_addr(axis:). */
|
|
443
580
|
static VALUE
|
|
444
581
|
rb_ca_sort_by_key (int argc, VALUE *argv, VALUE self)
|
|
@@ -449,6 +586,7 @@ rb_ca_sort_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
449
586
|
if ( NIL_P(raxis) ) {
|
|
450
587
|
raxis = INT2FIX(0);
|
|
451
588
|
}
|
|
589
|
+
ca_by_key_check_shape(self, rkey, "sort_by_key");
|
|
452
590
|
VALUE addrs = rb_ca_sort_addr_c(rkey, raxis, 0, 1); /* masked_last=1 (:last), unchanged default */
|
|
453
591
|
return rb_ca_fetch(self, addrs);
|
|
454
592
|
}
|
|
@@ -460,9 +598,11 @@ rb_ca_max_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
460
598
|
VALUE rkey, rkw = Qnil, raxis = Qnil;
|
|
461
599
|
rb_scan_args(argc, argv, "1:", &rkey, &rkw);
|
|
462
600
|
rb_scan_options(rkw, "axis", &raxis);
|
|
463
|
-
|
|
464
|
-
|
|
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;
|
|
465
604
|
}
|
|
605
|
+
rkey = ca_order_key(rkey, "max_by_key");
|
|
466
606
|
|
|
467
607
|
VALUE addrs;
|
|
468
608
|
|
|
@@ -473,9 +613,9 @@ rb_ca_max_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
473
613
|
else {
|
|
474
614
|
VALUE kw = rb_hash_new();
|
|
475
615
|
rb_hash_aset(kw, ID2SYM(id_axis), raxis);
|
|
476
|
-
addrs =
|
|
616
|
+
addrs = rb_funcallv_kw(rkey, rb_intern("max_addr"), 1, &kw, RB_PASS_KEYWORDS);
|
|
477
617
|
}
|
|
478
|
-
return
|
|
618
|
+
return ca_by_key_fetch(self, addrs);
|
|
479
619
|
}
|
|
480
620
|
|
|
481
621
|
/* min_by_key(key, axis: nil) -- self[key.min_addr(axis:)] (or UNDEF if empty). */
|
|
@@ -485,9 +625,11 @@ rb_ca_min_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
485
625
|
VALUE rkey, rkw = Qnil, raxis = Qnil;
|
|
486
626
|
rb_scan_args(argc, argv, "1:", &rkey, &rkw);
|
|
487
627
|
rb_scan_options(rkw, "axis", &raxis);
|
|
488
|
-
|
|
489
|
-
|
|
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;
|
|
490
631
|
}
|
|
632
|
+
rkey = ca_order_key(rkey, "min_by_key");
|
|
491
633
|
|
|
492
634
|
VALUE addrs;
|
|
493
635
|
|
|
@@ -498,9 +640,9 @@ rb_ca_min_by_key (int argc, VALUE *argv, VALUE self)
|
|
|
498
640
|
else {
|
|
499
641
|
VALUE kw = rb_hash_new();
|
|
500
642
|
rb_hash_aset(kw, ID2SYM(id_axis), raxis);
|
|
501
|
-
addrs =
|
|
643
|
+
addrs = rb_funcallv_kw(rkey, rb_intern("min_addr"), 1, &kw, RB_PASS_KEYWORDS);
|
|
502
644
|
}
|
|
503
|
-
return
|
|
645
|
+
return ca_by_key_fetch(self, addrs);
|
|
504
646
|
}
|
|
505
647
|
|
|
506
648
|
/* ---- take_along_axis / put_along_axis -------------------------------- */
|
|
@@ -515,6 +657,11 @@ rb_ca_take_along_axis_c (VALUE self, VALUE indices, VALUE raxis)
|
|
|
515
657
|
raxis = INT2FIX(0);
|
|
516
658
|
}
|
|
517
659
|
VALUE addrs = rb_ca_axis2addr_c(self, indices, raxis);
|
|
660
|
+
/* A masked index reads as UNDEF: project carries the mask of its
|
|
661
|
+
addresses into the result. */
|
|
662
|
+
if ( RTEST(rb_ca_has_mask(addrs)) ) {
|
|
663
|
+
return rb_funcall(self, rb_intern("project"), 1, addrs);
|
|
664
|
+
}
|
|
518
665
|
return rb_ca_fetch(self, addrs);
|
|
519
666
|
}
|
|
520
667
|
|
|
@@ -539,6 +686,18 @@ rb_ca_put_along_axis (int argc, VALUE *argv, VALUE self)
|
|
|
539
686
|
raxis = INT2FIX(0);
|
|
540
687
|
}
|
|
541
688
|
VALUE addrs = rb_ca_axis2addr_c(self, argv[0], raxis);
|
|
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. */
|
|
693
|
+
if ( RTEST(rb_ca_has_mask(addrs)) ) {
|
|
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));
|
|
699
|
+
return self;
|
|
700
|
+
}
|
|
542
701
|
rb_ca_store(self, addrs, argv[1]);
|
|
543
702
|
return self;
|
|
544
703
|
}
|
|
@@ -549,7 +708,12 @@ static VALUE
|
|
|
549
708
|
rb_ca_range_method (VALUE self)
|
|
550
709
|
{
|
|
551
710
|
VALUE mm_argv[1] = { Qnil };
|
|
552
|
-
|
|
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);
|
|
553
717
|
VALUE lo = rb_ary_entry(pair, 0);
|
|
554
718
|
VALUE hi = rb_ary_entry(pair, 1);
|
|
555
719
|
return rb_range_new(lo, hi, 0);
|
|
@@ -557,6 +721,221 @@ rb_ca_range_method (VALUE self)
|
|
|
557
721
|
|
|
558
722
|
/* ---- nlargest / nsmallest family ------------------------------------- */
|
|
559
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
|
+
|
|
560
939
|
/* Per-axis top-k positions (cap clamped, axis normalized).
|
|
561
940
|
* Called by rb_ca_topk_index below. */
|
|
562
941
|
static VALUE
|
|
@@ -567,12 +946,32 @@ rb_ca_topk_positions (VALUE self, long cap, long axis_norm, int desc)
|
|
|
567
946
|
long dim_axis = (long) ca->dim[axis_norm];
|
|
568
947
|
VALUE raxis_norm = LONG2NUM(axis_norm);
|
|
569
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
|
+
|
|
570
972
|
if ( cap >= dim_axis ) {
|
|
571
973
|
VALUE full = rb_ca_sort_index_ki_quick(self, raxis_norm);
|
|
572
|
-
|
|
573
|
-
full = rb_ca_flip_axis(full, NUM2LONG(raxis_norm));
|
|
574
|
-
}
|
|
575
|
-
return rb_ca_copy(full);
|
|
974
|
+
return ca_topk_stable(self, full, axis_norm, desc);
|
|
576
975
|
}
|
|
577
976
|
|
|
578
977
|
long pivot = desc ? (dim_axis - cap) : (cap - 1);
|
|
@@ -599,7 +998,7 @@ rb_ca_topk_positions (VALUE self, long cap, long axis_norm, int desc)
|
|
|
599
998
|
order = rb_ca_flip_axis(order, NUM2LONG(raxis_norm));
|
|
600
999
|
}
|
|
601
1000
|
VALUE picked = rb_ca_take_along_axis_c(partidx_top, order, raxis_norm);
|
|
602
|
-
return
|
|
1001
|
+
return ca_topk_stable(self, picked, axis_norm, desc);
|
|
603
1002
|
}
|
|
604
1003
|
|
|
605
1004
|
/* Dispatcher: normalize axis, clamp cap, empty-cap corner.
|
|
@@ -611,12 +1010,14 @@ rb_ca_topk_index (VALUE self, VALUE rn, VALUE raxis, int desc, const char *name)
|
|
|
611
1010
|
CArray *ca;
|
|
612
1011
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
613
1012
|
long a = rb_ca_normalize_axis_value(self, raxis, name);
|
|
614
|
-
long n_val =
|
|
1013
|
+
long n_val = ca_integer_arg(rn, "n", name);
|
|
615
1014
|
long dim_a = (long) ca->dim[a];
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
1015
|
+
/* As Array#max(n): a negative count is an error, one past the length
|
|
1016
|
+
gives the whole fiber. */
|
|
1017
|
+
if ( n_val < 0 ) {
|
|
1018
|
+
rb_raise(rb_eArgError, "%s: n must be non-negative (got %ld)", name, n_val);
|
|
619
1019
|
}
|
|
1020
|
+
long cap = (n_val < dim_a) ? n_val : dim_a;
|
|
620
1021
|
if ( cap == 0 ) {
|
|
621
1022
|
/* Return zero-along-axis int64 array via the C carray constructor. */
|
|
622
1023
|
ca_size_t out_dim[CA_RANK_MAX];
|
|
@@ -701,39 +1102,42 @@ rb_ca_nsmallest (int argc, VALUE *argv, VALUE self)
|
|
|
701
1102
|
* ever compare equal), so a later sort_addr key never gets consulted;
|
|
702
1103
|
* dense ranks preserve ties, so it does.
|
|
703
1104
|
*
|
|
704
|
-
* descending:
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
*
|
|
708
|
-
* 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. */
|
|
709
1109
|
|
|
710
1110
|
static VALUE
|
|
711
1111
|
rb_ca_order (int argc, VALUE *argv, VALUE self)
|
|
712
1112
|
{
|
|
713
1113
|
VALUE ropt = rb_pop_options(&argc, &argv);
|
|
714
|
-
VALUE raxis = Qnil, rdesc = Qfalse, rmethod = Qnil;
|
|
715
|
-
rb_scan_options(ropt, "axis,descending,method", &raxis, &rdesc, &rmethod);
|
|
1114
|
+
VALUE raxis = Qnil, rdesc = Qfalse, rmethod = Qnil, rkind = Qnil;
|
|
1115
|
+
rb_scan_options(ropt, "axis,descending,method,kind", &raxis, &rdesc, &rmethod, &rkind);
|
|
716
1116
|
rb_check_arity(argc, 0, 0);
|
|
717
1117
|
|
|
718
|
-
int dense =
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
1118
|
+
int dense = NIL_P(rmethod) ? 0
|
|
1119
|
+
: ca_symbol_choice(rmethod, "method", "ordinal", "dense", NULL);
|
|
1120
|
+
int do_stable = NIL_P(rkind) ? 0
|
|
1121
|
+
: ca_symbol_choice(rkind, "kind", "quick", "stable", NULL);
|
|
1122
|
+
|
|
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);
|
|
730
1133
|
}
|
|
731
1134
|
|
|
732
|
-
|
|
1135
|
+
/* The kernel's dense == 2 is the descending dense rank. */
|
|
1136
|
+
int kmode = ( dense && RTEST(rdesc) ) ? 2 : dense;
|
|
733
1137
|
if ( NIL_P(raxis) ) {
|
|
734
1138
|
VALUE flat = rb_ca_flatten(self);
|
|
735
1139
|
/* Direct C-level dispatch via c_callable: true extern (mkkernel). */
|
|
736
|
-
VALUE ranked =
|
|
1140
|
+
VALUE ranked = rb_ca_rank_index_ki_kind_dense(flat, INT2FIX(0), do_stable, kmode);
|
|
737
1141
|
/* reshape(*shape) */
|
|
738
1142
|
CArray *ca;
|
|
739
1143
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
@@ -741,43 +1145,12 @@ rb_ca_order (int argc, VALUE *argv, VALUE self)
|
|
|
741
1145
|
for ( long k = 0; k < (long) ca->ndim; k++ ) {
|
|
742
1146
|
shape_argv[k] = LONG2NUM((long) ca->dim[k]);
|
|
743
1147
|
}
|
|
744
|
-
|
|
745
|
-
n = RTEST(rb_ca_has_mask(self))
|
|
746
|
-
? SIZE2NUM(ca_count_not_masked(ca)) /* = elements - count_masked */
|
|
747
|
-
: rb_ca_elements(self);
|
|
748
|
-
} else {
|
|
749
|
-
long axis_norm = rb_ca_normalize_axis_value(self, raxis, "order");
|
|
750
|
-
VALUE raxis_norm = LONG2NUM(axis_norm);
|
|
751
|
-
asc = rb_ca_rank_index_ki_quick_dense(self, raxis_norm, dense);
|
|
752
|
-
if ( RTEST(rb_ca_has_mask(self)) ) {
|
|
753
|
-
n = rb_ca_count_not_masked_c(self, raxis_norm);
|
|
754
|
-
} else {
|
|
755
|
-
CArray *ca;
|
|
756
|
-
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
757
|
-
n = LONG2NUM((long) ca->dim[axis_norm]);
|
|
758
|
-
}
|
|
759
|
-
if ( RTEST(rb_obj_is_kind_of(n, rb_cCArray)) ) {
|
|
760
|
-
VALUE ia_argv[1] = { raxis_norm };
|
|
761
|
-
n = rb_ca_insert_axis(1, ia_argv, n);
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
VALUE diff;
|
|
766
|
-
if ( RTEST(rdesc) ) {
|
|
767
|
-
/* `-` via rb_funcall handles both Integer-Integer and
|
|
768
|
-
CArray/Integer mixed receivers uniformly via Ruby's operator
|
|
769
|
-
dispatch. No single C entry covers both. */
|
|
770
|
-
VALUE n_minus_1 = rb_funcall(n, id_sub, 1, INT2FIX(1));
|
|
771
|
-
diff = rb_funcall(n_minus_1, id_sub, 1, asc);
|
|
772
|
-
} else {
|
|
773
|
-
diff = asc;
|
|
1148
|
+
return rb_ca_reshape((int) ca->ndim, shape_argv, ranked);
|
|
774
1149
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
promotion in the descending branch preserves it. */
|
|
780
|
-
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);
|
|
781
1154
|
}
|
|
782
1155
|
|
|
783
1156
|
/* ---- linear_section / linear_fetch ----------------------------------- */
|
|
@@ -799,12 +1172,7 @@ ca_linear_prep (VALUE self, VALUE raxis, const char *name, long *axis_out)
|
|
|
799
1172
|
Face) is caught by the rb_ca_to_float64 cast below, so no separate
|
|
800
1173
|
float-numeric flag is needed. */
|
|
801
1174
|
if ( ca_is_face(ca) ) {
|
|
802
|
-
|
|
803
|
-
rb_raise(rb_eArgError,
|
|
804
|
-
"%s: Face-typed input (%s) is not orderable by storage; "
|
|
805
|
-
"use ca.parent to descend to storage",
|
|
806
|
-
name, rb_obj_classname(self));
|
|
807
|
-
}
|
|
1175
|
+
ca_face_require_orderable(self, name, "order");
|
|
808
1176
|
self = rb_ca_strip_face_value(self);
|
|
809
1177
|
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
810
1178
|
}
|
|
@@ -831,44 +1199,26 @@ rb_ca_linear_section_m (int argc, VALUE *argv, VALUE self)
|
|
|
831
1199
|
rb_check_arity(argc, 1, 1);
|
|
832
1200
|
VALUE val = argv[0];
|
|
833
1201
|
|
|
834
|
-
/* Query gate
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
-> strip a Face query, take a plain query as-is. A non-COMPARABLE Face
|
|
838
|
-
axis calls its own to_comparable(query) for ANY query type (Face CArray,
|
|
839
|
-
our Scalar, a Ruby Time / DateTime, ...), then strips; it raises if it
|
|
840
|
-
cannot reconcile the query. `self` is still the pre-strip axis Face
|
|
841
|
-
here, so it carries the unit for to_comparable and its COMPARABLE flag. */
|
|
842
|
-
{
|
|
843
|
-
int val_is_face = 0, self_is_face = 0, self_comparable = 0;
|
|
1202
|
+
/* Query gate: the reference axis, still a Face here, and the query are
|
|
1203
|
+
brought into one space (ca_face_reconcile_pair). */
|
|
1204
|
+
if ( rb_obj_is_carray(self) ) {
|
|
844
1205
|
CArray *sca;
|
|
845
|
-
if ( rb_obj_is_kind_of(val, rb_cCArray) ) {
|
|
846
|
-
CArray *vca;
|
|
847
|
-
TypedData_Get_Struct(val, CArray, &carray_data_type, vca);
|
|
848
|
-
val_is_face = ca_is_face(vca);
|
|
849
|
-
}
|
|
850
1206
|
TypedData_Get_Struct(self, CArray, &carray_data_type, sca);
|
|
851
1207
|
if ( ca_is_face(sca) ) {
|
|
852
|
-
|
|
853
|
-
|
|
1208
|
+
volatile VALUE ref = self, query = val;
|
|
1209
|
+
ca_face_reconcile_pair(&ref, &query, "linear_section");
|
|
1210
|
+
self = ref;
|
|
1211
|
+
val = query;
|
|
854
1212
|
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
}
|
|
865
|
-
else {
|
|
866
|
-
rb_raise(rb_eArgError,
|
|
867
|
-
"linear_section: non-comparable Face axis (%s) has no "
|
|
868
|
-
"to_comparable to reconcile the query; use ca.parent to "
|
|
869
|
-
"search the hidden storage explicitly",
|
|
870
|
-
rb_obj_classname(self));
|
|
871
|
-
}
|
|
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]);
|
|
872
1222
|
}
|
|
873
1223
|
}
|
|
874
1224
|
|
|
@@ -897,6 +1247,27 @@ rb_ca_linear_fetch_m (int argc, VALUE *argv, VALUE self)
|
|
|
897
1247
|
rb_check_arity(argc, 1, 1);
|
|
898
1248
|
VALUE addr = argv[0];
|
|
899
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
|
+
|
|
900
1271
|
long axis_norm = 0;
|
|
901
1272
|
VALUE sc = ca_linear_prep(self, raxis, "linear_fetch", &axis_norm);
|
|
902
1273
|
return rb_ca_linear_fetch_ki(sc, addr, LONG2NUM(axis_norm));
|
|
@@ -925,6 +1296,7 @@ Init_carray_order (void)
|
|
|
925
1296
|
id_sym_linear = rb_intern("linear");
|
|
926
1297
|
|
|
927
1298
|
rb_define_method(rb_cCArray, "project", rb_ca_project, -1);
|
|
1299
|
+
rb_define_private_method(rb_cCArray, "__count_below__", rb_ca_count_below, 2);
|
|
928
1300
|
|
|
929
1301
|
/* Search family (dual API: index / addr) -- see the trampoline
|
|
930
1302
|
comment block above for the axis: kwarg dispatch contract. */
|