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/carray_random.c
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
(rb_random_*).
|
|
10
10
|
|
|
11
11
|
Dispatch:
|
|
12
|
-
random! -> uniform fill (per-
|
|
12
|
+
random! -> uniform fill (per-type branch below)
|
|
13
13
|
randomn! -> standard normal via Box-Muller (float / complex only)
|
|
14
14
|
shuffle! -> Fisher-Yates over the flat buffer, or per-slice
|
|
15
15
|
when axis: is given (byte-chunk swap)
|
|
@@ -20,24 +20,111 @@
|
|
|
20
20
|
#include "carray.h"
|
|
21
21
|
#include <math.h>
|
|
22
22
|
#include <string.h>
|
|
23
|
+
#include <stdint.h>
|
|
24
|
+
|
|
25
|
+
/* The generator itself, shared verbatim with carray-jit. See the file's
|
|
26
|
+
own comment for why it carries no include guard. */
|
|
27
|
+
#include "ca_rng_normal.h"
|
|
28
|
+
#include "ca_rng_xoshiro256pp.h"
|
|
29
|
+
|
|
30
|
+
VALUE rb_cCARng;
|
|
31
|
+
|
|
32
|
+
/* Where a fill's numbers come from. Resolved once per call rather than
|
|
33
|
+
per cell: the `rng:` argument is one object for the whole array, and
|
|
34
|
+
asking what it is inside the loop would put a Ruby type test between
|
|
35
|
+
every pair of draws.
|
|
36
|
+
|
|
37
|
+
CA_RNG_OWN holds the state's cells directly. That array belongs to
|
|
38
|
+
the CArray::Rng the caller passed, so the draws advance it and the
|
|
39
|
+
next call -- here or in a kernel -- carries on from where this one
|
|
40
|
+
stopped. */
|
|
41
|
+
enum {
|
|
42
|
+
CA_RNG_DEFAULT = 0, /* no rng: given -- the per-ractor MT */
|
|
43
|
+
CA_RNG_RUBY = 1, /* a ::Random instance -- also MT */
|
|
44
|
+
CA_RNG_OWN = 2 /* a CArray::Rng -- the generator above */
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
typedef struct {
|
|
48
|
+
int kind;
|
|
49
|
+
VALUE rng;
|
|
50
|
+
CArray *state; /* attached for CA_RNG_OWN, else NULL */
|
|
51
|
+
int64_t *cells;
|
|
52
|
+
} ca_rng_t;
|
|
23
53
|
|
|
54
|
+
static void
|
|
55
|
+
ca_rng_open (VALUE rng, ca_rng_t *source)
|
|
56
|
+
{
|
|
57
|
+
source->rng = rng;
|
|
58
|
+
source->state = NULL;
|
|
59
|
+
source->cells = NULL;
|
|
60
|
+
if (NIL_P(rng)) {
|
|
61
|
+
source->kind = CA_RNG_DEFAULT;
|
|
62
|
+
}
|
|
63
|
+
else if (rb_obj_is_kind_of(rng, rb_cCARng)) {
|
|
64
|
+
VALUE state = rb_ivar_get(rng, rb_intern("@state"));
|
|
65
|
+
CArray *ca;
|
|
66
|
+
TypedData_Get_Struct(state, CArray, &carray_data_type, ca);
|
|
67
|
+
ca_attach(ca);
|
|
68
|
+
source->kind = CA_RNG_OWN;
|
|
69
|
+
source->state = ca;
|
|
70
|
+
source->cells = (int64_t *) ca->ptr;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
source->kind = CA_RNG_RUBY;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Writes the advanced state back where it came from. Safe to call twice,
|
|
78
|
+
which is what lets an error path close before it raises. */
|
|
79
|
+
static void
|
|
80
|
+
ca_rng_close (ca_rng_t *source)
|
|
81
|
+
{
|
|
82
|
+
if (source->state) {
|
|
83
|
+
ca_sync(source->state);
|
|
84
|
+
ca_detach(source->state);
|
|
85
|
+
source->state = NULL;
|
|
86
|
+
source->cells = NULL;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
24
89
|
|
|
25
90
|
static inline double
|
|
26
|
-
ca_random_real(
|
|
91
|
+
ca_random_real (ca_rng_t *source)
|
|
27
92
|
{
|
|
28
|
-
|
|
29
|
-
return
|
|
30
|
-
|
|
31
|
-
|
|
93
|
+
switch (source->kind) {
|
|
94
|
+
case CA_RNG_OWN: return ca_xoshiro256pp_next_real(source->cells);
|
|
95
|
+
case CA_RNG_RUBY: return rb_random_real(source->rng);
|
|
96
|
+
default: return rb_genrand_real();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* A draw in [0, limit], inclusive, matching what Ruby's own bounded draw
|
|
101
|
+
promises. For the generator above that is rejection sampling: taking
|
|
102
|
+
the remainder alone would favour the low end of the range whenever the
|
|
103
|
+
range does not divide 2**64. */
|
|
104
|
+
static inline uint64_t
|
|
105
|
+
ca_xoshiro256pp_below (int64_t *state, uint64_t range)
|
|
106
|
+
{
|
|
107
|
+
uint64_t threshold, draw;
|
|
108
|
+
if (range == 0) return ca_xoshiro256pp_next(state); /* the whole word */
|
|
109
|
+
threshold = (0 - range) % range; /* 2**64 mod range */
|
|
110
|
+
do {
|
|
111
|
+
draw = ca_xoshiro256pp_next(state);
|
|
112
|
+
} while (draw < threshold);
|
|
113
|
+
return draw % range;
|
|
32
114
|
}
|
|
33
115
|
|
|
34
116
|
static inline unsigned long
|
|
35
|
-
ca_random_ulong_limited(
|
|
117
|
+
ca_random_ulong_limited (ca_rng_t *source, unsigned long limit)
|
|
36
118
|
{
|
|
37
|
-
|
|
119
|
+
switch (source->kind) {
|
|
120
|
+
case CA_RNG_OWN:
|
|
121
|
+
return (unsigned long)
|
|
122
|
+
ca_xoshiro256pp_below(source->cells, (uint64_t) limit + 1);
|
|
123
|
+
case CA_RNG_RUBY:
|
|
124
|
+
return rb_random_ulong_limited(source->rng, limit);
|
|
125
|
+
default:
|
|
38
126
|
return rb_genrand_ulong_limited(limit);
|
|
39
|
-
|
|
40
|
-
return rb_random_ulong_limited(rng, limit);
|
|
127
|
+
}
|
|
41
128
|
}
|
|
42
129
|
|
|
43
130
|
/* ---- random! ----------------------------------------------------------- */
|
|
@@ -72,6 +159,7 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
|
|
|
72
159
|
unsigned long limit = 0;
|
|
73
160
|
ca_size_t i, n;
|
|
74
161
|
VALUE rng = Qnil;
|
|
162
|
+
ca_rng_t source;
|
|
75
163
|
|
|
76
164
|
rb_scan_args(argc, argv, "02:", &arg1, &arg2, &opts);
|
|
77
165
|
rb_scan_options(opts, "rng", &rng);
|
|
@@ -109,13 +197,13 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
|
|
|
109
197
|
}
|
|
110
198
|
|
|
111
199
|
/* Materialize (low, high) as the correct scalar type and validate.
|
|
112
|
-
* For integer
|
|
113
|
-
* for the sampler); for float
|
|
200
|
+
* For integer data types, `..` closed adds 1 to high (turns into half-open
|
|
201
|
+
* for the sampler); for float data types, closed and half-open are
|
|
114
202
|
* equivalent so no adjustment. */
|
|
115
203
|
if (!is_default) {
|
|
116
|
-
int
|
|
204
|
+
int is_integer_type = (ca->data_type >= CA_INT8
|
|
117
205
|
&& ca->data_type <= CA_UINT64);
|
|
118
|
-
if (
|
|
206
|
+
if (is_integer_type) {
|
|
119
207
|
low_long = NUM2LONG(low_val);
|
|
120
208
|
high_long = NUM2LONG(high_val);
|
|
121
209
|
if (high_is_closed) high_long += 1;
|
|
@@ -140,17 +228,18 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
|
|
|
140
228
|
|
|
141
229
|
n = ca->elements;
|
|
142
230
|
ca_attach(ca);
|
|
231
|
+
ca_rng_open(rng, &source);
|
|
143
232
|
|
|
144
233
|
switch (ca->data_type) {
|
|
145
234
|
case CA_FLOAT64: {
|
|
146
235
|
double *p = (double *)ca->ptr;
|
|
147
236
|
if (is_default) {
|
|
148
237
|
for (i = 0; i < n; i++)
|
|
149
|
-
p[i] = ca_random_real(
|
|
238
|
+
p[i] = ca_random_real(&source);
|
|
150
239
|
} else {
|
|
151
240
|
double range = high_dbl - low_dbl;
|
|
152
241
|
for (i = 0; i < n; i++)
|
|
153
|
-
p[i] = low_dbl + ca_random_real(
|
|
242
|
+
p[i] = low_dbl + ca_random_real(&source) * range;
|
|
154
243
|
}
|
|
155
244
|
break;
|
|
156
245
|
}
|
|
@@ -158,11 +247,11 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
|
|
|
158
247
|
float *p = (float *)ca->ptr;
|
|
159
248
|
if (is_default) {
|
|
160
249
|
for (i = 0; i < n; i++)
|
|
161
|
-
p[i] = (float)ca_random_real(
|
|
250
|
+
p[i] = (float)ca_random_real(&source);
|
|
162
251
|
} else {
|
|
163
252
|
double range = high_dbl - low_dbl;
|
|
164
253
|
for (i = 0; i < n; i++)
|
|
165
|
-
p[i] = (float)(low_dbl + ca_random_real(
|
|
254
|
+
p[i] = (float)(low_dbl + ca_random_real(&source) * range);
|
|
166
255
|
}
|
|
167
256
|
break;
|
|
168
257
|
}
|
|
@@ -170,12 +259,12 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
|
|
|
170
259
|
double complex *p = (double complex *)ca->ptr;
|
|
171
260
|
if (is_default) {
|
|
172
261
|
for (i = 0; i < n; i++)
|
|
173
|
-
p[i] = ca_random_real(
|
|
262
|
+
p[i] = ca_random_real(&source) + ca_random_real(&source) * I;
|
|
174
263
|
} else {
|
|
175
264
|
double range = high_dbl - low_dbl;
|
|
176
265
|
for (i = 0; i < n; i++)
|
|
177
|
-
p[i] = (low_dbl + ca_random_real(
|
|
178
|
-
+ (low_dbl + ca_random_real(
|
|
266
|
+
p[i] = (low_dbl + ca_random_real(&source) * range)
|
|
267
|
+
+ (low_dbl + ca_random_real(&source) * range) * I;
|
|
179
268
|
}
|
|
180
269
|
break;
|
|
181
270
|
}
|
|
@@ -183,24 +272,25 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
|
|
|
183
272
|
float complex *p = (float complex *)ca->ptr;
|
|
184
273
|
if (is_default) {
|
|
185
274
|
for (i = 0; i < n; i++)
|
|
186
|
-
p[i] = (float)ca_random_real(
|
|
275
|
+
p[i] = (float)ca_random_real(&source) + (float)ca_random_real(&source) * I;
|
|
187
276
|
} else {
|
|
188
277
|
double range = high_dbl - low_dbl;
|
|
189
278
|
for (i = 0; i < n; i++)
|
|
190
|
-
p[i] = (float)(low_dbl + ca_random_real(
|
|
191
|
-
+ (float)(low_dbl + ca_random_real(
|
|
279
|
+
p[i] = (float)(low_dbl + ca_random_real(&source) * range)
|
|
280
|
+
+ (float)(low_dbl + ca_random_real(&source) * range) * I;
|
|
192
281
|
}
|
|
193
282
|
break;
|
|
194
283
|
}
|
|
195
284
|
case CA_BOOLEAN: {
|
|
196
285
|
boolean8_t *p = (boolean8_t *)ca->ptr;
|
|
197
286
|
for (i = 0; i < n; i++)
|
|
198
|
-
p[i] = (ca_random_real(
|
|
287
|
+
p[i] = (ca_random_real(&source) < 0.5) ? 1 : 0;
|
|
199
288
|
break;
|
|
200
289
|
}
|
|
201
290
|
default: {
|
|
202
291
|
/* integer types: CA_INT8..CA_UINT64 */
|
|
203
292
|
if (is_default) {
|
|
293
|
+
ca_rng_close(&source);
|
|
204
294
|
ca_sync(ca);
|
|
205
295
|
ca_detach(ca);
|
|
206
296
|
rb_raise(rb_eArgError,
|
|
@@ -212,52 +302,53 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
|
|
|
212
302
|
case CA_INT8: {
|
|
213
303
|
int8_t *p = (int8_t *)ca->ptr;
|
|
214
304
|
for (i = 0; i < n; i++)
|
|
215
|
-
p[i] = (int8_t)(low_long + ca_random_ulong_limited(
|
|
305
|
+
p[i] = (int8_t)(low_long + ca_random_ulong_limited(&source, limit));
|
|
216
306
|
break;
|
|
217
307
|
}
|
|
218
308
|
case CA_UINT8: {
|
|
219
309
|
uint8_t *p = (uint8_t *)ca->ptr;
|
|
220
310
|
for (i = 0; i < n; i++)
|
|
221
|
-
p[i] = (uint8_t)(low_long + ca_random_ulong_limited(
|
|
311
|
+
p[i] = (uint8_t)(low_long + ca_random_ulong_limited(&source, limit));
|
|
222
312
|
break;
|
|
223
313
|
}
|
|
224
314
|
case CA_INT16: {
|
|
225
315
|
int16_t *p = (int16_t *)ca->ptr;
|
|
226
316
|
for (i = 0; i < n; i++)
|
|
227
|
-
p[i] = (int16_t)(low_long + ca_random_ulong_limited(
|
|
317
|
+
p[i] = (int16_t)(low_long + ca_random_ulong_limited(&source, limit));
|
|
228
318
|
break;
|
|
229
319
|
}
|
|
230
320
|
case CA_UINT16: {
|
|
231
321
|
uint16_t *p = (uint16_t *)ca->ptr;
|
|
232
322
|
for (i = 0; i < n; i++)
|
|
233
|
-
p[i] = (uint16_t)(low_long + ca_random_ulong_limited(
|
|
323
|
+
p[i] = (uint16_t)(low_long + ca_random_ulong_limited(&source, limit));
|
|
234
324
|
break;
|
|
235
325
|
}
|
|
236
326
|
case CA_INT32: {
|
|
237
327
|
int32_t *p = (int32_t *)ca->ptr;
|
|
238
328
|
for (i = 0; i < n; i++)
|
|
239
|
-
p[i] = (int32_t)(low_long + ca_random_ulong_limited(
|
|
329
|
+
p[i] = (int32_t)(low_long + ca_random_ulong_limited(&source, limit));
|
|
240
330
|
break;
|
|
241
331
|
}
|
|
242
332
|
case CA_UINT32: {
|
|
243
333
|
uint32_t *p = (uint32_t *)ca->ptr;
|
|
244
334
|
for (i = 0; i < n; i++)
|
|
245
|
-
p[i] = (uint32_t)(low_long + ca_random_ulong_limited(
|
|
335
|
+
p[i] = (uint32_t)(low_long + ca_random_ulong_limited(&source, limit));
|
|
246
336
|
break;
|
|
247
337
|
}
|
|
248
338
|
case CA_INT64: {
|
|
249
339
|
int64_t *p = (int64_t *)ca->ptr;
|
|
250
340
|
for (i = 0; i < n; i++)
|
|
251
|
-
p[i] = (int64_t)(low_long + ca_random_ulong_limited(
|
|
341
|
+
p[i] = (int64_t)(low_long + ca_random_ulong_limited(&source, limit));
|
|
252
342
|
break;
|
|
253
343
|
}
|
|
254
344
|
case CA_UINT64: {
|
|
255
345
|
uint64_t *p = (uint64_t *)ca->ptr;
|
|
256
346
|
for (i = 0; i < n; i++)
|
|
257
|
-
p[i] = (uint64_t)(low_long + ca_random_ulong_limited(
|
|
347
|
+
p[i] = (uint64_t)(low_long + ca_random_ulong_limited(&source, limit));
|
|
258
348
|
break;
|
|
259
349
|
}
|
|
260
350
|
default:
|
|
351
|
+
ca_rng_close(&source);
|
|
261
352
|
ca_sync(ca);
|
|
262
353
|
ca_detach(ca);
|
|
263
354
|
rb_raise(rb_eCADataTypeError,
|
|
@@ -267,6 +358,7 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
|
|
|
267
358
|
}
|
|
268
359
|
}
|
|
269
360
|
|
|
361
|
+
ca_rng_close(&source);
|
|
270
362
|
ca_sync(ca);
|
|
271
363
|
ca_detach(ca);
|
|
272
364
|
return self;
|
|
@@ -274,13 +366,30 @@ rb_ca_random_bang(int argc, VALUE *argv, VALUE self)
|
|
|
274
366
|
|
|
275
367
|
/* ---- randomn! ---------------------------------------------------------- */
|
|
276
368
|
|
|
369
|
+
/* One standard normal from the resolved source.
|
|
370
|
+
*
|
|
371
|
+
* For CArray::Rng this is two draws and no spare, which is what
|
|
372
|
+
* ca_rng_normal is and what lets a kernel's `randomn` continue a
|
|
373
|
+
* `randomn!` -- both are this function, called once per cell.
|
|
374
|
+
*
|
|
375
|
+
* For Ruby's MT the paired form below is kept: nothing there draws one
|
|
376
|
+
* at a time, so there is no second caller to agree with, and changing it
|
|
377
|
+
* would change the numbers an existing call gets. */
|
|
378
|
+
static inline double
|
|
379
|
+
ca_random_normal (ca_rng_t *source)
|
|
380
|
+
{
|
|
381
|
+
double u1 = ca_random_real(source);
|
|
382
|
+
double u2 = ca_random_real(source);
|
|
383
|
+
return ca_rng_normal(u1, u2);
|
|
384
|
+
}
|
|
385
|
+
|
|
277
386
|
static inline void
|
|
278
|
-
box_muller_pair(
|
|
387
|
+
box_muller_pair(ca_rng_t *source, double *r1, double *r2)
|
|
279
388
|
{
|
|
280
|
-
double u1 = ca_random_real(
|
|
281
|
-
double u2 = ca_random_real(
|
|
389
|
+
double u1 = ca_random_real(source);
|
|
390
|
+
double u2 = ca_random_real(source);
|
|
282
391
|
while (u1 == 0.0)
|
|
283
|
-
u1 = ca_random_real(
|
|
392
|
+
u1 = ca_random_real(source);
|
|
284
393
|
double r = sqrt(-2.0 * log(u1));
|
|
285
394
|
double theta = 2.0 * M_PI * u2;
|
|
286
395
|
*r1 = r * cos(theta);
|
|
@@ -290,7 +399,7 @@ box_muller_pair(VALUE rng, double *r1, double *r2)
|
|
|
290
399
|
/* CArray#randomn!(rng:) — fill self with standard normal N(0, 1)
|
|
291
400
|
* samples in-place via Box-Muller, returning self.
|
|
292
401
|
*
|
|
293
|
-
* Restricted to float / complex
|
|
402
|
+
* Restricted to float / complex data types. Complex fills real + imag as
|
|
294
403
|
* two independent normals per cell. */
|
|
295
404
|
static VALUE
|
|
296
405
|
rb_ca_randomn_bang(int argc, VALUE *argv, VALUE self)
|
|
@@ -301,6 +410,7 @@ rb_ca_randomn_bang(int argc, VALUE *argv, VALUE self)
|
|
|
301
410
|
|
|
302
411
|
rb_scan_args(argc, argv, "0:", &opts);
|
|
303
412
|
VALUE rng = Qnil;
|
|
413
|
+
ca_rng_t source;
|
|
304
414
|
rb_scan_options(opts, "rng", &rng);
|
|
305
415
|
|
|
306
416
|
rb_ca_modify(self);
|
|
@@ -314,17 +424,66 @@ rb_ca_randomn_bang(int argc, VALUE *argv, VALUE self)
|
|
|
314
424
|
|
|
315
425
|
n = ca->elements;
|
|
316
426
|
ca_attach(ca);
|
|
427
|
+
ca_rng_open(rng, &source);
|
|
428
|
+
|
|
429
|
+
/* A CArray::Rng fills one cell per call rather than two, so that this
|
|
430
|
+
and a kernel drawing afterwards are the one sequence: both are
|
|
431
|
+
`ca_random_normal` run once per cell. It costs a draw a cell over
|
|
432
|
+
the paired form, and what it buys is that where the generator
|
|
433
|
+
stands can be worked out rather than run. */
|
|
434
|
+
if (source.kind == CA_RNG_OWN) {
|
|
435
|
+
switch (ca->data_type) {
|
|
436
|
+
case CA_FLOAT64: {
|
|
437
|
+
double *p = (double *)ca->ptr;
|
|
438
|
+
for (i = 0; i < n; i++)
|
|
439
|
+
p[i] = ca_random_normal(&source);
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
case CA_FLOAT32: {
|
|
443
|
+
float *p = (float *)ca->ptr;
|
|
444
|
+
for (i = 0; i < n; i++)
|
|
445
|
+
p[i] = (float) ca_random_normal(&source);
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
case CA_CMPLX128: {
|
|
449
|
+
double complex *p = (double complex *)ca->ptr;
|
|
450
|
+
for (i = 0; i < n; i++) {
|
|
451
|
+
/* Into locals first: C does not say which order a call's
|
|
452
|
+
arguments are evaluated in, and these two advance a state. */
|
|
453
|
+
double re = ca_random_normal(&source);
|
|
454
|
+
double im = ca_random_normal(&source);
|
|
455
|
+
p[i] = re + im * I;
|
|
456
|
+
}
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
case CA_CMPLX64: {
|
|
460
|
+
float complex *p = (float complex *)ca->ptr;
|
|
461
|
+
for (i = 0; i < n; i++) {
|
|
462
|
+
double re = ca_random_normal(&source);
|
|
463
|
+
double im = ca_random_normal(&source);
|
|
464
|
+
p[i] = (float) re + (float) im * I;
|
|
465
|
+
}
|
|
466
|
+
break;
|
|
467
|
+
}
|
|
468
|
+
default:
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
ca_rng_close(&source);
|
|
472
|
+
ca_sync(ca);
|
|
473
|
+
ca_detach(ca);
|
|
474
|
+
return self;
|
|
475
|
+
}
|
|
317
476
|
|
|
318
477
|
switch (ca->data_type) {
|
|
319
478
|
case CA_FLOAT64: {
|
|
320
479
|
double *p = (double *)ca->ptr;
|
|
321
480
|
ca_size_t pairs = n / 2;
|
|
322
481
|
for (i = 0; i < pairs; i++) {
|
|
323
|
-
box_muller_pair(
|
|
482
|
+
box_muller_pair(&source, &p[2*i], &p[2*i+1]);
|
|
324
483
|
}
|
|
325
484
|
if (n % 2 == 1) {
|
|
326
485
|
double r1, r2;
|
|
327
|
-
box_muller_pair(
|
|
486
|
+
box_muller_pair(&source, &r1, &r2);
|
|
328
487
|
p[n-1] = r1;
|
|
329
488
|
}
|
|
330
489
|
break;
|
|
@@ -334,13 +493,13 @@ rb_ca_randomn_bang(int argc, VALUE *argv, VALUE self)
|
|
|
334
493
|
ca_size_t pairs = n / 2;
|
|
335
494
|
for (i = 0; i < pairs; i++) {
|
|
336
495
|
double r1, r2;
|
|
337
|
-
box_muller_pair(
|
|
496
|
+
box_muller_pair(&source, &r1, &r2);
|
|
338
497
|
p[2*i] = (float)r1;
|
|
339
498
|
p[2*i+1] = (float)r2;
|
|
340
499
|
}
|
|
341
500
|
if (n % 2 == 1) {
|
|
342
501
|
double r1, r2;
|
|
343
|
-
box_muller_pair(
|
|
502
|
+
box_muller_pair(&source, &r1, &r2);
|
|
344
503
|
p[n-1] = (float)r1;
|
|
345
504
|
}
|
|
346
505
|
break;
|
|
@@ -349,7 +508,7 @@ rb_ca_randomn_bang(int argc, VALUE *argv, VALUE self)
|
|
|
349
508
|
double complex *p = (double complex *)ca->ptr;
|
|
350
509
|
for (i = 0; i < n; i++) {
|
|
351
510
|
double r1, r2;
|
|
352
|
-
box_muller_pair(
|
|
511
|
+
box_muller_pair(&source, &r1, &r2);
|
|
353
512
|
p[i] = r1 + r2 * I;
|
|
354
513
|
}
|
|
355
514
|
break;
|
|
@@ -358,7 +517,7 @@ rb_ca_randomn_bang(int argc, VALUE *argv, VALUE self)
|
|
|
358
517
|
float complex *p = (float complex *)ca->ptr;
|
|
359
518
|
for (i = 0; i < n; i++) {
|
|
360
519
|
double r1, r2;
|
|
361
|
-
box_muller_pair(
|
|
520
|
+
box_muller_pair(&source, &r1, &r2);
|
|
362
521
|
p[i] = (float)r1 + (float)r2 * I;
|
|
363
522
|
}
|
|
364
523
|
break;
|
|
@@ -367,6 +526,7 @@ rb_ca_randomn_bang(int argc, VALUE *argv, VALUE self)
|
|
|
367
526
|
break;
|
|
368
527
|
}
|
|
369
528
|
|
|
529
|
+
ca_rng_close(&source);
|
|
370
530
|
ca_sync(ca);
|
|
371
531
|
ca_detach(ca);
|
|
372
532
|
return self;
|
|
@@ -399,6 +559,7 @@ rb_ca_shuffle_bang(int argc, VALUE *argv, VALUE self)
|
|
|
399
559
|
|
|
400
560
|
rb_scan_args(argc, argv, "0:", &opts);
|
|
401
561
|
VALUE rng = Qnil;
|
|
562
|
+
ca_rng_t source;
|
|
402
563
|
rb_scan_options(opts, "rng,axis", &rng, &v_axis);
|
|
403
564
|
|
|
404
565
|
rb_ca_modify(self);
|
|
@@ -407,6 +568,7 @@ rb_ca_shuffle_bang(int argc, VALUE *argv, VALUE self)
|
|
|
407
568
|
if (ca->elements <= 1) return self;
|
|
408
569
|
|
|
409
570
|
ca_attach(ca);
|
|
571
|
+
ca_rng_open(rng, &source);
|
|
410
572
|
|
|
411
573
|
if (NIL_P(v_axis)) {
|
|
412
574
|
/* shuffle all elements */
|
|
@@ -416,7 +578,7 @@ rb_ca_shuffle_bang(int argc, VALUE *argv, VALUE self)
|
|
|
416
578
|
char *p = ca->ptr;
|
|
417
579
|
|
|
418
580
|
for (ca_size_t i = n - 1; i > 0; i--) {
|
|
419
|
-
unsigned long j = ca_random_ulong_limited(
|
|
581
|
+
unsigned long j = ca_random_ulong_limited(&source, (unsigned long)i);
|
|
420
582
|
if ((ca_size_t)j != i) {
|
|
421
583
|
swap_chunks(p + i * elem_bytes, p + j * elem_bytes, elem_bytes, tmp);
|
|
422
584
|
}
|
|
@@ -427,6 +589,7 @@ rb_ca_shuffle_bang(int argc, VALUE *argv, VALUE self)
|
|
|
427
589
|
axis = NUM2INT(v_axis);
|
|
428
590
|
if (axis < 0) axis += ca->ndim;
|
|
429
591
|
if (axis < 0 || axis >= ca->ndim) {
|
|
592
|
+
ca_rng_close(&source);
|
|
430
593
|
ca_sync(ca);
|
|
431
594
|
ca_detach(ca);
|
|
432
595
|
rb_raise(rb_eArgError,
|
|
@@ -435,6 +598,7 @@ rb_ca_shuffle_bang(int argc, VALUE *argv, VALUE self)
|
|
|
435
598
|
|
|
436
599
|
n = ca->dim[axis];
|
|
437
600
|
if (n <= 1) {
|
|
601
|
+
ca_rng_close(&source);
|
|
438
602
|
ca_sync(ca);
|
|
439
603
|
ca_detach(ca);
|
|
440
604
|
return self;
|
|
@@ -455,7 +619,7 @@ rb_ca_shuffle_bang(int argc, VALUE *argv, VALUE self)
|
|
|
455
619
|
for (ca_size_t o = 0; o < outer; o++) {
|
|
456
620
|
char *base = ca->ptr + o * stride;
|
|
457
621
|
for (ca_size_t i = n - 1; i > 0; i--) {
|
|
458
|
-
unsigned long j = ca_random_ulong_limited(
|
|
622
|
+
unsigned long j = ca_random_ulong_limited(&source, (unsigned long)i);
|
|
459
623
|
if ((ca_size_t)j != i) {
|
|
460
624
|
swap_chunks(base + i * chunk_bytes,
|
|
461
625
|
base + j * chunk_bytes,
|
|
@@ -466,6 +630,7 @@ rb_ca_shuffle_bang(int argc, VALUE *argv, VALUE self)
|
|
|
466
630
|
xfree(tmp);
|
|
467
631
|
}
|
|
468
632
|
|
|
633
|
+
ca_rng_close(&source);
|
|
469
634
|
ca_sync(ca);
|
|
470
635
|
ca_detach(ca);
|
|
471
636
|
return self;
|
|
@@ -484,7 +649,7 @@ rb_ca_shuffle(int argc, VALUE *argv, VALUE self)
|
|
|
484
649
|
/* ---- random (copy) ----------------------------------------------------- */
|
|
485
650
|
|
|
486
651
|
/* CArray#random([low,] [high], rng:) — non-bang variant: return a
|
|
487
|
-
* newly templated array filled uniformly. Shape and
|
|
652
|
+
* newly templated array filled uniformly. Shape and data type come from
|
|
488
653
|
* CArray#template, so the receiver is only consulted for those.
|
|
489
654
|
* Accepts the same argument forms as {rb_ca_random_bang}. */
|
|
490
655
|
static VALUE
|
|
@@ -503,11 +668,190 @@ rb_ca_randomn(int argc, VALUE *argv, VALUE self)
|
|
|
503
668
|
return rb_ca_randomn_bang(argc, argv, copy);
|
|
504
669
|
}
|
|
505
670
|
|
|
671
|
+
/* ---- CArray::Rng ---------------------------------------------------- */
|
|
672
|
+
|
|
673
|
+
/* A generator with its own state, so that a sequence belongs to an object
|
|
674
|
+
* rather than to the process:
|
|
675
|
+
*
|
|
676
|
+
* r = CArray::Rng.new(seed: 4)
|
|
677
|
+
* a.random!(rng: r) # fills, advancing r
|
|
678
|
+
* CArray.jit_for(n) { |i| b[i] = r.call } # carries on from there
|
|
679
|
+
*
|
|
680
|
+
* The state is an ordinary CA_INT64 array of four cells, which is what
|
|
681
|
+
* lets the second line work: carray-jit hands that array's address to a
|
|
682
|
+
* kernel that pasted the same generator, and the kernel advances the
|
|
683
|
+
* same cells this file does. Nothing about the generator is hidden
|
|
684
|
+
* behind a struct only this extension can read.
|
|
685
|
+
*
|
|
686
|
+
* The seed is not part of the state. It is remembered so that #reset
|
|
687
|
+
* with no argument can repeat a run, and so `inspect` can say what a
|
|
688
|
+
* generator was started from. */
|
|
689
|
+
|
|
690
|
+
static VALUE rb_ca_rng_reset (int argc, VALUE *argv, VALUE self);
|
|
691
|
+
|
|
692
|
+
/* The state's cells, attached. Every entry point here goes through this
|
|
693
|
+
* rather than reaching into the ivar, so that "what is the state" has one
|
|
694
|
+
* answer even after another generator is added. */
|
|
695
|
+
static CArray *
|
|
696
|
+
ca_rng_cells (VALUE self, int64_t **cells)
|
|
697
|
+
{
|
|
698
|
+
CArray *ca;
|
|
699
|
+
VALUE state = rb_ivar_get(self, rb_intern("@state"));
|
|
700
|
+
TypedData_Get_Struct(state, CArray, &carray_data_type, ca);
|
|
701
|
+
ca_attach(ca);
|
|
702
|
+
*cells = (int64_t *) ca->ptr;
|
|
703
|
+
return ca;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/* CArray::Rng.new(generator = :xoshiro256pp, seed: nil) */
|
|
707
|
+
static VALUE
|
|
708
|
+
rb_ca_rng_initialize (int argc, VALUE *argv, VALUE self)
|
|
709
|
+
{
|
|
710
|
+
VALUE gen = Qnil, opts = Qnil, seed = Qnil, state;
|
|
711
|
+
|
|
712
|
+
rb_scan_args(argc, argv, "01:", &gen, &opts);
|
|
713
|
+
rb_scan_options(opts, "seed", &seed);
|
|
714
|
+
|
|
715
|
+
if (NIL_P(gen)) gen = ID2SYM(rb_intern("xoshiro256pp"));
|
|
716
|
+
if (!SYMBOL_P(gen) || SYM2ID(gen) != rb_intern("xoshiro256pp")) {
|
|
717
|
+
rb_raise(rb_eArgError,
|
|
718
|
+
"unknown generator %"PRIsVALUE"; carray has :xoshiro256pp",
|
|
719
|
+
rb_inspect(gen));
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
state = rb_funcall(rb_cCArray, rb_intern("int64"), 1, INT2FIX(4));
|
|
723
|
+
rb_ivar_set(self, rb_intern("@generator"), gen);
|
|
724
|
+
rb_ivar_set(self, rb_intern("@state"), state);
|
|
725
|
+
|
|
726
|
+
return rb_ca_rng_reset(NIL_P(seed) ? 0 : 1, &seed, self);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/* CArray::Rng#reset(seed = nil) — start the sequence over.
|
|
730
|
+
*
|
|
731
|
+
* With no argument, from the seed this generator already carries, which
|
|
732
|
+
* repeats the run exactly. A generator made without a seed is given one
|
|
733
|
+
* from Random.new_seed, so two of them differ; that drawn seed is kept,
|
|
734
|
+
* so even an unseeded run can be repeated once it has begun. */
|
|
735
|
+
static VALUE
|
|
736
|
+
rb_ca_rng_reset (int argc, VALUE *argv, VALUE self)
|
|
737
|
+
{
|
|
738
|
+
VALUE seed = Qnil, masked;
|
|
739
|
+
CArray *ca;
|
|
740
|
+
int64_t *cells;
|
|
741
|
+
|
|
742
|
+
rb_scan_args(argc, argv, "01", &seed);
|
|
743
|
+
if (NIL_P(seed)) seed = rb_ivar_get(self, rb_intern("@seed"));
|
|
744
|
+
if (NIL_P(seed)) {
|
|
745
|
+
seed = rb_funcall(rb_path2class("Random"), rb_intern("new_seed"), 0);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/* Any Integer is a seed: a negative one and one wider than a word are
|
|
749
|
+
folded into 64 bits rather than refused, which is what `&` does. */
|
|
750
|
+
masked = rb_funcall(rb_to_int(seed), rb_intern("&"),
|
|
751
|
+
1, ULL2NUM(0xFFFFFFFFFFFFFFFFULL));
|
|
752
|
+
|
|
753
|
+
ca = ca_rng_cells(self, &cells);
|
|
754
|
+
ca_xoshiro256pp_seed(cells, (uint64_t) NUM2ULL(masked));
|
|
755
|
+
ca_sync(ca);
|
|
756
|
+
ca_detach(ca);
|
|
757
|
+
|
|
758
|
+
rb_ivar_set(self, rb_intern("@seed"), seed);
|
|
759
|
+
return self;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/* CArray::Rng#random — one draw in [0.0, 1.0), the state advanced.
|
|
763
|
+
*
|
|
764
|
+
* Named for `CArray#random!`, which it is the one-cell form of, and to
|
|
765
|
+
* pair with `#randomn` the way those two pair. Not `#rand`: Ruby's
|
|
766
|
+
* `random:` keyword calls `rand(n)` on what it is given, and a `#rand`
|
|
767
|
+
* here that takes no argument would make this look usable there and
|
|
768
|
+
* then fail with an arity error rather than say what it is.
|
|
769
|
+
*
|
|
770
|
+
* It is the same draw `random!` takes for one cell, and the same one a
|
|
771
|
+
* kernel's `random(rng:)` takes, because all three run the code in
|
|
772
|
+
* ca_rng_xoshiro256pp.h. */
|
|
773
|
+
static VALUE
|
|
774
|
+
rb_ca_rng_random (VALUE self)
|
|
775
|
+
{
|
|
776
|
+
CArray *ca;
|
|
777
|
+
int64_t *cells;
|
|
778
|
+
double value;
|
|
779
|
+
|
|
780
|
+
ca = ca_rng_cells(self, &cells);
|
|
781
|
+
value = ca_xoshiro256pp_next_real(cells);
|
|
782
|
+
ca_sync(ca);
|
|
783
|
+
ca_detach(ca);
|
|
784
|
+
return rb_float_new(value);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/* CArray::Rng#bits — the same draw as the generator's raw 64 bits.
|
|
788
|
+
*
|
|
789
|
+
* Not a bounded draw and not Ruby's `rand(n)`: it is the word the
|
|
790
|
+
* generator produced, before it was turned into a double. What that is
|
|
791
|
+
* for is checking this generator against the sequence its authors
|
|
792
|
+
* published, which is the one question `#rand` cannot answer. */
|
|
793
|
+
static VALUE
|
|
794
|
+
rb_ca_rng_bits (VALUE self)
|
|
795
|
+
{
|
|
796
|
+
CArray *ca;
|
|
797
|
+
int64_t *cells;
|
|
798
|
+
uint64_t value;
|
|
799
|
+
|
|
800
|
+
ca = ca_rng_cells(self, &cells);
|
|
801
|
+
value = ca_xoshiro256pp_next(cells);
|
|
802
|
+
ca_sync(ca);
|
|
803
|
+
ca_detach(ca);
|
|
804
|
+
return ULL2NUM(value);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/* CArray::Rng#randomn — one standard normal, which is two draws.
|
|
808
|
+
*
|
|
809
|
+
* The same one `randomn!(rng: self)` writes into a cell and the same
|
|
810
|
+
* one a kernel's `randomn(rng: self)` takes, because all three are
|
|
811
|
+
* ca_random_normal. */
|
|
812
|
+
static VALUE
|
|
813
|
+
rb_ca_rng_randomn (VALUE self)
|
|
814
|
+
{
|
|
815
|
+
CArray *ca;
|
|
816
|
+
int64_t *cells;
|
|
817
|
+
ca_rng_t source;
|
|
818
|
+
double value;
|
|
819
|
+
|
|
820
|
+
ca = ca_rng_cells(self, &cells);
|
|
821
|
+
source.kind = CA_RNG_OWN;
|
|
822
|
+
source.rng = self;
|
|
823
|
+
source.state = NULL;
|
|
824
|
+
source.cells = cells;
|
|
825
|
+
value = ca_random_normal(&source);
|
|
826
|
+
ca_sync(ca);
|
|
827
|
+
ca_detach(ca);
|
|
828
|
+
return rb_float_new(value);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
static VALUE
|
|
832
|
+
rb_ca_rng_inspect (VALUE self)
|
|
833
|
+
{
|
|
834
|
+
return rb_sprintf("#<CArray::Rng %"PRIsVALUE" seed=%"PRIsVALUE">",
|
|
835
|
+
rb_ivar_get(self, rb_intern("@generator")),
|
|
836
|
+
rb_ivar_get(self, rb_intern("@seed")));
|
|
837
|
+
}
|
|
838
|
+
|
|
506
839
|
/* ---- Init -------------------------------------------------------------- */
|
|
507
840
|
|
|
508
841
|
void
|
|
509
842
|
Init_carray_random (void)
|
|
510
843
|
{
|
|
844
|
+
rb_cCARng = rb_define_class_under(rb_cCArray, "Rng", rb_cObject);
|
|
845
|
+
rb_define_method(rb_cCARng, "initialize", rb_ca_rng_initialize, -1);
|
|
846
|
+
rb_define_method(rb_cCARng, "reset", rb_ca_rng_reset, -1);
|
|
847
|
+
rb_define_method(rb_cCARng, "random", rb_ca_rng_random, 0);
|
|
848
|
+
rb_define_method(rb_cCARng, "randomn", rb_ca_rng_randomn, 0);
|
|
849
|
+
rb_define_method(rb_cCARng, "bits", rb_ca_rng_bits, 0);
|
|
850
|
+
rb_define_method(rb_cCARng, "inspect", rb_ca_rng_inspect, 0);
|
|
851
|
+
rb_define_attr(rb_cCARng, "generator", 1, 0);
|
|
852
|
+
rb_define_attr(rb_cCARng, "state", 1, 0);
|
|
853
|
+
rb_define_attr(rb_cCARng, "seed", 1, 0);
|
|
854
|
+
|
|
511
855
|
rb_define_method(rb_cCArray, "random!", rb_ca_random_bang, -1);
|
|
512
856
|
rb_define_method(rb_cCArray, "randomn!", rb_ca_randomn_bang, -1);
|
|
513
857
|
rb_define_method(rb_cCArray, "shuffle!", rb_ca_shuffle_bang, -1);
|