carray 3.0.2 → 3.0.3
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 +304 -0
- data/README.md +3 -4
- data/carray.gemspec +1 -1
- data/ext/ca_axis_dispatch.c +225 -0
- data/ext/ca_axis_group.c +177 -99
- data/ext/ca_binop_dispatch.c +54 -32
- data/ext/ca_binop_dispatch.h +1 -0
- data/ext/ca_categorical_iterator.c +66 -71
- data/ext/ca_compare.c +8 -2
- data/ext/ca_for_buffer.h +21 -68
- data/ext/ca_group_iter.c +27 -11
- data/ext/ca_kernel_iterator.c +663 -214
- data/ext/ca_kernel_iterator.h +231 -167
- data/ext/ca_monop_dispatch.c +4 -4
- data/ext/ca_monop_dispatch.h +4 -0
- data/ext/ca_obj_array.c +132 -22
- data/ext/ca_obj_bincmp.c +152 -121
- data/ext/ca_obj_binop.c +107 -210
- data/ext/ca_obj_bitarray.c +37 -24
- data/ext/ca_obj_bitfield.c +95 -62
- data/ext/ca_obj_block.c +1 -0
- data/ext/ca_obj_byte_swap.c +40 -40
- data/ext/ca_obj_const_string.c +96 -25
- data/ext/ca_obj_face.c +406 -64
- data/ext/ca_obj_face.h +92 -47
- data/ext/ca_obj_fake.c +21 -50
- data/ext/ca_obj_farray.c +1 -0
- data/ext/ca_obj_field.c +16 -3
- data/ext/ca_obj_fixlen_string.c +21 -21
- data/ext/ca_obj_grid.c +181 -124
- data/ext/ca_obj_meld.c +189 -107
- data/ext/ca_obj_moncmp.c +61 -61
- data/ext/ca_obj_monop.c +125 -107
- data/ext/ca_obj_object.c +543 -233
- data/ext/ca_obj_record.c +51 -16
- data/ext/ca_obj_reduce.c +5 -8
- data/ext/ca_obj_refer.c +117 -33
- data/ext/ca_obj_remap.c +57 -17
- data/ext/ca_obj_repeat.c +21 -5
- data/ext/ca_obj_roll.c +115 -11
- data/ext/ca_obj_select.c +47 -49
- data/ext/ca_obj_select_axis.c +58 -60
- data/ext/ca_obj_shift.c +22 -102
- data/ext/ca_obj_stack.c +223 -118
- data/ext/ca_obj_stride.c +195 -34
- data/ext/ca_obj_string.c +17 -18
- data/ext/ca_obj_tile.c +32 -16
- data/ext/ca_obj_time.c +23 -25
- data/ext/ca_obj_timedelta.c +21 -23
- data/ext/ca_obj_transpose.c +12 -3
- data/ext/ca_obj_triop.c +110 -117
- data/ext/ca_obj_window.c +149 -27
- 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 +102 -79
- 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 +463 -0
- data/ext/carray.h +70 -27
- data/ext/carray_access.c +455 -211
- data/ext/carray_address_basis.c +177 -36
- data/ext/carray_attribute.c +45 -3
- data/ext/carray_bincount.c +32 -2
- data/ext/carray_broadcast.c +46 -14
- data/ext/carray_call_cfunc.c +0 -28
- data/ext/carray_cast.c +1444 -209
- data/ext/carray_cast_func.rb +34 -21
- data/ext/carray_conversion.c +197 -73
- data/ext/carray_copy.c +32 -11
- data/ext/carray_core.c +514 -122
- data/ext/carray_count.c +140 -87
- data/ext/carray_element.c +18 -27
- data/ext/carray_factorize.c +569 -277
- data/ext/carray_generate.c +76 -40
- data/ext/carray_histogram.c +152 -94
- data/ext/carray_hold.c +2 -1
- data/ext/carray_index_classifier.c +63 -96
- data/ext/carray_internal.h +385 -3
- data/ext/carray_lazy.c +834 -79
- data/ext/carray_loop.c +81 -65
- data/ext/carray_mask.c +682 -316
- data/ext/carray_math_kernel.h +1 -0
- data/ext/carray_median_percentile.c +221 -76
- data/ext/carray_memory_view.c +254 -248
- data/ext/carray_operator.c +1089 -359
- data/ext/carray_order.c +133 -69
- data/ext/carray_partition.c +102 -56
- data/ext/carray_random.c +273 -239
- data/ext/carray_scatter.c +308 -65
- data/ext/carray_segment.c +257 -0
- data/ext/carray_slab.c +170 -70
- data/ext/carray_sort.c +215 -218
- data/ext/carray_sort_kernel.c +8 -1
- data/ext/carray_struct.c +99 -21
- data/ext/carray_test.c +167 -64
- data/ext/carray_time_text.c +1182 -0
- data/ext/carray_utils.c +363 -98
- data/ext/extconf.rb +27 -2
- data/ext/mk_call_cfunc.rb +0 -2
- data/ext/mk_pow5_table.rb +35 -0
- data/ext/mkkernel.rb +1076 -846
- data/ext/ruby_carray.c +7 -1
- data/ext/version.h +4 -4
- data/ext/version.rb +4 -2
- data/lib/carray/attribute.rb +39 -0
- data/lib/carray/autoload_carray.rb +19 -0
- data/lib/carray/autoload_method_extension.rb +6 -0
- data/lib/carray/axis_group.rb +174 -26
- data/lib/carray/basics.rb +91 -25
- data/lib/carray/bincount_nd.rb +6 -0
- data/lib/carray/block_iterator.rb +118 -48
- data/lib/carray/boolean_reduce.rb +21 -29
- data/lib/carray/categorical.rb +94 -26
- data/lib/carray/categorical_iterator.rb +333 -826
- data/lib/carray/complex.rb +36 -29
- data/lib/carray/conditional.rb +94 -7
- data/lib/carray/const_string.rb +46 -0
- data/lib/carray/frame/concat.rb +157 -6
- data/lib/carray/frame/convert.rb +13 -7
- data/lib/carray/frame/csv_parser.rb +589 -82
- data/lib/carray/frame/describe.rb +79 -0
- data/lib/carray/frame/frame.rb +124 -25
- data/lib/carray/frame/group.rb +189 -63
- data/lib/carray/frame/io.rb +412 -72
- data/lib/carray/frame/join.rb +134 -46
- data/lib/carray/frame/records.rb +37 -16
- data/lib/carray/frame/reshape.rb +448 -0
- data/lib/carray/frame/sort.rb +26 -2
- data/lib/carray/frame/verbs.rb +715 -48
- data/lib/carray/frame.rb +2 -0
- data/lib/carray/fuse_source.rb +111 -2
- data/lib/carray/fusion.rb +229 -38
- data/lib/carray/inspect.rb +29 -11
- data/lib/carray/iterator.rb +14 -2
- data/lib/carray/lazy.rb +54 -30
- data/lib/carray/mask_gap_fill.rb +66 -52
- data/lib/carray/math.rb +32 -19
- data/lib/carray/meld_reduce.rb +40 -7
- data/lib/carray/methods/align_addr.rb +8 -4
- data/lib/carray/methods/bincount.rb +2 -2
- data/lib/carray/methods/bit_string.rb +14 -3
- data/lib/carray/methods/composition.rb +16 -10
- data/lib/carray/methods/factorize.rb +2 -2
- data/lib/carray/methods/gather_nd.rb +13 -2
- data/lib/carray/methods/insert_block.rb +9 -14
- data/lib/carray/methods/is_in.rb +117 -4
- data/lib/carray/methods/join.rb +1 -1
- data/lib/carray/methods/locate_addr.rb +177 -36
- data/lib/carray/methods/mode.rb +18 -1
- 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/record_order.rb +208 -0
- data/lib/carray/runtime.rb +14 -11
- data/lib/carray/segment_iterator.rb +990 -0
- data/lib/carray/serialize.rb +197 -27
- data/lib/carray/slab_iterator.rb +51 -27
- data/lib/carray/stack.rb +10 -4
- data/lib/carray/string_operation_extension.rb +4 -3
- data/lib/carray/struct.rb +142 -51
- data/lib/carray/struct_builder.rb +110 -14
- data/lib/carray/table.rb +2 -2
- data/lib/carray/time.rb +517 -103
- data/lib/carray/window_iterator.rb +127 -72
- data/lib/carray.rb +2 -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 +1 -1
- data/yard-stubs/ca_obj_refer.rb +3 -3
- data/yard-stubs/ca_obj_roll.rb +0 -1
- data/yard-stubs/ca_obj_stride.rb +10 -7
- data/yard-stubs/ca_obj_transpose.rb +1 -1
- data/yard-stubs/ca_obj_window.rb +1 -2
- data/yard-stubs/carray_access.rb +5 -4
- data/yard-stubs/carray_broadcast.rb +1 -1
- data/yard-stubs/carray_cast.rb +78 -43
- data/yard-stubs/carray_conversion.rb +13 -1
- data/yard-stubs/carray_copy.rb +8 -3
- data/yard-stubs/carray_core.rb +3 -3
- data/yard-stubs/carray_count.rb +9 -0
- data/yard-stubs/carray_lazy.rb +5 -1
- data/yard-stubs/carray_loop.rb +4 -1
- data/yard-stubs/carray_mask.rb +34 -10
- data/yard-stubs/carray_math.rb +25 -13
- data/yard-stubs/carray_median_percentile.rb +10 -6
- data/yard-stubs/carray_order.rb +34 -13
- data/yard-stubs/carray_scatter.rb +10 -3
- data/yard-stubs/carray_segment.rb +72 -0
- data/yard-stubs/carray_slab.rb +2 -1
- data/yard-stubs/carray_sort.rb +43 -3
- data/yard-stubs/carray_test.rb +10 -0
- data/yard-stubs/carray_utils.rb +0 -26
- metadata +11 -19
- data/ext/ca_for_each_element.h +0 -239
- data/ext/carray_build_flags.h +0 -3
- data/ext/carray_config.h +0 -28
- data/ext/carray_kernels_bincmp.c +0 -4446
- data/ext/carray_kernels_binop.c +0 -11001
- data/ext/carray_kernels_init.c +0 -1131
- data/ext/carray_kernels_map.c +0 -3467
- data/ext/carray_kernels_moncmp.c +0 -2097
- data/ext/carray_kernels_monop.c +0 -18313
- data/ext/carray_kernels_reduce_aggregate.c +0 -26005
- data/ext/carray_kernels_reduce_boolean.c +0 -330
- data/ext/carray_kernels_reduce_cumulative.c +0 -14862
- data/ext/carray_kernels_reduce_extreme.c +0 -17494
- data/ext/carray_kernels_reduce_variance.c +0 -3910
- data/ext/carray_kernels_scan.c +0 -3693
- data/ext/carray_kernels_search.c +0 -32218
- data/ext/carray_kernels_sort.c +0 -10626
- data/ext/carray_kernels_triop.c +0 -1392
data/ext/carray_address_basis.c
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "carray.h"
|
|
2
|
+
#include "carray_internal.h"
|
|
2
3
|
|
|
3
4
|
/* ---------------------------------------------------------------------------
|
|
4
5
|
|
|
@@ -8,8 +9,8 @@
|
|
|
8
9
|
writes a[i] from its own loop, so what it needs from CArray is not element
|
|
9
10
|
delivery but an addressing basis: a pointer, already shifted to cell zero,
|
|
10
11
|
and one byte stride per axis. That is why this does not sit on the kernel
|
|
11
|
-
iterator (per-cell / per-slab delivery, and no N-ary form) or on the
|
|
12
|
-
|
|
12
|
+
iterator (per-cell / per-slab delivery, and no N-ary form) or on the
|
|
13
|
+
call_cfunc families (which flatten the array and cannot recover the axis
|
|
13
14
|
structure a stencil needs).
|
|
14
15
|
|
|
15
16
|
This is a runtime facility at the same layer as ca_attach, not a user
|
|
@@ -79,6 +80,8 @@ typedef struct {
|
|
|
79
80
|
VALUE bases;
|
|
80
81
|
VALUE box_starts; /* per array, per axis; nil for "all of it" */
|
|
81
82
|
VALUE box_counts;
|
|
83
|
+
int body_done; /* the block returned without raising */
|
|
84
|
+
volatile VALUE put_error; /* the first write-back that raised, or nil */
|
|
82
85
|
} open_state;
|
|
83
86
|
|
|
84
87
|
/* The view's own row-major byte layout, which is the address space
|
|
@@ -94,6 +97,15 @@ native_steps (CArray *ca, ca_size_t *steps)
|
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
|
|
100
|
+
/* Whether [start, start + count) leaves [0, dim). Written so that no sum
|
|
101
|
+
is formed: a start and a count near the top of the integer range add up
|
|
102
|
+
to a negative number, which `start + count > dim` lets through. */
|
|
103
|
+
static int
|
|
104
|
+
outside_axis (ca_size_t start, ca_size_t count, ca_size_t dim)
|
|
105
|
+
{
|
|
106
|
+
return start < 0 || count < 0 || start > dim || count > dim - start;
|
|
107
|
+
}
|
|
108
|
+
|
|
97
109
|
/* Checks one array's box description, all of it: that it is one start and one
|
|
98
110
|
count per axis, that they are numbers, and that the box they describe is
|
|
99
111
|
inside the array.
|
|
@@ -124,9 +136,11 @@ verify_box (VALUE box_starts, VALUE box_counts, int index, CArray *ca)
|
|
|
124
136
|
"this array has %d", (int) ca->ndim);
|
|
125
137
|
}
|
|
126
138
|
for ( k = 0; k < ca->ndim; k++ ) {
|
|
127
|
-
ca_size_t start =
|
|
128
|
-
|
|
129
|
-
|
|
139
|
+
ca_size_t start = ca_integer_arg(rb_ary_entry(starts, k), "a region start",
|
|
140
|
+
"CArray::AddressBasis.open");
|
|
141
|
+
ca_size_t count = ca_integer_arg(rb_ary_entry(counts, k), "a region count",
|
|
142
|
+
"CArray::AddressBasis.open");
|
|
143
|
+
if ( outside_axis(start, count, ca->dim[k]) ) {
|
|
130
144
|
rb_raise(rb_eArgError,
|
|
131
145
|
"the requested region falls outside the array on axis %d", (int) k);
|
|
132
146
|
}
|
|
@@ -156,7 +170,7 @@ read_box (open_state *state, int index, CArray *ca,
|
|
|
156
170
|
starts[k] = NUM2LL(rb_ary_entry(per_array_start, k));
|
|
157
171
|
counts[k] = NUM2LL(rb_ary_entry(per_array_count, k));
|
|
158
172
|
}
|
|
159
|
-
if ( starts[k]
|
|
173
|
+
if ( outside_axis(starts[k], counts[k], ca->dim[k]) ) {
|
|
160
174
|
rb_raise(rb_eArgError,
|
|
161
175
|
"the requested region falls outside the array on axis %d", (int) k);
|
|
162
176
|
}
|
|
@@ -217,6 +231,28 @@ folds_to_an_entity (CArray *ca)
|
|
|
217
231
|
return ca_is_entity(root);
|
|
218
232
|
}
|
|
219
233
|
|
|
234
|
+
/* A view that reinterprets the element size -- refer(CA_INT32, ...) over
|
|
235
|
+
a float64 array -- gets a mask of its own shape, but one mask cell of it
|
|
236
|
+
covers a fraction of a parent cell, so writing cell i's mask also marks
|
|
237
|
+
its neighbour. A per-cell kernel writes cells independently and cannot
|
|
238
|
+
express that. Checked for every tier: a box transfer moves the same
|
|
239
|
+
mask, and the neighbour is marked when it is written back. */
|
|
240
|
+
static void
|
|
241
|
+
verify_mask_cells (VALUE object, CArray *ca)
|
|
242
|
+
{
|
|
243
|
+
CArray *root;
|
|
244
|
+
ca_size_t strides[CA_RANK_MAX];
|
|
245
|
+
ca_size_t base = 0;
|
|
246
|
+
if ( ! ca->mask || ! ca_is_stride_family(ca) ) return;
|
|
247
|
+
ca_stride_compose_to_root((CAStride *) ca, &root, strides, &base);
|
|
248
|
+
if ( ca->bytes != root->bytes ) {
|
|
249
|
+
rb_raise(rb_eArgError,
|
|
250
|
+
"%"PRIsVALUE" reinterprets the element size and carries a mask; "
|
|
251
|
+
"its mask cells do not map one to one onto the parent's",
|
|
252
|
+
rb_obj_class(object));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
220
256
|
static int
|
|
221
257
|
tier_for (CArray *ca)
|
|
222
258
|
{
|
|
@@ -239,7 +275,7 @@ acquire_basis (open_state *state, int index, ca_size_t *strides)
|
|
|
239
275
|
switch ( state->tier[index] ) {
|
|
240
276
|
case TIER_ENTITY: {
|
|
241
277
|
CArray *root = ca;
|
|
242
|
-
ca_attach(root);
|
|
278
|
+
ca_attach(root); /* window: released by open_ensure */
|
|
243
279
|
state->roots[index] = root;
|
|
244
280
|
state->attached_root[index] = 1;
|
|
245
281
|
row_major_strides(ca, strides);
|
|
@@ -250,18 +286,7 @@ acquire_basis (open_state *state, int index, ca_size_t *strides)
|
|
|
250
286
|
case TIER_STRIDE: {
|
|
251
287
|
CArray *root;
|
|
252
288
|
ca_stride_compose_to_root((CAStride *) ca, &root, strides, &base);
|
|
253
|
-
/*
|
|
254
|
-
a float64 array -- gets a mask of its own shape, but one mask cell of
|
|
255
|
-
it covers a fraction of a parent cell, so writing cell i's mask also
|
|
256
|
-
marks its neighbour. A per-cell kernel writes cells independently and
|
|
257
|
-
cannot express that. */
|
|
258
|
-
if ( ca->mask && ca->bytes != root->bytes ) {
|
|
259
|
-
rb_raise(rb_eArgError,
|
|
260
|
-
"%"PRIsVALUE" reinterprets the element size and carries a mask; "
|
|
261
|
-
"its mask cells do not map one to one onto the parent's",
|
|
262
|
-
rb_obj_class(rb_ary_entry(state->arrays, index)));
|
|
263
|
-
}
|
|
264
|
-
ca_attach(root);
|
|
289
|
+
ca_attach(root); /* window: released by open_ensure */
|
|
265
290
|
state->roots[index] = root;
|
|
266
291
|
state->attached_root[index] = 1;
|
|
267
292
|
pointer = root->ptr + base;
|
|
@@ -287,12 +312,26 @@ acquire_basis (open_state *state, int index, ca_size_t *strides)
|
|
|
287
312
|
step *= counts[k];
|
|
288
313
|
}
|
|
289
314
|
|
|
290
|
-
|
|
315
|
+
/* Recorded before the read: the read can raise, and open_ensure
|
|
316
|
+
frees what state->region holds. The counts stay zero until the
|
|
317
|
+
read is done, so a buffer that was never filled is not written
|
|
318
|
+
back. */
|
|
319
|
+
/* A writable box keeps a second copy of what it read, so that the
|
|
320
|
+
write-back can send only the cells the kernel changed (see
|
|
321
|
+
put_changed). */
|
|
322
|
+
buffer = ALLOC_N(char, (state->writable[index] ? 2 : 1)
|
|
323
|
+
* (elements > 0 ? elements : 1) * ca->bytes);
|
|
324
|
+
for ( k = 0; k < ca->ndim; k++ ) {
|
|
325
|
+
state->region_count[index * CA_RANK_MAX + k] = 0;
|
|
326
|
+
}
|
|
327
|
+
state->region[index] = buffer;
|
|
291
328
|
if ( elements > 0 ) {
|
|
292
329
|
ca_xfer_stride(ca, starts, counts, steps, buffer, CA_XFER_GET);
|
|
330
|
+
if ( state->writable[index] ) {
|
|
331
|
+
memcpy(buffer + elements * ca->bytes, buffer, elements * ca->bytes);
|
|
332
|
+
}
|
|
293
333
|
}
|
|
294
334
|
|
|
295
|
-
state->region[index] = buffer;
|
|
296
335
|
for ( k = 0; k < ca->ndim; k++ ) {
|
|
297
336
|
state->region_start[index * CA_RANK_MAX + k] = starts[k];
|
|
298
337
|
state->region_count[index * CA_RANK_MAX + k] = counts[k];
|
|
@@ -350,10 +389,73 @@ open_body (VALUE argument)
|
|
|
350
389
|
}
|
|
351
390
|
rb_ary_push(state->bases, basis);
|
|
352
391
|
}
|
|
353
|
-
|
|
392
|
+
{
|
|
393
|
+
VALUE result = rb_yield(state->bases);
|
|
394
|
+
state->body_done = 1;
|
|
395
|
+
return result;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
typedef struct {
|
|
400
|
+
CArray *ca;
|
|
401
|
+
ca_size_t *start;
|
|
402
|
+
ca_size_t *count;
|
|
403
|
+
ca_size_t *steps;
|
|
404
|
+
char *data;
|
|
405
|
+
char *read; /* the box as it was read */
|
|
406
|
+
} write_back_args;
|
|
407
|
+
|
|
408
|
+
/* Sends back the cells whose bytes differ from what was read, one run
|
|
409
|
+
along the last axis at a time. Sending the whole box would also send the
|
|
410
|
+
cells the kernel never wrote, and those do not come back unchanged
|
|
411
|
+
through a view that converts -- a float64 array seen through an int32
|
|
412
|
+
view reads 1.75 as 1 and would be left holding 1.0. It would also
|
|
413
|
+
overwrite what the kernel wrote to the same cells through another basis
|
|
414
|
+
that addresses them in place. */
|
|
415
|
+
static VALUE
|
|
416
|
+
write_back (VALUE argument)
|
|
417
|
+
{
|
|
418
|
+
write_back_args *w = (write_back_args *) argument;
|
|
419
|
+
CArray *ca = w->ca;
|
|
420
|
+
int8_t nd = ca->ndim;
|
|
421
|
+
size_t bytes = ca->bytes;
|
|
422
|
+
ca_size_t inner = w->count[nd - 1];
|
|
423
|
+
ca_size_t outer = 1;
|
|
424
|
+
ca_size_t idx[CA_RANK_MAX], start[CA_RANK_MAX], count[CA_RANK_MAX];
|
|
425
|
+
ca_size_t o, j, e;
|
|
426
|
+
int8_t k;
|
|
427
|
+
|
|
428
|
+
for ( k = 0; k < nd - 1; k++ ) {
|
|
429
|
+
outer *= w->count[k];
|
|
430
|
+
idx[k] = 0;
|
|
431
|
+
count[k] = 1;
|
|
432
|
+
}
|
|
433
|
+
for ( o = 0; o < outer; o++ ) {
|
|
434
|
+
char *row = w->data + o * inner * bytes;
|
|
435
|
+
char *read = w->read + o * inner * bytes;
|
|
436
|
+
for ( k = 0; k < nd - 1; k++ ) start[k] = w->start[k] + idx[k];
|
|
437
|
+
j = 0;
|
|
438
|
+
while ( j < inner ) {
|
|
439
|
+
if ( ! memcmp(row + j * bytes, read + j * bytes, bytes) ) { j++; continue; }
|
|
440
|
+
e = j + 1;
|
|
441
|
+
while ( e < inner && memcmp(row + e * bytes, read + e * bytes, bytes) ) e++;
|
|
442
|
+
start[nd - 1] = w->start[nd - 1] + j;
|
|
443
|
+
count[nd - 1] = e - j;
|
|
444
|
+
ca_xfer_stride(ca, start, count, w->steps, row + j * bytes, CA_XFER_PUT);
|
|
445
|
+
j = e;
|
|
446
|
+
}
|
|
447
|
+
for ( k = nd - 2; k >= 0; k-- ) {
|
|
448
|
+
if ( ++idx[k] < w->count[k] ) break;
|
|
449
|
+
idx[k] = 0;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return Qnil;
|
|
354
453
|
}
|
|
355
454
|
|
|
356
|
-
/* Closes in reverse order, and runs whether or not the kernel raised.
|
|
455
|
+
/* Closes in reverse order, and runs whether or not the kernel raised. A
|
|
456
|
+
write-back that raises -- the array's own transfer slot failing -- is
|
|
457
|
+
set aside so that every other region is still written and freed and
|
|
458
|
+
every root detached; the block's own exception, if it raised, wins. */
|
|
357
459
|
static VALUE
|
|
358
460
|
open_ensure (VALUE argument)
|
|
359
461
|
{
|
|
@@ -371,11 +473,23 @@ open_ensure (VALUE argument)
|
|
|
371
473
|
elements *= state->region_count[i * CA_RANK_MAX + k];
|
|
372
474
|
}
|
|
373
475
|
if ( state->writable[i] && elements > 0 ) {
|
|
374
|
-
ca_size_t
|
|
476
|
+
ca_size_t steps[CA_RANK_MAX];
|
|
477
|
+
write_back_args w;
|
|
478
|
+
int tag = 0;
|
|
375
479
|
native_steps(ca, steps);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
480
|
+
w.ca = ca;
|
|
481
|
+
w.start = &state->region_start[i * CA_RANK_MAX];
|
|
482
|
+
w.count = &state->region_count[i * CA_RANK_MAX];
|
|
483
|
+
w.steps = steps;
|
|
484
|
+
w.data = state->region[i];
|
|
485
|
+
w.read = state->region[i] + elements * ca->bytes;
|
|
486
|
+
rb_protect(write_back, (VALUE) &w, &tag);
|
|
487
|
+
if ( tag ) {
|
|
488
|
+
if ( NIL_P(state->put_error) ) {
|
|
489
|
+
state->put_error = rb_errinfo();
|
|
490
|
+
}
|
|
491
|
+
rb_set_errinfo(Qnil);
|
|
492
|
+
}
|
|
379
493
|
}
|
|
380
494
|
xfree(state->region[i]);
|
|
381
495
|
}
|
|
@@ -384,6 +498,10 @@ open_ensure (VALUE argument)
|
|
|
384
498
|
}
|
|
385
499
|
}
|
|
386
500
|
xfree(state->block);
|
|
501
|
+
if ( state->body_done && RTEST(rb_obj_is_kind_of(state->put_error,
|
|
502
|
+
rb_eException)) ) {
|
|
503
|
+
rb_exc_raise(state->put_error);
|
|
504
|
+
}
|
|
387
505
|
return Qnil;
|
|
388
506
|
}
|
|
389
507
|
|
|
@@ -451,7 +569,12 @@ packed_body (VALUE argument)
|
|
|
451
569
|
}
|
|
452
570
|
}
|
|
453
571
|
|
|
454
|
-
|
|
572
|
+
{
|
|
573
|
+
VALUE result = rb_yield_values(4, pointers, strides, mask_pointers,
|
|
574
|
+
mask_strides);
|
|
575
|
+
state->body_done = 1;
|
|
576
|
+
return result;
|
|
577
|
+
}
|
|
455
578
|
}
|
|
456
579
|
|
|
457
580
|
/*
|
|
@@ -489,9 +612,25 @@ address_basis_open (int argc, VALUE *argv, VALUE module)
|
|
|
489
612
|
rb_raise(rb_eArgError, "one writable flag per array is required");
|
|
490
613
|
}
|
|
491
614
|
|
|
615
|
+
/* Every argument is checked before the block below is allocated: a
|
|
616
|
+
refusal raises, and it must find nothing to free. */
|
|
617
|
+
for ( i = 0; i < (int) RARRAY_LEN(arrays); i++ ) {
|
|
618
|
+
VALUE object = rb_ary_entry(arrays, i);
|
|
619
|
+
CArray *ca;
|
|
620
|
+
GetCArray(object, ca);
|
|
621
|
+
/* A view takes its mask from its parent when first asked for it; one
|
|
622
|
+
added to the parent after the view was made is not on ca->mask yet. */
|
|
623
|
+
ca_update_mask(ca);
|
|
624
|
+
verify_usable(object, ca, RTEST(rb_ary_entry(writable_flags, i)));
|
|
625
|
+
verify_mask_cells(object, ca);
|
|
626
|
+
verify_box(box_start, box_count, i, ca);
|
|
627
|
+
}
|
|
628
|
+
|
|
492
629
|
state.count = (int) RARRAY_LEN(arrays);
|
|
493
630
|
state.slots = state.count * 2;
|
|
494
|
-
|
|
631
|
+
/* Our own copy: the caller's Array can be emptied inside the block, and
|
|
632
|
+
the arrays it held are attached until open_ensure has run. */
|
|
633
|
+
state.arrays = rb_ary_dup(arrays);
|
|
495
634
|
state.bases = rb_ary_new_capa(state.count);
|
|
496
635
|
/* One allocation, carved up, rather than eight. Every array here is the
|
|
497
636
|
same length in slots and lives exactly as long as the open, so there is
|
|
@@ -521,15 +660,15 @@ address_basis_open (int argc, VALUE *argv, VALUE module)
|
|
|
521
660
|
}
|
|
522
661
|
state.box_starts = box_start;
|
|
523
662
|
state.box_counts = box_count;
|
|
663
|
+
state.body_done = 0;
|
|
664
|
+
state.put_error = Qnil;
|
|
524
665
|
|
|
525
666
|
for ( i = 0; i < state.count; i++ ) {
|
|
526
|
-
VALUE object = rb_ary_entry(arrays, i);
|
|
667
|
+
VALUE object = rb_ary_entry(state.arrays, i);
|
|
527
668
|
CArray *ca;
|
|
528
669
|
GetCArray(object, ca);
|
|
529
670
|
state.carrays[i] = ca;
|
|
530
671
|
state.writable[i] = RTEST(rb_ary_entry(writable_flags, i));
|
|
531
|
-
verify_usable(object, ca, state.writable[i]);
|
|
532
|
-
verify_box(box_start, box_count, i, ca);
|
|
533
672
|
state.tier[i] = tier_for(ca);
|
|
534
673
|
|
|
535
674
|
if ( ca->mask ) {
|
|
@@ -540,10 +679,12 @@ address_basis_open (int argc, VALUE *argv, VALUE module)
|
|
|
540
679
|
}
|
|
541
680
|
}
|
|
542
681
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
682
|
+
{
|
|
683
|
+
VALUE result = RTEST(packed)
|
|
684
|
+
? rb_ensure(packed_body, (VALUE) &state, open_ensure, (VALUE) &state)
|
|
685
|
+
: rb_ensure(open_body, (VALUE) &state, open_ensure, (VALUE) &state);
|
|
686
|
+
RB_GC_GUARD(state.arrays);
|
|
687
|
+
return result;
|
|
547
688
|
}
|
|
548
689
|
}
|
|
549
690
|
|
data/ext/carray_attribute.c
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
#include "carray.h"
|
|
15
15
|
#include "ca_obj_face.h" /* CA_OBJ_RECORD + rb_ca_record_get_data_class */
|
|
16
|
+
#include "carray_internal.h" /* rb_ca_inherit_attr */
|
|
16
17
|
|
|
17
18
|
/* ------------------------------------------------------------------- */
|
|
18
19
|
|
|
@@ -436,6 +437,8 @@ rb_ca_is_object_type (VALUE self)
|
|
|
436
437
|
/* ------------------------------------------------------------------- */
|
|
437
438
|
|
|
438
439
|
static ID id_parent;
|
|
440
|
+
static ID id_attr;
|
|
441
|
+
static ID id_attrs;
|
|
439
442
|
|
|
440
443
|
VALUE
|
|
441
444
|
rb_ca_parent (VALUE self)
|
|
@@ -443,13 +446,41 @@ rb_ca_parent (VALUE self)
|
|
|
443
446
|
return rb_ivar_get(self, id_parent);
|
|
444
447
|
}
|
|
445
448
|
|
|
449
|
+
/* Give dst the attributes (lib/carray/attribute.rb) that src shows, as its
|
|
450
|
+
own Hash. Used by the methods that produce a new entity holding the
|
|
451
|
+
same values -- copy, to_type. The parent walk here only decides
|
|
452
|
+
whether any array on the chain has an @attr at all; which of them
|
|
453
|
+
src actually shows (a lazy op view stops the chain) is left to #attrs,
|
|
454
|
+
so the rule lives in one place. */
|
|
455
|
+
void
|
|
456
|
+
rb_ca_inherit_attr (VALUE dst, VALUE src)
|
|
457
|
+
{
|
|
458
|
+
VALUE obj = src, attrs;
|
|
459
|
+
int depth;
|
|
460
|
+
|
|
461
|
+
for (depth = 0; depth < 64 && ! NIL_P(obj); depth++) {
|
|
462
|
+
if ( rb_ivar_defined(obj, id_attr) ) {
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
obj = rb_ivar_get(obj, id_parent);
|
|
466
|
+
}
|
|
467
|
+
if ( depth == 64 || NIL_P(obj) ) {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
attrs = rb_funcall(src, id_attrs, 0);
|
|
471
|
+
if ( RHASH_SIZE(attrs) > 0 ) {
|
|
472
|
+
rb_ivar_set(dst, id_attr, rb_hash_dup(attrs));
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/* A view of a frozen array is not frozen itself: building it may still set
|
|
477
|
+
it up after this (an ivar, a lift that moves it onto another parent), and
|
|
478
|
+
writes through it are refused by ca_is_readonly, which walks to the
|
|
479
|
+
frozen root and finds CA_FLAG_READ_ONLY there. */
|
|
446
480
|
VALUE
|
|
447
481
|
rb_ca_set_parent (VALUE self, VALUE obj)
|
|
448
482
|
{
|
|
449
483
|
rb_ivar_set(self, id_parent, obj);
|
|
450
|
-
if ( OBJ_FROZEN(obj) ) {
|
|
451
|
-
rb_ca_freeze(self);
|
|
452
|
-
}
|
|
453
484
|
return obj;
|
|
454
485
|
}
|
|
455
486
|
|
|
@@ -521,6 +552,15 @@ ca_root_array (void *ap)
|
|
|
521
552
|
}
|
|
522
553
|
}
|
|
523
554
|
|
|
555
|
+
/* Whether two arrays may share memory: their cells live in the same
|
|
556
|
+
root. An operation that writes one while reading the other must read
|
|
557
|
+
from a copy taken before it writes. */
|
|
558
|
+
int
|
|
559
|
+
ca_shares_root (void *ap, void *aq)
|
|
560
|
+
{
|
|
561
|
+
return ca_root_array(ap) == ca_root_array(aq);
|
|
562
|
+
}
|
|
563
|
+
|
|
524
564
|
static VALUE
|
|
525
565
|
rb_ca_root_array (VALUE self)
|
|
526
566
|
{
|
|
@@ -584,6 +624,8 @@ void
|
|
|
584
624
|
Init_carray_attribute (void)
|
|
585
625
|
{
|
|
586
626
|
id_parent = rb_intern("parent");
|
|
627
|
+
id_attr = rb_intern("@attr");
|
|
628
|
+
id_attrs = rb_intern("attrs");
|
|
587
629
|
|
|
588
630
|
rb_define_method(rb_cCArray, "obj_type", rb_ca_obj_type, 0);
|
|
589
631
|
rb_define_method(rb_cCArray, "data_type", rb_ca_data_type, 0);
|
data/ext/carray_bincount.c
CHANGED
|
@@ -72,6 +72,34 @@
|
|
|
72
72
|
} \
|
|
73
73
|
} while (0)
|
|
74
74
|
|
|
75
|
+
/* Checked before a window opens: the dispatches above raise on a type
|
|
76
|
+
they do not cover, which would leave the labels (and weights) attached. */
|
|
77
|
+
static void
|
|
78
|
+
bincount_check_types (CArray *cl, CArray *cw)
|
|
79
|
+
{
|
|
80
|
+
switch ( cl->data_type ) {
|
|
81
|
+
case CA_INT8: case CA_INT16: case CA_INT32: case CA_INT64:
|
|
82
|
+
case CA_UINT8: case CA_UINT16: case CA_UINT32: case CA_UINT64:
|
|
83
|
+
break;
|
|
84
|
+
default:
|
|
85
|
+
rb_raise(rb_eCADataTypeError,
|
|
86
|
+
"bincount: integer label array required (got %d)",
|
|
87
|
+
cl->data_type);
|
|
88
|
+
}
|
|
89
|
+
if ( ! cw ) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
switch ( cw->data_type ) {
|
|
93
|
+
case CA_FLOAT64: case CA_FLOAT32:
|
|
94
|
+
case CA_INT8: case CA_INT16: case CA_INT32: case CA_INT64:
|
|
95
|
+
case CA_UINT8: case CA_UINT16: case CA_UINT32: case CA_UINT64:
|
|
96
|
+
break;
|
|
97
|
+
default:
|
|
98
|
+
rb_raise(rb_eCADataTypeError,
|
|
99
|
+
"bincount: weights must be numeric (got %d)", cw->data_type);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
75
103
|
/* __bincount_count__(length) -- count occurrences of each label in
|
|
76
104
|
self. Allocates a zero-filled UInt32 (or UInt64 if length >= 2^32)
|
|
77
105
|
output of size `length`, then runs the 8-way label dispatch. */
|
|
@@ -104,7 +132,8 @@ rb_ca_bincount_count_kernel (VALUE self, VALUE rlength)
|
|
|
104
132
|
return vout;
|
|
105
133
|
}
|
|
106
134
|
|
|
107
|
-
|
|
135
|
+
bincount_check_types(cl, NULL);
|
|
136
|
+
ca_attach(cl); /* window: nothing raises inside */
|
|
108
137
|
n = cl->elements;
|
|
109
138
|
mlabel = cl->mask ? (boolean8_t *) cl->mask->ptr : NULL;
|
|
110
139
|
|
|
@@ -213,7 +242,8 @@ rb_ca_bincount_weighted_kernel (VALUE self, VALUE rweights, VALUE rlength)
|
|
|
213
242
|
return vout;
|
|
214
243
|
}
|
|
215
244
|
|
|
216
|
-
|
|
245
|
+
bincount_check_types(cl, cw);
|
|
246
|
+
ca_attach_n(2, cl, cw); /* window: nothing raises inside */
|
|
217
247
|
n = cl->elements;
|
|
218
248
|
mlabel = cl->mask ? (boolean8_t *) cl->mask->ptr : NULL;
|
|
219
249
|
mweight = cw->mask ? (boolean8_t *) cw->mask->ptr : NULL;
|
data/ext/carray_broadcast.c
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
---------------------------------------------------------------------------- */
|
|
31
31
|
|
|
32
32
|
#include "carray.h"
|
|
33
|
+
#include "ca_obj_face.h" /* CA_WRAPPER_LIFT */
|
|
33
34
|
|
|
34
35
|
NORETURN(static void ca_broadcast_refuse_write (VALUE dst, VALUE src));
|
|
35
36
|
|
|
@@ -39,7 +40,7 @@ ca_broadcast_refuse_write (VALUE dst, VALUE src)
|
|
|
39
40
|
{
|
|
40
41
|
volatile VALUE dst_s = rb_inspect(rb_funcall(dst, rb_intern("shape"), 0));
|
|
41
42
|
volatile VALUE src_s = rb_inspect(rb_funcall(src, rb_intern("shape"), 0));
|
|
42
|
-
rb_raise(
|
|
43
|
+
rb_raise(rb_eArgError,
|
|
43
44
|
"shape mismatch writing to carray (%s <- %s); shapes must agree "
|
|
44
45
|
"once size-1 axes are dropped, or one side must be 1-D, or the "
|
|
45
46
|
"source must be smaller and broadcastable -- use .flatten to "
|
|
@@ -119,7 +120,7 @@ ca_broadcast_view (VALUE src, int8_t ndim, ca_size_t *target_dim)
|
|
|
119
120
|
TypedData_Get_Struct(src, CArray, &carray_data_type, cs);
|
|
120
121
|
|
|
121
122
|
if (cs->ndim != ndim) {
|
|
122
|
-
rb_raise(
|
|
123
|
+
rb_raise(rb_eArgError,
|
|
123
124
|
"broadcast: ndim mismatch (%d vs %d)",
|
|
124
125
|
(int) cs->ndim, (int) ndim);
|
|
125
126
|
}
|
|
@@ -143,7 +144,7 @@ ca_broadcast_view (VALUE src, int8_t ndim, ca_size_t *target_dim)
|
|
|
143
144
|
needs_broadcast = 1;
|
|
144
145
|
}
|
|
145
146
|
else {
|
|
146
|
-
rb_raise(
|
|
147
|
+
rb_raise(rb_eArgError,
|
|
147
148
|
"broadcast: cannot broadcast axis %d (%lld vs %lld)",
|
|
148
149
|
i, (long long) cs->dim[i], (long long) target_dim[i]);
|
|
149
150
|
}
|
|
@@ -172,20 +173,48 @@ ca_broadcast_view (VALUE src, int8_t ndim, ca_size_t *target_dim)
|
|
|
172
173
|
raises). */
|
|
173
174
|
NORETURN(static void ca_broadcast_refuse (VALUE self, VALUE other));
|
|
174
175
|
|
|
175
|
-
/* Report a pair that cannot be brought to a common shape.
|
|
176
|
-
shapes
|
|
177
|
-
|
|
176
|
+
/* Report a pair that cannot be brought to a common shape. The message
|
|
177
|
+
names both shapes and points to the remedy that fits the pair: when
|
|
178
|
+
the ndim differs, the missing axes are added with :_; when the
|
|
179
|
+
element counts are equal, .flatten pairs the values in the order
|
|
180
|
+
they lie. */
|
|
178
181
|
static void
|
|
179
182
|
ca_broadcast_refuse (VALUE self, VALUE other)
|
|
180
183
|
{
|
|
184
|
+
CArray *ca, *cb;
|
|
181
185
|
volatile VALUE self_s = rb_inspect(rb_funcall(self, rb_intern("shape"), 0));
|
|
182
186
|
volatile VALUE other_s = rb_inspect(rb_funcall(other, rb_intern("shape"), 0));
|
|
187
|
+
const char *flatten_hint;
|
|
188
|
+
int i;
|
|
189
|
+
|
|
190
|
+
TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
|
|
191
|
+
TypedData_Get_Struct(other, CArray, &carray_data_type, cb);
|
|
192
|
+
|
|
193
|
+
flatten_hint = (ca->elements == cb->elements)
|
|
194
|
+
? "; to pair the values in the order they lie, use .flatten on both sides"
|
|
195
|
+
: "";
|
|
196
|
+
|
|
197
|
+
if (ca->ndim != cb->ndim) {
|
|
198
|
+
rb_raise(rb_eArgError,
|
|
199
|
+
"shape mismatch between operands (%s and %s): the operands "
|
|
200
|
+
"have different numbers of axes, and axes are not added "
|
|
201
|
+
"implicitly -- add size-1 axes with :_ so both have the same "
|
|
202
|
+
"number (x[:_, nil] makes a 1-D x a row, x[nil, :_] a column)%s",
|
|
203
|
+
StringValueCStr(self_s), StringValueCStr(other_s),
|
|
204
|
+
flatten_hint);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
for (i = 0; i < ca->ndim; i++) {
|
|
208
|
+
if (ca->dim[i] != cb->dim[i] && ca->dim[i] != 1 && cb->dim[i] != 1) {
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
183
212
|
rb_raise(rb_eArgError,
|
|
184
|
-
"shape mismatch between operands (%s and %s)
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
|
|
188
|
-
|
|
213
|
+
"shape mismatch between operands (%s and %s): axis %d has "
|
|
214
|
+
"sizes %lld and %lld; each axis must have the same size, or "
|
|
215
|
+
"size 1 on one side%s",
|
|
216
|
+
StringValueCStr(self_s), StringValueCStr(other_s), i,
|
|
217
|
+
(long long) ca->dim[i], (long long) cb->dim[i], flatten_hint);
|
|
189
218
|
}
|
|
190
219
|
|
|
191
220
|
void
|
|
@@ -272,7 +301,7 @@ rb_ca_broadcast_to (int argc, VALUE *argv, VALUE self)
|
|
|
272
301
|
target_ndim = (int8_t) argc;
|
|
273
302
|
|
|
274
303
|
if (target_ndim < cs->ndim) {
|
|
275
|
-
rb_raise(
|
|
304
|
+
rb_raise(rb_eArgError,
|
|
276
305
|
"broadcast_to: target ndim %d smaller than source ndim %d",
|
|
277
306
|
(int) target_ndim, (int) cs->ndim);
|
|
278
307
|
}
|
|
@@ -303,6 +332,7 @@ rb_ca_broadcast_to (int argc, VALUE *argv, VALUE self)
|
|
|
303
332
|
}
|
|
304
333
|
obj = ca_wrap_struct(view);
|
|
305
334
|
rb_ca_set_parent(obj, self);
|
|
335
|
+
CA_WRAPPER_LIFT(obj, self, cs);
|
|
306
336
|
return obj;
|
|
307
337
|
}
|
|
308
338
|
|
|
@@ -340,7 +370,7 @@ rb_ca_broadcast_to (int argc, VALUE *argv, VALUE self)
|
|
|
340
370
|
else {
|
|
341
371
|
/* sd == -1 (source exhausted) with dd > 1, or sd > 1 with
|
|
342
372
|
dd > 1 and not equal: cannot broadcast. */
|
|
343
|
-
rb_raise(
|
|
373
|
+
rb_raise(rb_eArgError,
|
|
344
374
|
"broadcast_to: cannot broadcast axis %d "
|
|
345
375
|
"(source %s, target %lld)",
|
|
346
376
|
t_idx,
|
|
@@ -351,7 +381,7 @@ rb_ca_broadcast_to (int argc, VALUE *argv, VALUE self)
|
|
|
351
381
|
}
|
|
352
382
|
|
|
353
383
|
if (s_idx >= 0) {
|
|
354
|
-
rb_raise(
|
|
384
|
+
rb_raise(rb_eArgError,
|
|
355
385
|
"broadcast_to: %d source axes left unmatched", s_idx + 1);
|
|
356
386
|
}
|
|
357
387
|
|
|
@@ -366,6 +396,8 @@ rb_ca_broadcast_to (int argc, VALUE *argv, VALUE self)
|
|
|
366
396
|
}
|
|
367
397
|
obj = ca_wrap_struct(view);
|
|
368
398
|
rb_ca_set_parent(obj, self);
|
|
399
|
+
/* The Face stays on top, as for every view. */
|
|
400
|
+
CA_WRAPPER_LIFT(obj, self, cs);
|
|
369
401
|
return obj;
|
|
370
402
|
}
|
|
371
403
|
|