enumerable-statistics 2.0.3 → 2.0.5

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: 85d1034d8bb8062a6d2469ab813518af28acad6b3a4e47e04335e4509f17f830
4
- data.tar.gz: 9886d7f3e791960f499666c4925263a9c163129a9cb8957907ac431d837d5c71
3
+ metadata.gz: 3fa86766eb3c5369422d08bac77705368b0bde5faa216eecd9f78115eb7548b6
4
+ data.tar.gz: 313dc69fe5d6b193278489b576af4bb90679eebf6814c36a2924a1241cd5c8be
5
5
  SHA512:
6
- metadata.gz: 5ccdb91def90bb4740d65bb01bd67fe8bae3932f4e1bb61180862e0b509ab92f7efe4034fcb9855ae0314e009d093c1f2852fe9f3126733f29b68fa706f60a31
7
- data.tar.gz: 59cffac4f18c6dae5dee8da57c222ce1fbb14594ef3e6e43c53d28bf1f606512c4c7f75a585d8b529992df2eb0c173bbd355b5e7b505d63ef0befdf1168aff6c
6
+ metadata.gz: 13fd8a73ae4e83aa85210cbbec1882a2129802aa377f7100ffa72e48ec7df685ba5eff1553cd2ef0b29eddd2b13715769de822adcc881c6d57122212d4c8c13a
7
+ data.tar.gz: d4dc08f32d2d9a43d743e213b2725f0bc41ac7d6d14c68ccecd1b3563d022c8c1c8b60eea682bce554bc7b5425e3c4b552766bb8b3a7faa386164ee8f00303b7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ # 2.0.5
2
+
3
+ - Add weighted histogram support
4
+
5
+ # 2.0.4
6
+
7
+ - Add `find_min`, `find_max`, `argmin`, `argmax` methods
8
+ - Fix `nbin=:auto` case in `histogram` method
9
+
1
10
  # 2.0.3
2
11
 
3
12
  - Ractor-safe version
@@ -0,0 +1,60 @@
1
+ #include <ruby/ruby.h>
2
+
3
+ static VALUE
4
+ ary_find_max(VALUE ary)
5
+ {
6
+ const long n = RARRAY_LEN(ary);
7
+ if (n == 0) {
8
+ return Qnil;
9
+ }
10
+
11
+ long imax = 0;
12
+ VALUE max = RARRAY_AREF(ary, imax);
13
+
14
+ long i;
15
+ for (i = 1; i < n; ++i) {
16
+ VALUE v = RARRAY_AREF(ary, i);
17
+ if (RTEST(rb_funcall(v, '>', 1, max))) {
18
+ imax = i;
19
+ max = v;
20
+ }
21
+ }
22
+
23
+ return rb_assoc_new(max, LONG2NUM(imax));
24
+ }
25
+
26
+ static VALUE
27
+ ary_find_min(VALUE ary)
28
+ {
29
+ const long n = RARRAY_LEN(ary);
30
+ if (n == 0) {
31
+ return Qnil;
32
+ }
33
+
34
+ long imin = 0;
35
+ VALUE min = RARRAY_AREF(ary, imin);
36
+
37
+ long i;
38
+ for (i = 1; i < n; ++i) {
39
+ VALUE v = RARRAY_AREF(ary, i);
40
+ if (RTEST(rb_funcall(v, '<', 1, min))) {
41
+ imin = i;
42
+ min = v;
43
+ }
44
+ }
45
+
46
+ return rb_assoc_new(min, LONG2NUM(imin));
47
+ }
48
+
49
+ void
50
+ Init_array_extension(void)
51
+ {
52
+ VALUE mEnumerableStatistics = rb_const_get_at(rb_cObject, rb_intern("EnumerableStatistics"));
53
+ VALUE mArrayExtension = rb_const_get_at(mEnumerableStatistics, rb_intern("ArrayExtension"));
54
+
55
+ rb_undef_method(mArrayExtension, "find_max");
56
+ rb_define_method(mArrayExtension, "find_max", ary_find_max, 0);
57
+
58
+ rb_undef_method(mArrayExtension, "find_min");
59
+ rb_define_method(mArrayExtension, "find_min", ary_find_min, 0);
60
+ }
@@ -97,7 +97,7 @@ static ID idPow, idPLUS, idMINUS, idSTAR, idDIV, idGE;
97
97
  static ID id_eqeq_p, id_idiv, id_negate, id_to_f, id_cmp, id_nan_p;
