carray 3.0.0 → 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/.yardopts +2 -1
- data/CHANGELOG.md +845 -3
- data/{NEWS.md → CHANGELOG.v1.md} +1 -1
- data/README.md +33 -33
- data/carray.gemspec +12 -8
- data/ext/ca_axis_dispatch.c +33 -4
- data/ext/ca_axis_group.c +256 -114
- data/ext/ca_binop_dispatch.c +5 -6
- data/ext/ca_binop_dispatch.h +0 -7
- data/ext/ca_categorical_iterator.c +121 -67
- data/ext/ca_for_each_element.h +6 -8
- data/ext/ca_group_iter.c +1 -1
- data/ext/ca_kernel_iterator.c +386 -74
- data/ext/ca_kernel_iterator.h +145 -45
- data/ext/ca_obj_array.c +62 -20
- data/ext/ca_obj_bincmp.c +57 -27
- data/ext/ca_obj_binop.c +86 -30
- data/ext/ca_obj_block.c +4 -4
- data/ext/ca_obj_const_string.c +88 -27
- data/ext/ca_obj_face.c +104 -0
- data/ext/ca_obj_face.h +48 -1
- data/ext/ca_obj_fake.c +11 -0
- data/ext/ca_obj_fixlen_string.c +21 -6
- data/ext/ca_obj_grid.c +11 -3
- data/ext/ca_obj_meld.c +125 -22
- data/ext/ca_obj_moncmp.c +33 -14
- data/ext/ca_obj_monop.c +19 -7
- data/ext/ca_obj_object.c +107 -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.c +49 -34
- data/ext/ca_obj_select_axis.c +16 -6
- data/ext/ca_obj_shift.c +3 -3
- data/ext/ca_obj_stack.c +3 -8
- data/ext/ca_obj_stride.c +178 -24
- data/ext/ca_obj_string.c +11 -5
- 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 +94 -19
- data/ext/ca_op_cmplx64.h +123 -0
- data/ext/ca_op_ipower.c +1 -5
- data/ext/ca_rng_normal.h +42 -0
- data/ext/ca_rng_xoshiro256pp.h +105 -0
- data/ext/ca_sort_kernels.h +5 -5
- data/ext/ca_sweep_engine.c +362 -155
- data/ext/ca_sweep_engine.h +39 -9
- data/ext/ca_transform_common.c +7 -0
- data/ext/carray.h +148 -132
- data/ext/carray_access.c +83 -49
- data/ext/carray_address_basis.c +590 -0
- data/ext/carray_bincount.c +8 -8
- data/ext/carray_broadcast.c +102 -9
- data/ext/carray_build_flags.h +3 -0
- data/ext/carray_call_cfunc.c +2010 -335
- data/ext/carray_call_cfunc.h +153 -0
- data/ext/carray_cast.c +184 -72
- data/ext/carray_conversion.c +22 -22
- data/ext/carray_copy.c +67 -32
- data/ext/carray_core.c +140 -13
- data/ext/carray_count.c +10 -11
- data/ext/carray_element.c +7 -7
- data/ext/carray_factorize.c +72 -51
- data/ext/carray_hold.c +1 -1
- data/ext/carray_index_classifier.c +7 -21
- data/ext/carray_internal.h +36 -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 +256 -87
- data/ext/carray_kernels_reduce_boolean.c +1 -0
- data/ext/carray_kernels_reduce_cumulative.c +324 -54
- data/ext/carray_kernels_reduce_extreme.c +605 -58
- data/ext/carray_kernels_reduce_variance.c +1 -0
- data/ext/carray_kernels_scan.c +5 -4
- data/ext/carray_kernels_search.c +187 -106
- 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_loop.c +7 -1
- data/ext/carray_mask.c +29 -13
- data/ext/carray_median_percentile.c +56 -1
- data/ext/carray_memory_view.c +46 -21
- data/ext/carray_operator.c +50 -53
- data/ext/carray_order.c +1 -1
- data/ext/carray_partition.c +4 -4
- data/ext/carray_random.c +391 -47
- data/ext/carray_scatter.c +1 -1
- data/ext/carray_slab.c +13 -0
- data/ext/carray_sort.c +22 -24
- 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 +323 -145
- data/ext/mkkernel.rb +651 -129
- data/ext/ruby_carray.c +28 -17
- data/ext/version.h +4 -4
- data/lib/carray/autoload_carray.rb +24 -3
- data/lib/carray/autoload_method_extension.rb +14 -1
- data/lib/carray/axis_group.rb +84 -7
- data/lib/carray/basics.rb +63 -59
- data/lib/carray/bincount_nd.rb +12 -12
- data/lib/carray/block_iterator.rb +111 -25
- data/lib/carray/categorical.rb +154 -37
- data/lib/carray/categorical_iterator.rb +300 -151
- data/lib/carray/conditional.rb +14 -14
- data/lib/carray/const_string.rb +131 -27
- data/lib/carray/construct.rb +61 -0
- data/lib/carray/core_extensions.rb +62 -5
- data/lib/carray/data_type_extension.rb +21 -1
- data/lib/carray/data_type_limits.rb +91 -0
- data/lib/carray/fixlen_string.rb +1 -1
- data/lib/carray/frame/concat.rb +3 -3
- data/lib/carray/frame/convert.rb +1 -1
- data/lib/carray/frame/csv_parser.rb +11 -4
- data/lib/carray/frame/frame.rb +85 -21
- data/lib/carray/frame/group.rb +36 -3
- data/lib/carray/frame/io.rb +224 -15
- data/lib/carray/frame/records.rb +18 -4
- data/lib/carray/frame/sort.rb +1 -1
- data/lib/carray/frame/verbs.rb +32 -12
- 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 +43 -16
- data/lib/carray/iterator.rb +147 -3
- data/lib/carray/lazy.rb +88 -73
- data/lib/carray/mask_gap_fill.rb +3 -1
- 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/discovery_along.rb +74 -0
- data/lib/carray/methods/factorize.rb +50 -0
- data/lib/carray/methods/is_in.rb +25 -14
- data/lib/carray/methods/locate_addr.rb +81 -3
- data/lib/carray/methods/mask_duplicates.rb +36 -2
- data/lib/carray/methods/meshgrid.rb +4 -5
- data/lib/carray/methods/mode.rb +2 -2
- data/lib/carray/methods/nunique.rb +23 -2
- data/lib/carray/methods/repeat.rb +110 -0
- data/lib/carray/methods/snap.rb +7 -2
- data/lib/carray/methods/unique.rb +44 -4
- data/lib/carray/methods/value_counts.rb +2 -2
- data/lib/carray/rng.rb +86 -0
- data/lib/carray/runtime.rb +0 -19
- data/lib/carray/slab_iterator.rb +77 -19
- data/lib/carray/string_operation_extension.rb +10 -6
- data/lib/carray/time.rb +906 -491
- data/lib/carray/window_iterator.rb +421 -27
- data/lib/carray.rb +7 -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 +68 -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 +57 -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 +34 -0
- data/yard-stubs/carray_count.rb +84 -0
- data/yard-stubs/carray_element.rb +108 -0
- data/yard-stubs/carray_generate.rb +66 -0
- data/yard-stubs/carray_lazy.rb +228 -0
- data/yard-stubs/carray_loop.rb +140 -0
- data/yard-stubs/carray_mask.rb +259 -0
- data/yard-stubs/carray_math.rb +1615 -0
- data/yard-stubs/carray_mathfunc.rb +45 -0
- data/yard-stubs/carray_median_percentile.rb +103 -0
- data/yard-stubs/carray_memory_view.rb +163 -0
- data/yard-stubs/carray_order.rb +252 -0
- data/yard-stubs/carray_random.rb +89 -0
- data/yard-stubs/carray_scatter.rb +106 -0
- data/yard-stubs/carray_slab.rb +59 -0
- data/yard-stubs/carray_sort.rb +165 -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 +67 -10
- data/ext/ca_obj_unbound_repeat.c +0 -496
data/ext/ca_obj_tile.c
CHANGED
|
@@ -214,10 +214,18 @@ ca_tile_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
214
214
|
s = ca->bytes;
|
|
215
215
|
for (k = ndim - 1; k >= 0; k--) { dstride[k] = s; s *= counts[k]; }
|
|
216
216
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
217
|
+
/* The request is over the view's addresses, so a transposed / flat request
|
|
218
|
+
is legal and must not be composed axis-by-axis; see
|
|
219
|
+
ca_xfer_stride_request_is_axis_box (carray.h). */
|
|
220
|
+
if ( ! ca_xfer_stride_request_is_axis_box(ca, starts, counts, strides) ) {
|
|
221
|
+
structural = 0;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
for (k = 0; k < ndim; k++) {
|
|
225
|
+
if (strides[k] % tnative[k] != 0 || strides[k] / tnative[k] != 1) {
|
|
226
|
+
structural = 0;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
221
229
|
}
|
|
222
230
|
}
|
|
223
231
|
|
|
@@ -546,7 +554,7 @@ rb_ca_tile (int argc, VALUE *argv, VALUE self)
|
|
|
546
554
|
|
|
547
555
|
{
|
|
548
556
|
VALUE obj = rb_ca_tile_new(self, reps);
|
|
549
|
-
|
|
557
|
+
CA_WRAPPER_LIFT(obj, self, ca);
|
|
550
558
|
return obj;
|
|
551
559
|
}
|
|
552
560
|
}
|
data/ext/ca_obj_time.c
CHANGED
|
@@ -293,7 +293,9 @@ ca_operation_function_t ca_time_func = {
|
|
|
293
293
|
ca_face_xfer_addrs,
|
|
294
294
|
NULL, /* fold_stride: identity Face is not foldable */
|
|
295
295
|
ca_face_xfer_stride,
|
|
296
|
-
ca_face_xfer_all
|
|
296
|
+
ca_face_xfer_all,
|
|
297
|
+
.fill_addrs = ca_face_fill_addrs,
|
|
298
|
+
.fill_stride = ca_face_fill_stride,
|
|
297
299
|
};
|
|
298
300
|
|
|
299
301
|
/* ------------------------------------------------------------------- */
|
data/ext/ca_obj_timedelta.c
CHANGED
|
@@ -273,7 +273,9 @@ ca_operation_function_t ca_timedelta_func = {
|
|
|
273
273
|
ca_face_xfer_addrs,
|
|
274
274
|
NULL, /* fold_stride */
|
|
275
275
|
ca_face_xfer_stride,
|
|
276
|
-
ca_face_xfer_all
|
|
276
|
+
ca_face_xfer_all,
|
|
277
|
+
.fill_addrs = ca_face_fill_addrs,
|
|
278
|
+
.fill_stride = ca_face_fill_stride,
|
|
277
279
|
};
|
|
278
280
|
|
|
279
281
|
/* ------------------------------------------------------------------- */
|
data/ext/ca_obj_transpose.c
CHANGED
data/ext/ca_obj_triop.c
CHANGED
|
@@ -61,12 +61,19 @@ typedef struct CATriOp {
|
|
|
61
61
|
CArray *parent; /* = op1 */
|
|
62
62
|
uint32_t attach;
|
|
63
63
|
uint8_t nosync;
|
|
64
|
+
/* ---- CAMultiParent conformance (CA_FLAG_MULTI_PARENTS): n_parents and
|
|
65
|
+
parents[] sit immediately after the CAView header, as carray.h's
|
|
66
|
+
layout convention requires, so ca_has_mask can fold over both
|
|
67
|
+
operands and build the mask on demand instead of at setup. ---- */
|
|
68
|
+
int32_t n_parents; /* always 3 */
|
|
69
|
+
CArray **parents; /* = &operands[0]; no separate allocation */
|
|
64
70
|
/* CATriOp-specific tail */
|
|
65
71
|
CArray *op2;
|
|
66
72
|
CArray *op3;
|
|
67
73
|
uint16_t op_id;
|
|
68
74
|
uint8_t op2_is_scalar;
|
|
69
75
|
uint8_t op3_is_scalar;
|
|
76
|
+
CArray *operands[3]; /* {op1, op2, op3}; what parents points at */
|
|
70
77
|
} CATriOp;
|
|
71
78
|
|
|
72
79
|
static size_t
|
|
@@ -117,7 +124,7 @@ ca_triop_setup (CATriOp *ca, CArray *op1, CArray *op2, CArray *op3,
|
|
|
117
124
|
|
|
118
125
|
ca->obj_type = CA_OBJ_TRIOP;
|
|
119
126
|
ca->data_type = out_dt;
|
|
120
|
-
ca->flags = CA_FLAG_READ_ONLY;
|
|
127
|
+
ca->flags = CA_FLAG_READ_ONLY | CA_FLAG_MULTI_PARENTS;
|
|
121
128
|
ca->ndim = op1->ndim;
|
|
122
129
|
ca->bytes = out_bytes;
|
|
123
130
|
ca->elements = op1->elements;
|
|
@@ -134,12 +141,17 @@ ca_triop_setup (CATriOp *ca, CArray *op1, CArray *op2, CArray *op3,
|
|
|
134
141
|
ca->op_id = op_id;
|
|
135
142
|
ca->op2_is_scalar = ( op2->elements == 1 && op1->elements > 1 ) ? 1 : 0;
|
|
136
143
|
ca->op3_is_scalar = ( op3->elements == 1 && op1->elements > 1 ) ? 1 : 0;
|
|
144
|
+
ca->operands[0] = op1;
|
|
145
|
+
ca->operands[1] = op2;
|
|
146
|
+
ca->operands[2] = op3;
|
|
147
|
+
ca->parents = ca->operands;
|
|
148
|
+
ca->n_parents = 3;
|
|
137
149
|
|
|
138
150
|
memcpy(ca->dim, op1->dim, op1->ndim * sizeof(ca_size_t));
|
|
139
151
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
152
|
+
/* The mask is NOT built here. ca_has_mask folds over parents[] for a
|
|
153
|
+
multi-parent view and creates it on demand, so an expression whose mask
|
|
154
|
+
nobody reads never allocates one. */
|
|
143
155
|
|
|
144
156
|
if ( ca_is_scalar(op1) && ca_is_scalar(op2) && ca_is_scalar(op3) ) {
|
|
145
157
|
ca_set_flag(ca, CA_FLAG_SCALAR);
|
|
@@ -253,7 +265,9 @@ pull_operand (CArray *op, int is_scalar, ca_size_t *starts,
|
|
|
253
265
|
one_counts[k] = 1;
|
|
254
266
|
one_strides[k] = bytes;
|
|
255
267
|
}
|
|
256
|
-
scratch =
|
|
268
|
+
scratch = ( op->data_type == CA_OBJECT )
|
|
269
|
+
? ca_lazy_arena_acquire_object(1)
|
|
270
|
+
: ca_lazy_arena_acquire(bytes);
|
|
257
271
|
ca_triop_scratch_acquire_count++;
|
|
258
272
|
ca_xfer_stride(op, one_starts, one_counts, one_strides, scratch,
|
|
259
273
|
CA_XFER_GET);
|
|
@@ -266,7 +280,9 @@ pull_operand (CArray *op, int is_scalar, ca_size_t *starts,
|
|
|
266
280
|
op_strides[k] = s;
|
|
267
281
|
s *= counts[k];
|
|
268
282
|
}
|
|
269
|
-
scratch =
|
|
283
|
+
scratch = ( op->data_type == CA_OBJECT )
|
|
284
|
+
? ca_lazy_arena_acquire_object(slab_n)
|
|
285
|
+
: ca_lazy_arena_acquire(slab_n * bytes);
|
|
270
286
|
ca_triop_scratch_acquire_count++;
|
|
271
287
|
ca_xfer_stride(op, starts, counts, op_strides, scratch, CA_XFER_GET);
|
|
272
288
|
*step_out = 1;
|
|
@@ -343,6 +359,14 @@ ca_triop_func_allocate (void *ap)
|
|
|
343
359
|
{
|
|
344
360
|
CATriOp *ca = (CATriOp *) ap;
|
|
345
361
|
ca->ptr = xmalloc(ca_length(ca));
|
|
362
|
+
/* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
|
|
363
|
+
soon as the view is, so it must not be handed to the GC as raw
|
|
364
|
+
xmalloc garbage. */
|
|
365
|
+
if ( ca->data_type == CA_OBJECT ) {
|
|
366
|
+
VALUE *p = (VALUE *) ca->ptr;
|
|
367
|
+
ca_size_t i;
|
|
368
|
+
for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
|
|
369
|
+
}
|
|
346
370
|
}
|
|
347
371
|
|
|
348
372
|
static void
|
|
@@ -362,6 +386,14 @@ ca_triop_func_attach (void *ap)
|
|
|
362
386
|
s = ca->bytes;
|
|
363
387
|
for ( k = ca->ndim - 1; k >= 0; k-- ) { native[k] = s; s *= ca->dim[k]; }
|
|
364
388
|
for ( k = 0; k < ca->ndim; k++ ) starts[k] = 0;
|
|
389
|
+
/* CA_OBJECT cells are VALUEs and this buffer is about to be marked as
|
|
390
|
+
soon as the view is, so it must not be handed to the GC as raw
|
|
391
|
+
xmalloc garbage. */
|
|
392
|
+
if ( ca->data_type == CA_OBJECT ) {
|
|
393
|
+
VALUE *p = (VALUE *) ca->ptr;
|
|
394
|
+
ca_size_t i;
|
|
395
|
+
for ( i = 0; i < ca->elements; i++ ) *p++ = Qnil;
|
|
396
|
+
}
|
|
365
397
|
ca_triop_func_xfer_stride(ca, starts, ca->dim, native, ca->ptr, CA_XFER_GET);
|
|
366
398
|
}
|
|
367
399
|
|
|
@@ -405,13 +437,26 @@ ca_triop_func_create_mask (void *ap)
|
|
|
405
437
|
has3 = ca_has_mask(op3);
|
|
406
438
|
if ( ! has1 && ! has2 && ! has3 ) return;
|
|
407
439
|
|
|
440
|
+
/* Exactly one masked operand: the answer is that operand's mask, cell
|
|
441
|
+
for cell. Share it rather than allocating a copy per node. */
|
|
442
|
+
if ( has1 + has2 + has3 == 1 ) {
|
|
443
|
+
CArray *src = has1 ? op1 : ( has2 ? op2 : op3 );
|
|
444
|
+
if ( src->elements == to->elements ) {
|
|
445
|
+
to->mask = (CArray *) ca_refer_new(src->mask, CA_BOOLEAN,
|
|
446
|
+
to->ndim, to->dim, 0, 0);
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
408
451
|
to->mask = (CArray *) carray_new(CA_BOOLEAN, to->ndim, to->dim, 0, NULL);
|
|
409
452
|
dst = (boolean8_t *) to->mask->ptr;
|
|
410
453
|
n = to->elements;
|
|
411
454
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
if (
|
|
455
|
+
/* The masks are what is read here; attaching the operand instead
|
|
456
|
+
materialises the whole subexpression under it. */
|
|
457
|
+
if ( has1 ) ca_attach(op1->mask);
|
|
458
|
+
if ( has2 ) ca_attach(op2->mask);
|
|
459
|
+
if ( has3 ) ca_attach(op3->mask);
|
|
415
460
|
|
|
416
461
|
m1 = has1 ? (boolean8_t *) op1->mask->ptr : NULL;
|
|
417
462
|
m2 = has2 ? (boolean8_t *) op2->mask->ptr : NULL;
|
|
@@ -426,9 +471,9 @@ ca_triop_func_create_mask (void *ap)
|
|
|
426
471
|
dst[i] = (boolean8_t) ( a | b | c );
|
|
427
472
|
}
|
|
428
473
|
|
|
429
|
-
if ( has3 ) ca_detach(op3);
|
|
430
|
-
if ( has2 ) ca_detach(op2);
|
|
431
|
-
if ( has1 ) ca_detach(op1);
|
|
474
|
+
if ( has3 ) ca_detach(op3->mask);
|
|
475
|
+
if ( has2 ) ca_detach(op2->mask);
|
|
476
|
+
if ( has1 ) ca_detach(op1->mask);
|
|
432
477
|
}
|
|
433
478
|
|
|
434
479
|
ca_operation_function_t ca_triop_func = {
|
|
@@ -597,23 +642,17 @@ rb_ca_triop_build (VALUE cary1, VALUE cary2, VALUE cary3, uint16_t op_id)
|
|
|
597
642
|
TypedData_Get_Struct(r1, CArray, &carray_data_type, op1);
|
|
598
643
|
TypedData_Get_Struct(r3, CArray, &carray_data_type, op3);
|
|
599
644
|
|
|
600
|
-
/* Step 3:
|
|
601
|
-
|
|
602
|
-
|
|
645
|
+
/* Step 3: each of op2 / op3 must match op1's element count OR be a
|
|
646
|
+
1-element CScalar (kernel walks with element_step = 0 in that case).
|
|
647
|
+
Unreachable from Ruby; see the note in ca_obj_binop.c. */
|
|
603
648
|
if ( op2->elements != op1->elements && op2->elements != 1 ) {
|
|
604
649
|
rb_raise(rb_eArgError,
|
|
605
|
-
"CATriOp:
|
|
606
|
-
"same-ndim size-1 broadcast is supported; cross-ndim "
|
|
607
|
-
"promotion is not adopted in CArray "
|
|
608
|
-
"(reshape explicitly)",
|
|
650
|
+
"CATriOp: element count mismatch on op2 (%lld vs %lld)",
|
|
609
651
|
(long long) op2->elements, (long long) op1->elements);
|
|
610
652
|
}
|
|
611
653
|
if ( op3->elements != op1->elements && op3->elements != 1 ) {
|
|
612
654
|
rb_raise(rb_eArgError,
|
|
613
|
-
"CATriOp:
|
|
614
|
-
"same-ndim size-1 broadcast is supported; cross-ndim "
|
|
615
|
-
"promotion is not adopted in CArray "
|
|
616
|
-
"(reshape explicitly)",
|
|
655
|
+
"CATriOp: element count mismatch on op3 (%lld vs %lld)",
|
|
617
656
|
(long long) op3->elements, (long long) op1->elements);
|
|
618
657
|
}
|
|
619
658
|
|
data/ext/ca_obj_window.c
CHANGED
|
@@ -334,12 +334,20 @@ ca_window_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
334
334
|
for (k = ndim - 1; k >= 0; k--) { dstride[k] = s; s *= counts[k]; }
|
|
335
335
|
for (k = 0; k < ndim; k++) n *= counts[k];
|
|
336
336
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
337
|
+
/* The request is over the view's addresses, so a transposed / flat request
|
|
338
|
+
is legal and must not be composed axis-by-axis; see
|
|
339
|
+
ca_xfer_stride_request_is_axis_box (carray.h). */
|
|
340
|
+
if ( ! ca_xfer_stride_request_is_axis_box(w, starts, counts, strides) ) {
|
|
341
|
+
structural = 0;
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
for (k = 0; k < ndim; k++) {
|
|
345
|
+
if ( (w->bounds[k] != CA_BOUNDS_FILL && w->bounds[k] != CA_BOUNDS_MASK)
|
|
346
|
+
|| strides[k] % wnative[k] != 0
|
|
347
|
+
|| strides[k] / wnative[k] != 1 ) {
|
|
348
|
+
structural = 0;
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
343
351
|
}
|
|
344
352
|
}
|
|
345
353
|
|
|
@@ -374,12 +382,31 @@ ca_window_func_xfer_stride (void *ap, ca_size_t *starts, ca_size_t *counts,
|
|
|
374
382
|
lo[k] = l; hi[k] = h;
|
|
375
383
|
}
|
|
376
384
|
|
|
385
|
+
/* An unattached parent that ca_attach_is_alias accepts has memory to lend
|
|
386
|
+
and the attach neither allocates nor copies, so borrow it and re-enter
|
|
387
|
+
on the batched branch below. The recursion runs at most once: the
|
|
388
|
+
second entry sees parent->ptr != NULL. A parent with nothing to lend is
|
|
389
|
+
left alone — the per-row loop is the region protocol and must not be
|
|
390
|
+
traded for a whole-parent attach. */
|
|
391
|
+
if ( ! parent->ptr && ca_attach_is_alias(parent) ) {
|
|
392
|
+
ca_attach(parent);
|
|
393
|
+
if ( parent->ptr ) {
|
|
394
|
+
ca_window_func_xfer_stride(ap, starts, counts, strides, data, dir);
|
|
395
|
+
if ( dir == CA_XFER_PUT ) {
|
|
396
|
+
ca_sync(parent);
|
|
397
|
+
}
|
|
398
|
+
ca_detach(parent);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
ca_detach(parent);
|
|
402
|
+
}
|
|
403
|
+
|
|
377
404
|
/* Fast path: when the parent is attached (ptr != NULL), drive
|
|
378
405
|
ca_composite_region_* + fill_complement directly with the sub-region
|
|
379
406
|
intersection geometry. This collapses the outer per-row dispatch loop
|
|
380
407
|
(one ca_xfer_stride per inner row) into a single batched routine. An
|
|
381
|
-
unattached parent falls through to the per-row loop
|
|
382
|
-
equivalent but slower. */
|
|
408
|
+
unattached parent with nothing to lend falls through to the per-row loop
|
|
409
|
+
below, which is equivalent but slower. */
|
|
383
410
|
if ( parent->ptr ) {
|
|
384
411
|
ca_size_t any_empty = 0;
|
|
385
412
|
ca_size_t alias_parent_start[CA_RANK_MAX];
|
|
@@ -1011,10 +1038,16 @@ ca_window_func_detach (void *ap)
|
|
|
1011
1038
|
so the caller must have made it available.
|
|
1012
1039
|
|
|
1013
1040
|
CAREFUL: neither this nor ca_window_func_xfer_all may call
|
|
1014
|
-
ca_attach(parent)
|
|
1015
|
-
|
|
1016
|
-
below instead materialises a
|
|
1017
|
-
which recurses under the
|
|
1041
|
+
ca_attach(parent) on a parent that would have to materialise to answer.
|
|
1042
|
+
A transfer slot that silently does that duplicates the whole parent
|
|
1043
|
+
behind the caller's back — the cold case below instead materialises a
|
|
1044
|
+
parent-shaped scratch through ca_xfer_all, which recurses under the
|
|
1045
|
+
same rule.
|
|
1046
|
+
|
|
1047
|
+
The exception is a parent that ca_attach_is_alias accepts: there the
|
|
1048
|
+
attach hands back parent (or root) memory that already exists, so
|
|
1049
|
+
nothing is allocated or copied and the rule has nothing to protect.
|
|
1050
|
+
ca_window_func_fill_data draws the same line. */
|
|
1018
1051
|
static void
|
|
1019
1052
|
ca_window_func_run_fast_path (CAWindow *ca, char *data, int dir)
|
|
1020
1053
|
{
|
|
@@ -1049,8 +1082,44 @@ ca_window_func_xfer_all (void *ap, void *data, int dir)
|
|
|
1049
1082
|
ca_window_func_run_fast_path(ca, (char *) data, dir);
|
|
1050
1083
|
return;
|
|
1051
1084
|
}
|
|
1052
|
-
/* Cold parent
|
|
1053
|
-
|
|
1085
|
+
/* Cold parent that has memory to lend (entity, or a CAStride-family view
|
|
1086
|
+
whose composed strides alias a ptr-bearing root): borrow it. The attach
|
|
1087
|
+
costs no allocation and no copy, and on the alias path ca->parent->ptr
|
|
1088
|
+
points into the root, so a PUT lands where the scratch path would have
|
|
1089
|
+
had to copy it back. Without this the window duplicates the entire
|
|
1090
|
+
parent on every transfer, which is what an ordinary `a[nil, nil]`,
|
|
1091
|
+
`a.refer` or `a.transpose.transpose` parent used to pay. */
|
|
1092
|
+
if ( ca_attach_is_alias(ca->parent) ) {
|
|
1093
|
+
ca_attach(ca->parent);
|
|
1094
|
+
ca_window_func_run_fast_path(ca, (char *) data, dir);
|
|
1095
|
+
if ( dir == CA_XFER_PUT ) {
|
|
1096
|
+
ca_sync(ca->parent);
|
|
1097
|
+
}
|
|
1098
|
+
ca_detach(ca->parent);
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
/* Second chance: ca_attach_is_alias reads the leaf view's own strides, so
|
|
1102
|
+
it declines a chain that is only contiguous once composed (a.transpose
|
|
1103
|
+
.transpose is the plain case). ca_resolve_attached_root_via_identity
|
|
1104
|
+
folds the chain and answers the same question about the root, and when
|
|
1105
|
+
it succeeds the parent's flat byte addressing IS the root's — so the
|
|
1106
|
+
root ptr can stand in for the parent's exactly as the scratch does
|
|
1107
|
+
below, with no copy in either direction. ca_window_func_xfer_addrs
|
|
1108
|
+
already resolves its parent this way. */
|
|
1109
|
+
{
|
|
1110
|
+
CArray *root = ca_resolve_attached_root_via_identity(ca->parent);
|
|
1111
|
+
if ( root != ca->parent && root->ptr ) {
|
|
1112
|
+
CArray *parent = ca->parent;
|
|
1113
|
+
parent->ptr = root->ptr;
|
|
1114
|
+
ca_window_func_run_fast_path(ca, (char *) data, dir);
|
|
1115
|
+
parent->ptr = NULL;
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/* Cold parent with nothing to lend: materialise it into a scratch buffer
|
|
1121
|
+
via ca_xfer_all, then run the normal fast path with the scratch standing
|
|
1122
|
+
in for parent->ptr. */
|
|
1054
1123
|
{
|
|
1055
1124
|
volatile VALUE holder;
|
|
1056
1125
|
CArray *parent = ca->parent;
|
|
@@ -1296,7 +1365,7 @@ rb_ca_window_new (VALUE cary,
|
|
|
1296
1365
|
VALUE
|
|
1297
1366
|
rb_ca_window (int argc, VALUE *argv, VALUE self)
|
|
1298
1367
|
{
|
|
1299
|
-
volatile VALUE obj, ropt, rfval =
|
|
1368
|
+
volatile VALUE obj, ropt, rfval = CA_UNSPECIFIED, rbounds = Qnil, rcs;
|
|
1300
1369
|
CArray *ca;
|
|
1301
1370
|
CScalar *cs;
|
|
1302
1371
|
ca_size_t start[CA_RANK_MAX];
|
|
@@ -1334,7 +1403,7 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
|
|
|
1334
1403
|
"use fill_value: kwarg (e.g. window(-1..1, fill_value: UNDEF))");
|
|
1335
1404
|
}
|
|
1336
1405
|
|
|
1337
|
-
if ( rfval ==
|
|
1406
|
+
if ( rfval == CA_UNSPECIFIED ) {
|
|
1338
1407
|
;
|
|
1339
1408
|
}
|
|
1340
1409
|
else if ( rfval == CA_UNDEF ) {
|
|
@@ -1347,6 +1416,12 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
|
|
|
1347
1416
|
}
|
|
1348
1417
|
|
|
1349
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
|
+
}
|
|
1350
1425
|
switch ( TYPE(rbounds) ) {
|
|
1351
1426
|
case T_STRING:
|
|
1352
1427
|
cbounds = StringValuePtr(rbounds);
|
|
@@ -1397,7 +1472,7 @@ rb_ca_window (int argc, VALUE *argv, VALUE self)
|
|
|
1397
1472
|
|
|
1398
1473
|
obj = rb_ca_window_new(self, start, count, bounds, fill);
|
|
1399
1474
|
|
|
1400
|
-
|
|
1475
|
+
CA_WRAPPER_LIFT(obj, self, ca);
|
|
1401
1476
|
return obj;
|
|
1402
1477
|
}
|
|
1403
1478
|
|
|
@@ -1528,7 +1603,6 @@ rb_ca_window_get_bounds (VALUE self)
|
|
|
1528
1603
|
}
|
|
1529
1604
|
|
|
1530
1605
|
static VALUE rb_cw_get_attr_ary(start);
|
|
1531
|
-
static VALUE rb_cw_get_attr_ary(count);
|
|
1532
1606
|
static VALUE rb_cw_get_attr_ary(size0);
|
|
1533
1607
|
|
|
1534
1608
|
#ifdef CARRAY_DEV_BUILD
|
|
@@ -1611,8 +1685,9 @@ Init_ca_obj_window (void)
|
|
|
1611
1685
|
|
|
1612
1686
|
rb_define_method(rb_cCAWindow, "bounds", rb_ca_window_get_bounds, 0);
|
|
1613
1687
|
|
|
1688
|
+
/* No `count` accessor: the per-axis window widths are what `shape`
|
|
1689
|
+
already answers, and the name belongs to CArray#count. */
|
|
1614
1690
|
rb_define_method(rb_cCAWindow, "start", rb_cw_start, 0);
|
|
1615
|
-
rb_define_method(rb_cCAWindow, "count", rb_cw_count, 0);
|
|
1616
1691
|
rb_define_method(rb_cCAWindow, "size0", rb_cw_size0, 0);
|
|
1617
1692
|
|
|
1618
1693
|
#ifdef CARRAY_DEV_BUILD
|
data/ext/ca_op_cmplx64.h
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
ca_op_cmplx64.h -- the cmplx64 products and quotients, computed in
|
|
4
|
+
double and rounded once
|
|
5
|
+
|
|
6
|
+
Used by:
|
|
7
|
+
- ext/carray_kernels_binop.c and ext/carray_kernels_monop.c
|
|
8
|
+
(generated from ext/mkkernel.rb): the `*`, `/`, `rcp` and
|
|
9
|
+
`rcp_mul` kernels for CA_CMPLX64.
|
|
10
|
+
|
|
11
|
+
Why these are not just `x * y` and `x / y`. Both the product and the
|
|
12
|
+
quotient of two complex numbers subtract two products of the parts, so
|
|
13
|
+
the result cancels whenever those two are close. Done at the operands'
|
|
14
|
+
own width there are no bits left underneath to absorb the cancellation.
|
|
15
|
+
Divide has a second cost: the compiler turns a `float _Complex` divide
|
|
16
|
+
into a call to `__divsc3`, which is Smith's algorithm (scale by the
|
|
17
|
+
larger component so the intermediate squares cannot overflow) plus the
|
|
18
|
+
C99 Annex G recovery for infinities -- branches and a call per cell.
|
|
19
|
+
|
|
20
|
+
For a cmplx64 the scaling is not needed at all: the operands are
|
|
21
|
+
floats, so a product of two parts reaches about 1.2e77 where a double
|
|
22
|
+
reaches 1.8e308. Computing the textbook formulas in double therefore
|
|
23
|
+
cannot overflow, and the double carries 29 extra mantissa bits, which
|
|
24
|
+
is what the cancellation needs. Measured against an exact rational
|
|
25
|
+
reference, the double route was correctly rounded on every sample
|
|
26
|
+
where the width-native route was off by up to 1806 ulp (divide) and
|
|
27
|
+
1679 ulp (multiply).
|
|
28
|
+
|
|
29
|
+
The two are not the same trade. Divide gets faster as well, because
|
|
30
|
+
the call and the scaling both go away. Multiply gets slower, because
|
|
31
|
+
the compiler already inlines a naive float product and only calls
|
|
32
|
+
`__mulsc3` when a NaN appears -- so the wider arithmetic is pure cost
|
|
33
|
+
there, and is paid for the accuracy alone.
|
|
34
|
+
|
|
35
|
+
Annex G is preserved by falling back rather than by reimplementing it.
|
|
36
|
+
The fallback is chosen from the *result*, not from a classification of
|
|
37
|
+
the inputs: if the quick answer is not an ordinary number, hand the
|
|
38
|
+
pair to the compiler's helper and return whatever it says. Writing an
|
|
39
|
+
input classification here would mean transcribing the Annex G table,
|
|
40
|
+
and a transcription drifts from what the runtime actually does.
|
|
41
|
+
|
|
42
|
+
cmplx128 has no wider type to borrow (`long double` is a double on
|
|
43
|
+
Apple ARM64 and a slow 80-bit on x86-64), so it keeps `__mulsc3` /
|
|
44
|
+
`__divdc3`.
|
|
45
|
+
|
|
46
|
+
--------------------------------------------------------------------------- */
|
|
47
|
+
|
|
48
|
+
#ifndef CA_OP_CMPLX64_H
|
|
49
|
+
#define CA_OP_CMPLX64_H
|
|
50
|
+
|
|
51
|
+
#include "carray.h"
|
|
52
|
+
#include <math.h>
|
|
53
|
+
|
|
54
|
+
#ifdef HAVE_COMPLEX_H
|
|
55
|
+
|
|
56
|
+
/* CMPLXF is the float sibling of the CMPLX defined in carray.h, and is
|
|
57
|
+
here for the same reason: `re + I * im` evaluates `I * im` first, so an
|
|
58
|
+
im of +0.0 loses the sign of a -0.0 real part. CMPLXF is C11; provide
|
|
59
|
+
it when the toolchain predates that. */
|
|
60
|
+
#ifndef CMPLXF
|
|
61
|
+
# if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
|
|
62
|
+
# define CMPLXF(re, im) __builtin_complex((float)(re), (float)(im))
|
|
63
|
+
# else
|
|
64
|
+
# define CMPLXF(re, im) \
|
|
65
|
+
(((union { float _parts[2]; float complex _value; }) \
|
|
66
|
+
{ { (float)(re), (float)(im) } })._value)
|
|
67
|
+
# endif
|
|
68
|
+
#endif
|
|
69
|
+
|
|
70
|
+
/* The real part is `xr*yr - xi*yi`, which cancels when the two products
|
|
71
|
+
are close; the double keeps the bits that cancellation eats. Only a
|
|
72
|
+
NaN can appear here that the naive form gets wrong, since a product of
|
|
73
|
+
two floats cannot overflow a double -- an infinite part in the answer
|
|
74
|
+
is the true answer. */
|
|
75
|
+
static inline cmplx64_t
|
|
76
|
+
op_cmul_cmplx64 (cmplx64_t x, cmplx64_t y)
|
|
77
|
+
{
|
|
78
|
+
double xr = crealf(x), xi = cimagf(x);
|
|
79
|
+
double yr = crealf(y), yi = cimagf(y);
|
|
80
|
+
float rr = (float) (xr * yr - xi * yi);
|
|
81
|
+
float ri = (float) (xr * yi + xi * yr);
|
|
82
|
+
if ( isnan(rr) || isnan(ri) ) {
|
|
83
|
+
return x * y; /* __mulsc3: an infinity met a zero (Annex G) */
|
|
84
|
+
}
|
|
85
|
+
return CMPLXF(rr, ri);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static inline cmplx64_t
|
|
89
|
+
op_cdiv_cmplx64 (cmplx64_t x, cmplx64_t y)
|
|
90
|
+
{
|
|
91
|
+
double yr = crealf(y), yi = cimagf(y);
|
|
92
|
+
double d = yr * yr + yi * yi;
|
|
93
|
+
if ( d > 0.0 && d < INFINITY ) {
|
|
94
|
+
double xr = crealf(x), xi = cimagf(x);
|
|
95
|
+
float rr = (float) ((xr * yr + xi * yi) / d);
|
|
96
|
+
float ri = (float) ((xi * yr - xr * yi) / d);
|
|
97
|
+
if ( isfinite(rr) && isfinite(ri) ) {
|
|
98
|
+
return CMPLXF(rr, ri);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return x / y; /* __divsc3: zero, infinite or NaN operands (Annex G) */
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* 1 / y. Same shape with the numerator's parts folded in, so that
|
|
105
|
+
`rcp` and `1 / z` keep giving the same answer. */
|
|
106
|
+
static inline cmplx64_t
|
|
107
|
+
op_crcp_cmplx64 (cmplx64_t y)
|
|
108
|
+
{
|
|
109
|
+
double yr = crealf(y), yi = cimagf(y);
|
|
110
|
+
double d = yr * yr + yi * yi;
|
|
111
|
+
if ( d > 0.0 && d < INFINITY ) {
|
|
112
|
+
float rr = (float) (yr / d);
|
|
113
|
+
float ri = (float) (-yi / d);
|
|
114
|
+
if ( isfinite(rr) && isfinite(ri) ) {
|
|
115
|
+
return CMPLXF(rr, ri);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return 1 / y;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
#endif /* HAVE_COMPLEX_H */
|
|
122
|
+
|
|
123
|
+
#endif /* CA_OP_CMPLX64_H */
|
data/ext/ca_op_ipower.c
CHANGED
|
@@ -233,8 +233,6 @@ rb_ca_ipower (VALUE self, VALUE other)
|
|
|
233
233
|
ALLOCV_END(h1);
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
obj = rb_ca_rewrap_unbound_repeat(self, obj);
|
|
237
|
-
|
|
238
236
|
return obj;
|
|
239
237
|
}
|
|
240
238
|
|
|
@@ -275,8 +273,7 @@ rb_ca_ipower_bang (VALUE self, VALUE other)
|
|
|
275
273
|
/* CArray#pow(other) (alias `**`) — Float/Complex ** Integer takes the
|
|
276
274
|
* ipower fast path in this file; everything else falls through to the
|
|
277
275
|
* mkkernel-generated general pow/cpow (rb_ca_power in
|
|
278
|
-
* ext/carray_kernels.c).
|
|
279
|
-
* wrapping on the result. */
|
|
276
|
+
* ext/carray_kernels.c). */
|
|
280
277
|
static VALUE rb_ca_pow (VALUE self, VALUE other)
|
|
281
278
|
{
|
|
282
279
|
volatile VALUE obj;
|
|
@@ -289,7 +286,6 @@ static VALUE rb_ca_pow (VALUE self, VALUE other)
|
|
|
289
286
|
}
|
|
290
287
|
else {
|
|
291
288
|
obj = rb_ca_power(self, other);
|
|
292
|
-
obj = rb_ca_rewrap_unbound_repeat(self, obj);
|
|
293
289
|
return obj;
|
|
294
290
|
}
|
|
295
291
|
}
|
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
|
+
}
|