numo-random 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4c6c4db2ffcb5672e571ad59dc94c36d51f87adb29007db4b9678b803840915
4
- data.tar.gz: c1debe024fe523f28d97a83f7eaee51dc27cf51acfd1efa1cc44cd2994659c72
3
+ metadata.gz: d9c0d26c2b1751451a84c8b53c6e38b9257a82ff7d2c3479bd94d7311cfb1628
4
+ data.tar.gz: ae9262ff84d81abb58af7d4856e0936160c33f3a824818515878ae97ce3c9ea0
5
5
  SHA512:
6
- metadata.gz: 6364e78337ab7d87b0aa3cc18a2264992cb75ab15c65b0ce41065c78eacacbb96e21e55a5872a3878cb1ab143b4f8f7145ce4475e22eca725aef8a16fa0a8409
7
- data.tar.gz: c3dfbd3d29761f951176395b2c48c596efbb998b3d1650484da908e576624557c60e8aabf64b015096aa0fb33780929c5a78b598a206ea659fdb4d75cea020f3
6
+ metadata.gz: f153a0090d65b3ee39d5f8cde36a3669e0d12b6e4f84c56045156c42c2f5fe7dfe3de7b6d649c994bafec730ff8bbcaff09e9befa6aba04e9b5fd0d77dae8d91
7
+ data.tar.gz: 27af398428b05b955c690f36d948112329484f47146631b2a4f58ef60551a84039144c387e96ad49ee0d13815225930100659823ece1040fb59898e73c13dc0d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
- ## [Unreleased]
2
- - Bernoulli distribution.
1
+ ## [0.5.0]
2
+ - Support 32-bit PCG and Mersenne Twister.
3
+
4
+ ```ruby
5
+ require 'numo/random'
6
+
7
+ # specify the pseudo random number generation algorithm by setting the algorithm argument of constructor.
8
+ rng = Numo::Random::Generator.new(algorithm: 'pcg32')
9
+ rng = Numo::Random::Generator.new(algorithm: 'pcg64') # default
10
+ rng = Numo::Random::Generator.new(algorithm: 'mt32')
11
+ rng = Numo::Random::Generator.new(algorithm: 'mt64')
12
+ ```
13
+
14
+ ## [0.4.0]
15
+ - Add method for random number generation with bernoulli distribution: bernoulli, binomial, negative_binomial, and geometric.
3
16
 
4
17
  ## [0.3.0]
5
18
  - Change native extension filename.