98
98
  static ID id_each, id_real_p, id_sum, id_population, id_closed, id_edge;
99
99
 
100
- static VALUE sym_left, sym_right;
100
+ static VALUE sym_auto, sym_left, sym_right;
101
101
 
102
102
  static VALUE cHistogram;
103
103
 
@@ -2102,50 +2102,61 @@ histogram_edge_bin_index(VALUE edge, VALUE rb_x, int left_p)
2102
2102
  }
2103
2103
 
2104
2104
  static void
2105
- histogram_weights_push_values(VALUE weights, VALUE edge, VALUE values, int left_p)
2105
+ histogram_weights_push_values(VALUE bin_weights, VALUE edge, VALUE values, VALUE weight_array, int left_p)
2106
2106
  {
2107
2107
  VALUE x, cur;
2108
- long i, n, bi;
2108
+ long i, n, bi, one, weighted = 0;
2109
2109
 
2110
2110
  n = RARRAY_LEN(values);
2111
+
2112
+ if (! NIL_P(weight_array)) {
2113
+ assert(RB_TYPE_P(weight_array, T_ARRAY));
2114
+ assert(RARRAY_LEN(weight_array) == n);
2115
+ weighted = 1;
2116
+ }
2117
+
2118
+ one = INT2FIX(1);
2111
2119
  for (i = 0; i < n; ++i) {
2112
2120
  x = RARRAY_AREF(values, i);
2113
2121
 
2122
+ VALUE w;
2123
+ if (weighted) {
2124
+ w = RARRAY_AREF(weight_array, i);
2125
+ if (RB_TYPE_P(w, T_COMPLEX)) {
2126
+ VALUE imag = RCOMPLEX(w)->imag;
2127
+ if (! RTEST(f_zero_p(imag))) {
2128
+ goto type_error;
2129
+ }
2130
+ }
2131
+ else if (rb_obj_is_kind_of(w, rb_cNumeric)) {
2132
+ if (!RTEST(f_real_p(w))) {
2133
+ goto type_error;
2134
+ }
2135
+ }
2136
+ else {
2137
+ goto type_error;
2138
+ }
2139
+ }
2140
+ else {
2141
+ w = one;
2142
+ }
2143
+
2114
2144
  bi = histogram_edge_bin_index(edge, x, left_p);
2115
2145
 
2116
- cur = rb_ary_entry(weights, bi);
2146
+ cur = rb_ary_entry(bin_weights, bi);
2117
2147
  if (NIL_P(cur)) {
2118
- cur = INT2FIX(1);
2148
+ cur = w;
2119
2149
  }
2120
2150
  else {
2121
- cur = rb_funcall(cur, idPLUS, 1, INT2FIX(1));
2151
+ cur = rb_funcall(cur, idPLUS, 1, w);
2122
2152
  }
2123
2153
 
2124
- rb_ary_store(weights, bi, cur);
2125
- }
2126
- }
2127
-
2128
- static int
2129
- opt_closed_left_p(VALUE opts)
2130
- {
2131
- int left_p = 1;
2132
-
2133
- if (!NIL_P(opts)) {
2134
- VALUE closed;
2135
- #ifdef HAVE_RB_GET_KWARGS
2136
- ID kwargs = id_closed;
2137
- rb_get_kwargs(opts, &kwargs, 0, 1, &closed);
2138
- #else
2139
- closed = rb_hash_lookup2(opts, ID2SYM(id_closed), sym_left);
2140
- #endif
2141
- left_p = (closed != sym_right);
2142
- if (left_p && closed != sym_left) {
2143
- rb_raise(rb_eArgError, "invalid value for :closed keyword "
2144
- "(%"PRIsVALUE" for :left or :right)", closed);
2145
- }
2154
+ rb_ary_store(bin_weights, bi, cur);
2146
2155
  }
2156
+ return;
2147
2157
 
2148
- return left_p;
2158
+ type_error:
2159
+ rb_raise(rb_eTypeError, "weight array must have only real numbers");
2149
2160
  }
