carray 3.0.6 → 3.0.7
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 +110 -0
- data/README.md +24 -3
- data/carray.gemspec +1 -1
- data/ext/ca_axis_group.c +6 -6
- data/ext/ca_binop_dispatch.c +8 -0
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +7 -7
- data/ext/ca_kernel_iterator.h +6 -4
- data/ext/ca_obj_array.c +4 -4
- data/ext/ca_obj_bincmp.c +19 -3
- data/ext/ca_obj_binop.c +36 -11
- data/ext/ca_obj_bitarray.c +2 -4
- data/ext/ca_obj_bitfield.c +86 -4
- data/ext/ca_obj_byte_swap.c +2 -4
- data/ext/ca_obj_const_string.c +422 -257
- data/ext/ca_obj_face.c +71 -33
- data/ext/ca_obj_fake.c +112 -13
- data/ext/ca_obj_farray.c +7 -1
- data/ext/ca_obj_fixlen_string.c +51 -17
- data/ext/ca_obj_grid.c +12 -7
- data/ext/ca_obj_meld.c +5 -5
- data/ext/ca_obj_monop.c +65 -39
- data/ext/ca_obj_object.c +9 -9
- data/ext/ca_obj_reduce.c +2 -4
- data/ext/ca_obj_refer.c +104 -10
- data/ext/ca_obj_repeat.c +1 -1
- data/ext/ca_obj_roll.c +2 -4
- data/ext/ca_obj_select.c +8 -6
- data/ext/ca_obj_select_axis.c +8 -6
- data/ext/ca_obj_stack.c +5 -5
- data/ext/ca_obj_stride.c +46 -8
- data/ext/ca_obj_string.c +2 -2
- data/ext/ca_obj_tile.c +2 -4
- data/ext/ca_obj_triop.c +15 -12
- data/ext/ca_obj_window.c +22 -15
- data/ext/ca_op_ipower.c +63 -15
- data/ext/ca_op_powi.h +6 -29
- data/ext/ca_sort_kernels.h +3 -0
- data/ext/ca_sweep_engine.c +90 -23
- data/ext/ca_sweep_engine.h +5 -6
- data/ext/caframe_csv_reader.c +1 -1
- data/ext/carray.h +3 -1
- data/ext/carray_access.c +98 -39
- data/ext/carray_address_basis.c +98 -24
- data/ext/carray_broadcast.c +2 -2
- data/ext/carray_call_cfunc.c +5 -8
- data/ext/carray_cast.c +311 -37
- data/ext/carray_cast_func.rb +37 -5
- data/ext/carray_conversion.c +56 -2
- data/ext/carray_copy.c +24 -0
- data/ext/carray_core.c +69 -6
- data/ext/carray_count.c +28 -9
- data/ext/carray_element.c +9 -3
- data/ext/carray_factorize.c +11 -11
- data/ext/carray_histogram.c +2 -2
- data/ext/carray_index_classifier.c +7 -5
- data/ext/carray_internal.h +94 -0
- data/ext/carray_kernels_binop.c +55 -55
- data/ext/carray_kernels_init.c +14 -14
- data/ext/carray_kernels_monop.c +90 -140
- data/ext/carray_lazy.c +16 -1
- data/ext/carray_loop.c +9 -2
- data/ext/carray_mask.c +118 -11
- data/ext/carray_median_percentile.c +13 -8
- data/ext/carray_memory_view.c +41 -22
- data/ext/carray_operator.c +72 -11
- data/ext/carray_order.c +52 -9
- data/ext/carray_partition.c +1 -1
- data/ext/carray_random.c +1 -1
- data/ext/carray_round.c +24 -1
- data/ext/carray_scatter.c +4 -0
- data/ext/carray_segment.c +1 -1
- data/ext/carray_slab.c +13 -4
- data/ext/carray_sort.c +6 -3
- data/ext/carray_sort_kernel.c +24 -0
- data/ext/carray_struct.c +21 -6
- data/ext/carray_test.c +85 -39
- data/ext/carray_time_text.c +6 -0
- data/ext/carray_utils.c +124 -54
- data/ext/mk_call_cfunc.rb +6 -11
- data/ext/mkkernel.rb +37 -27
- data/ext/version.h +4 -4
- data/lib/carray/axis_group.rb +9 -6
- data/lib/carray/basics.rb +26 -8
- data/lib/carray/bincount_nd.rb +8 -2
- data/lib/carray/block_iterator.rb +48 -21
- data/lib/carray/categorical.rb +21 -8
- data/lib/carray/categorical_iterator.rb +2 -1
- data/lib/carray/conditional.rb +52 -4
- data/lib/carray/const_string.rb +74 -0
- data/lib/carray/construct.rb +2 -2
- data/lib/carray/core_extensions.rb +19 -68
- data/lib/carray/data_type_extension.rb +1 -0
- data/lib/carray/fixlen_string.rb +83 -1
- data/lib/carray/frame/column_verbs.rb +61 -6
- data/lib/carray/frame/concat.rb +50 -6
- data/lib/carray/frame/csv_parser.rb +13 -4
- data/lib/carray/frame/frame.rb +38 -6
- data/lib/carray/frame/group.rb +67 -40
- data/lib/carray/frame/io.rb +10 -5
- data/lib/carray/frame/join.rb +20 -6
- data/lib/carray/frame/records.rb +6 -4
- data/lib/carray/frame/reshape.rb +25 -5
- data/lib/carray/frame/verbs.rb +78 -25
- data/lib/carray/frame/windows.rb +30 -6
- data/lib/carray/fuse_source.rb +4 -2
- data/lib/carray/iterator.rb +8 -0
- data/lib/carray/key_windows.rb +10 -4
- data/lib/carray/lazy.rb +12 -17
- data/lib/carray/methods/bin.rb +3 -0
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/factorize.rb +2 -0
- data/lib/carray/methods/gather_nd.rb +4 -1
- data/lib/carray/methods/is_in.rb +23 -3
- data/lib/carray/methods/locate_addr.rb +63 -12
- data/lib/carray/methods/repeat.rb +11 -1
- data/lib/carray/record_order.rb +35 -6
- data/lib/carray/runtime.rb +10 -0
- data/lib/carray/segment_iterator.rb +19 -16
- data/lib/carray/serialize.rb +22 -0
- data/lib/carray/slab_iterator.rb +1 -1
- data/lib/carray/stack.rb +3 -3
- data/lib/carray/string.rb +6 -6
- data/lib/carray/string_operation_extension.rb +25 -4
- data/lib/carray/struct_builder.rb +4 -1
- data/lib/carray/time.rb +190 -46
- data/lib/carray/window_iterator.rb +48 -12
- data/yard-stubs/ca_obj_bitfield.rb +4 -1
- data/yard-stubs/ca_obj_refer.rb +3 -0
- data/yard-stubs/ca_obj_window.rb +2 -1
- data/yard-stubs/carray_access.rb +4 -2
- data/yard-stubs/carray_cast.rb +6 -0
- data/yard-stubs/carray_count.rb +6 -3
- data/yard-stubs/carray_math.rb +5 -0
- data/yard-stubs/carray_order.rb +6 -0
- data/yard-stubs/carray_scatter.rb +2 -1
- data/yard-stubs/carray_test.rb +18 -5
- metadata +2 -2
data/ext/carray_utils.c
CHANGED
|
@@ -11,12 +11,14 @@
|
|
|
11
11
|
---------------------------------------------------------------------------- */
|
|
12
12
|
|
|
13
13
|
#include <stdarg.h>
|
|
14
|
+
#include <time.h>
|
|
14
15
|
#include "ruby.h"
|
|
15
16
|
#include "carray.h"
|
|
16
17
|
#include "carray_internal.h" /* ca_calling_method_name */
|
|
17
18
|
|
|
18
19
|
#include "ruby/st.h"
|
|
19
20
|
#include "ruby/thread_native.h"
|
|
21
|
+
#include "ruby/thread.h" /* rb_thread_call_without_gvl */
|
|
20
22
|
#include "ruby/ractor.h"
|
|
21
23
|
#include "ruby/debug.h" /* rb_profile_frames: the method the user called */
|
|
22
24
|
|
|
@@ -103,6 +105,14 @@ ca_get_loop_count (int n, ...)
|
|
|
103
105
|
return elements;
|
|
104
106
|
}
|
|
105
107
|
|
|
108
|
+
/* A bound of a range that is not a key of `[]`: a window or a bit range says
|
|
109
|
+
how many cells, so a Float is refused rather than cut down. */
|
|
110
|
+
static ca_size_t
|
|
111
|
+
ca_range_bound (VALUE v)
|
|
112
|
+
{
|
|
113
|
+
return ca_integer_arg(v, "a range bound", NULL);
|
|
114
|
+
}
|
|
115
|
+
|
|
106
116
|
/*
|
|
107
117
|
ca_parse_range and ca_parse_range_without_check parse the following
|
|
108
118
|
types of range specifications
|
|
@@ -138,7 +148,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
138
148
|
}
|
|
139
149
|
else if ( rb_obj_is_kind_of(arg, rb_cInteger) ) {
|
|
140
150
|
/* i */
|
|
141
|
-
start =
|
|
151
|
+
start = ca_range_bound(arg);
|
|
142
152
|
CA_CHECK_INDEX(start, size);
|
|
143
153
|
*poffset = start;
|
|
144
154
|
*pcount = 1;
|
|
@@ -146,8 +156,8 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
146
156
|
}
|
|
147
157
|
else if ( rb_obj_is_kind_of(arg, rb_cRange) ) {
|
|
148
158
|
/* i..j */
|
|
149
|
-
start =
|
|
150
|
-
last =
|
|
159
|
+
start = ca_range_bound(RANGE_BEG(arg));
|
|
160
|
+
last = ca_range_bound(RANGE_END(arg));
|
|
151
161
|
excl = RTEST(RANGE_EXCL(arg));
|
|
152
162
|
CA_CHECK_INDEX(start, size);
|
|
153
163
|
if ( last < 0 ) {
|
|
@@ -168,10 +178,10 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
168
178
|
rb_arithmetic_sequence_components_t x;
|
|
169
179
|
rb_arithmetic_sequence_extract(arg, &x);
|
|
170
180
|
|
|
171
|
-
start =
|
|
172
|
-
last =
|
|
181
|
+
start = ca_range_bound(x.begin);
|
|
182
|
+
last = ca_range_bound(x.end);
|
|
173
183
|
excl = RTEST(x.exclude_end);
|
|
174
|
-
step =
|
|
184
|
+
step = ca_range_bound(x.step);
|
|
175
185
|
if ( step == 0 ) {
|
|
176
186
|
rb_raise(rb_eArgError, "step should not be 0");
|
|
177
187
|
}
|
|
@@ -209,7 +219,7 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
209
219
|
VALUE arg0 = rb_ary_entry(arg, 0);
|
|
210
220
|
VALUE arg1 = rb_ary_entry(arg, 1);
|
|
211
221
|
if ( NIL_P(arg0) ) { /* [nil,k] */
|
|
212
|
-
step =
|
|
222
|
+
step = ca_range_bound(arg1);
|
|
213
223
|
if ( step == 0 ) {
|
|
214
224
|
rb_raise(rb_eArgError, "step should not be 0");
|
|
215
225
|
}
|
|
@@ -224,10 +234,10 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
224
234
|
*pstep = step;
|
|
225
235
|
}
|
|
226
236
|
else if ( rb_obj_is_kind_of(arg0, rb_cRange) ) { /* [i..j,k] */
|
|
227
|
-
start =
|
|
228
|
-
last =
|
|
237
|
+
start = ca_range_bound(RANGE_BEG(arg0));
|
|
238
|
+
last = ca_range_bound(RANGE_END(arg0));
|
|
229
239
|
excl = RTEST(RANGE_EXCL(arg0));
|
|
230
|
-
step =
|
|
240
|
+
step = ca_range_bound(arg1);
|
|
231
241
|
if ( step == 0 ) {
|
|
232
242
|
rb_raise(rb_eArgError, "step should not be 0");
|
|
233
243
|
}
|
|
@@ -260,10 +270,10 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
260
270
|
rb_arithmetic_sequence_components_t x;
|
|
261
271
|
rb_arithmetic_sequence_extract(arg0, &x);
|
|
262
272
|
|
|
263
|
-
start =
|
|
264
|
-
last =
|
|
273
|
+
start = ca_range_bound(x.begin);
|
|
274
|
+
last = ca_range_bound(x.end);
|
|
265
275
|
excl = RTEST(x.exclude_end);
|
|
266
|
-
step =
|
|
276
|
+
step = ca_range_bound(x.step);
|
|
267
277
|
if ( step == 0 ) {
|
|
268
278
|
rb_raise(rb_eArgError, "step should not be 0");
|
|
269
279
|
}
|
|
@@ -293,8 +303,8 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
293
303
|
}
|
|
294
304
|
#endif
|
|
295
305
|
else { /* [i,n] */
|
|
296
|
-
start =
|
|
297
|
-
count =
|
|
306
|
+
start = ca_range_bound(arg0);
|
|
307
|
+
count = ca_range_bound(arg1);
|
|
298
308
|
CA_CHECK_INDEX(start, size);
|
|
299
309
|
bound = start + (count - 1);
|
|
300
310
|
if ( count > 0 && ( bound < 0 || bound >= size ) ) {
|
|
@@ -306,9 +316,9 @@ ca_parse_range (VALUE arg, ca_size_t size,
|
|
|
306
316
|
}
|
|
307
317
|
}
|
|
308
318
|
else if ( RARRAY_LEN(arg) == 3 ) { /* [i,n,k] */
|
|
309
|
-
start =
|
|
310
|
-
count =
|
|
311
|
-
step =
|
|
319
|
+
start = ca_range_bound(rb_ary_entry(arg, 0));
|
|
320
|
+
count = ca_range_bound(rb_ary_entry(arg, 1));
|
|
321
|
+
step = ca_range_bound(rb_ary_entry(arg, 2));
|
|
312
322
|
if ( step == 0 ) {
|
|
313
323
|
rb_raise(rb_eArgError, "step should not be 0");
|
|
314
324
|
}
|
|
@@ -345,18 +355,18 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
345
355
|
}
|
|
346
356
|
else if ( rb_obj_is_kind_of(arg, rb_cInteger) ) {
|
|
347
357
|
/* i */
|
|
348
|
-
start =
|
|
358
|
+
start = ca_range_bound(arg);
|
|
349
359
|
*poffset = start;
|
|
350
360
|
*pcount = 1;
|
|
351
361
|
*pstep = 1;
|
|
352
362
|
}
|
|
353
363
|
else if ( rb_obj_is_kind_of(arg, rb_cRange) ) {
|
|
354
364
|
/* i..j */
|
|
355
|
-
start =
|
|
356
|
-
last =
|
|
365
|
+
start = ca_range_bound(RANGE_BEG(arg));
|
|
366
|
+
last = ca_range_bound(RANGE_END(arg));
|
|
357
367
|
excl = RTEST(RANGE_EXCL(arg));
|
|
358
368
|
if ( excl ) {
|
|
359
|
-
last
|
|
369
|
+
last -= 1;
|
|
360
370
|
}
|
|
361
371
|
*poffset = start;
|
|
362
372
|
*pcount = last - start + 1;
|
|
@@ -367,16 +377,16 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
367
377
|
rb_arithmetic_sequence_components_t x;
|
|
368
378
|
rb_arithmetic_sequence_extract(arg, &x);
|
|
369
379
|
|
|
370
|
-
start =
|
|
371
|
-
last =
|
|
380
|
+
start = ca_range_bound(x.begin);
|
|
381
|
+
last = ca_range_bound(x.end);
|
|
372
382
|
excl = RTEST(x.exclude_end);
|
|
373
|
-
step =
|
|
383
|
+
step = ca_range_bound(x.step);
|
|
374
384
|
if ( step == 0 ) {
|
|
375
385
|
rb_raise(rb_eArgError, "%s: step should not be 0",
|
|
376
386
|
ca_calling_method_name());
|
|
377
387
|
}
|
|
378
388
|
if ( excl ) {
|
|
379
|
-
last += ( (
|
|
389
|
+
last += ( (step>0) ? -1 : 1 );
|
|
380
390
|
}
|
|
381
391
|
count = (last - start)/llabs(step) + 1;
|
|
382
392
|
*poffset = start;
|
|
@@ -394,7 +404,7 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
394
404
|
VALUE arg1 = rb_ary_entry(arg, 1);
|
|
395
405
|
if ( NIL_P(arg0) ) { /* [nil,k] */
|
|
396
406
|
start = 0;
|
|
397
|
-
step =
|
|
407
|
+
step = ca_range_bound(arg1);
|
|
398
408
|
if ( step == 0 ) {
|
|
399
409
|
rb_raise(rb_eArgError, "%s: step should not be 0",
|
|
400
410
|
ca_calling_method_name());
|
|
@@ -405,10 +415,10 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
405
415
|
*pstep = step;
|
|
406
416
|
}
|
|
407
417
|
else if ( rb_obj_is_kind_of(arg0, rb_cRange) ) { /* [i..j,k] */
|
|
408
|
-
start =
|
|
409
|
-
last =
|
|
418
|
+
start = ca_range_bound(RANGE_BEG(arg0));
|
|
419
|
+
last = ca_range_bound(RANGE_END(arg0));
|
|
410
420
|
excl = RTEST(RANGE_EXCL(arg0));
|
|
411
|
-
step =
|
|
421
|
+
step = ca_range_bound(arg1);
|
|
412
422
|
if ( step == 0 ) {
|
|
413
423
|
rb_raise(rb_eArgError, "%s: step should not be 0",
|
|
414
424
|
ca_calling_method_name());
|
|
@@ -426,10 +436,10 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
426
436
|
rb_arithmetic_sequence_components_t x;
|
|
427
437
|
rb_arithmetic_sequence_extract(arg0, &x);
|
|
428
438
|
|
|
429
|
-
start =
|
|
430
|
-
last =
|
|
439
|
+
start = ca_range_bound(x.begin);
|
|
440
|
+
last = ca_range_bound(x.end);
|
|
431
441
|
excl = RTEST(x.exclude_end);
|
|
432
|
-
step =
|
|
442
|
+
step = ca_range_bound(x.step);
|
|
433
443
|
if ( step == 0 ) {
|
|
434
444
|
rb_raise(rb_eArgError, "%s: step should not be 0",
|
|
435
445
|
ca_calling_method_name());
|
|
@@ -444,17 +454,17 @@ ca_parse_range_without_check (VALUE arg, ca_size_t size,
|
|
|
444
454
|
}
|
|
445
455
|
#endif
|
|
446
456
|
else { /* [i,n] */
|
|
447
|
-
start =
|
|
448
|
-
count =
|
|
457
|
+
start = ca_range_bound(arg0);
|
|
458
|
+
count = ca_range_bound(arg1);
|
|
449
459
|
*poffset = start;
|
|
450
460
|
*pcount = count;
|
|
451
461
|
*pstep = 1;
|
|
452
462
|
}
|
|
453
463
|
}
|
|
454
464
|
else if ( RARRAY_LEN(arg) == 3 ) { /* [i,n,k] */
|
|
455
|
-
start =
|
|
456
|
-
count =
|
|
457
|
-
step =
|
|
465
|
+
start = ca_range_bound(rb_ary_entry(arg, 0));
|
|
466
|
+
count = ca_range_bound(rb_ary_entry(arg, 1));
|
|
467
|
+
step = ca_range_bound(rb_ary_entry(arg, 2));
|
|
458
468
|
*poffset = start;
|
|
459
469
|
*pcount = count;
|
|
460
470
|
*pstep = step;
|
|
@@ -528,7 +538,7 @@ ca_stable_id_name (ID id)
|
|
|
528
538
|
{
|
|
529
539
|
st_data_t found;
|
|
530
540
|
const char *name = NULL;
|
|
531
|
-
|
|
541
|
+
ca_native_lock_without_gvl(&ca_id_names_lock);
|
|
532
542
|
if ( st_lookup(ca_id_names, (st_data_t) id, &found) ) {
|
|
533
543
|
name = (const char *) found;
|
|
534
544
|
}
|
|
@@ -548,7 +558,8 @@ ca_stable_id_name (ID id)
|
|
|
548
558
|
memcpy(copy, RSTRING_PTR(str), len);
|
|
549
559
|
copy[len] = '\0';
|
|
550
560
|
RB_GC_GUARD(str);
|
|
551
|
-
|
|
561
|
+
/* lock: st_insert can run a GC, which does not take this lock */
|
|
562
|
+
ca_native_lock_without_gvl(&ca_id_names_lock);
|
|
552
563
|
if ( st_lookup(ca_id_names, (st_data_t) id, &found) ) {
|
|
553
564
|
xfree(copy);
|
|
554
565
|
name = (const char *) found;
|
|
@@ -786,17 +797,18 @@ ca_shape_elements (int8_t ndim, const ca_size_t *dim, ca_size_t bytes)
|
|
|
786
797
|
}
|
|
787
798
|
|
|
788
799
|
/* An index array is read as ca_size_t. A float or complex one would be
|
|
789
|
-
cut to an integer on the way,
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
is. */
|
|
800
|
+
cut to an integer on the way, as an object one would, and a boolean one
|
|
801
|
+
selects cells rather than naming addresses, so these are refused. A
|
|
802
|
+
uint64 one holding 2**63 or more would turn negative and count from the
|
|
803
|
+
end of the axis, so it is refused as the out-of-range index it is. */
|
|
793
804
|
void
|
|
794
805
|
ca_check_index_array (VALUE v)
|
|
795
806
|
{
|
|
796
807
|
CArray *ca;
|
|
797
808
|
if ( ! rb_obj_is_carray(v) ) return;
|
|
798
809
|
GetCArray(v, ca);
|
|
799
|
-
if ( ca_is_float_type(ca) || ca_is_complex_type(ca)
|
|
810
|
+
if ( ca_is_float_type(ca) || ca_is_complex_type(ca)
|
|
811
|
+
|| ca->data_type == CA_OBJECT || ca->data_type == CA_BOOLEAN ) {
|
|
800
812
|
rb_raise(rb_eIndexError,
|
|
801
813
|
"data_type %s is invalid for an index (should be integer)",
|
|
802
814
|
ca_type_name[ca->data_type]);
|
|
@@ -1156,12 +1168,12 @@ rb_ca_guess_type (VALUE obj)
|
|
|
1156
1168
|
}
|
|
1157
1169
|
else if ( TYPE(obj) == T_STRING ) {
|
|
1158
1170
|
const char *name0;
|
|
1159
|
-
char *name =
|
|
1171
|
+
const char *name = StringValueCStr(obj);
|
|
1160
1172
|
int i;
|
|
1161
1173
|
i = 0;
|
|
1162
1174
|
while ( ( name0 = ca_name_to_type[i].name ) ) {
|
|
1163
1175
|
name0 = ca_name_to_type[i].name;
|
|
1164
|
-
if ( !
|
|
1176
|
+
if ( ! strcmp(name, name0) ) {
|
|
1165
1177
|
return ca_name_to_type[i].data_type;
|
|
1166
1178
|
}
|
|
1167
1179
|
i++;
|
|
@@ -1196,7 +1208,7 @@ rb_ca_guess_type_and_bytes (VALUE rtype, VALUE rbytes,
|
|
|
1196
1208
|
*bytes = 0;
|
|
1197
1209
|
}
|
|
1198
1210
|
else {
|
|
1199
|
-
*bytes =
|
|
1211
|
+
*bytes = ca_integer_arg(rbytes, "bytes", NULL);
|
|
1200
1212
|
}
|
|
1201
1213
|
}
|
|
1202
1214
|
}
|
|
@@ -1345,13 +1357,16 @@ rb_scan_options (VALUE ropt, const char *spec_in, ...)
|
|
|
1345
1357
|
long i, n = RARRAY_LEN(keys);
|
|
1346
1358
|
for ( i = 0; i < n; i++ ) {
|
|
1347
1359
|
VALUE key = rb_ary_entry(keys, i);
|
|
1348
|
-
VALUE kname = SYMBOL_P(key) ? rb_sym2str(key) : rb_obj_as_string(key);
|
|
1349
|
-
const char *kn = StringValueCStr(kname);
|
|
1350
|
-
long kn_len = RSTRING_LEN(kname);
|
|
1351
1360
|
int found = 0;
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1361
|
+
/* A value is read by Symbol above, so only a Symbol can name a key. */
|
|
1362
|
+
if ( SYMBOL_P(key) ) {
|
|
1363
|
+
VALUE kname = rb_sym2str(key);
|
|
1364
|
+
const char *kn = StringValueCStr(kname);
|
|
1365
|
+
long kn_len = RSTRING_LEN(kname);
|
|
1366
|
+
sp = spec_in;
|
|
1367
|
+
while ( ( tok = option_key(&sp, &len) ) != NULL ) {
|
|
1368
|
+
if ( len == kn_len && memcmp(tok, kn, len) == 0 ) { found = 1; break; }
|
|
1369
|
+
}
|
|
1355
1370
|
}
|
|
1356
1371
|
if ( ! found ) {
|
|
1357
1372
|
rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE, rb_inspect(key));
|
|
@@ -1414,6 +1429,57 @@ rb_set_options (VALUE ropt, const char *spec_in, ...)
|
|
|
1414
1429
|
}
|
|
1415
1430
|
|
|
1416
1431
|
|
|
1432
|
+
/* RubyVM::InstructionSequence#to_a, one caller at a time across Ractors.
|
|
1433
|
+
The first to_a on an instruction sequence builds a decoded copy of its
|
|
1434
|
+
code and publishes the buffer before filling it, so a second Ractor
|
|
1435
|
+
that reads the same sequence at that moment decodes raw addresses and
|
|
1436
|
+
crashes the process (Ruby 3.4 and 4.0; fixed for 4.1). A block written
|
|
1437
|
+
inside Ractor.new is one sequence shared by every Ractor started from
|
|
1438
|
+
it. The wait for the lock is made without the GVL, so a Ractor that
|
|
1439
|
+
holds the lock and starts a GC is not left waiting on one that wants
|
|
1440
|
+
it. */
|
|
1441
|
+
static rb_nativethread_lock_t ca_iseq_to_a_lock;
|
|
1442
|
+
|
|
1443
|
+
static VALUE
|
|
1444
|
+
ca_iseq_to_a_call (VALUE iseq)
|
|
1445
|
+
{
|
|
1446
|
+
return rb_funcall(iseq, rb_intern("to_a"), 0);
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
static VALUE
|
|
1450
|
+
rb_ca_s_instruction_sequence_to_a (VALUE self, VALUE iseq)
|
|
1451
|
+
{
|
|
1452
|
+
VALUE result;
|
|
1453
|
+
int state = 0;
|
|
1454
|
+
/* lock: Ruby runs under it, to serialise to_a; every waiter waits without the GVL */
|
|
1455
|
+
ca_native_lock_without_gvl(&ca_iseq_to_a_lock);
|
|
1456
|
+
/* protect: what is held is the lock, not an array or a buffer */
|
|
1457
|
+
result = rb_protect(ca_iseq_to_a_call, iseq, &state);
|
|
1458
|
+
rb_nativethread_lock_unlock(&ca_iseq_to_a_lock);
|
|
1459
|
+
if ( state ) {
|
|
1460
|
+
rb_jump_tag(state);
|
|
1461
|
+
}
|
|
1462
|
+
return result;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
/* A short pause between tries for a lock, made without the GVL. */
|
|
1466
|
+
static void *
|
|
1467
|
+
ca_native_lock_pause (void *arg)
|
|
1468
|
+
{
|
|
1469
|
+
struct timespec t = { 0, 20000 }; /* 20 us */
|
|
1470
|
+
nanosleep(&t, NULL);
|
|
1471
|
+
return NULL;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
void
|
|
1475
|
+
ca_native_lock_without_gvl (rb_nativethread_lock_t *lock)
|
|
1476
|
+
{
|
|
1477
|
+
/* lock: the pause below runs while the lock is not held */
|
|
1478
|
+
while ( rb_native_mutex_trylock(lock) != 0 ) {
|
|
1479
|
+
rb_thread_call_without_gvl(ca_native_lock_pause, NULL, RUBY_UBF_IO, NULL);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1417
1483
|
/* Whether this runs in the main Ractor: Init does, and leaves a value in
|
|
1418
1484
|
its Ractor-local storage that no other Ractor has. */
|
|
1419
1485
|
static rb_ractor_local_key_t ca_main_ractor_key;
|
|
@@ -1432,11 +1498,15 @@ Init_carray_utils (void)
|
|
|
1432
1498
|
rb_ractor_local_storage_value_set(ca_main_ractor_key, Qtrue);
|
|
1433
1499
|
ca_id_names = st_init_numtable();
|
|
1434
1500
|
rb_nativethread_lock_initialize(&ca_id_names_lock);
|
|
1501
|
+
rb_nativethread_lock_initialize(&ca_iseq_to_a_lock);
|
|
1435
1502
|
id_answering = rb_intern("__carray_answering_method__");
|
|
1436
1503
|
id_begin = rb_intern("begin");
|
|
1437
1504
|
id_end = rb_intern("end");
|
|
1438
1505
|
id_excl_end = rb_intern("exclude_end?");
|
|
1439
1506
|
|
|
1507
|
+
rb_define_private_method(rb_singleton_class(rb_cCArray),
|
|
1508
|
+
"instruction_sequence_to_a",
|
|
1509
|
+
rb_ca_s_instruction_sequence_to_a, 1);
|
|
1440
1510
|
rb_define_singleton_method(rb_cCArray, "guess_type_and_bytes",
|
|
1441
1511
|
rb_ca_s_guess_type_and_bytes, -1);
|
|
1442
1512
|
|
data/ext/mk_call_cfunc.rb
CHANGED
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
# `ca_call_cfunc_M_N` (= typed dispatcher) used by external CArray gems
|
|
5
5
|
# (carray-gsl, etc.) to wrap C math functions over CArray operations.
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
# attach-elimination flow extension (= D phase): the raw `ca_call_cfunc_N`
|
|
9
|
-
# template applies C.7-style alias / non-alias bifurcation for INPUT-only
|
|
7
|
+
# The raw `ca_call_cfunc_N` template splits alias / non-alias for INPUT-only
|
|
10
8
|
# operands (= fsync[k] == '0') and ca_xfer_all-based safe mask gather (= no
|
|
11
9
|
# `ca_attach` on operand masks). OUTPUT operands (= fsync[k] == '1') still
|
|
12
10
|
# use ca_attach + ca_sync (= legitimate per the refined input-only-operand
|
|
@@ -500,11 +498,9 @@ $src.puts <<~END_C
|
|
|
500
498
|
* file-static / global plumbing.
|
|
501
499
|
*
|
|
502
500
|
* Attach-safe: INPUT-only operands (= fsync[k] == '0') never call
|
|
503
|
-
* ca_attach on the operand or its mask (= alias check +
|
|
501
|
+
* ca_attach on the operand or its mask (= alias check + xmalloc +
|
|
504
502
|
* ca_xfer_all for non-alias). OUTPUT operands (= fsync[k] == '1')
|
|
505
|
-
* use ca_attach + ca_sync
|
|
506
|
-
* operand invariant established in PROPOSAL_EAGER_ELEMENTWISE_NO_ATTACH
|
|
507
|
-
* and extended in PROPOSAL_EAGER_SLOWPATH_CHUNKING_ARENA).
|
|
503
|
+
* use ca_attach + ca_sync.
|
|
508
504
|
*
|
|
509
505
|
* Slab variants `ca_call_cslab_N` / `ca_call_cslab_N_r` take the chunked
|
|
510
506
|
* path instead (ca_sweep_acquire_chunked / ca_sweep_next_chunk /
|
|
@@ -518,10 +514,9 @@ $src.puts <<~END_C
|
|
|
518
514
|
* function to wrap); use cslab when the operand is large, virtual, or the
|
|
519
515
|
* body is worth vectorising.
|
|
520
516
|
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
* file keeps the arity-dependent inner loop only. ABI unchanged.
|
|
517
|
+
* The per-operand acquire + broadcast check + mask OR + release lifecycle
|
|
518
|
+
* lives in ext/ca_sweep_engine.{c,h} (ca_sweep_acquire / ca_sweep_release).
|
|
519
|
+
* This file keeps the arity-dependent inner loop only.
|
|
525
520
|
*
|
|
526
521
|
* --------------------------------------------------------------------------- */
|
|
527
522
|
|
data/ext/mkkernel.rb
CHANGED
|
@@ -189,6 +189,17 @@ module MkKernel
|
|
|
189
189
|
}
|
|
190
190
|
end
|
|
191
191
|
|
|
192
|
+
# A power body: the exponents -2 .. 4 take at most two roundings
|
|
193
|
+
# (x * x, x * x * x, (x * x) * (x * x), 1 / x, 1 / (x * x)), the rest go
|
|
194
|
+
# to `general`. The Integer exponent kernel (ext/ca_op_ipower.c) takes
|
|
195
|
+
# the same ones, so an exponent answers alike as a scalar and as an array.
|
|
196
|
+
def self.pow_short(general)
|
|
197
|
+
"(#3) = (#2) == 2 ? (#1) * (#1) : (#2) == 3 ? (#1) * (#1) * (#1) : " \
|
|
198
|
+
"(#2) == 4 ? ((#1) * (#1)) * ((#1) * (#1)) : (#2) == 1 ? (#1) : " \
|
|
199
|
+
"(#2) == 0 ? 1 : (#2) == -1 ? 1 / (#1) : (#2) == -2 ? 1 / ((#1) * (#1)) : " \
|
|
200
|
+
"#{general};"
|
|
201
|
+
end
|
|
202
|
+
|
|
192
203
|
# Substitute the width markers in a kernel body.
|
|
193
204
|
def self.at_width(body, suffix, real_type)
|
|
194
205
|
body.gsub("<f>", suffix).gsub("<t>", real_type)
|
|
@@ -6799,11 +6810,14 @@ module MkKernel
|
|
|
6799
6810
|
|
|
6800
6811
|
# Kernels written outside this generator that a lazy expression can still
|
|
6801
6812
|
# hold. A Float or Complex array to an Integer power is CABinOp's ipow
|
|
6802
|
-
# (ext/ca_op_ipower.c,
|
|
6803
|
-
#
|
|
6804
|
-
EXTRA_BODY_ROWS =
|
|
6805
|
-
["binop", "ipow",
|
|
6806
|
-
|
|
6813
|
+
# (ext/ca_op_ipower.c, ca_ipow_<type>): #2 is an int64, converted as an
|
|
6814
|
+
# int64 cell is converted to the base's type, then the power body.
|
|
6815
|
+
EXTRA_BODY_ROWS = [
|
|
6816
|
+
["binop", "ipow", "float32", pow_short("powf((#1), (float)(double)(#2))")],
|
|
6817
|
+
["binop", "ipow", "float64", pow_short("pow((#1), (double)(#2))")],
|
|
6818
|
+
["binop", "ipow", "cmplx64", pow_short("cpow((#1), (float)(double)(#2))")],
|
|
6819
|
+
["binop", "ipow", "cmplx128", pow_short("cpow((#1), (double)(#2))")],
|
|
6820
|
+
].freeze
|
|
6807
6821
|
|
|
6808
6822
|
# The helpers the bodies call that are not in the C standard library:
|
|
6809
6823
|
# the part of ca_op_powi.h between its markers, as it stands.
|
|
@@ -9068,21 +9082,18 @@ MkKernel.monfunc :deg_360,
|
|
|
9068
9082
|
expr: {
|
|
9069
9083
|
float: <<~C,
|
|
9070
9084
|
{
|
|
9071
|
-
double
|
|
9072
|
-
|
|
9073
|
-
(#2)
|
|
9074
|
-
? (_fa - floor(_fa)) * 360.0
|
|
9075
|
-
: (_fa - ceil(_fa) + 1.0) * 360.0;
|
|
9085
|
+
double _fa = (double)(#1) / 360.0;
|
|
9086
|
+
(#2) = (_fa - floor(_fa)) * 360.0;
|
|
9087
|
+
if ( (#2) >= 360.0 ) (#2) = 0.0; /* a tiny negative rounds to the top */
|
|
9076
9088
|
}
|
|
9077
9089
|
C
|
|
9078
9090
|
object: <<~SNIPPET,
|
|
9079
9091
|
{
|
|
9080
9092
|
VALUE _obj_arg = (#1);
|
|
9081
9093
|
if (RB_FLOAT_TYPE_P(_obj_arg) || RB_INTEGER_TYPE_P(_obj_arg) || RB_TYPE_P(_obj_arg, T_RATIONAL)) {
|
|
9082
|
-
double
|
|
9083
|
-
double
|
|
9084
|
-
(#2) = DBL2NUM(
|
|
9085
|
-
: (_fa - ceil(_fa) + 1.0) * 360.0);
|
|
9094
|
+
double _fa = NUM2DBL(_obj_arg) / 360.0;
|
|
9095
|
+
double _r = (_fa - floor(_fa)) * 360.0;
|
|
9096
|
+
(#2) = DBL2NUM(_r >= 360.0 ? 0.0 : _r);
|
|
9086
9097
|
} else {
|
|
9087
9098
|
(#2) = rb_funcall(_obj_arg, rb_intern("deg_360"), 0);
|
|
9088
9099
|
}
|
|
@@ -9090,7 +9101,7 @@ MkKernel.monfunc :deg_360,
|
|
|
9090
9101
|
SNIPPET
|
|
9091
9102
|
}
|
|
9092
9103
|
|
|
9093
|
-
# deg_180: fold into
|
|
9104
|
+
# deg_180: fold into (-180, 180]. Preserves trailing `if (b <= -180)
|
|
9094
9105
|
# b += 360` guard from the legacy implementation.
|
|
9095
9106
|
MkKernel.monfunc :deg_180,
|
|
9096
9107
|
source: MkKernel::FLOAT_DTYPES + [:object],
|
|
@@ -9130,11 +9141,9 @@ MkKernel.monfunc :rad_2pi,
|
|
|
9130
9141
|
float: <<~C,
|
|
9131
9142
|
{
|
|
9132
9143
|
double _two_pi = 2.0 * M_PI;
|
|
9133
|
-
double
|
|
9134
|
-
|
|
9135
|
-
(#2)
|
|
9136
|
-
? (_fa - floor(_fa)) * _two_pi
|
|
9137
|
-
: (_fa - ceil(_fa) + 1.0) * _two_pi;
|
|
9144
|
+
double _fa = (double)(#1) / _two_pi;
|
|
9145
|
+
(#2) = (_fa - floor(_fa)) * _two_pi;
|
|
9146
|
+
if ( (#2) >= _two_pi ) (#2) = 0.0; /* a tiny negative rounds to the top */
|
|
9138
9147
|
}
|
|
9139
9148
|
C
|
|
9140
9149
|
object: <<~SNIPPET,
|
|
@@ -9142,10 +9151,9 @@ MkKernel.monfunc :rad_2pi,
|
|
|
9142
9151
|
VALUE _obj_arg = (#1);
|
|
9143
9152
|
if (RB_FLOAT_TYPE_P(_obj_arg) || RB_INTEGER_TYPE_P(_obj_arg) || RB_TYPE_P(_obj_arg, T_RATIONAL)) {
|
|
9144
9153
|
double _two_pi = 2.0 * M_PI;
|
|
9145
|
-
double
|
|
9146
|
-
double
|
|
9147
|
-
(#2) = DBL2NUM(
|
|
9148
|
-
: (_fa - ceil(_fa) + 1.0) * _two_pi);
|
|
9154
|
+
double _fa = NUM2DBL(_obj_arg) / _two_pi;
|
|
9155
|
+
double _r = (_fa - floor(_fa)) * _two_pi;
|
|
9156
|
+
(#2) = DBL2NUM(_r >= _two_pi ? 0.0 : _r);
|
|
9149
9157
|
} else {
|
|
9150
9158
|
(#2) = rb_funcall(_obj_arg, rb_intern("rad_2pi"), 0);
|
|
9151
9159
|
}
|
|
@@ -9404,7 +9412,9 @@ MkKernel.binop :bit_or_i,
|
|
|
9404
9412
|
kleene: :or,
|
|
9405
9413
|
source: MkKernel::INT_DTYPES + [:bool, :object],
|
|
9406
9414
|
expr: {
|
|
9407
|
-
|
|
9415
|
+
# 0 / 1 even when a side is a masked cell: its byte is not defined, and
|
|
9416
|
+
# an OR that Kleene resolves to true keeps the value written here.
|
|
9417
|
+
bool: "(#3) = ((#1) | (#2)) ? 1 : 0;",
|
|
9408
9418
|
int: "(#3) = (#1) | (#2);",
|
|
9409
9419
|
object: '(#3) = rb_funcall((#1), rb_intern("|"), 1, (#2));',
|
|
9410
9420
|
}
|
|
@@ -9607,9 +9617,9 @@ MkKernel.binop :power,
|
|
|
9607
9617
|
source: MkKernel::MATH_NUMERIC + [:object],
|
|
9608
9618
|
expr: {
|
|
9609
9619
|
int: "(#3) = op_powi_<type>((#1), (#2));",
|
|
9610
|
-
complex: "
|
|
9620
|
+
complex: MkKernel.pow_short("cpow((#1), (#2))"), # see exp2 on why cpow stays wide
|
|
9611
9621
|
object: '(#3) = rb_funcall((#1), rb_intern("**"), 1, (#2));',
|
|
9612
|
-
}.merge(MkKernel.float_widths("
|
|
9622
|
+
}.merge(MkKernel.float_widths(MkKernel.pow_short("pow<f>((#1), (#2))")))
|
|
9613
9623
|
|
|
9614
9624
|
# ---- M.2 + M.3 (PyTorch alignment): float-only binop family --------------
|
|
9615
9625
|
#
|
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.7"
|
|
2
|
+
#define CA_VERSION_CODE 30007
|
|
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 7
|
|
6
|
+
#define CA_VERSION_DATE "2026/11/03"
|
data/lib/carray/axis_group.rb
CHANGED
|
@@ -846,16 +846,19 @@ class CAGroupIterator
|
|
|
846
846
|
place = Array.new(gslots.size, 1) # place value per slot
|
|
847
847
|
(gslots.size - 2).downto(0) { |i| place[i] = place[i + 1] * gslots[i + 1][:k] }
|
|
848
848
|
comp = nil
|
|
849
|
+
groups = kdims.inject(1, :*)
|
|
849
850
|
gslots.each_with_index do |m, i|
|
|
850
851
|
target = Array.new(gb_rank, 1)
|
|
851
852
|
m[:axes].each { |a| target[gaxes.index(a)] = shape[a] }
|
|
852
853
|
term = m[:codes].reshape(*target)
|
|
854
|
+
# The composite code has to reach the last group in the codes' type.
|
|
855
|
+
term = term.int64 if groups > CACategorical::MAX_LABELS[term.data_type]
|
|
853
856
|
term = term * place[i] if place[i] != 1
|
|
854
857
|
comp = comp.nil? ? term : comp + term
|
|
855
858
|
end
|
|
856
859
|
gb_size = gaxes.map { |a| shape[a] }.inject(1, :*)
|
|
857
860
|
ccat = CACategorical.from_codes(comp.reshape(gb_size),
|
|
858
|
-
CArray.int32(
|
|
861
|
+
CArray.int32(groups).seq!)
|
|
859
862
|
[ccat, kdims, gslots, bslots, gaxes]
|
|
860
863
|
end
|
|
861
864
|
|
|
@@ -940,7 +943,7 @@ class CAGroupIterator
|
|
|
940
943
|
# and cumcount in int64 -- not the core's answer for a boolean's running sum.
|
|
941
944
|
def kernel_scans? (op)
|
|
942
945
|
return false unless CArray.__fast_paths_enabled__(:axis_group_scan_kernel)
|
|
943
|
-
return false if value.face? || value.complex?
|
|
946
|
+
return false if value.face? || value.complex? || value.data_type == CA_FIXLEN
|
|
944
947
|
return true if value.object? || op == :cumcount
|
|
945
948
|
core = CAIterator.core_probe(value).public_send(op).data_type
|
|
946
949
|
kernel = [:cumsum, :cumprod].include?(op) ? CA_FLOAT64 : value.data_type
|
|
@@ -977,10 +980,10 @@ class CAGroupIterator
|
|
|
977
980
|
end
|
|
978
981
|
|
|
979
982
|
# An array of +shape+ of the same kind as +model+ -- its data type, or its
|
|
980
|
-
# Face -- with every cell UNDEF. A
|
|
981
|
-
# cell, so its values are held in an object array.
|
|
983
|
+
# Face -- with every cell UNDEF. A Face that holds no new value cannot be
|
|
984
|
+
# written cell by cell, so its values are held in an object array.
|
|
982
985
|
def blank_of (model, shape)
|
|
983
|
-
out = if model.face? && model.
|
|
986
|
+
out = if model.face? && !model.__send__(:holds_new_values?)
|
|
984
987
|
CArray.new(CA_OBJECT, shape)
|
|
985
988
|
else
|
|
986
989
|
model.__send__(:blank_like, shape)
|
|
@@ -1058,7 +1061,7 @@ class CAGroupIterator
|
|
|
1058
1061
|
gb_rank = gaxes.size
|
|
1059
1062
|
gb_shape = gaxes.map { |a| shape[a] }
|
|
1060
1063
|
gb_size = gb_shape.inject(1, :*)
|
|
1061
|
-
nvalid = ccat.category_sizes.int64.sum
|
|
1064
|
+
nvalid = ccat.category_sizes.int64.sum.to_i
|
|
1062
1065
|
nband = bslots.map { |m| m[:len] }.inject(1, :*)
|
|
1063
1066
|
out = CArray.int64(nband * nvalid)
|
|
1064
1067
|
cursor = 0
|