data/README.md CHANGED
@@ -50,6 +50,32 @@ end
50
50
  ![normal2d.png](https://user-images.githubusercontent.com/5562409/197376738-ee8d2b12-1902-4a12-bcf3-757461f2f2db.png)
51
51
 
52
52
 
53
+ An example of generating random numbers according to the Poisson distribution:
54
+
55
+ ```ruby
56
+ require 'numo/narray'
57
+ require 'numo/gnuplot'
58
+
59
+ require 'numo/random'
60
+
61
+ # Creating random number generator.
62
+ rng = Numo::Random::Generator.new(seed: 9)
63
+
64
+ # Generating random numbers with Poisson distribution.
65
+ x = rng.poisson(shape: 10000, mean: 12)
66
+
67
+ # Plotting the generated result.
68
+ h = x.bincount
69
+
70
+ Numo.gnuplot do
71
+ set(terminal: 'png')
72
+ set(output: 'poisson2d.png')
73
+ plot(h, with: 'boxes')
74
+ end
75
+ ```
76
+
77
+ ![poisson2d.png](https://user-images.githubusercontent.com/5562409/201478863-61d31eb8-7c0b-4406-b255-fff29187a16a.png)
78
+
53
79
  ## Contributing
54
80
 
55
81
  Bug reports and pull requests are welcome on GitHub at https://github.com/yoshoku/numo-random.
@@ -22,5 +22,8 @@ extern "C" void Init_ext(void) {
22
22
  rb_require("numo/narray");
23
23
 
24
24
  VALUE rb_mNumoRandom = rb_define_module_under(mNumo, "Random");
25
- RbNumoRandomPCG64::define_class(rb_mNumoRandom);
25
+ RbNumoRandomPCG32::define_class(rb_mNumoRandom, "PCG32");
26
+ RbNumoRandomPCG64::define_class(rb_mNumoRandom, "PCG64");
27
+ RbNumoRandomMT32::define_class(rb_mNumoRandom, "MT32");
28
+ RbNumoRandomMT64::define_class(rb_mNumoRandom, "MT64");
26
29
  }
@@ -28,71 +28,74 @@
28
28
 
29
29
  #include <pcg_random.hpp>
30
30
 
31
- class RbNumoRandomPCG64 {
31
+ template<class Rng, class Impl> class RbNumoRandom {
32
32
  public:
33
- static VALUE numo_random_pcg64_alloc(VALUE self) {
34
- pcg64* ptr = (pcg64*)ruby_xmalloc(sizeof(pcg64));
35
- new (ptr) pcg64();
36
- return TypedData_Wrap_Struct(self, &pcg64_type, ptr);
33
+ // static const rb_data_type_t rng_type;
34
+
35
+ static VALUE numo_random_alloc(VALUE self) {
36
+ Rng* ptr = (Rng*)ruby_xmalloc(sizeof(Rng));
37
+ new (ptr) Rng();
38
+ return TypedData_Wrap_Struct(self, &Impl::rng_type, ptr);
37
39
  }
38
40
 
39
- static void numo_random_pcg64_free(void* ptr) {
40
- ((pcg64*)ptr)->~pcg64();
41
+ static void numo_random_free(void* ptr) {
42
+ ((Rng*)ptr)->~Rng();
41
43
  ruby_xfree(ptr);
42
44
  }
43
45
 
44
- static size_t numo_random_pcg64_size(const void* ptr) {
45
- return sizeof(*((pcg64*)ptr));
46
+ static size_t numo_random_size(const void* ptr) {
47
+ return sizeof(*((Rng*)ptr));
46
48
  }
47
49
 
48
- static pcg64* get_pcg64(VALUE self) {
49
- pcg64* ptr;
50
- TypedData_Get_Struct(self, pcg64, &pcg64_type, ptr);
50
+ static Rng* get_rng(VALUE self) {
51
+ Rng* ptr;
52
+ TypedData_Get_Struct(self, Rng, &Impl::rng_type, ptr);
51
53
  return ptr;
52
54
  }
53
55
 
54
- static VALUE define_class(VALUE rb_mNumoRandom) {
55
- VALUE rb_cPCG64 = rb_define_class_under(rb_mNumoRandom, "PCG64", rb_cObject);
56
- rb_define_alloc_func(rb_cPCG64, numo_random_pcg64_alloc);
57
- rb_define_method(rb_cPCG64, "initialize", RUBY_METHOD_FUNC(_numo_random_pcg64_init), -1);
58
- rb_define_method(rb_cPCG64, "seed=", RUBY_METHOD_FUNC(_numo_random_pcg64_set_seed), 1);
59
- rb_define_method(rb_cPCG64, "seed", RUBY_METHOD_FUNC(_numo_random_pcg64_get_seed), 0);
60
- rb_define_method(rb_cPCG64, "random", RUBY_METHOD_FUNC(_numo_random_pcg64_random), 0);
61
- rb_define_method(rb_cPCG64, "exponential", RUBY_METHOD_FUNC(_numo_random_pcg64_exponential), -1);
62
- rb_define_method(rb_cPCG64, "gamma", RUBY_METHOD_FUNC(_numo_random_pcg64_gamma), -1);
63
- rb_define_method(rb_cPCG64, "gumbel", RUBY_METHOD_FUNC(_numo_random_pcg64_gumbel), -1);
64
- rb_define_method(rb_cPCG64, "poisson", RUBY_METHOD_FUNC(_numo_random_pcg64_poisson), -1);
65
- rb_define_method(rb_cPCG64, "weibull", RUBY_METHOD_FUNC(_numo_random_pcg64_weibull), -1);
66
- rb_define_method(rb_cPCG64, "discrete", RUBY_METHOD_FUNC(_numo_random_pcg64_discrete), -1);
67
- rb_define_method(rb_cPCG64, "uniform", RUBY_METHOD_FUNC(_numo_random_pcg64_uniform), -1);
68
- rb_define_method(rb_cPCG64, "cauchy", RUBY_METHOD_FUNC(_numo_random_pcg64_cauchy), -1);
69
- rb_define_method(rb_cPCG64, "chisquare", RUBY_METHOD_FUNC(_numo_random_pcg64_chisquare), -1);
70
- rb_define_method(rb_cPCG64, "f", RUBY_METHOD_FUNC(_numo_random_pcg64_f), -1);
71
- rb_define_method(rb_cPCG64, "normal", RUBY_METHOD_FUNC(_numo_random_pcg64_normal), -1);
72
- rb_define_method(rb_cPCG64, "lognormal", RUBY_METHOD_FUNC(_numo_random_pcg64_lognormal), -1);
73
- rb_define_method(rb_cPCG64, "standard_t", RUBY_METHOD_FUNC(_numo_random_pcg64_standard_t), -1);
74
- return rb_cPCG64;
56
+ static VALUE define_class(VALUE rb_mNumoRandom, const char* class_name) {
57
+ VALUE rb_cRng = rb_define_class_under(rb_mNumoRandom, class_name, rb_cObject);
58
+ rb_define_alloc_func(rb_cRng, numo_random_alloc);
59
+ rb_define_method(rb_cRng, "initialize", RUBY_METHOD_FUNC(_numo_random_init), -1);
60
+ rb_define_method(rb_cRng, "seed=", RUBY_METHOD_FUNC(_numo_random_set_seed), 1);
61
+ rb_define_method(rb_cRng, "seed", RUBY_METHOD_FUNC(_numo_random_get_seed), 0);
62
+ rb_define_method(rb_cRng, "random", RUBY_METHOD_FUNC(_numo_random_random), 0);
63
+ rb_define_method(rb_cRng, "binomial", RUBY_METHOD_FUNC(_numo_random_binomial), -1);
64
+ rb_define_method(rb_cRng, "negative_binomial", RUBY_METHOD_FUNC(_numo_random_negative_binomial), -1);
65
+ rb_define_method(rb_cRng, "geometric", RUBY_METHOD_FUNC(_numo_random_geometric), -1);
66
+ rb_define_method(rb_cRng, "exponential", RUBY_METHOD_FUNC(_numo_random_exponential), -1);
67
+ rb_define_method(rb_cRng, "gamma", RUBY_METHOD_FUNC(_numo_random_gamma), -1);
68
+ rb_define_method(rb_cRng, "gumbel", RUBY_METHOD_FUNC(_numo_random_gumbel), -1);
69
+ rb_define_method(rb_cRng, "poisson", RUBY_METHOD_FUNC(_numo_random_poisson), -1);
70
+ rb_define_method(rb_cRng, "weibull", RUBY_METHOD_FUNC(_numo_random_weibull), -1);
71
+ rb_define_method(rb_cRng, "discrete", RUBY_METHOD_FUNC(_numo_random_discrete), -1);
72
+ rb_define_method(rb_cRng, "uniform", RUBY_METHOD_FUNC(_numo_random_uniform), -1);
73
+ rb_define_method(rb_cRng, "cauchy", RUBY_METHOD_FUNC(_numo_random_cauchy), -1);
74
+ rb_define_method(rb_cRng, "chisquare", RUBY_METHOD_FUNC(_numo_random_chisquare), -1);
75
+ rb_define_method(rb_cRng, "f", RUBY_METHOD_FUNC(_numo_random_f), -1);
76
+ rb_define_method(rb_cRng, "normal", RUBY_METHOD_FUNC(_numo_random_normal), -1);
77
+ rb_define_method(rb_cRng, "lognormal", RUBY_METHOD_FUNC(_numo_random_lognormal), -1);
78
+ rb_define_method(rb_cRng, "standard_t", RUBY_METHOD_FUNC(_numo_random_standard_t), -1);
79
+ return rb_cRng;
75
80
  }
76
81
 
77
82
  private:
78
- static const rb_data_type_t pcg64_type;
79
-
80
83
  // #initialize
81
84
 
82
- static VALUE _numo_random_pcg64_init(int argc, VALUE* argv, VALUE self) {
85
+ static VALUE _numo_random_init(int argc, VALUE* argv, VALUE self) {
83
86
  VALUE kw_args = Qnil;
84
87
  ID kw_table[1] = { rb_intern("seed") };
85
88
  VALUE kw_values[1] = { Qundef };
86
89
  rb_scan_args(argc, argv, ":", &kw_args);
87
90
  rb_get_kwargs(kw_args, kw_table, 0, 1, kw_values);
88
- pcg64* ptr = get_pcg64(self);
91
+ Rng* ptr = get_rng(self);
89
92
  if (kw_values[0] == Qundef || NIL_P(kw_values[0])) {
90
93
  std::random_device rd;
91
94
  const unsigned int seed = rd();
92
- new (ptr) pcg64(seed);
95
+ new (ptr) Rng(seed);
93
96
  rb_iv_set(self, "seed", UINT2NUM(seed));
94
97
  } else {
95
- new (ptr) pcg64(NUM2LONG(kw_values[0]));
98
+ new (ptr) Rng(NUM2LONG(kw_values[0]));
96
99
  rb_iv_set(self, "seed", kw_values[0]);
97
100
  }
98
101
  return Qnil;
@@ -100,23 +103,23 @@ private:
100
103
 
101
104
  // #seed=
102
105
 
103
- static VALUE _numo_random_pcg64_set_seed(VALUE self, VALUE seed) {
104
- get_pcg64(self)->seed(NUM2LONG(seed));
106
+ static VALUE _numo_random_set_seed(VALUE self, VALUE seed) {
107
+ get_rng(self)->seed(NUM2LONG(seed));
105
108
  rb_iv_set(self, "seed", seed);
106
109
  return Qnil;
107
110
  }
108
111
 
109
112
  // #seed
110
113
 
111
- static VALUE _numo_random_pcg64_get_seed(VALUE self) {
114
+ static VALUE _numo_random_get_seed(VALUE self) {
112
115
  return rb_iv_get(self, "seed");
113
116
  }
114
117
 
115
118
  // #random
116
119
 
117
- static VALUE _numo_random_pcg64_random(VALUE self) {
120
+ static VALUE _numo_random_random(VALUE self) {
118
121
  std::uniform_real_distribution<double> uniform_dist(0, 1);
119
- pcg64* ptr = get_pcg64(self);
122
+ Rng* ptr = get_rng(self);
120
123
  const double x = uniform_dist(*ptr);
121
124
  return DBL2NUM(x);
122
125
  }
@@ -125,7 +128,7 @@ private:
125
128
 
126
129
  template<class D> struct rand_opt_t {
127
130
  D dist;
128
- pcg64* rnd;
131
+ Rng* rnd;
129
132
  };
130
133
 
131
134
  template<class D, typename T> static void _iter_rand(na_loop_t* const lp) {
@@ -149,10 +152,161 @@ private:
149
152
  }
150
153
  }
151
154
 
155
+ // #binomial
156
+
157
+ template<typename T> static void _rand_binomial(VALUE& self, VALUE& x, const long n, const double& p) {
158
+ Rng* ptr = get_rng(self);
159
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
160
+ std::binomial_distribution<T> binomial_dist(n, p);
161
+ ndfunc_t ndf = { _iter_rand<std::binomial_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
162
+ rand_opt_t<std::binomial_distribution<T>> opt = { binomial_dist, ptr };
163
+ na_ndloop3(&ndf, &opt, 1, x);
164
+ }
165
+
166
+ static VALUE _numo_random_binomial(int argc, VALUE* argv, VALUE self) {
167
+ VALUE x = Qnil;
168
+ VALUE kw_args = Qnil;
169
+ ID kw_table[2] = { rb_intern("n"), rb_intern("p") };
170
+ VALUE kw_values[2] = { Qundef, Qundef };
171
+ rb_scan_args(argc, argv, "1:", &x, &kw_args);
172
+ rb_get_kwargs(kw_args, kw_table, 2, 0, kw_values);
173
+
174
+ const VALUE klass = rb_obj_class(x);
175
+ if (klass != numo_cInt8 && klass != numo_cInt16 && klass != numo_cInt32 && klass != numo_cInt64
176
+ && klass != numo_cUInt8 && klass != numo_cUInt16 && klass != numo_cUInt32 && klass != numo_cUInt64)
177
+ rb_raise(rb_eTypeError, "invalid NArray class, it must be integer typed array");
178
+
179
+ const long n = NUM2LONG(kw_values[0]);
180
+ const double p = NUM2DBL(kw_values[1]);
181
+ if (n < 0) rb_raise(rb_eArgError, "n must be a non-negative value");
182
+ if (p < 0.0 || p > 1.0) rb_raise(rb_eArgError, "p must be >= 0 and <= 1");
183
+
184
+ if (klass == numo_cInt8) {
185
+ _rand_binomial<int8_t>(self, x, n, p);
186
+ } else if (klass == numo_cInt16) {
187
+ _rand_binomial<int16_t>(self, x, n, p);
188
+ } else if (klass == numo_cInt32) {
189
+ _rand_binomial<int32_t>(self, x, n, p);
190
+ } else if (klass == numo_cInt64) {
191
+ _rand_binomial<int64_t>(self, x, n, p);
192
+ } else if (klass == numo_cUInt8) {
193
+ _rand_binomial<uint8_t>(self, x, n, p);
194
+ } else if (klass == numo_cUInt16) {
195
+ _rand_binomial<uint16_t>(self, x, n, p);
196
+ } else if (klass == numo_cUInt32) {
197
+ _rand_binomial<uint32_t>(self, x, n, p);
198
+ } else if (klass == numo_cUInt64) {
199
+ _rand_binomial<uint64_t>(self, x, n, p);
200
+ }
201
+
202
+ RB_GC_GUARD(x);
203
+ return Qnil;
204
+ }
205
+
206
+ // #negative_binomial
207
+
208
+ template<typename T> static void _rand_negative_binomial(VALUE& self, VALUE& x, const long n, const double& p) {
209
+ Rng* ptr = get_rng(self);
210
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
211
+ std::negative_binomial_distribution<T> negative_binomial_dist(n, p);
212
+ ndfunc_t ndf = { _iter_rand<std::negative_binomial_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
213
+ rand_opt_t<std::negative_binomial_distribution<T>> opt = { negative_binomial_dist, ptr };
214
+ na_ndloop3(&ndf, &opt, 1, x);
215
+ }
216
+
217
+ static VALUE _numo_random_negative_binomial(int argc, VALUE* argv, VALUE self) {
218
+ VALUE x = Qnil;
219
+ VALUE kw_args = Qnil;
220
+ ID kw_table[2] = { rb_intern("n"), rb_intern("p") };
221
+ VALUE kw_values[2] = { Qundef, Qundef };
222
+ rb_scan_args(argc, argv, "1:", &x, &kw_args);
223
+ rb_get_kwargs(kw_args, kw_table, 2, 0, kw_values);
224
+
225
+ const VALUE klass = rb_obj_class(x);
226
+ if (klass != numo_cInt8 && klass != numo_cInt16 && klass != numo_cInt32 && klass != numo_cInt64
227
+ && klass != numo_cUInt8 && klass != numo_cUInt16 && klass != numo_cUInt32 && klass != numo_cUInt64)
228
+ rb_raise(rb_eTypeError, "invalid NArray class, it must be integer typed array");
229
+
230
+ const long n = NUM2LONG(kw_values[0]);
231
+ const double p = NUM2DBL(kw_values[1]);
232
+ if (n < 0) rb_raise(rb_eArgError, "n must be a non-negative value");
233
+ if (p <= 0.0 || p > 1.0) rb_raise(rb_eArgError, "p must be > 0 and <= 1");
234
+
235
+ if (klass == numo_cInt8) {
236
+ _rand_negative_binomial<int8_t>(self, x, n, p);
237
+ } else if (klass == numo_cInt16) {
238
+ _rand_negative_binomial<int16_t>(self, x, n, p);
239
+ } else if (klass == numo_cInt32) {
240
+ _rand_negative_binomial<int32_t>(self, x, n, p);
241
+ } else if (klass == numo_cInt64) {
242
+ _rand_negative_binomial<int64_t>(self, x, n, p);
243
+ } else if (klass == numo_cUInt8) {
244
+ _rand_negative_binomial<uint8_t>(self, x, n, p);
245
+ } else if (klass == numo_cUInt16) {
246
+ _rand_negative_binomial<uint16_t>(self, x, n, p);
247
+ } else if (klass == numo_cUInt32) {
248
+ _rand_negative_binomial<uint32_t>(self, x, n, p);
249
+ } else if (klass == numo_cUInt64) {
250
+ _rand_negative_binomial<uint64_t>(self, x, n, p);
251
+ }
252
+
253
+ RB_GC_GUARD(x);
254
+ return Qnil;
255
+ }
256
+
257
+ // #geometric
258
+
259
+ template<typename T> static void _rand_geometric(VALUE& self, VALUE& x, const double& p) {
260
+ Rng* ptr = get_rng(self);
261
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
262
+ std::geometric_distribution<T> geometric_dist(p);
263
+ ndfunc_t ndf = { _iter_rand<std::geometric_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
264
+ rand_opt_t<std::geometric_distribution<T>> opt = { geometric_dist, ptr };
265
+ na_ndloop3(&ndf, &opt, 1, x);
266
+ }
267
+
268
+ static VALUE _numo_random_geometric(int argc, VALUE* argv, VALUE self) {
269
+ VALUE x = Qnil;
270
+ VALUE kw_args = Qnil;
271
+ ID kw_table[1] = { rb_intern("p") };
272
+ VALUE kw_values[1] = { Qundef };
273
+ rb_scan_args(argc, argv, "1:", &x, &kw_args);
274
+ rb_get_kwargs(kw_args, kw_table, 1, 0, kw_values);
275
+
276
+ const VALUE klass = rb_obj_class(x);
277
+ if (klass != numo_cInt8 && klass != numo_cInt16 && klass != numo_cInt32 && klass != numo_cInt64
278
+ && klass != numo_cUInt8 && klass != numo_cUInt16 && klass != numo_cUInt32 && klass != numo_cUInt64)
279
+ rb_raise(rb_eTypeError, "invalid NArray class, it must be integer typed array");
280
+
281
+ const double p = NUM2DBL(kw_values[0]);
282
+ if (p <= 0.0 || p >= 1.0) rb_raise(rb_eArgError, "p must be > 0 and < 1");
283
+
284
+ if (klass == numo_cInt8) {
285
+ _rand_geometric<int8_t>(self, x, p);
286
+ } else if (klass == numo_cInt16) {
287
+ _rand_geometric<int16_t>(self, x, p);
288
+ } else if (klass == numo_cInt32) {
289
+ _rand_geometric<int32_t>(self, x, p);
290
+ } else if (klass == numo_cInt64) {
291
+ _rand_geometric<int64_t>(self, x, p);
292
+ } else if (klass == numo_cUInt8) {
293
+ _rand_geometric<uint8_t>(self, x, p);
294
+ } else if (klass == numo_cUInt16) {
295
+ _rand_geometric<uint16_t>(self, x, p);
296
+ } else if (klass == numo_cUInt32) {
297
+ _rand_geometric<uint32_t>(self, x, p);
298
+ } else if (klass == numo_cUInt64) {
299
+ _rand_geometric<uint64_t>(self, x, p);
300
+ }
301
+
302
+ RB_GC_GUARD(x);
303
+ return Qnil;
304
+ }
305
+
152
306
  // #exponential
153
307
 
154
308
  template<typename T> static void _rand_exponential(VALUE& self, VALUE& x, const double& lam) {
155
- pcg64* ptr = get_pcg64(self);
309
+ Rng* ptr = get_rng(self);
156
310
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
157
311
  std::exponential_distribution<T> exponential_dist(lam);
158
312
  ndfunc_t ndf = { _iter_rand<std::exponential_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -160,7 +314,7 @@ private:
160
314
  na_ndloop3(&ndf, &opt, 1, x);
161
315
  }
162
316
 
163
- static VALUE _numo_random_pcg64_exponential(int argc, VALUE* argv, VALUE self) {
317
+ static VALUE _numo_random_exponential(int argc, VALUE* argv, VALUE self) {
164
318
  VALUE x = Qnil;
165
319
  VALUE kw_args = Qnil;
166
320
  ID kw_table[1] = { rb_intern("scale") };
@@ -188,7 +342,7 @@ private:
188
342
  // #gamma
189
343
 
190
344
  template<typename T> static void _rand_gamma(VALUE& self, VALUE& x, const double& k, const double&scale) {
191
- pcg64* ptr = get_pcg64(self);
345
+ Rng* ptr = get_rng(self);
192
346
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
193
347
  std::gamma_distribution<T> gamma_dist(k, scale);
194
348
  ndfunc_t ndf = { _iter_rand<std::gamma_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -196,7 +350,7 @@ private:
196
350
  na_ndloop3(&ndf, &opt, 1, x);
197
351
  }
198
352
 
199
- static VALUE _numo_random_pcg64_gamma(int argc, VALUE* argv, VALUE self) {
353
+ static VALUE _numo_random_gamma(int argc, VALUE* argv, VALUE self) {
200
354
  VALUE x = Qnil;
201
355
  VALUE kw_args = Qnil;
202
356
  ID kw_table[2] = { rb_intern("k"), rb_intern("scale") };
@@ -225,7 +379,7 @@ private:
225
379
  // #gumbel
226
380
 
227
381
  template<typename T> static void _rand_gumbel(VALUE& self, VALUE& x, const double& loc, const double&scale) {
228
- pcg64* ptr = get_pcg64(self);
382
+ Rng* ptr = get_rng(self);
229
383
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
230
384
  std::extreme_value_distribution<T> extreme_value_dist(loc, scale);
231
385
  ndfunc_t ndf = { _iter_rand<std::extreme_value_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -233,7 +387,7 @@ private:
233
387
  na_ndloop3(&ndf, &opt, 1, x);
234
388
  }
235
389
 
236
- static VALUE _numo_random_pcg64_gumbel(int argc, VALUE* argv, VALUE self) {
390
+ static VALUE _numo_random_gumbel(int argc, VALUE* argv, VALUE self) {
237
391
  VALUE x = Qnil;
238
392
  VALUE kw_args = Qnil;
239
393
  ID kw_table[2] = { rb_intern("loc"), rb_intern("scale") };
@@ -261,7 +415,7 @@ private:
261
415
  // #poisson
262
416
 
263
417
  template<typename T> static void _rand_poisson(VALUE& self, VALUE& x, const double& mean) {
264
- pcg64* ptr = get_pcg64(self);
418
+ Rng* ptr = get_rng(self);
265
419
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
266
420
  std::poisson_distribution<T> poisson_dist(mean);
267
421
  ndfunc_t ndf = { _iter_rand<std::poisson_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -269,11 +423,11 @@ private:
269
423
  na_ndloop3(&ndf, &opt, 1, x);
270
424
  }
271
425
 
272
- static VALUE _numo_random_pcg64_poisson(int argc, VALUE* argv, VALUE self) {
426
+ static VALUE _numo_random_poisson(int argc, VALUE* argv, VALUE self) {
273
427
  VALUE x = Qnil;
274
428
  VALUE kw_args = Qnil;
275
- ID kw_table[2] = { rb_intern("mean") };
276
- VALUE kw_values[2] = { Qundef, Qundef };
429
+ ID kw_table[1] = { rb_intern("mean") };
430
+ VALUE kw_values[1] = { Qundef };
277
431
  rb_scan_args(argc, argv, "1:", &x, &kw_args);
278
432
  rb_get_kwargs(kw_args, kw_table, 0, 1, kw_values);
279
433
 
@@ -310,7 +464,7 @@ private:
310
464
  // #weibull
311
465
 
312
466
  template<typename T> static void _rand_weibull(VALUE& self, VALUE& x, const double& k, const double&scale) {
313
- pcg64* ptr = get_pcg64(self);
467
+ Rng* ptr = get_rng(self);
314
468
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
315
469
  std::weibull_distribution<T> weibull_dist(k, scale);
316
470
  ndfunc_t ndf = { _iter_rand<std::weibull_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -318,7 +472,7 @@ private:
318
472
  na_ndloop3(&ndf, &opt, 1, x);
319
473
  }
320
474
 
321
- static VALUE _numo_random_pcg64_weibull(int argc, VALUE* argv, VALUE self) {
475
+ static VALUE _numo_random_weibull(int argc, VALUE* argv, VALUE self) {
322
476
  VALUE x = Qnil;
323
477
  VALUE kw_args = Qnil;
324
478
  ID kw_table[2] = { rb_intern("k"), rb_intern("scale") };
@@ -347,7 +501,7 @@ private:
347
501
  // #discrete
348
502
 
349
503
  template<typename T, typename P> static void _rand_discrete(VALUE& self, VALUE& x, const std::vector<P>& weight) {
350
- pcg64* ptr = get_pcg64(self);
504
+ Rng* ptr = get_rng(self);
351
505
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
352
506
  std::discrete_distribution<T> discrete_dist(weight.begin(), weight.end());
353
507
  ndfunc_t ndf = { _iter_rand<std::discrete_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -355,7 +509,7 @@ private:
355
509
  na_ndloop3(&ndf, &opt, 1, x);
356
510
  }
357
511
 
358
- static VALUE _numo_random_pcg64_discrete(int argc, VALUE* argv, VALUE self) {
512
+ static VALUE _numo_random_discrete(int argc, VALUE* argv, VALUE self) {
359
513
  VALUE x = Qnil;
360
514
  VALUE kw_args = Qnil;
361
515
  ID kw_table[1] = { rb_intern("weight") };
@@ -430,7 +584,7 @@ private:
430
584
  // #uniform
431
585
 
432
586
  template<typename T> static void _rand_uniform(VALUE& self, VALUE& x, const double& low, const double& high) {
433
- pcg64* ptr = get_pcg64(self);
587
+ Rng* ptr = get_rng(self);
434
588
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
435
589
  std::uniform_real_distribution<T> uniform_dist(low, high);
436
590
  ndfunc_t ndf = { _iter_rand<std::uniform_real_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -438,7 +592,7 @@ private:
438
592
  na_ndloop3(&ndf, &opt, 1, x);
439
593
  }
440
594
 
441
- static VALUE _numo_random_pcg64_uniform(int argc, VALUE* argv, VALUE self) {
595
+ static VALUE _numo_random_uniform(int argc, VALUE* argv, VALUE self) {
442
596
  VALUE x = Qnil;
443
597
  VALUE kw_args = Qnil;
444
598
  ID kw_table[2] = { rb_intern("low"), rb_intern("high") };
@@ -466,7 +620,7 @@ private:
466
620
  // #cauchy
467
621
 
468
622
  template<typename T> static void _rand_cauchy(VALUE& self, VALUE& x, const double& loc, const double& scale) {
469
- pcg64* ptr = get_pcg64(self);
623
+ Rng* ptr = get_rng(self);
470
624
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
471
625
  std::cauchy_distribution<T> cauchy_dist(loc, scale);
472
626
  ndfunc_t ndf = { _iter_rand<std::cauchy_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -474,7 +628,7 @@ private:
474
628
  na_ndloop3(&ndf, &opt, 1, x);
475
629
  }
476
630
 
477
- static VALUE _numo_random_pcg64_cauchy(int argc, VALUE* argv, VALUE self) {
631
+ static VALUE _numo_random_cauchy(int argc, VALUE* argv, VALUE self) {
478
632
  VALUE x = Qnil;
479
633
  VALUE kw_args = Qnil;
480
634
  ID kw_table[2] = { rb_intern("loc"), rb_intern("scale") };
@@ -502,7 +656,7 @@ private:
502
656
  // #chisqure
503
657
 
504
658
  template<typename T> static void _rand_chisquare(VALUE& self, VALUE& x, const double& df) {
505
- pcg64* ptr = get_pcg64(self);
659
+ Rng* ptr = get_rng(self);
506
660
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
507
661
  std::chi_squared_distribution<T> chisquare_dist(df);
508
662
  ndfunc_t ndf = { _iter_rand<std::chi_squared_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -510,7 +664,7 @@ private:
510
664
  na_ndloop3(&ndf, &opt, 1, x);
511
665
  }
512
666
 
513
- static VALUE _numo_random_pcg64_chisquare(int argc, VALUE* argv, VALUE self) {
667
+ static VALUE _numo_random_chisquare(int argc, VALUE* argv, VALUE self) {
514
668
  VALUE x = Qnil;
515
669
  VALUE kw_args = Qnil;
516
670
  ID kw_table[1] = { rb_intern("df") };
@@ -537,7 +691,7 @@ private:
537
691
  // #f
538
692
 
539
693
  template<typename T> static void _rand_f(VALUE& self, VALUE& x, const double& dfnum, const double& dfden) {
540
- pcg64* ptr = get_pcg64(self);
694
+ Rng* ptr = get_rng(self);
541
695
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
542
696
  std::fisher_f_distribution<T> f_dist(dfnum, dfden);
543
697
  ndfunc_t ndf = { _iter_rand<std::fisher_f_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -545,7 +699,7 @@ private:
545
699
  na_ndloop3(&ndf, &opt, 1, x);
546
700
  }
547
701
 
548
- static VALUE _numo_random_pcg64_f(int argc, VALUE* argv, VALUE self) {
702
+ static VALUE _numo_random_f(int argc, VALUE* argv, VALUE self) {
549
703
  VALUE x = Qnil;
550
704
  VALUE kw_args = Qnil;
551
705
  ID kw_table[2] = { rb_intern("dfnum"), rb_intern("dfden") };
@@ -574,7 +728,7 @@ private:
574
728
  // #normal
575
729
 
576
730
  template<typename T> static void _rand_normal(VALUE& self, VALUE& x, const double& loc, const double& scale) {
577
- pcg64* ptr = get_pcg64(self);
731
+ Rng* ptr = get_rng(self);
578
732
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
579
733
  std::normal_distribution<T> normal_dist(loc, scale);
580
734
  ndfunc_t ndf = { _iter_rand<std::normal_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -582,7 +736,7 @@ private:
582
736
  na_ndloop3(&ndf, &opt, 1, x);
583
737
  }
584
738
 
585
- static VALUE _numo_random_pcg64_normal(int argc, VALUE* argv, VALUE self) {
739
+ static VALUE _numo_random_normal(int argc, VALUE* argv, VALUE self) {
586
740
  VALUE x = Qnil;
587
741
  VALUE kw_args = Qnil;
588
742
  ID kw_table[2] = { rb_intern("loc"), rb_intern("scale") };
@@ -610,7 +764,7 @@ private:
610
764
  // #lognormal
611
765
 
612
766
  template<typename T> static void _rand_lognormal(VALUE& self, VALUE& x, const double& mean, const double& sigma) {
613
- pcg64* ptr = get_pcg64(self);
767
+ Rng* ptr = get_rng(self);
614
768
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
615
769
  std::lognormal_distribution<T> lognormal_dist(mean, sigma);
616
770
  ndfunc_t ndf = { _iter_rand<std::lognormal_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -618,7 +772,7 @@ private:
618
772
  na_ndloop3(&ndf, &opt, 1, x);
619
773
  }
620
774
 
621
- static VALUE _numo_random_pcg64_lognormal(int argc, VALUE* argv, VALUE self) {
775
+ static VALUE _numo_random_lognormal(int argc, VALUE* argv, VALUE self) {
622
776
  VALUE x = Qnil;
623
777
  VALUE kw_args = Qnil;
624
778
  ID kw_table[2] = { rb_intern("mean"), rb_intern("sigma") };
@@ -646,7 +800,7 @@ private:
646
800
  // #standard_t
647
801
 
648
802
  template<typename T> static void _rand_t(VALUE& self, VALUE& x, const double& df) {
649
- pcg64* ptr = get_pcg64(self);
803
+ Rng* ptr = get_rng(self);
650
804
  ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
651
805
  std::student_t_distribution<T> t_dist(df);
652
806
  ndfunc_t ndf = { _iter_rand<std::student_t_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
@@ -654,7 +808,7 @@ private:
654
808
  na_ndloop3(&ndf, &opt, 1, x);
655
809
  }
656
810
 
657
- static VALUE _numo_random_pcg64_standard_t(int argc, VALUE* argv, VALUE self) {
811
+ static VALUE _numo_random_standard_t(int argc, VALUE* argv, VALUE self) {
658
812
  VALUE x = Qnil;
659
813
  VALUE kw_args = Qnil;
660
814
  ID kw_table[1] = { rb_intern("df") };
@@ -679,16 +833,72 @@ private:
679
833
  }
680
834
  };
681
835
 
682
- const rb_data_type_t RbNumoRandomPCG64::pcg64_type = {
836
+ class RbNumoRandomPCG32 : public RbNumoRandom<pcg32, RbNumoRandomPCG32> {
837
+ public:
838
+ static const rb_data_type_t rng_type;
839
+ };
840
+
841
+ const rb_data_type_t RbNumoRandomPCG32::rng_type = {
842
+ "RbNumoRandomPCG32",
843
+ {
844
+ NULL,
845
+ RbNumoRandomPCG32::numo_random_free,
846
+ RbNumoRandomPCG32::numo_random_size
847
+ },
848
+ NULL,
849
+ NULL,
850
+ 0
851
+ };
852
+
853
+ class RbNumoRandomPCG64 : public RbNumoRandom<pcg64, RbNumoRandomPCG64> {
854
+ public:
855
+ static const rb_data_type_t rng_type;
856
+ };
857
+
858
+ const rb_data_type_t RbNumoRandomPCG64::rng_type = {
683
859
  "RbNumoRandomPCG64",
684
860
  {
685
861
  NULL,
686
- RbNumoRandomPCG64::numo_random_pcg64_free,
687
- RbNumoRandomPCG64::numo_random_pcg64_size
862
+ RbNumoRandomPCG64::numo_random_free,
863
+ RbNumoRandomPCG64::numo_random_size
864
+ },
865
+ NULL,
866
+ NULL,
867
+ 0
868
+ };
869
+
870
+ class RbNumoRandomMT32 : public RbNumoRandom<std::mt19937, RbNumoRandomMT32> {
871
+ public:
872
+ static const rb_data_type_t rng_type;
873
+ };
874
+
875
+ const rb_data_type_t RbNumoRandomMT32::rng_type = {
876
+ "RbNumoRandomMT32",
877
+ {
878
+ NULL,
879
+ RbNumoRandomMT32::numo_random_free,
880
+ RbNumoRandomMT32::numo_random_size
881
+ },
882
+ NULL,
883
+ NULL,
884
+ 0
885
+ };
886
+
887
+ class RbNumoRandomMT64 : public RbNumoRandom<std::mt19937_64, RbNumoRandomMT64> {
888
+ public:
889
+ static const rb_data_type_t rng_type;
890
+ };
891
+
892
+ const rb_data_type_t RbNumoRandomMT64::rng_type = {
893
+ "RbNumoRandomMT64",
894
+ {
895
+ NULL,
896
+ RbNumoRandomMT64::numo_random_free,
897
+ RbNumoRandomMT64::numo_random_size
688
898
  },
689
899
  NULL,
690
900
  NULL,
691
- RUBY_TYPED_FREE_IMMEDIATELY
901
+ 0
692
902
  };
693
903
 
694
904
  #endif /* NUMO_RANDOM_EXT_HPP */
@@ -24,10 +24,21 @@ module Numo
24
24
  # Creates a new random number generator.
25
25
  #
26
26
  # @param seed [Integer] random seed used to initialize the random number generator.
27
- # @param algorithm [String] random number generation algorithm.
28
- def initialize(seed: nil, algorithm: 'pcg64') # rubocop:disable Lint/UnusedMethodArgument
29
- @algorithm = 'pcg64'
30
- @rng = PCG64.new(seed: seed)
27
+ # @param algorithm [String] random number generation algorithm ('mt32', 'mt64', 'pcg32', and 'pcg64').
28
+ def initialize(seed: nil, algorithm: 'pcg64') # rubocop:disable Metrics/MethodLength
29
+ @algorithm = algorithm.to_s
30
+ @rng = case @algorithm
31
+ when 'mt32'
32
+ MT32.new(seed: seed)
33
+ when 'mt64'
34
+ MT64.new(seed: seed)
35
+ when 'pcg32'
36
+ PCG32.new(seed: seed)
37
+ when 'pcg64'
38
+ PCG64.new(seed: seed)
39
+ else
40
+ raise ArgumentError, "Numo::Random::Generator does not support '#{@algorithm}' algorithm"
41
+ end
31
42
  end
32
43
 
33
44
  # Returns the seed of random number generator.
@@ -57,6 +68,78 @@ module Numo
57
68
  rng.random
58
69
  end
59
70
 
71
+ # Generates array consists of random values according to the Bernoulli distribution.
72
+ #
73
+ # @example
74
+ # require 'numo/random'
75
+ #
76
+ # rng = Numo::Random::Generator.new(seed: 42)
77
+ # x = rng.bernoulli(shape: 1000, p: 0.4)
78
+ #
79
+ # @param shape [Integer | Array<Integer>] size of random array.
80
+ # @param p [Float] probability of success.
81
+ # @param dtype [Symbol] data type of random array.
82
+ # @return [Numo::IntX | Numo::UIntX]
83
+ def bernoulli(shape:, p:, dtype: :int32)
84
+ binomial(shape: shape, n: 1, p: p, dtype: dtype)
85
+ end
86
+
87
+ # Generates array consists of random values according to a binomial distribution.
88
+ #
89
+ # @example
90
+ # require 'numo/random'
91
+ #
92
+ # rng = Numo::Random::Generator.new(seed: 42)
93
+ # x = rng.binomial(shape: 1000, n: 10, p: 0.4)
94
+ #
95
+ # @param shape [Integer | Array<Integer>] size of random array.
96
+ # @param n [Integer] number of trials.
97
+ # @param p [Float] probability of success.
98
+ # @param dtype [Symbol] data type of random array.
99
+ # @return [Numo::IntX | Numo::UIntX]
100
+ def binomial(shape:, n:, p:, dtype: :int32)
101
+ x = klass(dtype).new(shape)
102
+ rng.binomial(x, n: n, p: p)
103
+ x
104
+ end
105
+
106
+ # Generates array consists of random values according to a negative binomial distribution.
107
+ #
108
+ # @example
109
+ # require 'numo/random'
110
+ #
111
+ # rng = Numo::Random::Generator.new(seed: 42)
112
+ # x = rng.negative_binomial(shape: 1000, n: 10, p: 0.4)
113
+ #
114
+ # @param shape [Integer | Array<Integer>] size of random array.
115
+ # @param n [Integer] number of trials.
116
+ # @param p [Float] probability of success.
117
+ # @param dtype [Symbol] data type of random array.
118
+ # @return [Numo::IntX | Numo::UIntX]
119
+ def negative_binomial(shape:, n:, p:, dtype: :int32)
120
+ x = klass(dtype).new(shape)
121
+ rng.negative_binomial(x, n: n, p: p)
122
+ x
123
+ end
124
+
125
+ # Generates array consists of random values according to a geometric distribution.
126
+ #
127
+ # @example
128
+ # require 'numo/random'
129
+ #
130
+ # rng = Numo::Random::Generator.new(seed: 42)
131
+ # x = rng.geometric(shape: 1000, p: 0.4)
132
+ #
133
+ # @param shape [Integer | Array<Integer>] size of random array.
134
+ # @param p [Float] probability of success on each trial.
135
+ # @param dtype [Symbol] data type of random array.
136
+ # @return [Numo::IntX | Numo::UIntX]
137
+ def geometric(shape:, p:, dtype: :int32)
138
+ x = klass(dtype).new(shape)
139
+ rng.geometric(x, p: p)
140
+ x
141
+ end
142
+
60
143
  # Generates array consists of random values with an exponential distribution.
61
144
  #
62
145
  # @example
@@ -3,6 +3,6 @@
3
3
  module Numo
4
4
  module Random
5
5
  # The version of Numo::Random you install.
6
- VERSION = '0.3.0'
6
+ VERSION = '0.5.0'
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: numo-random
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yoshoku
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-05 00:00:00.000000000 Z
11
+ date: 2022-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: numo-narray