2150
2161
 
2151
2162
  static inline long
@@ -2270,9 +2281,12 @@ ary_histogram_calculate_edge(VALUE ary, const long nbins, const int left_p)
2270
2281
  }
2271
2282
 
2272
2283
  /* call-seq:
2273
- * ary.histogram(nbins=:auto, closed: :left)
2284
+ * ary.histogram(nbins=:auto, weight: nil, closed: :left)
2274
2285
  *
2275
2286
  * @param [Integer] nbins The approximate number of bins
2287
+ * @params [Array<Numeric>] weight
2288
+ * An optional weight array, that has the same length as the receiver.
2289
+ * `weight[i]` means the weight value of the i-th element in the receiver.
2276
2290
  * @param [:left, :right] closed
2277
2291
  * If :left (the default), the bin interval are left-closed.
2278
2292
  * If :right, the bin interval are right-closed.
@@ -2282,30 +2296,63 @@ ary_histogram_calculate_edge(VALUE ary, const long nbins, const int left_p)
2282
2296
  static VALUE
2283
2297
  ary_histogram(int argc, VALUE *argv, VALUE ary)
2284
2298
  {
2285
- VALUE arg0, opts, edge, weights;
2286
- int left_p;
2287
- long nbins, nweights, i;
2299
+ VALUE arg0, kwargs, edge, bin_weights;
2300
+ long nbins, n_bin_weights, i;
2288
2301
 
2289
- rb_scan_args(argc, argv, "01:", &arg0, &opts);
2290
- if (NIL_P(arg0)) {
2302
+ VALUE weight_array = Qnil;
2303
+ int left_p = 1;
2304
+
2305
+ rb_scan_args(argc, argv, "01:", &arg0, &kwargs);
2306
+ if (NIL_P(arg0) || arg0 == sym_auto) {
2291
2307
  nbins = sturges(RARRAY_LEN(ary));
2292
2308
  }
2293
2309
  else {
2294
2310
  nbins = NUM2LONG(arg0);
2295
2311
  }
2296
- left_p = opt_closed_left_p(opts);
2312
+
2313
+ if (!NIL_P(kwargs)) {
2314
+ enum { kw_weight, kw_closed };
2315
+ static ID kwarg_keys[2];
2316
+ VALUE kwarg_vals[2];
2317
+ VALUE closed;
2318
+
2319
+ if (!kwarg_keys[0]) {
2320
+ kwarg_keys[kw_weight] = rb_intern("weight");
2321
+ kwarg_keys[kw_closed] = rb_intern("closed");
2322
+ }
2323
+
2324
+ rb_get_kwargs(kwargs, kwarg_keys, 0, 2, kwarg_vals);
2325
+
2326
+ weight_array = kwarg_vals[kw_weight];
2327
+ if (weight_array != Qundef) {
2328
+ weight_array = rb_check_convert_type(weight_array, T_ARRAY, "Array", "to_ary");
2329
+ if (RARRAY_LEN(weight_array) != RARRAY_LEN(ary)) {
2330
+ rb_raise(rb_eArgError, "weight array must have the same number of items as the receiver array");
2331
+ }
2332
+ }
2333
+ else {
2334
+ weight_array = Qnil;
2335
+ }
2336
+
2337
+ closed = kwarg_vals[kw_closed];
2338
+ left_p = (closed != sym_right);
2339
+ if (left_p && closed != Qundef && closed != sym_left) {
2340
+ rb_raise(rb_eArgError, "invalid value for :closed keyword "
2341
+ "(%"PRIsVALUE" for :left or :right)", closed);
2342
+ }
2343
+ }
2297
2344
 
2298
2345
  edge = ary_histogram_calculate_edge(ary, nbins, left_p);
2299
2346
 
2300
- nweights = RARRAY_LEN(edge) - 1;
2301
- weights = rb_ary_new_capa(nweights);
2302
- for (i = 0; i < nweights; ++i) {
2303
- rb_ary_store(weights, i, INT2FIX(0));
2347
+ n_bin_weights = RARRAY_LEN(edge) - 1;
2348
+ bin_weights = rb_ary_new_capa(n_bin_weights);
2349
+ for (i = 0; i < n_bin_weights; ++i) {
2350
+ rb_ary_store(bin_weights, i, INT2FIX(0));
2304
2351
  }
2305
2352
 
2306
- histogram_weights_push_values(weights, edge, ary, left_p);
2353
+ histogram_weights_push_values(bin_weights, edge, ary, weight_array, left_p);
2307
2354
 
2308
- return rb_struct_new(cHistogram, edge, weights,
2355
+ return rb_struct_new(cHistogram, edge, bin_weights,
2309
2356
  left_p ? sym_left : sym_right,
2310
2357
  Qfalse);
2311
2358
  }
@@ -2352,6 +2399,9 @@ Init_extension(void)
2352
2399
 
2353
2400
  rb_define_method(rb_cArray, "histogram", ary_histogram, -1);
2354
2401
 
2402
+ void Init_array_extension(void);
2403
+ Init_array_extension();
2404
+
2355
2405
  idPLUS = '+';
2356
2406
  idMINUS = '-';
2357
2407
  idSTAR = '*';
@@ -2371,6 +2421,7 @@ Init_extension(void)
2371
2421
  id_closed = rb_intern("closed");
2372
2422
  id_edge = rb_intern("edge");
2373
2423
 
2424
+ sym_auto = ID2SYM(rb_intern("auto"));
2374
2425
  sym_left = ID2SYM(rb_intern("left"));
2375
2426
  sym_right = ID2SYM(rb_intern("right"));
2376
2427
  }
@@ -1,2 +1,3 @@
1
1
  require_relative "enumerable_statistics/version"
2
+ require_relative "enumerable_statistics/array_ext"
2
3
  require_relative "enumerable_statistics/histogram"
@@ -0,0 +1,37 @@
1
+ module EnumerableStatistics
2
+ module ArrayExtension
3
+ def find_max
4
+ n = size
5
+ return nil if n == 0
6
+
7
+ imax, i = 0, 1
8
+ while i < n
9
+ imax = i if self[i] > self[imax]
10
+ i += 1
11
+ end
12
+ [self[imax], imax]
13
+ end
14
+
15
+ def argmax
16
+ find_max[1]
17
+ end
18
+
19
+ def find_min
20
+ n = size
21
+ return nil if n == 0
22
+
23
+ imin, i = 0, 1
24
+ while i < n
25
+ imin = i if self[i] < self[imax]
26
+ i += 1
27
+ end
28
+ [self[imin], imin]
29
+ end
30
+
31
+ def argmin
32
+ find_min[1]
33
+ end
34
+ end
35
+
36
+ Array.include ArrayExtension
37
+ end
@@ -1,5 +1,5 @@
1
1
  module EnumerableStatistics
2
- VERSION = '2.0.3'
2
+ VERSION = '2.0.5'
3
3
 
4
4
  module Version
5
5
  numbers, TAG = VERSION.split('-', 2)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enumerable-statistics
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenta Murata
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-04 00:00:00.000000000 Z
11
+ date: 2021-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -149,11 +149,13 @@ files:
149
149
  - bin/rspec
150
150
  - bin/setup
151
151
  - enumerable-statistics.gemspec
152
+ - ext/enumerable/statistics/extension/array_ext.c
152
153
  - ext/enumerable/statistics/extension/extconf.rb
153
154
  - ext/enumerable/statistics/extension/statistics.c
154
155
  - images/benchmark.png
155
156
  - lib/enumerable/statistics.rb
156
157
  - lib/enumerable_statistics.rb
158
+ - lib/enumerable_statistics/array_ext.rb
157
159
  - lib/enumerable_statistics/histogram.rb
158
160
  - lib/enumerable_statistics/version.rb
159
161
  - templates/default/layout/html/headers.erb