carray 3.0.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +520 -0
- data/README.md +2 -2
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +33 -4
- data/ext/ca_axis_group.c +202 -96
- data/ext/ca_categorical_iterator.c +108 -54
- data/ext/ca_kernel_iterator.c +317 -51
- data/ext/ca_kernel_iterator.h +142 -35
- data/ext/ca_obj_array.c +62 -20
- data/ext/ca_obj_block.c +4 -4
- data/ext/ca_obj_const_string.c +85 -26
- data/ext/ca_obj_face.c +24 -0
- data/ext/ca_obj_face.h +15 -0
- data/ext/ca_obj_fixlen_string.c +18 -5
- data/ext/ca_obj_meld.c +123 -25
- data/ext/ca_obj_object.c +8 -0
- data/ext/ca_obj_select.c +49 -34
- data/ext/ca_obj_stack.c +3 -8
- data/ext/ca_obj_stride.c +72 -1
- data/ext/ca_obj_string.c +8 -4
- data/ext/ca_obj_window.c +8 -2
- data/ext/ca_op_ipower.c +1 -2
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sweep_engine.c +307 -143
- data/ext/ca_sweep_engine.h +26 -5
- data/ext/carray.h +21 -2
- data/ext/carray_access.c +32 -20
- data/ext/carray_address_basis.c +590 -0
- data/ext/carray_broadcast.c +3 -3
- data/ext/carray_call_cfunc.c +667 -483
- data/ext/carray_cast.c +115 -41
- data/ext/carray_copy.c +55 -30
- data/ext/carray_core.c +83 -3
- data/ext/carray_count.c +9 -10
- data/ext/carray_factorize.c +46 -25
- data/ext/carray_internal.h +17 -0
- data/ext/carray_kernels_reduce_aggregate.c +168 -0
- data/ext/carray_kernels_reduce_cumulative.c +270 -1
- data/ext/carray_kernels_reduce_extreme.c +554 -8
- data/ext/carray_kernels_scan.c +4 -4
- data/ext/carray_kernels_search.c +94 -14
- data/ext/carray_loop.c +7 -1
- data/ext/carray_mask.c +23 -8
- data/ext/carray_median_percentile.c +55 -0
- data/ext/carray_operator.c +4 -4
- data/ext/carray_order.c +1 -1
- data/ext/carray_random.c +384 -40
- data/ext/carray_slab.c +13 -0
- data/ext/carray_sort.c +20 -22
- data/ext/mk_call_cfunc.rb +103 -116
- data/ext/mkkernel.rb +297 -29
- data/ext/ruby_carray.c +10 -1
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +5 -3
- data/lib/carray/autoload_method_extension.rb +12 -0
- data/lib/carray/axis_group.rb +77 -0
- data/lib/carray/basics.rb +4 -0
- data/lib/carray/block_iterator.rb +92 -16
- data/lib/carray/categorical.rb +150 -33
- data/lib/carray/categorical_iterator.rb +207 -80
- data/lib/carray/const_string.rb +131 -27
- data/lib/carray/construct.rb +40 -0
- data/lib/carray/data_type_extension.rb +3 -0
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/csv_parser.rb +11 -4
- data/lib/carray/frame/frame.rb +81 -10
- data/lib/carray/frame/group.rb +36 -3
- data/lib/carray/frame/io.rb +67 -15
- data/lib/carray/frame/records.rb +18 -4
- data/lib/carray/frame/verbs.rb +14 -11
- data/lib/carray/inspect.rb +42 -9
- data/lib/carray/iterator.rb +143 -0
- data/lib/carray/lazy.rb +0 -37
- data/lib/carray/mask_gap_fill.rb +3 -1
- data/lib/carray/methods/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/is_in.rb +13 -2
- data/lib/carray/methods/locate_addr.rb +75 -2
- data/lib/carray/methods/mask_duplicates.rb +35 -1
- data/lib/carray/methods/nunique.rb +22 -1
- data/lib/carray/methods/repeat.rb +110 -0
- data/lib/carray/methods/unique.rb +41 -1
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/slab_iterator.rb +58 -13
- data/lib/carray/string_operation_extension.rb +5 -1
- data/lib/carray/time.rb +18 -2
- data/lib/carray/window_iterator.rb +142 -20
- data/lib/carray.rb +2 -0
- data/yard-stubs/ca_obj_block.rb +2 -7
- data/yard-stubs/ca_obj_window.rb +10 -2
- data/yard-stubs/carray_access.rb +1 -1
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_core.rb +0 -80
- data/yard-stubs/carray_count.rb +7 -2
- data/yard-stubs/carray_lazy.rb +205 -0
- data/yard-stubs/carray_math.rb +1486 -3
- data/yard-stubs/carray_median_percentile.rb +16 -2
- data/yard-stubs/carray_order.rb +9 -69
- data/yard-stubs/carray_slab.rb +9 -7
- data/yard-stubs/carray_sort.rb +7 -5
- metadata +9 -1
data/ext/ca_obj_face.h
CHANGED
|
@@ -259,6 +259,21 @@ void ca_face_register_state_portable (int obj_type, int portable);
|
|
|
259
259
|
(= falls through to default). */
|
|
260
260
|
int ca_face_state_portable (int obj_type, VALUE klass);
|
|
261
261
|
|
|
262
|
+
/* Bring a Face *operand* into the reference's storage space, or refuse.
|
|
263
|
+
|
|
264
|
+
The gate asks `fz_face_descend`'s question -- "is your storage your
|
|
265
|
+
surface?" -- of the receiver, and for a long time asked nothing at all of
|
|
266
|
+
the operand: a COMPARABLE receiver stripped any Face handed to it, and got
|
|
267
|
+
back that Face's encoding rather than its values. Where the two encodings
|
|
268
|
+
happened to be the same width the comparison then answered, wrongly and
|
|
269
|
+
silently. Call this instead of stripping an operand by hand.
|
|
270
|
+
|
|
271
|
+
A Face passes only if it declares COMPARABLE_STORAGE, i.e. its storage
|
|
272
|
+
cells *are* the values it shows. Anything else -- a byte range, a code, a
|
|
273
|
+
tick -- is refused rather than compared as bytes. Non-Face operands are
|
|
274
|
+
returned untouched. `name` opens the message. */
|
|
275
|
+
VALUE ca_face_operand_descend (VALUE operand, const char *name);
|
|
276
|
+
|
|
262
277
|
#define CA_FACE_STORAGE_TO_SCALAR_IF_FACE(obj, self, ca) do { \
|
|
263
278
|
if ( ca_is_face(ca) && (obj) != CA_UNDEF && (obj) != Qnil \
|
|
264
279
|
&& ! rb_obj_is_kind_of((obj), rb_cCArray) ) { \
|
data/ext/ca_obj_fixlen_string.c
CHANGED
|
@@ -91,11 +91,24 @@ ca_fixlen_string_setup (CAFixlenString *ca, CArray *parent)
|
|
|
91
91
|
|
|
92
92
|
ca->obj_type = CA_OBJ_FIXLEN_STRING;
|
|
93
93
|
ca->data_type = CA_FIXLEN;
|
|
94
|
-
/* ORDERABLE + COMPARABLE
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
/* ORDERABLE + COMPARABLE. The descent is NOT the identity map -- the
|
|
95
|
+
scalar decode below strips trailing NUL -- but both flags still hold,
|
|
96
|
+
for a reason worth stating exactly, since it is what a Face author
|
|
97
|
+
copying this would need:
|
|
98
|
+
|
|
99
|
+
ORDERABLE: every cell is padded to the same K with NUL, and NUL is
|
|
100
|
+
the smallest byte, so memcmp on the padded cells orders them the same
|
|
101
|
+
way String#<=> orders the stripped strings (a prefix sorts before any
|
|
102
|
+
continuation, which is what the padding reproduces). Stripping is
|
|
103
|
+
order-preserving; it is not order-irrelevant by being absent.
|
|
104
|
+
|
|
105
|
+
COMPARABLE: a String query is padded out to the cell width before it
|
|
106
|
+
is compared, so byte equality on the padded form is equality on the
|
|
107
|
+
stripped form -- for a query that fits. A query longer than K is
|
|
108
|
+
truncated to its own first K bytes by that same padding step, and
|
|
109
|
+
then matches a cell it is not equal to.
|
|
110
|
+
|
|
111
|
+
Which is what the equality families need (docs/topics/CAFace.md §6.3).
|
|
99
112
|
Without the flags the sort family still worked (it exempts CA_FIXLEN
|
|
100
113
|
storage from the gate and orders by memcmp), but the value-hash family
|
|
101
114
|
handed its results back as a plain fixlen array, and search refused a
|
data/ext/ca_obj_meld.c
CHANGED
|
@@ -39,6 +39,8 @@
|
|
|
39
39
|
---------------------------------------------------------------------------- */
|
|
40
40
|
|
|
41
41
|
#include "carray.h"
|
|
42
|
+
#include "carray_internal.h" /* ca_attach_all */
|
|
43
|
+
#include "ca_obj_face.h" /* ca_face_state_portable */
|
|
42
44
|
|
|
43
45
|
/* ------------------------------------------------------------------- */
|
|
44
46
|
/* TypedData */
|
|
@@ -150,6 +152,19 @@ ca_meld_setup (CAMeld *ca, int32_t n_parents, CArray **parents, int8_t meld_axis
|
|
|
150
152
|
int32_t i;
|
|
151
153
|
int8_t a;
|
|
152
154
|
|
|
155
|
+
/* Pre-strip Face parents one level to storage, as CAStack does, so a
|
|
156
|
+
melded Face lifts to a single-Face chain (CATime[CAMeld[entity, ...]])
|
|
157
|
+
rather than a Face sitting on Face parents. One level, not a full walk,
|
|
158
|
+
preserves any distinct Face a parent melded underneath. A Face is
|
|
159
|
+
storage-transparent, so welding over storage reads the same bytes; the
|
|
160
|
+
lifted top Face (rb_ca_meld_s_new) carries the identity. The @parents
|
|
161
|
+
accessor keeps the originals, which the callers set. */
|
|
162
|
+
for ( i = 0; i < n_parents; i++ ) {
|
|
163
|
+
if ( ca_is_face(parents[i]) ) {
|
|
164
|
+
parents[i] = CAVIEW(parents[i])->parent;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
153
168
|
ca_meld_check_uniform(n_parents, parents, meld_axis);
|
|
154
169
|
ref = parents[0];
|
|
155
170
|
|
|
@@ -601,21 +616,6 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
601
616
|
s = ca->bytes;
|
|
602
617
|
for ( i = ca->ndim - 1; i >= 0; i-- ) { native[i] = s; s *= ca->dim[i]; }
|
|
603
618
|
|
|
604
|
-
/* Bound check on meld_axis. The step along the axis is strides[ma] /
|
|
605
|
-
native[ma] and it can be negative -- a reversed read starts at the far
|
|
606
|
-
end and walks down -- so the region runs between the first and last
|
|
607
|
-
index, which is not the same as starts[ma] .. starts[ma] + counts[ma]. */
|
|
608
|
-
{
|
|
609
|
-
ca_size_t step = strides[ma] / native[ma];
|
|
610
|
-
ca_size_t last = starts[ma] + (counts[ma] - 1) * step;
|
|
611
|
-
ca_size_t req_lo = ( last < starts[ma] ) ? last : starts[ma];
|
|
612
|
-
ca_size_t req_hi = (( last < starts[ma] ) ? starts[ma] : last) + 1;
|
|
613
|
-
if ( counts[ma] > 0 && ( req_lo < 0 || req_hi > ca->dim[ma] ) ) {
|
|
614
|
-
rb_raise(rb_eIndexError,
|
|
615
|
-
"CAMeld xfer_stride meld_axis (axis %d) [%lld, %lld) out of range [0, %lld)",
|
|
616
|
-
(int) ma, (long long) req_lo, (long long) req_hi, (long long) ca->dim[ma]);
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
619
|
for ( i = 0; i < ca->ndim; i++ ) {
|
|
620
620
|
if ( strides[i] != native[i] ) { structural = 0; break; }
|
|
621
621
|
}
|
|
@@ -624,6 +624,23 @@ ca_meld_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
624
624
|
ca_meld_xfer_stride_per_cell(ca, starts, counts, strides, data, dir);
|
|
625
625
|
return;
|
|
626
626
|
}
|
|
627
|
+
|
|
628
|
+
/* Bound check on meld_axis, after the gate and not before it. Only once
|
|
629
|
+
strides == native is established does request axis ma mean view axis ma;
|
|
630
|
+
asked earlier, strides[ma] / native[ma] is not a step along the meld axis
|
|
631
|
+
and legal requests get rejected. Inside the gate the step is 1, so the
|
|
632
|
+
region is starts[ma] .. starts[ma] + counts[ma]. ca_meld_xfer_stride_ma_
|
|
633
|
+
internal below is handed no strides at all and depends on both facts. */
|
|
634
|
+
{
|
|
635
|
+
ca_size_t req_lo = starts[ma];
|
|
636
|
+
ca_size_t req_hi = starts[ma] + counts[ma];
|
|
637
|
+
if ( counts[ma] > 0 && ( req_lo < 0 || req_hi > ca->dim[ma] ) ) {
|
|
638
|
+
rb_raise(rb_eIndexError,
|
|
639
|
+
"CAMeld xfer_stride meld_axis (axis %d) [%lld, %lld) out of range [0, %lld)",
|
|
640
|
+
(int) ma, (long long) req_lo, (long long) req_hi, (long long) ca->dim[ma]);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
627
644
|
if ( ma == 0 ) {
|
|
628
645
|
ca_meld_xfer_stride_ma0(ca, starts, counts, strides, data, dir);
|
|
629
646
|
} else {
|
|
@@ -770,10 +787,7 @@ static void
|
|
|
770
787
|
ca_meld_func_allocate (void *ap)
|
|
771
788
|
{
|
|
772
789
|
CAMeld *ca = (CAMeld *) ap;
|
|
773
|
-
|
|
774
|
-
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
775
|
-
ca_attach(ca->parents[k]);
|
|
776
|
-
}
|
|
790
|
+
ca_attach_all(ca->parents, ca->n_parents);
|
|
777
791
|
ca->ptr = xmalloc(ca_length(ca));
|
|
778
792
|
}
|
|
779
793
|
|
|
@@ -781,10 +795,7 @@ static void
|
|
|
781
795
|
ca_meld_func_attach (void *ap)
|
|
782
796
|
{
|
|
783
797
|
CAMeld *ca = (CAMeld *) ap;
|
|
784
|
-
|
|
785
|
-
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
786
|
-
ca_attach(ca->parents[k]);
|
|
787
|
-
}
|
|
798
|
+
ca_attach_all(ca->parents, ca->n_parents);
|
|
788
799
|
ca->ptr = xmalloc(ca_length(ca));
|
|
789
800
|
ca_meld_func_xfer_all(ca, ca->ptr, CA_XFER_GET);
|
|
790
801
|
}
|
|
@@ -887,6 +898,17 @@ ca_operation_function_t ca_meld_func = {
|
|
|
887
898
|
/* Ruby surface */
|
|
888
899
|
/* ------------------------------------------------------------------- */
|
|
889
900
|
|
|
901
|
+
/* One-level strip of a Face VALUE to its storage-side parent (non-Face as-is).
|
|
902
|
+
Keeps the @parent ivar in step with the pre-stripped C parents, so the
|
|
903
|
+
Ruby-visible chain of a melded Face is single-Face too. */
|
|
904
|
+
static VALUE
|
|
905
|
+
ca_meld_face_parent1 (VALUE v)
|
|
906
|
+
{
|
|
907
|
+
CArray *c;
|
|
908
|
+
TypedData_Get_Struct(v, CArray, &carray_data_type, c);
|
|
909
|
+
return ca_is_face(c) ? rb_ca_parent(v) : v;
|
|
910
|
+
}
|
|
911
|
+
|
|
890
912
|
VALUE
|
|
891
913
|
rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
|
|
892
914
|
{
|
|
@@ -910,7 +932,7 @@ rb_ca_meld_new (VALUE parents_ary, int8_t meld_axis)
|
|
|
910
932
|
ca = ca_meld_new((int32_t) n, parents, meld_axis);
|
|
911
933
|
obj = ca_wrap_struct(ca);
|
|
912
934
|
rb_ivar_set(obj, id_parents, rb_ary_dup(parents_ary));
|
|
913
|
-
rb_ca_set_parent(obj, rb_ary_entry(parents_ary, 0));
|
|
935
|
+
rb_ca_set_parent(obj, ca_meld_face_parent1(rb_ary_entry(parents_ary, 0)));
|
|
914
936
|
ALLOCV_END(holder);
|
|
915
937
|
return obj;
|
|
916
938
|
}
|
|
@@ -967,11 +989,86 @@ rb_ca_meld_initialize (int argc, VALUE *argv, VALUE self)
|
|
|
967
989
|
}
|
|
968
990
|
ca_meld_setup(ca, (int32_t) n, parents, meld_axis);
|
|
969
991
|
rb_ivar_set(self, id_parents, rb_ary_dup(list));
|
|
970
|
-
rb_ca_set_parent(self, rb_ary_entry(list, 0));
|
|
992
|
+
rb_ca_set_parent(self, ca_meld_face_parent1(rb_ary_entry(list, 0)));
|
|
971
993
|
ALLOCV_END(holder);
|
|
972
994
|
return self;
|
|
973
995
|
}
|
|
974
996
|
|
|
997
|
+
/* CAMeld.new(list, axis: 0) -- Class#new override, the twin of
|
|
998
|
+
rb_ca_stack_s_new. A melded view has one surface over many parents, so a
|
|
999
|
+
homogeneous Face list is treated the way CAStack treats it: refuse a Face
|
|
1000
|
+
whose state is per-parent (the cells of parent i are only readable against
|
|
1001
|
+
parent i's own state -- a CAConstString's cells are byte ranges into ITS
|
|
1002
|
+
buffer), and lift the rest so the Face survives the weld.
|
|
1003
|
+
|
|
1004
|
+
Without this meld was the one multi-parent constructor that neither asked
|
|
1005
|
+
nor lifted: it returned the raw storage of whatever it was given, which for
|
|
1006
|
+
CAConstString meant 16-byte (start,end) pairs presented as the string cells,
|
|
1007
|
+
and for CATime meant raw int64 ticks. Both looked like data.
|
|
1008
|
+
|
|
1009
|
+
Doing it here rather than in CArray.meld covers CAFrame.meld and a direct
|
|
1010
|
+
CAMeld.new by the same check. */
|
|
1011
|
+
static VALUE
|
|
1012
|
+
rb_ca_meld_s_new (int argc, VALUE *argv, VALUE klass)
|
|
1013
|
+
{
|
|
1014
|
+
VALUE list, kwargs;
|
|
1015
|
+
long n, i;
|
|
1016
|
+
int all_face = 1;
|
|
1017
|
+
VALUE face_class = Qnil;
|
|
1018
|
+
CArray *ref_face = NULL;
|
|
1019
|
+
VALUE obj;
|
|
1020
|
+
|
|
1021
|
+
rb_scan_args(argc, argv, "1:", &list, &kwargs);
|
|
1022
|
+
Check_Type(list, T_ARRAY);
|
|
1023
|
+
n = RARRAY_LEN(list);
|
|
1024
|
+
if ( n <= 0 ) {
|
|
1025
|
+
rb_raise(rb_eArgError, "CAMeld.new requires at least one parent");
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
for ( i = 0; i < n; i++ ) {
|
|
1029
|
+
VALUE p = rb_ary_entry(list, i);
|
|
1030
|
+
CArray *ca;
|
|
1031
|
+
rb_check_carray_object(p);
|
|
1032
|
+
TypedData_Get_Struct(p, CArray, &carray_data_type, ca);
|
|
1033
|
+
if ( !ca_is_face(ca) ) { all_face = 0; break; }
|
|
1034
|
+
if ( i == 0 ) {
|
|
1035
|
+
face_class = rb_obj_class(p);
|
|
1036
|
+
ref_face = ca;
|
|
1037
|
+
} else if ( rb_obj_class(p) != face_class ) {
|
|
1038
|
+
all_face = 0; break;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/* A single parent has nothing to weld against, so its Face rides the
|
|
1043
|
+
chain as it always did; refuse and lift only apply from two up. */
|
|
1044
|
+
if ( all_face && n > 1
|
|
1045
|
+
&& !ca_face_state_portable(ref_face->obj_type, face_class) ) {
|
|
1046
|
+
rb_raise(rb_eArgError,
|
|
1047
|
+
"CAMeld.new: %s state is not portable across multiple "
|
|
1048
|
+
"parents (= per-parent storage like CAConstString's buffer); "
|
|
1049
|
+
"strip Face with .parent if a storage-level CAMeld is intended",
|
|
1050
|
+
rb_class2name(face_class));
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
obj = rb_obj_alloc(klass);
|
|
1054
|
+
rb_obj_call_init_kw(obj, argc, argv, RB_PASS_CALLED_KEYWORDS);
|
|
1055
|
+
|
|
1056
|
+
if ( !all_face || n < 2 ) return obj;
|
|
1057
|
+
|
|
1058
|
+
for ( i = 1; i < n; i++ ) {
|
|
1059
|
+
VALUE p = rb_ary_entry(list, i);
|
|
1060
|
+
CArray *ca;
|
|
1061
|
+
TypedData_Get_Struct(p, CArray, &carray_data_type, ca);
|
|
1062
|
+
if ( !ca_face_state_compatible(rb_ary_entry(list, 0), ref_face, p, ca) ) {
|
|
1063
|
+
rb_raise(rb_eArgError,
|
|
1064
|
+
"CAMeld.new: Face state mismatch across parents "
|
|
1065
|
+
"(= %s instance at index %ld differs in state from index 0)",
|
|
1066
|
+
rb_class2name(face_class), i);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
return ca_face_lift(obj, rb_ary_entry(list, 0));
|
|
1070
|
+
}
|
|
1071
|
+
|
|
975
1072
|
static VALUE
|
|
976
1073
|
rb_ca_meld_n_parents (VALUE self)
|
|
977
1074
|
{
|
|
@@ -1027,6 +1124,7 @@ Init_ca_obj_meld (void)
|
|
|
1027
1124
|
id_parents = rb_intern("parents");
|
|
1028
1125
|
|
|
1029
1126
|
rb_define_alloc_func(rb_cCAMeld, rb_ca_meld_s_allocate);
|
|
1127
|
+
rb_define_singleton_method(rb_cCAMeld, "new", rb_ca_meld_s_new, -1);
|
|
1030
1128
|
rb_define_method(rb_cCAMeld, "initialize",
|
|
1031
1129
|
rb_ca_meld_initialize, -1);
|
|
1032
1130
|
rb_define_method(rb_cCAMeld, "initialize_copy",
|
data/ext/ca_obj_object.c
CHANGED
|
@@ -738,6 +738,14 @@ ca_object_dispatch_fill (CAObject *ca, void *ptr)
|
|
|
738
738
|
volatile VALUE rval = rb_ca_ptr2obj(ca->self, ptr);
|
|
739
739
|
rb_funcall(ca->self, rb_intern("fill_data"), 1, rval);
|
|
740
740
|
}
|
|
741
|
+
else if ( rb_obj_respond_to(ca->self, rb_intern("fill_block"), Qtrue)
|
|
742
|
+
|| rb_obj_respond_to(ca->self, rb_intern("fill_addrs"), Qtrue) ) {
|
|
743
|
+
/* An author who wrote the region slots but not fill_data would otherwise
|
|
744
|
+
get the per-cell default for the one request that is easiest to batch.
|
|
745
|
+
Hand the whole extent to the region path, which reaches `fill_block` in
|
|
746
|
+
one call or `fill_addrs` in address windows. */
|
|
747
|
+
ca_fill_stride_whole(ca, ptr);
|
|
748
|
+
}
|
|
741
749
|
else {
|
|
742
750
|
ca_size_t addr;
|
|
743
751
|
for ( addr = 0; addr < ca->elements; addr++ ) {
|
data/ext/ca_obj_select.c
CHANGED
|
@@ -83,22 +83,57 @@ VALUE rb_cCASelectMask;
|
|
|
83
83
|
|
|
84
84
|
/* ------------------------------------------------------------------- */
|
|
85
85
|
|
|
86
|
-
/*
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
/* Owned snapshot of the selector: masked selector cells become false.
|
|
87
|
+
After construction, mutating the caller's live selector does not affect
|
|
88
|
+
the view. Reading the selector can raise (a lazy boolean view), so the
|
|
89
|
+
snapshot is taken before the view struct is allocated, and a snapshot
|
|
90
|
+
whose fill raises is freed on the way out. */
|
|
91
|
+
static VALUE
|
|
92
|
+
ca_select_snapshot_masked (VALUE arg)
|
|
92
93
|
{
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
CArray **pair = (CArray **) arg;
|
|
95
|
+
CArray *select = pair[0], *snap = pair[1];
|
|
96
|
+
boolean8_t *p, *q, *m;
|
|
95
97
|
ca_size_t i;
|
|
98
|
+
ca_attach(select);
|
|
99
|
+
q = (boolean8_t *) snap->ptr;
|
|
100
|
+
p = (boolean8_t *) select->ptr;
|
|
101
|
+
m = (boolean8_t *) select->mask->ptr;
|
|
102
|
+
for (i = 0; i < select->elements; i++) {
|
|
103
|
+
*q = ( *m ) ? 0 : *p;
|
|
104
|
+
q++; p++; m++;
|
|
105
|
+
}
|
|
106
|
+
ca_detach(select);
|
|
107
|
+
return Qnil;
|
|
108
|
+
}
|
|
96
109
|
|
|
110
|
+
static CArray *
|
|
111
|
+
ca_select_snapshot (CArray *select)
|
|
112
|
+
{
|
|
97
113
|
if ( ! ca_is_boolean_type(select) ) {
|
|
98
114
|
rb_raise(rb_eRuntimeError,
|
|
99
115
|
"selection array for CASelect should be have "
|
|
100
116
|
"the data_type of CA_BOOLEAN");
|
|
101
117
|
}
|
|
118
|
+
if ( ca_has_mask(select) ) {
|
|
119
|
+
CArray *pair[2];
|
|
120
|
+
pair[0] = select;
|
|
121
|
+
pair[1] = ca_template(select);
|
|
122
|
+
ca_fill_or_free(pair[1], ca_select_snapshot_masked, (VALUE) pair);
|
|
123
|
+
return pair[1];
|
|
124
|
+
}
|
|
125
|
+
return ca_copy(select);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* Set up the view over `parent` from an owned selector snapshot (see
|
|
129
|
+
ca_select_snapshot) and pre-compute ca->indices (TRUE positions in flat
|
|
130
|
+
parent order). Does not raise. */
|
|
131
|
+
static int
|
|
132
|
+
ca_select_setup (CASelect *ca, CArray *parent, CArray *snapshot)
|
|
133
|
+
{
|
|
134
|
+
int8_t data_type;
|
|
135
|
+
ca_size_t bytes;
|
|
136
|
+
ca_size_t i;
|
|
102
137
|
|
|
103
138
|
data_type = parent->data_type;
|
|
104
139
|
bytes = parent->bytes;
|
|
@@ -114,26 +149,7 @@ ca_select_setup (CASelect *ca, CArray *parent, CArray *select, int share)
|
|
|
114
149
|
ca->attach = 0;
|
|
115
150
|
ca->nosync = 0;
|
|
116
151
|
ca->indices = NULL;
|
|
117
|
-
|
|
118
|
-
/* The `share` argument is preserved for source compatibility but
|
|
119
|
-
no longer toggles a live-reference path; both paths copy.
|
|
120
|
-
Masked selector cells become false in the snapshot. */
|
|
121
|
-
(void) share;
|
|
122
|
-
if ( ca_has_mask(select) ) {
|
|
123
|
-
boolean8_t *p, *q, *m;
|
|
124
|
-
ca->select = ca_template(select);
|
|
125
|
-
ca_attach(select);
|
|
126
|
-
q = (boolean8_t *) ca->select->ptr;
|
|
127
|
-
p = (boolean8_t *) select->ptr;
|
|
128
|
-
m = (boolean8_t *) select->mask->ptr;
|
|
129
|
-
for (i = 0; i < select->elements; i++) {
|
|
130
|
-
*q = ( *m ) ? 0 : *p;
|
|
131
|
-
q++; p++; m++;
|
|
132
|
-
}
|
|
133
|
-
ca_detach(select);
|
|
134
|
-
} else {
|
|
135
|
-
ca->select = ca_copy(select);
|
|
136
|
-
}
|
|
152
|
+
ca->select = snapshot;
|
|
137
153
|
|
|
138
154
|
/* Count TRUE positions and snapshot them into ca->indices. */
|
|
139
155
|
{
|
|
@@ -181,7 +197,7 @@ ca_select_setup (CASelect *ca, CArray *parent, CArray *select, int share)
|
|
|
181
197
|
ca->dim = &(ca->_dim);
|
|
182
198
|
ca->dim[0] = ca->elements;
|
|
183
199
|
|
|
184
|
-
if ( ca_is_scalar(
|
|
200
|
+
if ( ca_is_scalar(snapshot) ) {
|
|
185
201
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
186
202
|
}
|
|
187
203
|
|
|
@@ -191,8 +207,9 @@ ca_select_setup (CASelect *ca, CArray *parent, CArray *select, int share)
|
|
|
191
207
|
CArray *
|
|
192
208
|
ca_select_new (CArray *parent, CArray *select)
|
|
193
209
|
{
|
|
210
|
+
CArray *snapshot = ca_select_snapshot(select);
|
|
194
211
|
CASelect *ca = ALLOC(CASelect);
|
|
195
|
-
ca_select_setup(ca, parent,
|
|
212
|
+
ca_select_setup(ca, parent, snapshot);
|
|
196
213
|
return (CArray*) ca;
|
|
197
214
|
}
|
|
198
215
|
|
|
@@ -202,9 +219,7 @@ ca_select_new (CArray *parent, CArray *select)
|
|
|
202
219
|
CArray *
|
|
203
220
|
ca_select_new_share (CArray *parent, CArray *select)
|
|
204
221
|
{
|
|
205
|
-
|
|
206
|
-
ca_select_setup(ca, parent, select, 1);
|
|
207
|
-
return (CArray*) ca;
|
|
222
|
+
return ca_select_new(parent, select);
|
|
208
223
|
}
|
|
209
224
|
|
|
210
225
|
static void
|
|
@@ -613,7 +628,7 @@ rb_cm_initialize_copy (VALUE self, VALUE other)
|
|
|
613
628
|
|
|
614
629
|
/* Re-snapshot from the source's selector copy so the two views
|
|
615
630
|
end up with independent indices buffers. */
|
|
616
|
-
ca_select_setup(ca, cs->parent, cs->select
|
|
631
|
+
ca_select_setup(ca, cs->parent, ca_select_snapshot(cs->select));
|
|
617
632
|
|
|
618
633
|
return self;
|
|
619
634
|
}
|
data/ext/ca_obj_stack.c
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
---------------------------------------------------------------------------- */
|
|
19
19
|
|
|
20
20
|
#include "carray.h"
|
|
21
|
+
#include "carray_internal.h" /* ca_attach_all */
|
|
21
22
|
#include "ca_composite_dispatch.h"
|
|
22
23
|
#include "ca_obj_face.h"
|
|
23
24
|
|
|
@@ -740,10 +741,7 @@ static void
|
|
|
740
741
|
ca_stack_func_allocate (void *ap)
|
|
741
742
|
{
|
|
742
743
|
CAStack *ca = (CAStack *) ap;
|
|
743
|
-
|
|
744
|
-
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
745
|
-
ca_attach(ca->parents[k]);
|
|
746
|
-
}
|
|
744
|
+
ca_attach_all(ca->parents, ca->n_parents);
|
|
747
745
|
ca->ptr = xmalloc(ca_length(ca));
|
|
748
746
|
}
|
|
749
747
|
|
|
@@ -751,10 +749,7 @@ static void
|
|
|
751
749
|
ca_stack_func_attach (void *ap)
|
|
752
750
|
{
|
|
753
751
|
CAStack *ca = (CAStack *) ap;
|
|
754
|
-
|
|
755
|
-
for ( k = 0; k < ca->n_parents; k++ ) {
|
|
756
|
-
ca_attach(ca->parents[k]);
|
|
757
|
-
}
|
|
752
|
+
ca_attach_all(ca->parents, ca->n_parents);
|
|
758
753
|
ca->ptr = xmalloc(ca_length(ca));
|
|
759
754
|
ca_stack_func_xfer_all(ca, ca->ptr, CA_XFER_GET);
|
|
760
755
|
}
|
data/ext/ca_obj_stride.c
CHANGED
|
@@ -836,6 +836,59 @@ ca_stride_region_axes (CAStride *ca, ca_size_t base, int8_t ndim,
|
|
|
836
836
|
root in units root does not share, so there is no address to hand over
|
|
837
837
|
and the per-cell descent stands in. */
|
|
838
838
|
|
|
839
|
+
static void
|
|
840
|
+
ca_stride_func_fill_addrs (void *ap, ca_size_t n, ca_size_t *addrs, void *ptr)
|
|
841
|
+
{
|
|
842
|
+
CAStride *ca = (CAStride *) ap;
|
|
843
|
+
CArray *root;
|
|
844
|
+
ca_size_t composed_strides[CA_RANK_MAX];
|
|
845
|
+
ca_size_t composed_base;
|
|
846
|
+
ca_size_t rbytes;
|
|
847
|
+
ca_size_t *paddrs;
|
|
848
|
+
ca_size_t i;
|
|
849
|
+
int8_t k;
|
|
850
|
+
int all_aligned = 1;
|
|
851
|
+
volatile VALUE holder;
|
|
852
|
+
|
|
853
|
+
/* Addresses name cells one by one, so unlike fill_stride there is nothing
|
|
854
|
+
here that only the whole extent can express: translate each view address
|
|
855
|
+
into the root's and hand the list down in one call. Without this the
|
|
856
|
+
region is still the only thing touched -- ca_fill_addrs_default sees to
|
|
857
|
+
that -- but it costs the parent one call per cell, which is the whole
|
|
858
|
+
difference on a backing where a call is a request. */
|
|
859
|
+
if ( n == 0 ) {
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
ca_stride_compose_to_root(ca, &root, composed_strides, &composed_base);
|
|
864
|
+
rbytes = root->bytes;
|
|
865
|
+
|
|
866
|
+
if ( ca->bytes != rbytes ) {
|
|
867
|
+
ca_fill_addrs_default(ca, n, addrs, ptr);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
paddrs = ALLOCV_N(ca_size_t, holder, n);
|
|
872
|
+
for ( i = 0; i < n; i++ ) {
|
|
873
|
+
ca_size_t idx[CA_RANK_MAX];
|
|
874
|
+
ca_size_t off = composed_base;
|
|
875
|
+
ca_addr2index((CArray *) ca, addrs[i], idx);
|
|
876
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
877
|
+
off += idx[k] * composed_strides[k];
|
|
878
|
+
}
|
|
879
|
+
if ( off % rbytes != 0 ) { all_aligned = 0; break; }
|
|
880
|
+
paddrs[i] = off / rbytes;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if ( all_aligned ) {
|
|
884
|
+
ca_fill_addrs(root, n, paddrs, ptr);
|
|
885
|
+
}
|
|
886
|
+
else {
|
|
887
|
+
ca_fill_addrs_default(ca, n, addrs, ptr);
|
|
888
|
+
}
|
|
889
|
+
ALLOCV_END(holder);
|
|
890
|
+
}
|
|
891
|
+
|
|
839
892
|
static void
|
|
840
893
|
ca_stride_func_fill_stride (void *ap, ca_size_t base, int8_t ndim,
|
|
841
894
|
ca_size_t *counts, ca_size_t *steps, void *ptr)
|
|
@@ -1003,6 +1056,15 @@ ca_stride_func_allocate (void *ap)
|
|
|
1003
1056
|
}
|
|
1004
1057
|
}
|
|
1005
1058
|
|
|
1059
|
+
/* Region request into the cold-root attach buffer; a lazy root can raise. */
|
|
1060
|
+
static VALUE
|
|
1061
|
+
ca_stride_cold_fill (VALUE arg)
|
|
1062
|
+
{
|
|
1063
|
+
void **args = (void **) arg;
|
|
1064
|
+
ca_copy_data((CArray *) args[0], (char *) args[1]);
|
|
1065
|
+
return Qnil;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1006
1068
|
static void
|
|
1007
1069
|
ca_stride_func_attach (void *ap)
|
|
1008
1070
|
{
|
|
@@ -1018,7 +1080,15 @@ ca_stride_func_attach (void *ap)
|
|
|
1018
1080
|
view with a live ptr is what makes the per-cell dispatchers bypass the
|
|
1019
1081
|
transfer slots. */
|
|
1020
1082
|
char *buf = xmalloc(ca_length(ca));
|
|
1021
|
-
|
|
1083
|
+
void *args[2];
|
|
1084
|
+
int tag = 0;
|
|
1085
|
+
args[0] = ca;
|
|
1086
|
+
args[1] = buf;
|
|
1087
|
+
rb_protect(ca_stride_cold_fill, (VALUE) args, &tag); /* root stays cold */
|
|
1088
|
+
if (tag) {
|
|
1089
|
+
xfree(buf);
|
|
1090
|
+
rb_jump_tag(tag);
|
|
1091
|
+
}
|
|
1022
1092
|
ca->ptr = buf;
|
|
1023
1093
|
return;
|
|
1024
1094
|
}
|
|
@@ -1483,6 +1553,7 @@ ca_operation_function_t ca_stride_func = {
|
|
|
1483
1553
|
sizeof(CAStride), /* struct_size: pool framework */
|
|
1484
1554
|
ca_stride_pool_bytes, /* pool_bytes */
|
|
1485
1555
|
ca_stride_pool_init, /* pool_init */
|
|
1556
|
+
.fill_addrs = ca_stride_func_fill_addrs,
|
|
1486
1557
|
.fill_stride = ca_stride_func_fill_stride,
|
|
1487
1558
|
};
|
|
1488
1559
|
|
data/ext/ca_obj_string.c
CHANGED
|
@@ -90,10 +90,14 @@ ca_string_setup (CAString *ca, CArray *parent)
|
|
|
90
90
|
|
|
91
91
|
ca->obj_type = CA_OBJ_STRING;
|
|
92
92
|
ca->data_type = CA_OBJECT;
|
|
93
|
-
/* ORDERABLE
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
/* ORDERABLE + COMPARABLE, and both hold by construction: a storage cell
|
|
94
|
+
IS the Ruby String the surface shows, so storage order is surface
|
|
95
|
+
order and an external String compares against storage directly, with
|
|
96
|
+
nothing to reconcile. (A unit-bearing Face like CATime is the case
|
|
97
|
+
that has to stop at ORDERABLE; this one carries no unit.) */
|
|
98
|
+
ca->flags = CA_FLAG_IS_FACE
|
|
99
|
+
| CA_FLAG_FACE_ORDERABLE_STORAGE
|
|
100
|
+
| CA_FLAG_FACE_COMPARABLE_STORAGE;
|
|
97
101
|
ca->ndim = parent->ndim;
|
|
98
102
|
ca->bytes = sizeof(VALUE);
|
|
99
103
|
ca->elements = parent->elements;
|
data/ext/ca_obj_window.c
CHANGED
|
@@ -1416,6 +1416,12 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
|
|
|
1416
1416
|
}
|
|
1417
1417
|
|
|
1418
1418
|
if ( ! NIL_P(rbounds) ) {
|
|
1419
|
+
/* A Symbol says the same thing as the String, and is what the window
|
|
1420
|
+
iterator (CArray#windows) is given -- accept both so the two spellings
|
|
1421
|
+
of one policy do not diverge. */
|
|
1422
|
+
if ( SYMBOL_P(rbounds) ) {
|
|
1423
|
+
rbounds = rb_sym2str(rbounds);
|
|
1424
|
+
}
|
|
1419
1425
|
switch ( TYPE(rbounds) ) {
|
|
1420
1426
|
case T_STRING:
|
|
1421
1427
|
cbounds = StringValuePtr(rbounds);
|
|
@@ -1597,7 +1603,6 @@ rb_ca_window_get_bounds (VALUE self)
|
|
|
1597
1603
|
}
|
|
1598
1604
|
|
|
1599
1605
|
static VALUE rb_cw_get_attr_ary(start);
|
|
1600
|
-
static VALUE rb_cw_get_attr_ary(count);
|
|
1601
1606
|
static VALUE rb_cw_get_attr_ary(size0);
|
|
1602
1607
|
|
|
1603
1608
|
#ifdef CARRAY_DEV_BUILD
|
|
@@ -1680,8 +1685,9 @@ Init_ca_obj_window (void)
|
|
|
1680
1685
|
|
|
1681
1686
|
rb_define_method(rb_cCAWindow, "bounds", rb_ca_window_get_bounds, 0);
|
|
1682
1687
|
|
|
1688
|
+
/* No `count` accessor: the per-axis window widths are what `shape`
|
|
1689
|
+
already answers, and the name belongs to CArray#count. */
|
|
1683
1690
|
rb_define_method(rb_cCAWindow, "start", rb_cw_start, 0);
|
|
1684
|
-
rb_define_method(rb_cCAWindow, "count", rb_cw_count, 0);
|
|
1685
1691
|
rb_define_method(rb_cCAWindow, "size0", rb_cw_size0, 0);
|
|
1686
1692
|
|
|
1687
1693
|
#ifdef CARRAY_DEV_BUILD
|
data/ext/ca_op_ipower.c
CHANGED
|
@@ -273,8 +273,7 @@ rb_ca_ipower_bang (VALUE self, VALUE other)
|
|
|
273
273
|
/* CArray#pow(other) (alias `**`) — Float/Complex ** Integer takes the
|
|
274
274
|
* ipower fast path in this file; everything else falls through to the
|
|
275
275
|
* mkkernel-generated general pow/cpow (rb_ca_power in
|
|
276
|
-
* ext/carray_kernels.c).
|
|
277
|
-
* wrapping on the result. */
|
|
276
|
+
* ext/carray_kernels.c). */
|
|
278
277
|
static VALUE rb_ca_pow (VALUE self, VALUE other)
|
|
279
278
|
{
|
|
280
279
|
volatile VALUE obj;
|
data/ext/ca_rng_normal.h
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
ca_rng_normal.h -- uniform to standard normal, as text
|
|
4
|
+
|
|
5
|
+
Read the two ways ca_rng_xoshiro256pp.h is read: compiled into this
|
|
6
|
+
extension, and handed out through CArray::Rng::COMMON_SOURCE for
|
|
7
|
+
another gem to paste. The same rules apply -- no include guard,
|
|
8
|
+
nothing beyond <math.h>, `static inline` only.
|
|
9
|
+
|
|
10
|
+
Separate from any generator's file because it belongs to none of
|
|
11
|
+
them: it takes two uniforms and gives a normal, whichever generator
|
|
12
|
+
the uniforms came from. Whoever pastes it pastes it once however
|
|
13
|
+
many generators are drawing, which is why it is not simply repeated
|
|
14
|
+
inside each generator's text.
|
|
15
|
+
|
|
16
|
+
--------------------------------------------------------------------------- */
|
|
17
|
+
|
|
18
|
+
/* One standard normal from two uniforms in [0.0, 1.0), by Box-Muller.
|
|
19
|
+
*
|
|
20
|
+
* Exactly two, always. The classical form takes two uniforms and gives
|
|
21
|
+
* two normals, and keeping the second would make the cost one uniform
|
|
22
|
+
* apiece -- but the spare has to live somewhere between calls, and the
|
|
23
|
+
* place it would live is the generator's state. A kernel draws one
|
|
24
|
+
* number per cell and `CArray#random!` fills whole arrays, so a spare
|
|
25
|
+
* held across that boundary is a second kind of state to keep in step,
|
|
26
|
+
* on top of the one this design exists to keep in step. Two uniforms
|
|
27
|
+
* and no spare costs an extra draw, at about a nanosecond, and buys a
|
|
28
|
+
* rule with nothing behind it: one normal is two draws, wherever it is
|
|
29
|
+
* taken.
|
|
30
|
+
*
|
|
31
|
+
* `1.0 - u1` rather than `u1`, so the argument to log is in (0.0, 1.0]
|
|
32
|
+
* and never zero. Redrawing on a zero -- which is what the paired form
|
|
33
|
+
* does -- would make the number of uniforms per normal depend on the
|
|
34
|
+
* draw, and then "where is this generator" has no answer that can be
|
|
35
|
+
* worked out rather than run. */
|
|
36
|
+
static inline double
|
|
37
|
+
ca_rng_normal (double u1, double u2)
|
|
38
|
+
{
|
|
39
|
+
const double radius = sqrt(-2.0 * log(1.0 - u1));
|
|
40
|
+
const double theta = 2.0 * M_PI * u2;
|
|
41
|
+
return radius * cos(theta);
|
|
42
|
+
}
|