numo-random 0.1.0 → 0.3.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: d990f496714f1d2a594e3f9a919f65d4458d6e9ae455bbff9fc4a118aa059770
4
- data.tar.gz: 1017db53d848fb8e3c4d6724b51527d7d46974d813a93a2eb623270f24edb919
3
+ metadata.gz: a4c6c4db2ffcb5672e571ad59dc94c36d51f87adb29007db4b9678b803840915
4
+ data.tar.gz: c1debe024fe523f28d97a83f7eaee51dc27cf51acfd1efa1cc44cd2994659c72
5
5
  SHA512:
6
- metadata.gz: 7df9d692aa5222adb12ff53768eb804027333f381012e3c137232d847f05bc53514193f2c566092bceedc2ec863e14d100415a6a3fb70f1de08bbf8a78f89286
7
- data.tar.gz: 153d4fb9f6fc18f24e29c14b3f519dadfb0e8f979a1d4b60c31eac667c54e2d75cdaa937700f6fce9e73dc97f368dc08a4b7f2a92f77a241b909825cc573627a
6
+ metadata.gz: 6364e78337ab7d87b0aa3cc18a2264992cb75ab15c65b0ce41065c78eacacbb96e21e55a5872a3878cb1ab143b4f8f7145ce4475e22eca725aef8a16fa0a8409
7
+ data.tar.gz: c3dfbd3d29761f951176395b2c48c596efbb998b3d1650484da908e576624557c60e8aabf64b015096aa0fb33780929c5a78b598a206ea659fdb4d75cea020f3
data/CHANGELOG.md CHANGED
@@ -1,7 +1,15 @@
1
1
  ## [Unreleased]
2
- - Sampling distribution.
3
2
  - Bernoulli distribution.
4
- - Poisson distribution.
3
+
4
+ ## [0.3.0]
5
+ - Change native extension filename.
6
+ - Add methods for random number generation with poisson distributions: poisson, exponential, gamma, gumbel, and weibull.
7
+
8
+ ## [0.2.0]
9
+ - Add discrete method.
10
+
11
+ ### Breaking Changes
12
+ - Change to return array for all methods that fill array with random numbers in Generator class.
5
13
 
6
14
  ## [0.1.0]
7
15
  - Initial release.
data/README.md CHANGED
@@ -33,14 +33,11 @@ require 'numo/gnuplot'
33
33
 
34
34
  require 'numo/random'
35
35
 
36
- # Prepareing array to be filled with random numbers.
37
- x = Numo::DFloat.new(5000, 2)
38
-
39
36
  # Creating random number generator.
40
37
  rng = Numo::Random::Generator.new(seed: 42)
41
38
 
42
39
  # Generating random numbers with a normal distribution.
43
- rng.normal(x, loc: 0.0, scale: 1.0)
40
+ x = rng.normal(shape: [5000, 2], loc: 0.0, scale: 1.0)
44
41
 
45
42
  # Plotting the generated result.
46
43
  Numo.gnuplot do
@@ -16,9 +16,9 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- #include "randomext.hpp"
19
+ #include "ext.hpp"
20
20
 
21
- extern "C" void Init_randomext(void) {
21
+ 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");
@@ -16,8 +16,8 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- #ifndef NUMO_RANDOMEXT_HPP
20
- #define NUMO_RANDOMEXT_HPP 1
19
+ #ifndef NUMO_RANDOM_EXT_HPP
20
+ #define NUMO_RANDOM_EXT_HPP 1
21
21
 
22
22
  #include <ruby.h>
23
23
 
@@ -58,6 +58,12 @@ public:
58
58
  rb_define_method(rb_cPCG64, "seed=", RUBY_METHOD_FUNC(_numo_random_pcg64_set_seed), 1);
59
59
  rb_define_method(rb_cPCG64, "seed", RUBY_METHOD_FUNC(_numo_random_pcg64_get_seed), 0);
60
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);
61
67
  rb_define_method(rb_cPCG64, "uniform", RUBY_METHOD_FUNC(_numo_random_pcg64_uniform), -1);
62
68
  rb_define_method(rb_cPCG64, "cauchy", RUBY_METHOD_FUNC(_numo_random_pcg64_cauchy), -1);
63
69
  rb_define_method(rb_cPCG64, "chisquare", RUBY_METHOD_FUNC(_numo_random_pcg64_chisquare), -1);
@@ -143,6 +149,284 @@ private:
143
149
  }
144
150
  }
145
151
 
