carray 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +2 -1
- data/CHANGELOG.md +325 -3
- data/{NEWS.md → CHANGELOG.v1.md} +1 -1
- data/README.md +32 -32
- data/carray.gemspec +12 -8
- data/ext/ca_axis_group.c +55 -19
- data/ext/ca_binop_dispatch.c +5 -6
- data/ext/ca_binop_dispatch.h +0 -7
- data/ext/ca_categorical_iterator.c +13 -13
- data/ext/ca_for_each_element.h +6 -8
- data/ext/ca_group_iter.c +1 -1
- data/ext/ca_kernel_iterator.c +69 -23
- data/ext/ca_kernel_iterator.h +3 -10
- data/ext/ca_obj_bincmp.c +57 -27
- data/ext/ca_obj_binop.c +86 -30
- data/ext/ca_obj_const_string.c +3 -1
- data/ext/ca_obj_face.c +80 -0
- data/ext/ca_obj_face.h +33 -1
- data/ext/ca_obj_fake.c +11 -0
- data/ext/ca_obj_fixlen_string.c +3 -1
- data/ext/ca_obj_grid.c +11 -3
- data/ext/ca_obj_meld.c +13 -8
- data/ext/ca_obj_moncmp.c +33 -14
- data/ext/ca_obj_monop.c +19 -7
- data/ext/ca_obj_object.c +99 -4
- data/ext/ca_obj_record.c +3 -1
- data/ext/ca_obj_refer.c +30 -6
- data/ext/ca_obj_roll.c +13 -5
- data/ext/ca_obj_select_axis.c +16 -6
- data/ext/ca_obj_shift.c +3 -3
- data/ext/ca_obj_stride.c +106 -23
- data/ext/ca_obj_string.c +3 -1
- data/ext/ca_obj_tile.c +13 -5
- data/ext/ca_obj_time.c +3 -1
- data/ext/ca_obj_timedelta.c +3 -1
- data/ext/ca_obj_transpose.c +1 -1
- data/ext/ca_obj_triop.c +62 -23
- data/ext/ca_obj_window.c +86 -17
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +0 -3
- data/ext/ca_sort_kernels.h +5 -5
- data/ext/ca_sweep_engine.c +78 -35
- data/ext/ca_sweep_engine.h +13 -4
- data/ext/ca_transform_common.c +7 -0
- data/ext/carray.h +127 -130
- data/ext/carray_access.c +56 -34
- data/ext/carray_bincount.c +8 -8
- data/ext/carray_broadcast.c +99 -6
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +1491 -0
- data/ext/carray_call_cfunc.h +153 -0
- data/ext/carray_cast.c +69 -31
- data/ext/carray_conversion.c +22 -22
- data/ext/carray_copy.c +12 -2
- data/ext/carray_core.c +57 -10
- data/ext/carray_count.c +1 -1
- data/ext/carray_element.c +7 -7
- data/ext/carray_factorize.c +28 -28
- data/ext/carray_hold.c +1 -1
- data/ext/carray_index_classifier.c +7 -21
- data/ext/carray_internal.h +19 -3
- data/ext/carray_kernels_bincmp.c +1 -0
- data/ext/carray_kernels_binop.c +320 -298
- data/ext/carray_kernels_init.c +1095 -0
- data/ext/carray_kernels_map.c +1 -0
- data/ext/carray_kernels_moncmp.c +1 -0
- data/ext/carray_kernels_monop.c +412 -411
- data/ext/carray_kernels_reduce_aggregate.c +88 -87
- data/ext/carray_kernels_reduce_boolean.c +1 -0
- data/ext/carray_kernels_reduce_cumulative.c +54 -53
- data/ext/carray_kernels_reduce_extreme.c +51 -50
- data/ext/carray_kernels_reduce_variance.c +1 -0
- data/ext/carray_kernels_scan.c +1 -0
- data/ext/carray_kernels_search.c +93 -92
- data/ext/carray_kernels_sort.c +1 -0
- data/ext/carray_kernels_triop.c +1 -0
- data/ext/carray_lazy.c +175 -5
- data/ext/carray_mask.c +6 -5
- data/ext/carray_median_percentile.c +1 -1
- data/ext/carray_memory_view.c +46 -21
- data/ext/carray_operator.c +46 -49
- data/ext/carray_partition.c +4 -4
- data/ext/carray_random.c +7 -7
- data/ext/carray_scatter.c +1 -1
- data/ext/carray_sort.c +3 -3
- data/ext/carray_sort_kernel.c +10 -10
- data/ext/carray_test.c +1 -1
- data/ext/extconf.rb +18 -0
- data/ext/mk_call_cfunc.rb +243 -52
- data/ext/mkkernel.rb +354 -100
- data/ext/ruby_carray.c +18 -16
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +19 -0
- data/lib/carray/autoload_method_extension.rb +2 -1
- data/lib/carray/axis_group.rb +7 -7
- data/lib/carray/basics.rb +59 -59
- data/lib/carray/bincount_nd.rb +12 -12
- data/lib/carray/block_iterator.rb +24 -14
- data/lib/carray/categorical.rb +4 -4
- data/lib/carray/categorical_iterator.rb +98 -76
- data/lib/carray/conditional.rb +14 -14
- data/lib/carray/construct.rb +21 -0
- data/lib/carray/core_extensions.rb +62 -5
- data/lib/carray/data_type_extension.rb +18 -1
- data/lib/carray/frame/concat.rb +3 -3
- data/lib/carray/frame/convert.rb +1 -1
- data/lib/carray/frame/frame.rb +4 -11
- data/lib/carray/frame/io.rb +159 -2
- data/lib/carray/frame/sort.rb +1 -1
- data/lib/carray/frame/verbs.rb +18 -1
- data/lib/carray/fuse_source.rb +123 -0
- data/lib/carray/fusion.rb +218 -0
- data/lib/carray/histogram.rb +16 -16
- data/lib/carray/inspect.rb +1 -7
- data/lib/carray/iterator.rb +4 -3
- data/lib/carray/lazy.rb +125 -73
- data/lib/carray/meld_reduce.rb +2 -2
- data/lib/carray/methods/align_addr.rb +1 -1
- data/lib/carray/methods/composition.rb +1 -1
- data/lib/carray/methods/is_in.rb +12 -12
- data/lib/carray/methods/locate_addr.rb +6 -1
- data/lib/carray/methods/mask_duplicates.rb +1 -1
- data/lib/carray/methods/meshgrid.rb +4 -5
- data/lib/carray/methods/mode.rb +2 -2
- data/lib/carray/methods/nunique.rb +1 -1
- data/lib/carray/methods/snap.rb +7 -2
- data/lib/carray/methods/unique.rb +3 -3
- data/lib/carray/methods/value_counts.rb +2 -2
- data/lib/carray/runtime.rb +0 -19
- data/lib/carray/slab_iterator.rb +20 -7
- data/lib/carray/string_operation_extension.rb +5 -5
- data/lib/carray/time.rb +890 -491
- data/lib/carray/window_iterator.rb +285 -13
- data/lib/carray.rb +5 -5
- data/yard-stubs/ca_obj_array.rb +385 -0
- data/yard-stubs/ca_obj_bitarray.rb +38 -0
- data/yard-stubs/ca_obj_bitfield.rb +43 -0
- data/yard-stubs/ca_obj_block.rb +73 -0
- data/yard-stubs/ca_obj_byte_swap.rb +56 -0
- data/yard-stubs/ca_obj_fake.rb +31 -0
- data/yard-stubs/ca_obj_farray.rb +32 -0
- data/yard-stubs/ca_obj_field.rb +45 -0
- data/yard-stubs/ca_obj_grid.rb +35 -0
- data/yard-stubs/ca_obj_refer.rb +72 -0
- data/yard-stubs/ca_obj_roll.rb +45 -0
- data/yard-stubs/ca_obj_shift.rb +43 -0
- data/yard-stubs/ca_obj_stride.rb +181 -0
- data/yard-stubs/ca_obj_tile.rb +29 -0
- data/yard-stubs/ca_obj_transpose.rb +40 -0
- data/yard-stubs/ca_obj_window.rb +49 -0
- data/yard-stubs/carray_access.rb +131 -0
- data/yard-stubs/carray_attribute.rb +246 -0
- data/yard-stubs/carray_broadcast.rb +37 -0
- data/yard-stubs/carray_cast.rb +489 -0
- data/yard-stubs/carray_class.rb +65 -0
- data/yard-stubs/carray_conversion.rb +76 -0
- data/yard-stubs/carray_copy.rb +79 -0
- data/yard-stubs/carray_core.rb +114 -0
- data/yard-stubs/carray_count.rb +79 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +23 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +132 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +89 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +312 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +57 -0
- data/yard-stubs/carray_sort.rb +163 -0
- data/yard-stubs/carray_test.rb +85 -0
- data/yard-stubs/carray_undef.rb +64 -0
- data/yard-stubs/carray_utils.rb +97 -0
- data/yard-stubs/ruby_carray.rb +193 -0
- metadata +59 -10
- data/ext/ca_obj_unbound_repeat.c +0 -496
data/ext/carray_access.c
CHANGED
|
@@ -492,6 +492,14 @@ rb_ca_ref_all (VALUE self, CAIndexInfo *info)
|
|
|
492
492
|
return rb_funcall(self, rb_intern("refer"), 0);
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
+
static ID
|
|
496
|
+
ca_id_expression_evaluator (void)
|
|
497
|
+
{
|
|
498
|
+
static ID id = 0;
|
|
499
|
+
if ( ! id ) id = rb_intern("@expression_evaluator");
|
|
500
|
+
return id;
|
|
501
|
+
}
|
|
502
|
+
|
|
495
503
|
VALUE
|
|
496
504
|
rb_ca_store_all (VALUE self, VALUE rval)
|
|
497
505
|
{
|
|
@@ -515,16 +523,34 @@ rb_ca_store_all (VALUE self, VALUE rval)
|
|
|
515
523
|
CArray *cv;
|
|
516
524
|
TypedData_Get_Struct(rval, CArray, &carray_data_type, cv);
|
|
517
525
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
526
|
+
/* Where something is registered to compute an expression, and this is
|
|
527
|
+
one, it is asked before the walk below -- it fills the destination
|
|
528
|
+
directly, which is the whole of the saving; making an array and
|
|
529
|
+
copying it over is most of the work once the expression itself is
|
|
530
|
+
fast. It may decline, and then the walk does it. Narrow on purpose:
|
|
531
|
+
the same shape and data type, so nothing here has to broadcast or
|
|
532
|
+
cast on the way. */
|
|
533
|
+
if ( ca_is_lazy_view(cv)
|
|
534
|
+
&& ca->data_type == cv->data_type
|
|
535
|
+
&& ca->ndim == cv->ndim
|
|
536
|
+
&& ca->elements == cv->elements
|
|
537
|
+
&& RTEST(rb_attr_get(rb_cCArray, ca_id_expression_evaluator())) ) {
|
|
538
|
+
int8_t k;
|
|
539
|
+
int same = 1;
|
|
540
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
541
|
+
if ( ca->dim[k] != cv->dim[k] ) { same = 0; break; }
|
|
542
|
+
}
|
|
543
|
+
if ( same ) {
|
|
544
|
+
VALUE fusion = rb_const_get(rb_cCArray, rb_intern("Fusion"));
|
|
545
|
+
if ( RTEST(rb_funcall(fusion, rb_intern("evaluate_into"), 2, rval, self)) ) {
|
|
546
|
+
return rval;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
521
549
|
}
|
|
522
550
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
(ca_size_t) ca->elements, (ca_size_t) cv->elements);
|
|
527
|
-
}
|
|
551
|
+
/* The destination owns the shape; see ca_broadcast_to_destination. */
|
|
552
|
+
ca_broadcast_to_destination(self, &rval);
|
|
553
|
+
TypedData_Get_Struct(rval, CArray, &carray_data_type, cv);
|
|
528
554
|
|
|
529
555
|
/* Source delivery via ca_xfer_all into a local scratch instead of
|
|
530
556
|
ca_attach(cv). This routes through ca_*_func_xfer_all's per-region
|
|
@@ -985,7 +1011,16 @@ rb_ca_fetch_method (int argc, VALUE *argv, VALUE self)
|
|
|
985
1011
|
|
|
986
1012
|
switch ( info.type ) {
|
|
987
1013
|
case CA_REG_ADDRESS_COMPLEX:
|
|
1014
|
+
/* Re-enter against a flattened view of self. rb_ca_refer_new_flatten
|
|
1015
|
+
is an internal builder and hands back a bare refer, so a marker
|
|
1016
|
+
receiver would be dropped here and the result would never be lifted
|
|
1017
|
+
at the tail. Put it back on before the re-entry. (A Face survives
|
|
1018
|
+
on its own -- the internal builder still lifts those.) */
|
|
988
1019
|
self = rb_ca_refer_new_flatten(self);
|
|
1020
|
+
if ( ca_is_lazy_marker(ca) ) {
|
|
1021
|
+
extern VALUE rb_ca_lazy_marker_new (VALUE cary);
|
|
1022
|
+
self = rb_ca_lazy_marker_new(self);
|
|
1023
|
+
}
|
|
989
1024
|
goto retry;
|
|
990
1025
|
case CA_REG_ADDRESS:
|
|
991
1026
|
obj = rb_ca_ref_address(self, &info);
|
|
@@ -1011,9 +1046,6 @@ rb_ca_fetch_method (int argc, VALUE *argv, VALUE self)
|
|
|
1011
1046
|
case CA_REG_REPEAT:
|
|
1012
1047
|
obj = rb_ca_repeat(argc, argv, self);
|
|
1013
1048
|
break;
|
|
1014
|
-
case CA_REG_UNBOUND_REPEAT:
|
|
1015
|
-
obj = rb_funcall2(self, rb_intern("unbound_repeat"), (int) argc, argv);
|
|
1016
|
-
break;
|
|
1017
1049
|
case CA_REG_MAPPING:
|
|
1018
1050
|
obj = rb_ca_fancy_index_chain(self, argv[0]);
|
|
1019
1051
|
break;
|
|
@@ -1050,19 +1082,19 @@ rb_ca_fetch_method (int argc, VALUE *argv, VALUE self)
|
|
|
1050
1082
|
rb_raise(rb_eIndexError, "invalid index specified");
|
|
1051
1083
|
}
|
|
1052
1084
|
|
|
1053
|
-
/*
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1085
|
+
/* Wrapper lift at the read touch point: if `self` is a Face or a
|
|
1086
|
+
CALazyMarker, re-wrap the view result so the wrapper stays on top.
|
|
1087
|
+
Guarded to CArray results, which drops the scalar / CASlabIterator /
|
|
1088
|
+
CAGroupIterator / Hash cases the switch above can produce. The
|
|
1089
|
+
already-a-Face case (some builders lift their own result) is handled
|
|
1090
|
+
inside ca_wrapper_lift.
|
|
1091
|
+
|
|
1092
|
+
Every CA_REG_* branch converges here, so this one line covers all of
|
|
1093
|
+
them -- but not every index form: `a[:*, nil]` builds a CAUnboundRepeat,
|
|
1094
|
+
whose shape stays open until an operand binds it, and a marker copies
|
|
1095
|
+
shape at construction. ca_wrapper_lift refuses that one, in one place,
|
|
1096
|
+
because `unbound_repeat` reaches it by a second route. */
|
|
1097
|
+
CA_WRAPPER_LIFT(obj, self, ca);
|
|
1066
1098
|
|
|
1067
1099
|
return obj;
|
|
1068
1100
|
}
|
|
@@ -1305,9 +1337,6 @@ rb_cs_fetch_method (int argc, VALUE *argv, VALUE self)
|
|
|
1305
1337
|
case CA_REG_REPEAT:
|
|
1306
1338
|
obj = rb_ca_repeat(argc, argv, self);
|
|
1307
1339
|
break;
|
|
1308
|
-
case CA_REG_UNBOUND_REPEAT:
|
|
1309
|
-
obj = rb_funcall2(self, rb_intern("unbound_repeat"), (int) argc, argv);
|
|
1310
|
-
break;
|
|
1311
1340
|
case CA_REG_MAPPING:
|
|
1312
1341
|
obj = rb_ca_fancy_index_chain(self, argv[0]);
|
|
1313
1342
|
break;
|
|
@@ -1491,10 +1520,6 @@ rb_ca_store_method (int argc, VALUE *argv, VALUE self)
|
|
|
1491
1520
|
obj = rb_ca_store_all(obj, rval);
|
|
1492
1521
|
break;
|
|
1493
1522
|
}
|
|
1494
|
-
case CA_REG_UNBOUND_REPEAT:
|
|
1495
|
-
obj = rb_funcall2(self, rb_intern("unbound_repeat"), (int) argc, argv);
|
|
1496
|
-
obj = rb_ca_store_all(obj, rval);
|
|
1497
|
-
break;
|
|
1498
1523
|
case CA_REG_MAPPING: {
|
|
1499
1524
|
obj = rb_ca_fancy_index_chain(self, argv[0]);
|
|
1500
1525
|
obj = rb_ca_store_all(obj, rval);
|
|
@@ -1669,7 +1694,6 @@ rb_ca_s_scan_index (VALUE self, VALUE rdim, VALUE ridx)
|
|
|
1669
1694
|
case CA_REG_GRID:
|
|
1670
1695
|
case CA_REG_MAPPING:
|
|
1671
1696
|
case CA_REG_METHOD_CALL:
|
|
1672
|
-
case CA_REG_UNBOUND_REPEAT:
|
|
1673
1697
|
case CA_REG_MEMBER:
|
|
1674
1698
|
case CA_REG_ATTRIBUTE:
|
|
1675
1699
|
break;
|
|
@@ -2094,8 +2118,6 @@ Init_carray_access (void)
|
|
|
2094
2118
|
rb_define_const(rb_cObject, "CA_REG_MAPPING", INT2NUM(CA_REG_MAPPING));
|
|
2095
2119
|
rb_define_const(rb_cObject, "CA_REG_METHOD_CALL",
|
|
2096
2120
|
INT2NUM(CA_REG_METHOD_CALL));
|
|
2097
|
-
rb_define_const(rb_cObject, "CA_REG_UNBOUND_REPEAT",
|
|
2098
|
-
INT2NUM(CA_REG_UNBOUND_REPEAT));
|
|
2099
2121
|
rb_define_const(rb_cObject, "CA_REG_MEMBER", INT2NUM(CA_REG_MEMBER));
|
|
2100
2122
|
rb_define_const(rb_cObject, "CA_REG_ATTRIBUTE", INT2NUM(CA_REG_ATTRIBUTE));
|
|
2101
2123
|
|
data/ext/carray_bincount.c
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
carray_bincount.c — dedicated bincount kernels (count-only + weighted)
|
|
4
4
|
|
|
5
5
|
Tight per-element scatter into a pre-sized 1-D output buffer. The
|
|
6
|
-
inner loop reads labels in their native integer
|
|
6
|
+
inner loop reads labels in their native integer data type (no cast to
|
|
7
7
|
int64), skips per-iteration bounds checking (caller validates label
|
|
8
|
-
range), and emits the output
|
|
8
|
+
range), and emits the output data type directly.
|
|
9
9
|
|
|
10
|
-
Output
|
|
10
|
+
Output data type:
|
|
11
11
|
- count-only: UInt32 if length < 2^32, else UInt64.
|
|
12
12
|
- weighted: weights.data_type.
|
|
13
13
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
weight is also skipped (its label contributes 0).
|
|
16
16
|
|
|
17
17
|
Caller contract (= lib/carray/methods/bincount.rb's CArray#bincount):
|
|
18
|
-
- self is integer
|
|
18
|
+
- self is integer data type.
|
|
19
19
|
- length is the output size, pre-sized to max(length, label_max+1)
|
|
20
20
|
with label_min >= 0 already verified.
|
|
21
21
|
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
|
|
31
31
|
#include "carray.h"
|
|
32
32
|
|
|
33
|
-
/* Tight inner loop: 2 mask-aware variants × 8 label
|
|
34
|
-
|
|
33
|
+
/* Tight inner loop: 2 mask-aware variants × 8 label data types × 2 output
|
|
34
|
+
data types = 32 specializations. Generated via macro expansion.
|
|
35
35
|
|
|
36
36
|
Layout:
|
|
37
37
|
COUNT_KERNEL(LABEL_T, OUT_T)
|
|
@@ -91,7 +91,7 @@ rb_ca_bincount_count_kernel (VALUE self, VALUE rlength)
|
|
|
91
91
|
rb_raise(rb_eArgError, "bincount: length must be non-negative");
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
/* Output
|
|
94
|
+
/* Output data type: UInt32 default; UInt64 if length doesn't fit. */
|
|
95
95
|
out_type = (length > 0xFFFFFFFFLL) ? CA_UINT64 : CA_UINT32;
|
|
96
96
|
shape_out[0] = length;
|
|
97
97
|
vout = rb_carray_new(out_type, 1, shape_out, 0, NULL);
|
|
@@ -125,7 +125,7 @@ rb_ca_bincount_count_kernel (VALUE self, VALUE rlength)
|
|
|
125
125
|
|
|
126
126
|
/* --------------------------------------------------------------- */
|
|
127
127
|
|
|
128
|
-
/* Weighted variant: output
|
|
128
|
+
/* Weighted variant: output data type = weights data type.
|
|
129
129
|
Inner: out[label[i]] += weight[i].
|
|
130
130
|
Mask: skip if label[i] masked OR weight[i] masked. */
|
|
131
131
|
|
data/ext/carray_broadcast.c
CHANGED
|
@@ -12,10 +12,12 @@
|
|
|
12
12
|
ca_broadcast_pair (&self, &other)
|
|
13
13
|
Two-sided expansion for binary ops (case A only: same ndim,
|
|
14
14
|
size-1 axes broadcast pairwise). Leaves both operands
|
|
15
|
-
unchanged when shapes are already equal
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
coercion path and by the binop
|
|
15
|
+
unchanged when shapes are already equal, and raises when they
|
|
16
|
+
cannot be paired: both operands of a binary operation are
|
|
17
|
+
equally authoritative, so a shape conflict has no resolution.
|
|
18
|
+
Called by carray_cast.c's coercion path and by the binop,
|
|
19
|
+
bincmp and triop builders, which is every place two operands
|
|
20
|
+
are brought together.
|
|
19
21
|
|
|
20
22
|
rb_ca_broadcast_to -- backs the public CArray#broadcast_to method
|
|
21
23
|
(right-to-left axis pairing; see the docstring at the function).
|
|
@@ -29,6 +31,75 @@
|
|
|
29
31
|
|
|
30
32
|
#include "carray.h"
|
|
31
33
|
|
|
34
|
+
NORETURN(static void ca_broadcast_refuse_write (VALUE dst, VALUE src));
|
|
35
|
+
|
|
36
|
+
/* Report a source that cannot be brought to the destination's shape. */
|
|
37
|
+
static void
|
|
38
|
+
ca_broadcast_refuse_write (VALUE dst, VALUE src)
|
|
39
|
+
{
|
|
40
|
+
volatile VALUE dst_s = rb_inspect(rb_funcall(dst, rb_intern("shape"), 0));
|
|
41
|
+
volatile VALUE src_s = rb_inspect(rb_funcall(src, rb_intern("shape"), 0));
|
|
42
|
+
rb_raise(rb_eRuntimeError,
|
|
43
|
+
"shape mismatch writing to carray (%s <- %s); shapes must agree "
|
|
44
|
+
"once size-1 axes are dropped, or one side must be 1-D, or the "
|
|
45
|
+
"source must be smaller and broadcastable -- use .flatten to "
|
|
46
|
+
"write the values in the order they lie",
|
|
47
|
+
StringValueCStr(dst_s), StringValueCStr(src_s));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Bring `*src` to `dst`'s shape for a write into `dst` (assignment, and
|
|
51
|
+
the in-place operators, whose result shape is the destination's by
|
|
52
|
+
definition). The destination owns the shape and the source only
|
|
53
|
+
supplies values, so what is allowed here is wider than what two
|
|
54
|
+
operands of a binary operation may do -- but only where nothing is
|
|
55
|
+
duplicated. When the counts already agree the values land in the
|
|
56
|
+
order they lie and the shape is merely a reading of them: shapes that
|
|
57
|
+
both sides claim must agree once size-1 axes are dropped, since such
|
|
58
|
+
an axis moves no element, and a 1-D side claims no shape at all,
|
|
59
|
+
whether it is the flat source or the flat container. When the source
|
|
60
|
+
is smaller it is repeated instead, and that is held to same-ndim
|
|
61
|
+
size-1 and is one-sided: the destination never grows. Raises when
|
|
62
|
+
neither reading applies. */
|
|
63
|
+
void
|
|
64
|
+
ca_broadcast_to_destination (VALUE dst, volatile VALUE *src)
|
|
65
|
+
{
|
|
66
|
+
CArray *cd, *cs;
|
|
67
|
+
|
|
68
|
+
TypedData_Get_Struct(dst, CArray, &carray_data_type, cd);
|
|
69
|
+
TypedData_Get_Struct(*src, CArray, &carray_data_type, cs);
|
|
70
|
+
|
|
71
|
+
if ( cs->elements == cd->elements ) {
|
|
72
|
+
ca_size_t dst_dim[CA_RANK_MAX], src_dim[CA_RANK_MAX];
|
|
73
|
+
int dst_ndim = 0, src_ndim = 0, i, agree;
|
|
74
|
+
if ( cd->ndim <= 1 || cs->ndim <= 1 ) return;
|
|
75
|
+
for ( i = 0; i < cd->ndim; i++ ) {
|
|
76
|
+
if ( cd->dim[i] != 1 ) dst_dim[dst_ndim++] = cd->dim[i];
|
|
77
|
+
}
|
|
78
|
+
for ( i = 0; i < cs->ndim; i++ ) {
|
|
79
|
+
if ( cs->dim[i] != 1 ) src_dim[src_ndim++] = cs->dim[i];
|
|
80
|
+
}
|
|
81
|
+
agree = ( dst_ndim == src_ndim );
|
|
82
|
+
for ( i = 0; agree && i < dst_ndim; i++ ) {
|
|
83
|
+
if ( dst_dim[i] != src_dim[i] ) agree = 0;
|
|
84
|
+
}
|
|
85
|
+
if ( ! agree ) ca_broadcast_refuse_write(dst, *src);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if ( cs->elements < cd->elements && cs->ndim == cd->ndim ) {
|
|
90
|
+
int i;
|
|
91
|
+
for ( i = 0; i < cd->ndim; i++ ) {
|
|
92
|
+
if ( cs->dim[i] != cd->dim[i] && cs->dim[i] != 1 ) break;
|
|
93
|
+
}
|
|
94
|
+
if ( i == cd->ndim ) {
|
|
95
|
+
*src = ca_broadcast_view(*src, cd->ndim, cd->dim);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
ca_broadcast_refuse_write(dst, *src);
|
|
101
|
+
}
|
|
102
|
+
|
|
32
103
|
/* Build a CAStride view of `src` with shape `target_dim`. For each
|
|
33
104
|
axis where src.dim[i] == target_dim[i], inherit the row-major byte
|
|
34
105
|
stride; for src.dim[i] == 1 and target_dim[i] > 1, use stride 0.
|
|
@@ -99,6 +170,24 @@ ca_broadcast_view (VALUE src, int8_t ndim, ca_size_t *target_dim)
|
|
|
99
170
|
pairwise equal, no-op. If any axis pair is incompatible (neither
|
|
100
171
|
side is 1 nor equal), no-op (caller's existing element-count check
|
|
101
172
|
raises). */
|
|
173
|
+
NORETURN(static void ca_broadcast_refuse (VALUE self, VALUE other));
|
|
174
|
+
|
|
175
|
+
/* Report a pair that cannot be brought to a common shape. Naming both
|
|
176
|
+
shapes is the point of the message: the caller wrote two arrays that
|
|
177
|
+
cannot be combined, and the only remedy is to say which two. */
|
|
178
|
+
static void
|
|
179
|
+
ca_broadcast_refuse (VALUE self, VALUE other)
|
|
180
|
+
{
|
|
181
|
+
volatile VALUE self_s = rb_inspect(rb_funcall(self, rb_intern("shape"), 0));
|
|
182
|
+
volatile VALUE other_s = rb_inspect(rb_funcall(other, rb_intern("shape"), 0));
|
|
183
|
+
rb_raise(rb_eArgError,
|
|
184
|
+
"shape mismatch between operands (%s and %s); shapes must "
|
|
185
|
+
"agree, or differ only in size-1 axes with equal ndim -- use "
|
|
186
|
+
".flatten on both sides to operate on the values in the order "
|
|
187
|
+
"they lie",
|
|
188
|
+
StringValueCStr(self_s), StringValueCStr(other_s));
|
|
189
|
+
}
|
|
190
|
+
|
|
102
191
|
void
|
|
103
192
|
ca_broadcast_pair (volatile VALUE *self, volatile VALUE *other)
|
|
104
193
|
{
|
|
@@ -111,8 +200,11 @@ ca_broadcast_pair (volatile VALUE *self, volatile VALUE *other)
|
|
|
111
200
|
TypedData_Get_Struct(*self, CArray, &carray_data_type, ca);
|
|
112
201
|
TypedData_Get_Struct(*other, CArray, &carray_data_type, cb);
|
|
113
202
|
|
|
203
|
+
/* A scalar carries no shape and reaches every cell; leave the pair to
|
|
204
|
+
the caller's own scalar handling. A one-element array is not a
|
|
205
|
+
scalar: it states a shape, and is held to it. */
|
|
114
206
|
if (ca_is_scalar(ca) || ca_is_scalar(cb)) return;
|
|
115
|
-
if (ca->ndim != cb->ndim)
|
|
207
|
+
if (ca->ndim != cb->ndim) ca_broadcast_refuse(*self, *other);
|
|
116
208
|
if (ca->ndim == 0) return;
|
|
117
209
|
|
|
118
210
|
for (i = 0; i < ca->ndim; i++) {
|
|
@@ -133,7 +225,8 @@ ca_broadcast_pair (volatile VALUE *self, volatile VALUE *other)
|
|
|
133
225
|
}
|
|
134
226
|
}
|
|
135
227
|
|
|
136
|
-
if (!can_broadcast
|
|
228
|
+
if (!can_broadcast) ca_broadcast_refuse(*self, *other);
|
|
229
|
+
if (!needs_broadcast) return;
|
|
137
230
|
|
|
138
231
|
*self = ca_broadcast_view(*self, ca->ndim, target_dim);
|
|
139
232
|
*other = ca_broadcast_view(*other, ca->ndim, target_dim);
|