numo-random 0.3.0 → 0.5.0

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 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