152
+ // #exponential
153
+
154
+ template<typename T> static void _rand_exponential(VALUE& self, VALUE& x, const double& lam) {
155
+ pcg64* ptr = get_pcg64(self);
156
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
157
+ std::exponential_distribution<T> exponential_dist(lam);
158
+ ndfunc_t ndf = { _iter_rand<std::exponential_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
159
+ rand_opt_t<std::exponential_distribution<T>> opt = { exponential_dist, ptr };
160
+ na_ndloop3(&ndf, &opt, 1, x);
161
+ }
162
+
163
+ static VALUE _numo_random_pcg64_exponential(int argc, VALUE* argv, VALUE self) {
164
+ VALUE x = Qnil;
165
+ VALUE kw_args = Qnil;
166
+ ID kw_table[1] = { rb_intern("scale") };
167
+ VALUE kw_values[1] = { Qundef };
168
+ rb_scan_args(argc, argv, "1:", &x, &kw_args);
169
+ rb_get_kwargs(kw_args, kw_table, 0, 1, kw_values);
170
+
171
+ const VALUE klass = rb_obj_class(x);
172
+ if (klass != numo_cSFloat && klass != numo_cDFloat) rb_raise(rb_eTypeError, "invalid NArray class, it must be DFloat or SFloat");
173
+
174
+ const double scale = kw_values[0] == Qundef ? 1.0 : NUM2DBL(kw_values[0]);
175
+ if (scale <= 0) rb_raise(rb_eArgError, "scale must be > 0");
176
+
177
+ const double lam = 1.0 / scale;
178
+ if (klass == numo_cSFloat) {
179
+ _rand_exponential<float>(self, x, lam);
180
+ } else {
181
+ _rand_exponential<double>(self, x, lam);
182
+ }
183
+
184
+ RB_GC_GUARD(x);
185
+ return Qnil;
186
+ }
187
+
188
+ // #gamma
189
+
190
+ template<typename T> static void _rand_gamma(VALUE& self, VALUE& x, const double& k, const double&scale) {
191
+ pcg64* ptr = get_pcg64(self);
192
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
193
+ std::gamma_distribution<T> gamma_dist(k, scale);
194
+ ndfunc_t ndf = { _iter_rand<std::gamma_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
195
+ rand_opt_t<std::gamma_distribution<T>> opt = { gamma_dist, ptr };
196
+ na_ndloop3(&ndf, &opt, 1, x);
197
+ }
198
+
199
+ static VALUE _numo_random_pcg64_gamma(int argc, VALUE* argv, VALUE self) {
200
+ VALUE x = Qnil;
201
+ VALUE kw_args = Qnil;
202
+ ID kw_table[2] = { rb_intern("k"), rb_intern("scale") };
203
+ VALUE kw_values[2] = { Qundef, Qundef };
204
+ rb_scan_args(argc, argv, "1:", &x, &kw_args);
205
+ rb_get_kwargs(kw_args, kw_table, 1, 1, kw_values);
206
+
207
+ const VALUE klass = rb_obj_class(x);
208
+ if (klass != numo_cSFloat && klass != numo_cDFloat) rb_raise(rb_eTypeError, "invalid NArray class, it must be DFloat or SFloat");
209
+
210
+ const double k = NUM2DBL(kw_values[0]);
211
+ if (k <= 0) rb_raise(rb_eArgError, "k must be > 0");
212
+ const double scale = kw_values[1] == Qundef ? 1.0 : NUM2DBL(kw_values[1]);
213
+ if (scale <= 0) rb_raise(rb_eArgError, "scale must be > 0");
214
+
215
+ if (klass == numo_cSFloat) {
216
+ _rand_gamma<float>(self, x, k, scale);
217
+ } else {
218
+ _rand_gamma<double>(self, x, k, scale);
219
+ }
220
+
221
+ RB_GC_GUARD(x);
222
+ return Qnil;
223
+ }
224
+
225
+ // #gumbel
226
+
227
+ template<typename T> static void _rand_gumbel(VALUE& self, VALUE& x, const double& loc, const double&scale) {
228
+ pcg64* ptr = get_pcg64(self);
229
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
230
+ std::extreme_value_distribution<T> extreme_value_dist(loc, scale);
231
+ ndfunc_t ndf = { _iter_rand<std::extreme_value_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
232
+ rand_opt_t<std::extreme_value_distribution<T>> opt = { extreme_value_dist, ptr };
233
+ na_ndloop3(&ndf, &opt, 1, x);
234
+ }
235
+
236
+ static VALUE _numo_random_pcg64_gumbel(int argc, VALUE* argv, VALUE self) {
237
+ VALUE x = Qnil;
238
+ VALUE kw_args = Qnil;
239
+ ID kw_table[2] = { rb_intern("loc"), rb_intern("scale") };
240
+ VALUE kw_values[2] = { Qundef, Qundef };
241
+ rb_scan_args(argc, argv, "1:", &x, &kw_args);
242
+ rb_get_kwargs(kw_args, kw_table, 0, 2, kw_values);
243
+
244
+ const VALUE klass = rb_obj_class(x);
245
+ if (klass != numo_cSFloat && klass != numo_cDFloat) rb_raise(rb_eTypeError, "invalid NArray class, it must be DFloat or SFloat");
246
+
247
+ const double loc = kw_values[0] == Qundef ? 0.0 : NUM2DBL(kw_values[0]);
248
+ const double scale = kw_values[1] == Qundef ? 1.0 : NUM2DBL(kw_values[1]);
249
+ if (scale <= 0) rb_raise(rb_eArgError, "scale must be > 0");
250
+
251
+ if (klass == numo_cSFloat) {
252
+ _rand_gumbel<float>(self, x, loc, scale);
253
+ } else {
254
+ _rand_gumbel<double>(self, x, loc, scale);
255
+ }
256
+
257
+ RB_GC_GUARD(x);
258
+ return Qnil;
259
+ }
260
+
261
+ // #poisson
262
+
263
+ template<typename T> static void _rand_poisson(VALUE& self, VALUE& x, const double& mean) {
264
+ pcg64* ptr = get_pcg64(self);
265
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
266
+ std::poisson_distribution<T> poisson_dist(mean);
267
+ ndfunc_t ndf = { _iter_rand<std::poisson_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
268
+ rand_opt_t<std::poisson_distribution<T>> opt = { poisson_dist, ptr };
269
+ na_ndloop3(&ndf, &opt, 1, x);
270
+ }
271
+
272
+ static VALUE _numo_random_pcg64_poisson(int argc, VALUE* argv, VALUE self) {
273
+ VALUE x = Qnil;
274
+ VALUE kw_args = Qnil;
275
+ ID kw_table[2] = { rb_intern("mean") };
276
+ VALUE kw_values[2] = { Qundef, Qundef };
277
+ rb_scan_args(argc, argv, "1:", &x, &kw_args);
278
+ rb_get_kwargs(kw_args, kw_table, 0, 1, kw_values);
279
+
280
+ const VALUE klass = rb_obj_class(x);
281
+ if (klass != numo_cInt8 && klass != numo_cInt16 && klass != numo_cInt32 && klass != numo_cInt64
282
+ && klass != numo_cUInt8 && klass != numo_cUInt16 && klass != numo_cUInt32 && klass != numo_cUInt64)
283
+ rb_raise(rb_eTypeError, "invalid NArray class, it must be integer typed array");
284
+
285
+ const double mean = kw_values[0] == Qundef ? 0.0 : NUM2DBL(kw_values[0]);
286
+ if (mean <= 0.0) rb_raise(rb_eArgError, "mean must be > 0");
287
+
288
+ if (klass == numo_cInt8) {
289
+ _rand_poisson<int8_t>(self, x, mean);
290
+ } else if (klass == numo_cInt16) {
291
+ _rand_poisson<int16_t>(self, x, mean);
292
+ } else if (klass == numo_cInt32) {
293
+ _rand_poisson<int32_t>(self, x, mean);
294
+ } else if (klass == numo_cInt64) {
295
+ _rand_poisson<int64_t>(self, x, mean);
296
+ } else if (klass == numo_cUInt8) {
297
+ _rand_poisson<uint8_t>(self, x, mean);
298
+ } else if (klass == numo_cUInt16) {
299
+ _rand_poisson<uint16_t>(self, x, mean);
300
+ } else if (klass == numo_cUInt32) {
301
+ _rand_poisson<uint32_t>(self, x, mean);
302
+ } else if (klass == numo_cUInt64) {
303
+ _rand_poisson<uint64_t>(self, x, mean);
304
+ }
305
+
306
+ RB_GC_GUARD(x);
307
+ return Qnil;
308
+ }
309
+
310
+ // #weibull
311
+
312
+ template<typename T> static void _rand_weibull(VALUE& self, VALUE& x, const double& k, const double&scale) {
313
+ pcg64* ptr = get_pcg64(self);
314
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
315
+ std::weibull_distribution<T> weibull_dist(k, scale);
316
+ ndfunc_t ndf = { _iter_rand<std::weibull_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
317
+ rand_opt_t<std::weibull_distribution<T>> opt = { weibull_dist, ptr };
318
+ na_ndloop3(&ndf, &opt, 1, x);
319
+ }
320
+
321
+ static VALUE _numo_random_pcg64_weibull(int argc, VALUE* argv, VALUE self) {
322
+ VALUE x = Qnil;
323
+ VALUE kw_args = Qnil;
324
+ ID kw_table[2] = { rb_intern("k"), rb_intern("scale") };
325
+ VALUE kw_values[2] = { Qundef, Qundef };
326
+ rb_scan_args(argc, argv, "1:", &x, &kw_args);
327
+ rb_get_kwargs(kw_args, kw_table, 1, 1, kw_values);
328
+
329
+ const VALUE klass = rb_obj_class(x);
330
+ if (klass != numo_cSFloat && klass != numo_cDFloat) rb_raise(rb_eTypeError, "invalid NArray class, it must be DFloat or SFloat");
331
+
332
+ const double k = NUM2DBL(kw_values[0]);
333
+ if (k <= 0) rb_raise(rb_eArgError, "k must be > 0");
334
+ const double scale = kw_values[1] == Qundef ? 1.0 : NUM2DBL(kw_values[1]);
335
+ if (scale <= 0) rb_raise(rb_eArgError, "scale must be > 0");
336
+
337
+ if (klass == numo_cSFloat) {
338
+ _rand_weibull<float>(self, x, k, scale);
339
+ } else {
340
+ _rand_weibull<double>(self, x, k, scale);
341
+ }
342
+
343
+ RB_GC_GUARD(x);
344
+ return Qnil;
345
+ }
346
+
347
+ // #discrete
348
+
349
+ template<typename T, typename P> static void _rand_discrete(VALUE& self, VALUE& x, const std::vector<P>& weight) {
350
+ pcg64* ptr = get_pcg64(self);
351
+ ndfunc_arg_in_t ain[1] = { { OVERWRITE, 0 } };
352
+ std::discrete_distribution<T> discrete_dist(weight.begin(), weight.end());
353
+ ndfunc_t ndf = { _iter_rand<std::discrete_distribution<T>, T>, FULL_LOOP, 1, 0, ain, 0 };
354
+ rand_opt_t<std::discrete_distribution<T>> opt = { discrete_dist, ptr };
355
+ na_ndloop3(&ndf, &opt, 1, x);
356
+ }
357
+
358
+ static VALUE _numo_random_pcg64_discrete(int argc, VALUE* argv, VALUE self) {
359
+ VALUE x = Qnil;
360
+ VALUE kw_args = Qnil;
361
+ ID kw_table[1] = { rb_intern("weight") };
362
+ VALUE kw_values[1] = { Qundef };
363
+ rb_scan_args(argc, argv, "1:", &x, &kw_args);
364
+ rb_get_kwargs(kw_args, kw_table, 1, 0, kw_values);
365
+
366
+ VALUE klass = rb_obj_class(x);
367
+ if (klass != numo_cInt8 && klass != numo_cInt16 && klass != numo_cInt32 && klass != numo_cInt64
368
+ && klass != numo_cUInt8 && klass != numo_cUInt16 && klass != numo_cUInt32 && klass != numo_cUInt64)
369
+ rb_raise(rb_eTypeError, "invalid NArray class, it must be integer typed array");
370
+
371
+ VALUE w = kw_values[0];
372
+ VALUE w_klass = rb_obj_class(w);
373
+ if (w_klass != numo_cSFloat && w_klass != numo_cDFloat) rb_raise(rb_eTypeError, "weight must be Numo::DFloat or Numo::SFloat");
374
+
375
+ if (!RTEST(nary_check_contiguous(w))) w = nary_dup(w);
376
+ narray_t* w_nary;
377
+ GetNArray(w, w_nary);
378
+ if (NA_NDIM(w_nary) != 1) rb_raise(rb_eArgError, "weight must be 1-dimensional array");
379
+
380
+ const size_t w_len = NA_SHAPE(w_nary)[0];
381
+ if (w_len < 1) rb_raise(rb_eArgError, "length of weight must be > 0");
382
+
383
+ if (w_klass == numo_cSFloat) {
384
+ const float* w_ptr = (float*)na_get_pointer_for_read(w);
385
+ std::vector<float> w_vec(w_ptr, w_ptr + w_len);
386
+ if (klass == numo_cInt8) {
387
+ _rand_discrete<int8_t, float>(self, x, w_vec);
388
+ } else if (klass == numo_cInt16) {
389
+ _rand_discrete<int16_t, float>(self, x, w_vec);
390
+ } else if (klass == numo_cInt32) {
391
+ _rand_discrete<int32_t, float>(self, x, w_vec);
392
+ } else if (klass == numo_cInt64) {
393
+ _rand_discrete<int64_t, float>(self, x, w_vec);
394
+ } else if (klass == numo_cUInt8) {
395
+ _rand_discrete<uint8_t, float>(self, x, w_vec);
396
+ } else if (klass == numo_cUInt16) {
397
+ _rand_discrete<uint16_t, float>(self, x, w_vec);
398
+ } else if (klass == numo_cUInt32) {
399
+ _rand_discrete<uint32_t, float>(self, x, w_vec);
400
+ } else if (klass == numo_cUInt64) {
401
+ _rand_discrete<uint64_t, float>(self, x, w_vec);
402
+ }
403
+ } else {
404
+ const double* w_ptr = (double*)na_get_pointer_for_read(w);
405
+ std::vector<double> w_vec(w_ptr, w_ptr + w_len);
406
+ if (klass == numo_cInt8) {
407
+ _rand_discrete<int8_t, double>(self, x, w_vec);
408
+ } else if (klass == numo_cInt16) {
409
+ _rand_discrete<int16_t, double>(self, x, w_vec);
410
+ } else if (klass == numo_cInt32) {
411
+ _rand_discrete<int32_t, double>(self, x, w_vec);
412
+ } else if (klass == numo_cInt64) {
413
+ _rand_discrete<int64_t, double>(self, x, w_vec);
414
+ } else if (klass == numo_cUInt8) {
415
+ _rand_discrete<uint8_t, double>(self, x, w_vec);
416
+ } else if (klass == numo_cUInt16) {
417
+ _rand_discrete<uint16_t, double>(self, x, w_vec);
418
+ } else if (klass == numo_cUInt32) {
419
+ _rand_discrete<uint32_t, double>(self, x, w_vec);
420
+ } else if (klass == numo_cUInt64) {
421
+ _rand_discrete<uint64_t, double>(self, x, w_vec);
422
+ }
423
+ }
424
+
425
+ RB_GC_GUARD(w);
426
+ RB_GC_GUARD(x);
427
+ return Qnil;
428
+ }
429
+
146
430
  // #uniform
147
431
 
148
432
  template<typename T> static void _rand_uniform(VALUE& self, VALUE& x, const double& low, const double& high) {
@@ -407,4 +691,4 @@ const rb_data_type_t RbNumoRandomPCG64::pcg64_type = {
407
691
  RUBY_TYPED_FREE_IMMEDIATELY
408
692
  };
409
693
 
410
- #endif /* NUMO_RANDOMEXT_HPP */
694
+ #endif /* NUMO_RANDOM_EXT_HPP */
@@ -26,4 +26,4 @@ $CXXFLAGS << " -std=c++11"
26
26
  $INCFLAGS << " -I$(srcdir)/src"
27
27
  $VPATH << "$(srcdir)/src"
28
28
 
29
- create_makefile("numo/random/randomext")
29
+ create_makefile("numo/random/ext")
@@ -0,0 +1,342 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Ruby/Numo (NUmerical MOdules)
4
+ module Numo
5
+ # Numo::Random provides random number generation with several distributions for Numo::NArray.
6
+ module Random
7
+ # Generator is a class that generates random number with several distributions.
8
+ #
9
+ # @example
10
+ # require 'numo/random'
11
+ #
12
+ # rng = Numo::Random::Generator.new(seed: 496)
13
+ # x = rng.uniform(shape: [2, 5], low: -1, high: 2)
14
+ #
15
+ # p x
16
+ # # Numo::DFloat#shape=[2,5]
17
+ # # [[1.90546, -0.543299, 0.673332, 0.759583, -0.40945],
18
+ # # [0.334635, -0.0558342, 1.28115, 1.93644, -0.0689543]]
19
+ class Generator # rubocop:disable Metrics/ClassLength
20
+ # Returns random number generation algorithm.
21
+ # @return [String]
22
+ attr_accessor :algorithm
23
+
24
+ # Creates a new random number generator.
25
+ #
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)
31
+ end
32
+
33
+ # Returns the seed of random number generator.
34
+ #
35
+ # @return [Integer]
36
+ def seed
37
+ rng.seed
38
+ end
39
+
40
+ # Sets the seed of random number generator.
41
+ #
42
+ # @param val [Integer] random seed.
43
+ def seed=(val)
44
+ rng.seed = val
45
+ end
46
+
47
+ # Returns random number with uniform distribution in the half-open interval [0, 1).
48
+ #
49
+ # @example
50
+ # require 'numo/random'
51
+ #
52
+ # rng = Numo::Random::Generator.new
53
+ # v = rng.random
54
+ #
55
+ # @return [Float]
56
+ def random
57
+ rng.random
58
+ end
59
+
60
+ # Generates array consists of random values with an exponential distribution.
61
+ #
62
+ # @example
63
+ # require 'numo/random'
64
+ #
65
+ # rng = Numo::Random::Generator.new
66
+ # x = rng.exponential(shape: 100, scale: 2)
67
+ #
68
+ # @param shape [Integer | Array<Integer>] size of random array.
69
+ # @param scale [Float] scale parameter, lambda = 1.fdiv(scale).
70
+ # @param dtype [Symbol] data type of random array.
71
+ # @return [Numo::DFloat | Numo::SFloat]
72
+ def exponential(shape:, scale: 1.0, dtype: :float64)
73
+ x = klass(dtype).new(shape)
74
+ rng.exponential(x, scale: scale)
75
+ x
76
+ end
77
+
78
+ # Generates array consists of random values with a gamma distribution.
79
+ #
80
+ # @example
81
+ # require 'numo/random'
82
+ #
83
+ # rng = Numo::Random::Generator.new
84
+ # x = rng.gamma(shape: 100, k: 9, scale: 0.5)
85
+ #
86
+ # @param shape [Integer | Array<Integer>] size of random array.
87
+ # @param k [Float] shape parameter.
88
+ # @param scale [Float] scale parameter.
89
+ # @param dtype [Symbol] data type of random array.
90
+ # @return [Numo::DFloat | Numo::SFloat]
91
+ def gamma(shape:, k:, scale: 1.0, dtype: :float64)
92
+ x = klass(dtype).new(shape)
93
+ rng.gamma(x, k: k, scale: scale)
94
+ x
95
+ end
96
+
97
+ # Generates array consists of random values according to the Gumbel distribution.
98
+ #
99
+ # @example
100
+ # require 'numo/random'
101
+ #
102
+ # rng = Numo::Random::Generator.new
103
+ # x = rng.gumbel(shape: 100, loc: 0.0, scale: 1.0)
104
+ #
105
+ # @param shape [Integer | Array<Integer>] size of random array.
106
+ # @param loc [Float] location parameter.
107
+ # @param scale [Float] scale parameter.
108
+ # @param dtype [Symbol] data type of random array.
109
+ # @return [Numo::DFloat | Numo::SFloat]
110
+ def gumbel(shape:, loc: 0.0, scale: 1.0, dtype: :float64)
111
+ x = klass(dtype).new(shape)
112
+ rng.gumbel(x, loc: loc, scale: scale)
113
+ x
114
+ end
115
+
116
+ # Generates array consists of random values according to the Poisson distribution.
117
+ #
118
+ # @example
119
+ # require 'numo/random'
120
+ #
121
+ # rng = Numo::Random::Generator.new(seed: 42)
122
+ # x = rng.poisson(shape: 1000, mean: 4)
123
+ #
124
+ # @param shape [Integer | Array<Integer>] size of random array.
125
+ # @param mean [Float] mean of poisson distribution.
126
+ # @param dtype [Symbol] data type of random array.
127
+ # @return [Numo::IntX | Numo::UIntX]
128
+ def poisson(shape:, mean: 1.0, dtype: :int32)
129
+ x = klass(dtype).new(shape)
130
+ rng.poisson(x, mean: mean)
131
+ x
132
+ end
133
+
134
+ # Generates array consists of random values with the Weibull distribution.
135
+ #
136
+ # @example
137
+ # require 'numo/random'
138
+ #
139
+ # rng = Numo::Random::Generator.new
140
+ # x = rng.weibull(shape: 100, k: 5, scale: 2)
141
+ #
142
+ # @param shape [Integer | Array<Integer>] size of random array.
143
+ # @param k [Float] shape parameter.
144
+ # @param scale [Float] scale parameter.
145
+ # @param dtype [Symbol] data type of random array.
146
+ # @return [Numo::DFloat | Numo::SFloat]
147
+ def weibull(shape:, k:, scale: 1.0, dtype: :float64)
148
+ x = klass(dtype).new(shape)
149
+ rng.weibull(x, k: k, scale: scale)
150
+ x
151
+ end
152
+
153
+ # Generates array consists of random integer values in the interval [0, n).
154
+ #
155
+ # @example
156
+ # require 'numo/random'
157
+ #
158
+ # rng = Numo::Random::Generator.new(seed: 42)
159
+ # w = Numo::DFloat[0.1, 0.6, 0.2]
160
+ # x = rng.discrete(shape: [3, 10], weight: w)
161
+ #
162
+ # p x
163
+ #
164
+ # # Numo::Int32#shape=[3,10]
165
+ # # [[1, 1, 1, 1, 1, 1, 1, 1, 2, 1],
166
+ # # [0, 1, 0, 1, 1, 0, 1, 1, 2, 1],
167
+ # # [2, 1, 1, 1, 1, 2, 2, 1, 1, 2]]
168
+ #
169
+ # @param shape [Integer | Array<Integer>] size of random array.
170
+ # @param weight [Numo::DFloat | Numo::SFloat] (shape: [n]) list of probabilities of each integer being generated.
171
+ # @param dtype [Symbol] data type of random array.
172
+ # @return [Numo::IntX | Numo::UIntX]
173
+ def discrete(shape:, weight:, dtype: :int32)
174
+ x = klass(dtype).new(shape)
175
+ rng.discrete(x, weight: weight)
176
+ x
177
+ end
178
+
179
+ # Generates array consists of uniformly distributed random values in the interval [low, high).
180
+ #
181
+ # @example
182
+ # require 'numo/random'
183
+ #
184
+ # rng = Numo::Random::Generator.new
185
+ # x = rng.uniform(shape: 100, low: -1.5, high: 1.5)
186
+ #
187
+ # @param shape [Integer | Array<Integer>] size of random array.
188
+ # @param low [Float] lower boundary.
189
+ # @param high [Float] upper boundary.
190
+ # @param dtype [Symbol] data type of random array.
191
+ # @return [Numo::DFloat | Numo::SFloat]
192
+ def uniform(shape:, low: 0.0, high: 1.0, dtype: :float64)
193
+ x = klass(dtype).new(shape)
194
+ rng.uniform(x, low: low, high: high)
195
+ x
196
+ end
197
+
198
+ # Generates array consists of random values according to the Cauchy (Lorentz) distribution.
199
+ #
200
+ # @example
201
+ # require 'numo/random'
202
+ #
203
+ # rng = Numo::Random::Generator.new
204
+ # x = rng.cauchy(shape: 100, loc: 0.0, scale: 1.0)
205
+ #
206
+ # @param shape [Integer | Array<Integer>] size of random array.
207
+ # @param loc [Float] location parameter.
208
+ # @param scale [Float] scale parameter.
209
+ # @param dtype [Symbol] data type of random array.
210
+ # @return [Numo::DFloat | Numo::SFloat]
211
+ def cauchy(shape:, loc: 0.0, scale: 1.0, dtype: :float64)
212
+ x = klass(dtype).new(shape)
213
+ rng.cauchy(x, loc: loc, scale: scale)
214
+ x
215
+ end
216
+
217
+ # Generates array consists of random values according to the Chi-squared distribution.
218
+ #
219
+ # @example
220
+ # require 'numo/random'
221
+ #
222
+ # rng = Numo::Random::Generator.new
223
+ # x = rng.chisquare(shape: 100, df: 2.0)
224
+ #
225
+ # @param shape [Integer | Array<Integer>] size of random array.
226
+ # @param df [Float] degrees of freedom, must be > 0.
227
+ # @param dtype [Symbol] data type of random array.
228
+ # @return [Numo::DFloat | Numo::SFloat]
229
+ def chisquare(shape:, df:, dtype: :float64)
230
+ x = klass(dtype).new(shape)
231
+ rng.chisquare(x, df: df)
232
+ x
233
+ end
234
+
235
+ # Generates array consists of random values according to the F-distribution.
236
+ #
237
+ # @example
238
+ # require 'numo/random'
239
+ #
240
+ # rng = Numo::Random::Generator.new
241
+ # x = rng.f(shape: 100, dfnum: 2.0, dfden: 4.0)
242
+ #
243
+ # @param shape [Integer | Array<Integer>] size of random array.
244
+ # @param dfnum [Float] degrees of freedom in numerator, must be > 0.
245
+ # @param dfden [Float] degrees of freedom in denominator, must be > 0.
246
+ # @param dtype [Symbol] data type of random array.
247
+ # @return [Numo::DFloat | Numo::SFloat]
248
+ def f(shape:, dfnum:, dfden:, dtype: :float64)
249
+ x = klass(dtype).new(shape)
250
+ rng.f(x, dfnum: dfnum, dfden: dfden)
251
+ x
252
+ end
253
+
254
+ # Generates array consists of random values according to a normal (Gaussian) distribution.
255
+ #
256
+ # @example
257
+ # require 'numo/random'
258
+ #
259
+ # rng = Numo::Random::Generator.new
260
+ # x = rng.normal(shape: 100, loc: 0.0, scale: 1.0)
261
+ #
262
+ # @param shape [Integer | Array<Integer>] size of random array.
263
+ # @param loc [Float] location parameter.
264
+ # @param scale [Float] scale parameter.
265
+ # @param dtype [Symbol] data type of random array.
266
+ # @return [Numo::DFloat | Numo::SFloat]
267
+ def normal(shape:, loc: 0.0, scale: 1.0, dtype: :float64)
268
+ x = klass(dtype).new(shape)
269
+ rng.normal(x, loc: loc, scale: scale)
270
+ x
271
+ end
272
+
273
+ # Generates array consists of random values according to a log-normal distribution.
274
+ #
275
+ # @example
276
+ # require 'numo/random'
277
+ #
278
+ # rng = Numo::Random::Generator.new
279
+ # x = rng.lognormal(shape: 100, mean: 0.0, sigma: 1.0)
280
+ #
281
+ # @param shape [Integer | Array<Integer>] size of random array.
282
+ # @param mean [Float] mean of normal distribution.
283
+ # @param sigma [Float] standard deviation of normal distribution.
284
+ # @param dtype [Symbol] data type of random array.
285
+ # @return [Numo::DFloat | Numo::SFloat]
286
+ def lognormal(shape:, mean: 0.0, sigma: 1.0, dtype: :float64)
287
+ x = klass(dtype).new(shape)
288
+ rng.lognormal(x, mean: mean, sigma: sigma)
289
+ x
290
+ end
291
+
292
+ # Generates array consists of random values according to the Student's t-distribution.
293
+ #
294
+ # @example
295
+ # require 'numo/random'
296
+ #
297
+ # rng = Numo::Random::Generator.new
298
+ # x = rng.standard_t(shape: 100, df: 8.0)
299
+ #
300
+ # @param shape [Integer | Array<Integer>] size of random array.
301
+ # @param df [Float] degrees of freedom, must be > 0.
302
+ # @param dtype [Symbol] data type of random array.
303
+ # @return [Numo::DFloat | Numo::SFloat]
304
+ def standard_t(shape:, df:, dtype: :float64)
305
+ x = klass(dtype).new(shape)
306
+ rng.standard_t(x, df: df)
307
+ x
308
+ end
309
+
310
+ private
311
+
312
+ attr_reader :rng
313
+
314
+ def klass(dtype) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
315
+ case dtype.to_sym
316
+ when :int8
317
+ Numo::Int8
318
+ when :int16
319
+ Numo::Int16
320
+ when :int32
321
+ Numo::Int32
322
+ when :int64
323
+ Numo::Int64
324
+ when :uint8
325
+ Numo::UInt8
326
+ when :uint16
327
+ Numo::UInt16
328
+ when :uint32
329
+ Numo::UInt32
330
+ when :uint64
331
+ Numo::UInt64
332
+ when :float32, :sfloat
333
+ Numo::SFloat
334
+ when :float64, :dfloat
335
+ Numo::DFloat
336
+ else
337
+ raise ArgumentError, "wrong dtype is given: #{dtype}"
338
+ end
339
+ end
340
+ end
341
+ end
342
+ end
@@ -3,6 +3,6 @@
3
3
  module Numo
4
4
  module Random
5
5
  # The version of Numo::Random you install.
6
- VERSION = '0.1.0'
6
+ VERSION = '0.3.0'
7
7
  end
8
8
  end
data/lib/numo/random.rb CHANGED
@@ -3,182 +3,5 @@
3
3
  require 'numo/narray'
4
4
 
5
5
  require_relative 'random/version'
6
- require_relative 'random/randomext'
7
-
8
- # Ruby/Numo (NUmerical MOdules)
9
- module Numo
10
- # Numo::Random provides random number generation with several distributions for Numo::NArray.
11
- module Random
12
- # Generator is a class that generates random number with several distributions.
13
- #
14
- # @example
15
- # require 'numo/random'
16
- #
17
- # x = Numo::DFloat.new(100)
18
- #
19
- # rng = Numo::Random::Generator.new
20
- # rng.uniform(x, low: -1, high: 2)
21
- class Generator
22
- # Returns random number generation algorithm.
23
- # @return [String]
24
- attr_accessor :algorithm
25
-
26
- # Creates a new random number generator.
27
- #
28
- # @param seed [Integer] random seed used to initialize the random number generator.
29
- # @param algorithm [String] random number generation algorithm.
30
- def initialize(seed: nil, algorithm: 'pcg64') # rubocop:disable Lint/UnusedMethodArgument
31
- @algorithm = 'pcg64'
32
- @rng = PCG64.new(seed: seed)
33
- end
34
-
35
- # Returns the seed of random number generator.
36
- #
37
- # @return [Integer]
38
- def seed
39
- rng.seed
40
- end
41
-
42
- # Sets the seed of random number generator.
43
- #
44
- # @param val [Integer] random seed.
45
- def seed=(val)
46
- rng.seed = val
47
- end
48
-
49
- # Returns random number with uniform distribution in the half-open interval [0, 1).
50
- #
51
- # @example
52
- # require 'numo/random'
53
- #
54
- # rng = Numo::Random::Generator.new
55
- # v = rng.random
56
- #
57
- # @return [Float]
58
- def random
59
- rng.random
60
- end
61
-
62
- # Fills given array with uniformly distributed random values in the interval [low, high).
63
- #
64
- # @example
65
- # require 'numo/random'
66
- #
67
- # x = Numo::DFloat.new(100)
68
- #
69
- # rng = Numo::Random::Generator.new
70
- # rng.uniform(x, low: -1.5, high: 1.5)
71
- #
72
- # @param x [Numo::DFloat | Numo::SFloat] array filled with random values.
73
- # @param low [Float] lower boundary.
74
- # @param high [Float] upper boundary.
75
- def uniform(x, low: 0.0, high: 1.0)
76
- rng.uniform(x, low: low, high: high)
77
- end
78
-
79
- # Fills given array with random values according to the Cauchy (Lorentz) distribution.
80
- #
81
- # @example
82
- # require 'numo/random'
83
- #
84
- # x = Numo::DFloat.new(100)
85
- #
86
- # rng = Numo::Random::Generator.new
87
- # rng.cauchy(x, loc: 0.0, scale: 1.0)
88
- #
89
- # @param x [Numo::DFloat | Numo::SFloat] array filled with random values.
90
- # @param loc [Float] location parameter.
91
- # @param scale [Float] scale parameter.
92
- def cauchy(x, loc: 0.0, scale: 1.0)
93
- rng.cauchy(x, loc: loc, scale: scale)
94
- end
95
-
96
- # Fills given array with random values according to the Chi-squared distribution.
97
- #
98
- # @example
99
- # require 'numo/random'
100
- #
101
- # x = Numo::DFloat.new(100)
102
- #
103
- # rng = Numo::Random::Generator.new
104
- # rng.chisquare(x, df: 2.0)
105
- #
106
- # @param x [Numo::DFloat | Numo::SFloat] array filled with random values.
107
- # @param df [Float] degrees of freedom, must be > 0.
108
- def chisquare(x, df:)
109
- rng.chisquare(x, df: df)
110
- end
111
-
112
- # Fills given array with random values according to the F-distribution.
113
- #
114
- # @example
115
- # require 'numo/random'
116
- #
117
- # x = Numo::DFloat.new(100)
118
- #
119
- # rng = Numo::Random::Generator.new
120
- # rng.f(x, dfnum: 2.0, dfden: 4.0)
121
- #
122
- # @param x [Numo::DFloat | Numo::SFloat] array filled with random values.
123
- # @param dfnum [Float] degrees of freedom in numerator, must be > 0.
124
- # @param dfden [Float] degrees of freedom in denominator, must be > 0.
125
- def f(x, dfnum:, dfden:)
126
- rng.f(x, dfnum: dfnum, dfden: dfden)
127
- end
128
-
129
- # Fills given array with random values according to a normal (Gaussian) distribution.
130
- #
131
- # @example
132
- # require 'numo/random'
133
- #
134
- # x = Numo::DFloat.new(100)
135
- #
136
- # rng = Numo::Random::Generator.new
137
- # rng.normal(x, loc: 0.0, scale: 1.0)
138
- #
139
- # @param x [Numo::DFloat | Numo::SFloat] array filled with random values.
140
- # @param loc [Float] location parameter.
141
- # @param scale [Float] scale parameter.
142
- def normal(x, loc: 0.0, scale: 1.0)
143
- rng.normal(x, loc: loc, scale: scale)
144
- end
145
-
146
- # Fills given array with random values according to a log-normal distribution.
147
- #
148
- # @example
149
- # require 'numo/random'
150
- #
151
- # x = Numo::DFloat.new(100)
152
- #
153
- # rng = Numo::Random::Generator.new
154
- # rng.lognormal(x, mean: 0.0, sigma: 1.0)
155
- #
156
- # @param x [Numo::DFloat | Numo::SFloat] array filled with random values.
157
- # @param mean [Float] mean of normal distribution.
158
- # @param sigma [Float] standard deviation of normal distribution.
159
- def lognormal(x, mean: 0.0, sigma: 1.0)
160
- rng.lognormal(x, mean: mean, sigma: sigma)
161
- end
162
-
163
- # Fills given array with random values according to the Student's t-distribution.
164
- #
165
- # @example
166
- # require 'numo/random'
167
- #
168
- # x = Numo::DFloat.new(100)
169
- #
170
- # rng = Numo::Random::Generator.new
171
- # rng.standard_t(x, df: 8.0)
172
- #
173
- # @param x [Numo::DFloat | Numo::SFloat] array filled with random values.
174
- # @param df [Float] degrees of freedom, must be > 0.
175
- def standard_t(x, df:)
176
- rng.standard_t(x, df: df)
177
- end
178
-
179
- private
180
-
181
- attr_reader :rng
182
- end
183
- end
184
- end
6
+ require_relative 'random/ext'
7
+ require_relative 'random/generator'
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.1.0
4
+ version: 0.3.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-10-24 00:00:00.000000000 Z
11
+ date: 2022-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: numo-narray
@@ -37,14 +37,15 @@ files:
37
37
  - CODE_OF_CONDUCT.md
38
38
  - LICENSE.txt
39
39
  - README.md
40
+ - ext/numo/random/ext.cpp
41
+ - ext/numo/random/ext.hpp
40
42
  - ext/numo/random/extconf.rb
41
- - ext/numo/random/randomext.cpp
42
- - ext/numo/random/randomext.hpp
43
43
  - ext/numo/random/src/LICENSE.txt
44
44
  - ext/numo/random/src/pcg_extras.hpp
45
45
  - ext/numo/random/src/pcg_random.hpp
46
46
  - ext/numo/random/src/pcg_uint128.hpp
47
47
  - lib/numo/random.rb
48
+ - lib/numo/random/generator.rb
48
49
  - lib/numo/random/version.rb
49
50
  homepage: https://github.com/yoshoku/numo-random
50
51
  licenses:
@@ -53,7 +54,7 @@ metadata:
53
54
  homepage_uri: https://github.com/yoshoku/numo-random
54
55
  source_code_uri: https://github.com/yoshoku/numo-random
55
56
  changelog_uri: https://github.com/yoshoku/numo-random/blob/main/CHANGELOG.md
56
- documentation_uri: https://www.rubydoc.info/gems/numo-random
57
+ documentation_uri: https://yoshoku.github.io/numo-random/doc/
57
58
  rubygems_mfa_required: 'true'
58
59
  post_install_message:
59
60
  rdoc_options: []