carray 3.0.2 → 3.0.4

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.
Files changed (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +568 -0
  3. data/README.md +6 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_descriptor.h +27 -24
  6. data/ext/ca_axis_dispatch.c +220 -0
  7. data/ext/ca_axis_group.c +201 -123
  8. data/ext/ca_binop_dispatch.c +46 -52
  9. data/ext/ca_binop_dispatch.h +1 -1
  10. data/ext/ca_categorical_iterator.c +249 -183
  11. data/ext/ca_compare.c +7 -12
  12. data/ext/ca_for_buffer.h +21 -68
  13. data/ext/ca_group_iter.c +38 -23
  14. data/ext/ca_kernel_iterator.c +1765 -2076
  15. data/ext/ca_kernel_iterator.h +584 -566
  16. data/ext/ca_monop_dispatch.c +86 -63
  17. data/ext/ca_monop_dispatch.h +5 -0
  18. data/ext/ca_obj_array.c +223 -56
  19. data/ext/ca_obj_bincmp.c +172 -138
  20. data/ext/ca_obj_binop.c +116 -230
  21. data/ext/ca_obj_bitarray.c +40 -26
  22. data/ext/ca_obj_bitfield.c +100 -68
  23. data/ext/ca_obj_block.c +19 -9
  24. data/ext/ca_obj_byte_swap.c +45 -46
  25. data/ext/ca_obj_const_string.c +269 -44
  26. data/ext/ca_obj_face.c +612 -89
  27. data/ext/ca_obj_face.h +111 -47
  28. data/ext/ca_obj_fake.c +36 -79
  29. data/ext/ca_obj_farray.c +7 -3
  30. data/ext/ca_obj_field.c +33 -8
  31. data/ext/ca_obj_fixlen_string.c +23 -24
  32. data/ext/ca_obj_grid.c +541 -210
  33. data/ext/ca_obj_meld.c +331 -111
  34. data/ext/ca_obj_moncmp.c +80 -65
  35. data/ext/ca_obj_monop.c +177 -149
  36. data/ext/ca_obj_object.c +664 -248
  37. data/ext/ca_obj_record.c +63 -23
  38. data/ext/ca_obj_reduce.c +18 -16
  39. data/ext/ca_obj_refer.c +140 -58
  40. data/ext/ca_obj_remap.c +85 -24
  41. data/ext/ca_obj_repeat.c +24 -9
  42. data/ext/ca_obj_roll.c +121 -16
  43. data/ext/ca_obj_select.c +61 -58
  44. data/ext/ca_obj_select_axis.c +73 -107
  45. data/ext/ca_obj_shift.c +32 -102
  46. data/ext/ca_obj_stack.c +372 -122
  47. data/ext/ca_obj_stride.c +348 -140
  48. data/ext/ca_obj_string.c +88 -22
  49. data/ext/ca_obj_tile.c +38 -21
  50. data/ext/ca_obj_time.c +45 -31
  51. data/ext/ca_obj_timedelta.c +43 -29
  52. data/ext/ca_obj_transpose.c +17 -6
  53. data/ext/ca_obj_triop.c +125 -141
  54. data/ext/ca_obj_window.c +330 -44
  55. data/ext/ca_op_ipower.c +24 -11
  56. data/ext/ca_op_powi.h +57 -30
  57. data/ext/ca_pow5_table.h +656 -0
  58. data/ext/ca_sort_kernels.h +70 -0
  59. data/ext/ca_sweep_engine.c +104 -81
  60. data/ext/ca_sweep_engine.h +7 -20
  61. data/ext/ca_triop_dispatch.c +4 -1
  62. data/ext/ca_triop_dispatch.h +5 -2
  63. data/ext/caframe_csv_reader.c +542 -0
  64. data/ext/carray.h +241 -92
  65. data/ext/carray_access.c +608 -276
  66. data/ext/carray_address_basis.c +494 -97
  67. data/ext/carray_attribute.c +129 -4
  68. data/ext/carray_bincount.c +39 -7
  69. data/ext/carray_broadcast.c +56 -19
  70. data/ext/carray_build_flags.h +1 -1
  71. data/ext/carray_call_cfunc.c +108 -28
  72. data/ext/carray_cast.c +1576 -223
  73. data/ext/carray_cast_func.rb +77 -24
  74. data/ext/carray_class.c +4 -3
  75. data/ext/carray_conversion.c +208 -75
  76. data/ext/carray_copy.c +82 -24
  77. data/ext/carray_core.c +646 -162
  78. data/ext/carray_count.c +171 -88
  79. data/ext/carray_element.c +94 -60
  80. data/ext/carray_factorize.c +670 -324
  81. data/ext/carray_generate.c +260 -83
  82. data/ext/carray_histogram.c +209 -106
  83. data/ext/carray_hold.c +14 -16
  84. data/ext/carray_index_classifier.c +422 -243
  85. data/ext/carray_internal.h +692 -3
  86. data/ext/carray_kernels_bincmp.c +7 -0
  87. data/ext/carray_kernels_binop.c +487 -120
  88. data/ext/carray_kernels_init.c +653 -50
  89. data/ext/carray_kernels_moncmp.c +15 -8
  90. data/ext/carray_kernels_monop.c +99 -43
  91. data/ext/carray_kernels_reduce_aggregate.c +3925 -6112
  92. data/ext/carray_kernels_reduce_boolean.c +112 -36
  93. data/ext/carray_kernels_reduce_cumulative.c +2127 -6903
  94. data/ext/carray_kernels_reduce_extreme.c +3032 -2892
  95. data/ext/carray_kernels_reduce_variance.c +439 -500
  96. data/ext/carray_kernels_scan.c +1097 -488
  97. data/ext/carray_kernels_search.c +3787 -2176
  98. data/ext/carray_kernels_sort.c +1200 -920
  99. data/ext/carray_kernels_triop.c +479 -7
  100. data/ext/carray_key_windows.c +216 -0
  101. data/ext/carray_lazy.c +967 -153
  102. data/ext/carray_loop.c +81 -65
  103. data/ext/carray_mask.c +910 -324
  104. data/ext/carray_math_kernel.h +1 -0
  105. data/ext/carray_median_percentile.c +299 -100
  106. data/ext/carray_memory_view.c +872 -758
  107. data/ext/carray_operator.c +1171 -364
  108. data/ext/carray_order.c +505 -133
  109. data/ext/carray_partition.c +112 -65
  110. data/ext/carray_random.c +327 -239
  111. data/ext/carray_round.c +273 -0
  112. data/ext/carray_scatter.c +346 -78
  113. data/ext/carray_segment.c +257 -0
  114. data/ext/carray_slab.c +249 -86
  115. data/ext/carray_sort.c +224 -227
  116. data/ext/carray_sort_kernel.c +8 -1
  117. data/ext/carray_struct.c +118 -39
  118. data/ext/carray_test.c +193 -69
  119. data/ext/carray_time_text.c +1182 -0
  120. data/ext/carray_undef.c +4 -0
  121. data/ext/carray_utils.c +579 -113
  122. data/ext/extconf.rb +27 -2
  123. data/ext/mk_call_cfunc.rb +19 -4
  124. data/ext/mk_pow5_table.rb +35 -0
  125. data/ext/mkkernel.rb +1202 -1014
  126. data/ext/ruby_carray.c +17 -5
  127. data/ext/version.h +4 -4
  128. data/ext/version.rb +4 -2
  129. data/lib/carray/attribute.rb +160 -17
  130. data/lib/carray/autoload_carray.rb +23 -27
  131. data/lib/carray/autoload_method_extension.rb +20 -5
  132. data/lib/carray/axis_group.rb +360 -63
  133. data/lib/carray/basics.rb +162 -28
  134. data/lib/carray/bincount_nd.rb +18 -2
  135. data/lib/carray/block_iterator.rb +231 -58
  136. data/lib/carray/boolean_reduce.rb +34 -42
  137. data/lib/carray/categorical.rb +242 -52
  138. data/lib/carray/categorical_iterator.rb +437 -827
  139. data/lib/carray/complex.rb +41 -34
  140. data/lib/carray/conditional.rb +150 -14
  141. data/lib/carray/const_string.rb +59 -4
  142. data/lib/carray/construct.rb +15 -11
  143. data/lib/carray/data_type_extension.rb +1 -0
  144. data/lib/carray/distance_limit.rb +77 -0
  145. data/lib/carray/fixlen_string.rb +7 -1
  146. data/lib/carray/frame/column_verbs.rb +70 -0
  147. data/lib/carray/frame/concat.rb +157 -6
  148. data/lib/carray/frame/convert.rb +82 -7
  149. data/lib/carray/frame/csv_parser.rb +688 -87
  150. data/lib/carray/frame/describe.rb +80 -0
  151. data/lib/carray/frame/frame.rb +369 -45
  152. data/lib/carray/frame/group.rb +631 -90
  153. data/lib/carray/frame/io.rb +506 -79
  154. data/lib/carray/frame/join.rb +411 -62
  155. data/lib/carray/frame/records.rb +116 -19
  156. data/lib/carray/frame/reshape.rb +455 -0
  157. data/lib/carray/frame/sort.rb +30 -18
  158. data/lib/carray/frame/verbs.rb +868 -61
  159. data/lib/carray/frame/windows.rb +117 -0
  160. data/lib/carray/frame.rb +4 -0
  161. data/lib/carray/fuse_source.rb +118 -2
  162. data/lib/carray/fusion.rb +257 -42
  163. data/lib/carray/histogram.rb +6 -1
  164. data/lib/carray/inspect.rb +54 -13
  165. data/lib/carray/iterator.rb +99 -9
  166. data/lib/carray/key_windows.rb +620 -0
  167. data/lib/carray/lazy.rb +216 -193
  168. data/lib/carray/mask_gap_fill.rb +112 -92
  169. data/lib/carray/math.rb +32 -19
  170. data/lib/carray/meld_reduce.rb +52 -21
  171. data/lib/carray/methods/align_addr.rb +8 -4
  172. data/lib/carray/methods/bin.rb +26 -18
  173. data/lib/carray/methods/bincount.rb +18 -2
  174. data/lib/carray/methods/bit_string.rb +15 -4
  175. data/lib/carray/methods/choose.rb +16 -3
  176. data/lib/carray/methods/composition.rb +18 -10
  177. data/lib/carray/methods/factorize.rb +2 -2
  178. data/lib/carray/methods/gather_nd.rb +25 -5
  179. data/lib/carray/methods/insert_block.rb +9 -14
  180. data/lib/carray/methods/is_between.rb +59 -0
  181. data/lib/carray/methods/is_in.rb +140 -10
  182. data/lib/carray/methods/join.rb +2 -7
  183. data/lib/carray/methods/lag.rb +49 -0
  184. data/lib/carray/methods/locate_addr.rb +182 -45
  185. data/lib/carray/methods/mode.rb +18 -1
  186. data/lib/carray/methods/nunique.rb +11 -6
  187. data/lib/carray/methods/repeat.rb +1 -20
  188. data/lib/carray/methods/resize.rb +21 -23
  189. data/lib/carray/methods/snap.rb +34 -12
  190. data/lib/carray/methods/unique.rb +11 -2
  191. data/lib/carray/methods/value_counts.rb +4 -11
  192. data/lib/carray/record_order.rb +208 -0
  193. data/lib/carray/rng.rb +3 -0
  194. data/lib/carray/runtime.rb +65 -17
  195. data/lib/carray/segment_iterator.rb +1221 -0
  196. data/lib/carray/serialize.rb +214 -30
  197. data/lib/carray/slab_iterator.rb +101 -27
  198. data/lib/carray/stack.rb +10 -4
  199. data/lib/carray/string.rb +105 -5
  200. data/lib/carray/string_operation_extension.rb +12 -4
  201. data/lib/carray/struct.rb +137 -58
  202. data/lib/carray/struct_builder.rb +124 -17
  203. data/lib/carray/time.rb +1222 -186
  204. data/lib/carray/window_iterator.rb +242 -81
  205. data/lib/carray.rb +9 -2
  206. data/yard-stubs/ca_obj_array.rb +4 -4
  207. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  208. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  209. data/yard-stubs/ca_obj_fake.rb +1 -1
  210. data/yard-stubs/ca_obj_field.rb +5 -1
  211. data/yard-stubs/ca_obj_grid.rb +21 -10
  212. data/yard-stubs/ca_obj_refer.rb +5 -4
  213. data/yard-stubs/ca_obj_roll.rb +2 -3
  214. data/yard-stubs/ca_obj_shift.rb +5 -1
  215. data/yard-stubs/ca_obj_stride.rb +10 -7
  216. data/yard-stubs/ca_obj_tile.rb +1 -1
  217. data/yard-stubs/ca_obj_transpose.rb +1 -1
  218. data/yard-stubs/ca_obj_window.rb +9 -5
  219. data/yard-stubs/carray_access.rb +11 -5
  220. data/yard-stubs/carray_attribute.rb +0 -5
  221. data/yard-stubs/carray_broadcast.rb +1 -1
  222. data/yard-stubs/carray_cast.rb +88 -43
  223. data/yard-stubs/carray_conversion.rb +15 -2
  224. data/yard-stubs/carray_copy.rb +12 -5
  225. data/yard-stubs/carray_core.rb +3 -3
  226. data/yard-stubs/carray_count.rb +9 -0
  227. data/yard-stubs/carray_element.rb +10 -4
  228. data/yard-stubs/carray_generate.rb +21 -1
  229. data/yard-stubs/carray_lazy.rb +5 -1
  230. data/yard-stubs/carray_loop.rb +4 -1
  231. data/yard-stubs/carray_mask.rb +60 -12
  232. data/yard-stubs/carray_math.rb +52 -14
  233. data/yard-stubs/carray_median_percentile.rb +15 -8
  234. data/yard-stubs/carray_memory_view.rb +40 -23
  235. data/yard-stubs/carray_order.rb +61 -29
  236. data/yard-stubs/carray_random.rb +13 -4
  237. data/yard-stubs/carray_scatter.rb +21 -9
  238. data/yard-stubs/carray_segment.rb +72 -0
  239. data/yard-stubs/carray_slab.rb +10 -2
  240. data/yard-stubs/carray_sort.rb +49 -8
  241. data/yard-stubs/carray_test.rb +15 -3
  242. data/yard-stubs/carray_utils.rb +0 -26
  243. metadata +19 -5
  244. data/ext/ca_for_each_element.h +0 -239
  245. data/ext/carray_kernels_map.c +0 -3467
  246. data/lib/carray/arrow_tensor.rb +0 -401
  247. data/lib/carray/table.rb +0 -108
@@ -23,13 +23,42 @@
23
23
  ---------------------------------------------------------------------------- */
24
24
 
25
25
  #include "carray.h"
26
+ #include "carray_internal.h" /* ca_attach_window */
26
27
  #include <math.h>
27
28
 
28
- /* Resolve `redges` to a contiguous, attached, 1-D float64 CArray.
29
- Returns the CArray* and (via out params) the data pointer + element
30
- count. Caller must ca_detach when done. */
31
- static CArray *
32
- histbin_attach_edges (VALUE self, VALUE redges, double **ep_out, ca_size_t *ne_out)
29
+ /* Edges are the bin boundaries and must read as such: no masked edge (its
30
+ stored value is no boundary), no NaN, and no edge below the one before
31
+ it. Equal edges (a bin of zero width) and infinite ones are kept. */
32
+ static void
33
+ histbin_check_edge_mask (CArray *ce, const char *name)
34
+ {
35
+ if ( ca_has_mask(ce) && ca_is_any_masked(ce) ) {
36
+ rb_raise(rb_eArgError, "%s: edges has a masked value", name);
37
+ }
38
+ }
39
+
40
+ static void
41
+ histbin_check_edge_order (const double *ep, ca_size_t n, const char *name)
42
+ {
43
+ ca_size_t i;
44
+ for (i = 0; i < n; i++) {
45
+ if ( isnan(ep[i]) ) {
46
+ rb_raise(rb_eArgError, "%s: edges has NaN at %lld", name, (long long) i);
47
+ }
48
+ if ( i > 0 && ep[i] < ep[i-1] ) {
49
+ rb_raise(rb_eArgError, "%s: edges must not decrease "
50
+ "(%g at %lld after %g)", name, ep[i], (long long) i, ep[i-1]);
51
+ }
52
+ }
53
+ }
54
+
55
+ /* Resolve `redges` to a 1-D float64 CArray of at least two edges, and
56
+ return it: it may be a view made here, which only the caller can keep
57
+ alive. The caller copies the edges out (ca_xfer_all into its own
58
+ buffer) rather than attaching them: the walk that follows reads the
59
+ caller's array, and a raise there must not leave the edges attached. */
60
+ static VALUE
61
+ histbin_resolve_edges (VALUE self, VALUE redges)
33
62
  {
34
63
  CArray *ce;
35
64
 
@@ -48,11 +77,9 @@ histbin_attach_edges (VALUE self, VALUE redges, double **ep_out, ca_size_t *ne_o
48
77
  if ( ce->elements < 2 ) {
49
78
  rb_raise(rb_eArgError, "histbin_ki: edges needs at least 2 values");
50
79
  }
80
+ histbin_check_edge_mask(ce, "bin_to");
51
81
 
52
- ca_attach(ce);
53
- *ep_out = (double *) ce->ptr;
54
- *ne_out = ce->elements;
55
- return ce;
82
+ return redges;
56
83
  }
57
84
 
58
85
  /* ---- shared binning helpers (used by histbin_ki + the fused kernel) ---- */
@@ -105,19 +132,24 @@ histbin_index (const histbin_axis_t *ax, double v)
105
132
  }
106
133
 
107
134
  static void
108
- histbin_axis_setup (histbin_axis_t *ax, CArray *ce, int include_max)
135
+ histbin_axis_setup (histbin_axis_t *ax, const double *ep, ca_size_t ne,
136
+ int include_max)
109
137
  {
110
- ca_size_t ne = ce->elements, kk;
138
+ ca_size_t kk;
111
139
  double dx, tol;
112
140
 
113
- ax->ep = (const double *) ce->ptr;
141
+ ax->ep = ep;
114
142
  ax->n = ne - 1;
115
143
  ax->lo = ax->ep[0];
116
144
  ax->hi = ax->ep[ne - 1];
117
145
  dx = (ax->hi - ax->lo) / (double) ax->n;
118
146
  tol = fabs(dx) * 1e-9 + 1e-12;
119
- ax->uniform = 1;
120
- for ( kk = 0; kk <= ax->n; kk++ ) {
147
+ /* The linearised index needs a width and its reciprocal that are both
148
+ finite and nonzero: edges spanning more than a double holds make the
149
+ width infinite, and a subnormal width makes the reciprocal infinite.
150
+ Either turns the position into NaN, which has no integer. */
151
+ ax->uniform = isfinite(dx) && dx != 0.0 && isfinite(1.0 / dx);
152
+ for ( kk = 0; ax->uniform && kk <= ax->n; kk++ ) {
121
153
  if ( fabs(ax->ep[kk] - (ax->lo + (double) kk * dx)) > tol ) { ax->uniform = 0; break; }
122
154
  }
123
155
  ax->inv_dx = (dx != 0.0) ? 1.0 / dx : 0.0;
@@ -129,8 +161,8 @@ rb_ca_histbin_ki (VALUE self, VALUE redges, VALUE rinclude_max)
129
161
  {
130
162
  CArray *ca, *co, *ce;
131
163
  VALUE vout;
164
+ volatile VALUE hedges = 0;
132
165
  double *ep;
133
- ca_size_t ne;
134
166
  histbin_axis_t ax;
135
167
 
136
168
  GetCArray(self, ca);
@@ -140,9 +172,13 @@ rb_ca_histbin_ki (VALUE self, VALUE redges, VALUE rinclude_max)
140
172
  ca_type_name[ca->data_type]);
141
173
  }
142
174
 
143
- ce = histbin_attach_edges(self, redges, &ep, &ne);
144
- (void) ep; (void) ne; /* axis setup reads ce directly */
145
- histbin_axis_setup(&ax, ce, RTEST(rinclude_max));
175
+ redges = histbin_resolve_edges(self, redges);
176
+ GetCArray(redges, ce);
177
+ ep = ALLOCV_N(double, hedges, ce->elements);
178
+ ca_xfer_all(ce, ep, CA_XFER_GET);
179
+ histbin_check_edge_order(ep, ce->elements, "bin_to");
180
+ histbin_axis_setup(&ax, ep, ce->elements, RTEST(rinclude_max));
181
+ RB_GC_GUARD(redges); /* a view made by histbin_resolve_edges is read through ce */
146
182
 
147
183
  /* output: fresh contiguous int64, same shape as self. */
148
184
  vout = rb_carray_new(CA_INT64, ca->ndim, ca->dim, 0, NULL);
@@ -179,7 +215,7 @@ rb_ca_histbin_ki (VALUE self, VALUE redges, VALUE rinclude_max)
179
215
  }
180
216
  }
181
217
 
182
- ca_detach(ce);
218
+ ALLOCV_END(hedges);
183
219
 
184
220
  return vout;
185
221
  }
@@ -201,6 +237,129 @@ rb_ca_histbin_ki (VALUE self, VALUE redges, VALUE rinclude_max)
201
237
  off = fiber_base + Σ_k histbin_index(axis_k, v_{a,k}) * ext_stride[k]
202
238
  counts[off] += 1 (or += weight when weighted)
203
239
  =========================================================================== */
240
+ /* histogram_scatter_ki reads its edges inside an attach window and walks
241
+ the samples (and the weights) with two kernel iterators, whose states
242
+ live here, outside the walk: a sample view that raises as it is read --
243
+ a lazy source meeting a cell it cannot compute -- leaves neither the
244
+ edges nor the other walk open. */
245
+ typedef struct {
246
+ ca_iter_state states[2]; /* the samples, the weights */
247
+ CArray *ca, *cc, *cw;
248
+ long M, nf;
249
+ int weighted;
250
+ CArray **edge_ca;
251
+ VALUE rincmax;
252
+ histbin_axis_t *axes;
253
+ ca_size_t *ext_stride;
254
+ ca_size_t *fiber_stride;
255
+ } histogram_scatter_t;
256
+
257
+ static VALUE
258
+ histogram_scatter_walk (VALUE arg)
259
+ {
260
+ histogram_scatter_t *c = (histogram_scatter_t *) arg;
261
+ CArray *ca = c->ca, *cc = c->cc, *cw = c->cw;
262
+ long M = c->M, k;
263
+ int weighted = c->weighted;
264
+ histbin_axis_t *axes = c->axes;
265
+ ca_size_t *ext_stride = c->ext_stride;
266
+ ca_size_t *fiber_stride = c->fiber_stride;
267
+ #define st (c->states[0])
268
+ #define stw (c->states[1])
269
+ int64_t *cpi = (int64_t *) cc->ptr; /* unweighted */
270
+ double *cpd = (double *) cc->ptr; /* weighted */
271
+ char *p, *pw = NULL;
272
+ boolean8_t *m, *mw = NULL;
273
+ ca_size_t cur_outer_idx[CA_RANK_MAX];
274
+ int8_t slab_axes[2] = { (int8_t)(ca->ndim - 2), (int8_t)(ca->ndim - 1) };
275
+ int8_t w_slab_axes[1] = { (int8_t)(ca->ndim - 2) }; /* weights sample axis */
276
+ int8_t mm;
277
+ int rc;
278
+
279
+ rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES, slab_axes, 2, 0);
280
+ if ( rc != CA_ITER_OK ) {
281
+ rb_raise(rb_eRuntimeError, "histogram_scatter_ki: iter init failed rc=%d", rc);
282
+ }
283
+ if ( weighted ) {
284
+ rc = ca_iter_state_init_l2(&stw, cw, CA_SLAB_AXES, w_slab_axes, 1, 0);
285
+ if ( rc != CA_ITER_OK ) {
286
+ rb_raise(rb_eRuntimeError, "histogram_scatter_ki: weights iter init failed rc=%d", rc);
287
+ }
288
+ }
289
+ for ( mm = 0; mm < st.outer_ndim; mm++ ) cur_outer_idx[mm] = 0;
290
+
291
+ while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
292
+ ca_size_t fiber_base = 0;
293
+ ca_size_t A, a, kk;
294
+ ca_size_t ss, cs, sms, cms, ws = 0, wms = 0;
295
+
296
+ if ( weighted && ! ca_iter_state_next_slab_axes(&stw, &pw, &mw) ) break;
297
+
298
+ for ( mm = 0; mm < st.outer_ndim; mm++ )
299
+ fiber_base += cur_outer_idx[mm] * fiber_stride[mm];
300
+
301
+ A = st.slab_dims[0]; /* samples */
302
+ ss = st.slab_strides[0]; /* sample byte stride */
303
+ cs = st.slab_strides[1]; /* channel byte stride */
304
+ sms = st.slab_mask_strides[0];
305
+ cms = st.slab_mask_strides[1];
306
+ if ( weighted ) {
307
+ ws = stw.slab_strides[0];
308
+ wms = stw.slab_mask_strides[0];
309
+ }
310
+
311
+ for ( a = 0; a < A; a++ ) {
312
+ ca_size_t off = fiber_base;
313
+ int masked = 0;
314
+ for ( kk = 0; kk < (ca_size_t) M; kk++ ) {
315
+ double v = *(const double *)(p + a * ss + kk * cs);
316
+ if ( (m && m[a * sms + kk * cms]) || isnan(v) ) { masked = 1; break; }
317
+ off += histbin_index(&axes[kk], v) * ext_stride[kk];
318
+ }
319
+ if ( masked ) continue;
320
+ if ( weighted ) {
321
+ double w = *(const double *)(pw + a * ws);
322
+ if ( (mw && mw[a * wms]) || isnan(w) ) continue; /* skip masked / NaN weight */
323
+ cpd[off] += w;
324
+ }
325
+ else {
326
+ cpi[off] += 1;
327
+ }
328
+ }
329
+
330
+ for ( mm = (int8_t)(st.outer_ndim - 1); mm >= 0; mm-- ) {
331
+ if ( ++cur_outer_idx[mm] < st.outer_dims[mm] ) break;
332
+ cur_outer_idx[mm] = 0;
333
+ }
334
+ }
335
+ ca_iter_state_finish(&st);
336
+ if ( weighted ) ca_iter_state_finish(&stw);
337
+ #undef st
338
+ #undef stw
339
+ (void) k;
340
+ return Qnil;
341
+ }
342
+
343
+ static VALUE
344
+ histogram_scatter_edges (VALUE arg)
345
+ {
346
+ histogram_scatter_t *c = (histogram_scatter_t *) arg;
347
+ long k;
348
+ for ( k = 0; k < c->M; k++ ) {
349
+ histbin_check_edge_order((const double *) c->edge_ca[k]->ptr,
350
+ c->edge_ca[k]->elements, "histogram");
351
+ }
352
+ for ( k = 0; k < c->M; k++ ) {
353
+ histbin_axis_setup(&c->axes[k], (const double *) c->edge_ca[k]->ptr,
354
+ c->edge_ca[k]->elements,
355
+ RTEST(RARRAY_AREF(c->rincmax, k)));
356
+ }
357
+ if ( c->ca->elements > 0 ) {
358
+ ca_iter_ensure(2, c->states, histogram_scatter_walk, arg);
359
+ }
360
+ return Qnil;
361
+ }
362
+
204
363
  static VALUE
205
364
  rb_ca_histogram_scatter_ki (VALUE self, VALUE rcounts, VALUE redges,
206
365
  VALUE rincmax, VALUE rweights)
@@ -258,8 +417,7 @@ rb_ca_histogram_scatter_ki (VALUE self, VALUE rcounts, VALUE redges,
258
417
  for ( k = 0; k < M; k++ ) {
259
418
  VALUE e = RARRAY_AREF(redges, k);
260
419
  GetCArray(e, edge_ca[k]);
261
- ca_attach(edge_ca[k]);
262
- histbin_axis_setup(&axes[k], edge_ca[k], RTEST(RARRAY_AREF(rincmax, k)));
420
+ histbin_check_edge_mask(edge_ca[k], "histogram");
263
421
  }
264
422
 
265
423
  /* ext strides (row-major within the trailing M bin axes of counts). */
@@ -275,83 +433,19 @@ rb_ca_histogram_scatter_ki (VALUE self, VALUE rcounts, VALUE redges,
275
433
  s *= cc->dim[k];
276
434
  }
277
435
 
278
- if ( ca->elements > 0 ) {
279
- int64_t *cpi = (int64_t *) cc->ptr; /* unweighted */
280
- double *cpd = (double *) cc->ptr; /* weighted */
281
- ca_iter_state st, stw;
282
- char *p, *pw = NULL;
283
- boolean8_t *m, *mw = NULL;
284
- ca_size_t cur_outer_idx[CA_RANK_MAX];
285
- int8_t slab_axes[2] = { (int8_t)(ca->ndim - 2), (int8_t)(ca->ndim - 1) };
286
- int8_t w_slab_axes[1] = { (int8_t)(ca->ndim - 2) }; /* weights sample axis */
287
- int8_t mm;
288
- int rc;
289
-
290
- rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES, slab_axes, 2, 0);
291
- if ( rc != CA_ITER_OK ) {
292
- for ( k = 0; k < M; k++ ) ca_detach(edge_ca[k]);
293
- rb_raise(rb_eRuntimeError, "histogram_scatter_ki: iter init failed rc=%d", rc);
294
- }
295
- if ( weighted ) {
296
- rc = ca_iter_state_init_l2(&stw, cw, CA_SLAB_AXES, w_slab_axes, 1, 0);
297
- if ( rc != CA_ITER_OK ) {
298
- ca_iter_state_finish(&st);
299
- for ( k = 0; k < M; k++ ) ca_detach(edge_ca[k]);
300
- rb_raise(rb_eRuntimeError, "histogram_scatter_ki: weights iter init failed rc=%d", rc);
301
- }
302
- }
303
- for ( mm = 0; mm < st.outer_ndim; mm++ ) cur_outer_idx[mm] = 0;
304
-
305
- while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
306
- ca_size_t fiber_base = 0;
307
- ca_size_t A, a, kk;
308
- ca_size_t ss, cs, sms, cms, ws = 0, wms = 0;
309
-
310
- if ( weighted && ! ca_iter_state_next_slab_axes(&stw, &pw, &mw) ) break;
311
-
312
- for ( mm = 0; mm < st.outer_ndim; mm++ )
313
- fiber_base += cur_outer_idx[mm] * fiber_stride[mm];
314
-
315
- A = st.slab_dims[0]; /* samples */
316
- ss = st.slab_strides[0]; /* sample byte stride */
317
- cs = st.slab_strides[1]; /* channel byte stride */
318
- sms = st.slab_mask_strides[0];
319
- cms = st.slab_mask_strides[1];
320
- if ( weighted ) {
321
- ws = stw.slab_strides[0];
322
- wms = stw.slab_mask_strides[0];
323
- }
324
-
325
- for ( a = 0; a < A; a++ ) {
326
- ca_size_t off = fiber_base;
327
- int masked = 0;
328
- for ( kk = 0; kk < (ca_size_t) M; kk++ ) {
329
- double v = *(const double *)(p + a * ss + kk * cs);
330
- if ( (m && m[a * sms + kk * cms]) || isnan(v) ) { masked = 1; break; }
331
- off += histbin_index(&axes[kk], v) * ext_stride[kk];
332
- }
333
- if ( masked ) continue;
334
- if ( weighted ) {
335
- double w = *(const double *)(pw + a * ws);
336
- if ( (mw && mw[a * wms]) || isnan(w) ) continue; /* skip masked / NaN weight */
337
- cpd[off] += w;
338
- }
339
- else {
340
- cpi[off] += 1;
341
- }
342
- }
343
-
344
- for ( mm = (int8_t)(st.outer_ndim - 1); mm >= 0; mm-- ) {
345
- if ( ++cur_outer_idx[mm] < st.outer_dims[mm] ) break;
346
- cur_outer_idx[mm] = 0;
347
- }
348
- }
349
- ca_iter_state_finish(&st);
350
- if ( weighted ) ca_iter_state_finish(&stw);
436
+ {
437
+ histogram_scatter_t c;
438
+ char modes[CA_RANK_MAX + 1];
439
+ for ( k = 0; k < M; k++ ) modes[k] = 'r';
440
+ modes[M] = '\0';
441
+ c.ca = ca; c.cc = cc; c.cw = cw;
442
+ c.M = M; c.nf = nf; c.weighted = weighted;
443
+ c.edge_ca = edge_ca; c.rincmax = rincmax; c.axes = axes;
444
+ c.ext_stride = ext_stride; c.fiber_stride = fiber_stride;
445
+ ca_attach_window((int32_t) M, edge_ca, modes, histogram_scatter_edges,
446
+ (VALUE) &c);
351
447
  }
352
448
 
353
- for ( k = 0; k < M; k++ ) ca_detach(edge_ca[k]);
354
-
355
449
  return rcounts;
356
450
  }
357
451
 
@@ -370,7 +464,16 @@ rb_ca_histogram_scatter_ki (VALUE self, VALUE rcounts, VALUE redges,
370
464
  weights = nil OR float64 [fiber..., A] (second iterator in lockstep).
371
465
  =========================================================================== */
372
466
 
373
- #define BINCOUNT_ND_BODY(LABEL_T) \
467
+ /* A label at or above the last bin lands in the overflow cell. An unsigned
468
+ 64-bit label above INT64_MAX must be clamped before it becomes an int64,
469
+ or it turns negative and indexes before the counts. */
470
+ static inline int64_t
471
+ bincount_nd_label_u64 (uint64_t x)
472
+ {
473
+ return ( x > (uint64_t) INT64_MAX ) ? INT64_MAX : (int64_t) x;
474
+ }
475
+
476
+ #define BINCOUNT_ND_BODY(LABEL_T, TO_INT64) \
374
477
  do { \
375
478
  while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) { \
376
479
  ca_size_t fiber_base = 0, A, a, kk, ss, cs, sms, cms, ws = 0, wms = 0; \
@@ -383,7 +486,7 @@ rb_ca_histogram_scatter_ki (VALUE self, VALUE rcounts, VALUE redges,
383
486
  for ( a = 0; a < A; a++ ) { \
384
487
  ca_size_t off = fiber_base; int masked = 0; \
385
488
  for ( kk = 0; kk < (ca_size_t) M; kk++ ) { \
386
- int64_t v = (int64_t) *(const LABEL_T *)(p + a * ss + kk * cs); \
489
+ int64_t v = TO_INT64(*(const LABEL_T *)(p + a * ss + kk * cs)); \
387
490
  if ( m && m[a * sms + kk * cms] ) { masked = 1; break; } \
388
491
  if ( v >= ext_dim[kk] - 1 ) v = ext_dim[kk] - 1; \
389
492
  off += (ca_size_t) v * ext_stride[kk]; \
@@ -457,14 +560,14 @@ rb_ca_bincount_nd_count_ki (VALUE self, VALUE rcounts, VALUE rweights)
457
560
  for ( mm = 0; mm < st.outer_ndim; mm++ ) cur_outer_idx[mm] = 0;
458
561
 
459
562
  switch ( ca->data_type ) {
460
- case CA_INT8: BINCOUNT_ND_BODY(int8_t); break;
461
- case CA_UINT8: BINCOUNT_ND_BODY(uint8_t); break;
462
- case CA_INT16: BINCOUNT_ND_BODY(int16_t); break;
463
- case CA_UINT16: BINCOUNT_ND_BODY(uint16_t); break;
464
- case CA_INT32: BINCOUNT_ND_BODY(int32_t); break;
465
- case CA_UINT32: BINCOUNT_ND_BODY(uint32_t); break;
466
- case CA_INT64: BINCOUNT_ND_BODY(int64_t); break;
467
- case CA_UINT64: BINCOUNT_ND_BODY(uint64_t); break;
563
+ case CA_INT8: BINCOUNT_ND_BODY(int8_t, (int64_t)); break;
564
+ case CA_UINT8: BINCOUNT_ND_BODY(uint8_t, (int64_t)); break;
565
+ case CA_INT16: BINCOUNT_ND_BODY(int16_t, (int64_t)); break;
566
+ case CA_UINT16: BINCOUNT_ND_BODY(uint16_t, (int64_t)); break;
567
+ case CA_INT32: BINCOUNT_ND_BODY(int32_t, (int64_t)); break;
568
+ case CA_UINT32: BINCOUNT_ND_BODY(uint32_t, (int64_t)); break;
569
+ case CA_INT64: BINCOUNT_ND_BODY(int64_t, (int64_t)); break;
570
+ case CA_UINT64: BINCOUNT_ND_BODY(uint64_t, bincount_nd_label_u64); break;
468
571
  default:
469
572
  ca_iter_state_finish(&st);
470
573
  if ( weighted ) ca_iter_state_finish(&stw);
data/ext/carray_hold.c CHANGED
@@ -20,6 +20,7 @@
20
20
  #include "carray.h"
21
21
  #include "ca_kernel_iterator.h"
22
22
  #include "ca_obj_face.h"
23
+ #include "carray_internal.h" /* ca_normalize_axis_arg */
23
24
 
24
25
  /* Forward hold along `axis`. Per fiber along the scan axis:
25
26
  - present cell -> output = cell value, becomes the held value;
@@ -47,21 +48,24 @@ rb_ca_hold_forward (VALUE self, int axis)
47
48
  ca_iter_state st_in, st_out;
48
49
  int rc = ca_iter_state_init_l2(&st_in, ca, CA_SLAB_AXES, slab_axes, 1, 0);
49
50
  if ( rc != CA_ITER_OK ) {
50
- rb_raise(rb_eRuntimeError, "__hold__: input init failed rc=%d", rc);
51
+ rb_raise(rb_eRuntimeError, "hold_forward: input init failed rc=%d", rc);
51
52
  }
52
- rc = ca_iter_state_init_l2(&st_out, co, CA_SLAB_AXES, slab_axes, 1,
53
+ rc = ca_iter_state_init_l2_paired(&st_out, &st_in, co, CA_SLAB_AXES,
54
+ slab_axes, 1,
53
55
  CA_KERNEL_WRITE);
54
56
  if ( rc != CA_ITER_OK ) {
55
57
  ca_iter_state_finish(&st_in);
56
- rb_raise(rb_eRuntimeError, "__hold__: output init failed rc=%d", rc);
58
+ rb_raise(rb_eRuntimeError, "hold_forward: output init failed rc=%d", rc);
57
59
  }
58
60
 
59
61
  /* Output mask allocated lazily on the first leading-masked (UNDEF) cell:
60
62
  a fiber can only go UNDEF on a leading masked run, so a fully filled
61
- result carries no mask at all. op_mask parallels the fresh contiguous
62
- output value buffer co->ptr. */
63
+ result carries no mask at all. The output is a fresh row-major entity
64
+ and the walk cuts its slabs from a buffer laid out the same way (the
65
+ output's memory, or the walk's scratch when it delivers by transfer),
66
+ so a slab's offset from st_out.alias_ptr is its offset in co, which
67
+ op_mask parallels. */
63
68
  boolean8_t *op_mask = NULL;
64
- char *co_root = (char *) co->ptr;
65
69
 
66
70
  char *pi, *po;
67
71
  boolean8_t *mi, *mo;
@@ -72,7 +76,7 @@ rb_ca_hold_forward (VALUE self, int axis)
72
76
  ca_size_t oS = st_out.slab_strides[0]; /* output data byte stride */
73
77
  ca_size_t iMS = st_in.slab_mask_strides[0]; /* input mask element stride */
74
78
  ca_size_t oMStep = oS / K; /* output mask element step */
75
- ca_size_t oMBase = (ca_size_t)(po - co_root) / K;
79
+ ca_size_t oMBase = (ca_size_t)(po - st_out.alias_ptr) / K;
76
80
  const char *held = NULL; /* last valid cell (points into input slab) */
77
81
 
78
82
  for ( ca_size_t j = 0; j < N; j++ ) {
@@ -103,7 +107,7 @@ rb_ca_hold_forward (VALUE self, int axis)
103
107
  return vout;
104
108
  }
105
109
 
106
- /* __hold__(axis): private forward-hold primitive. axis is a required
110
+ /* hold_forward(axis): private forward-hold primitive. axis is a required
107
111
  Integer (negative counts from the end). The Ruby wrapper composes
108
112
  backward / flatten / linear on top of this. */
109
113
  static VALUE
@@ -111,13 +115,7 @@ rb_ca_hold_method (VALUE self, VALUE raxis)
111
115
  {
112
116
  CArray *ca;
113
117
  GetCArray(self, ca);
114
- int axis = NUM2INT(raxis);
115
- if ( axis < 0 ) axis += ca->ndim;
116
- if ( axis < 0 || axis >= ca->ndim ) {
117
- rb_raise(rb_eArgError, "__hold__: axis %d out of range for ndim %d",
118
- NUM2INT(raxis), ca->ndim);
119
- }
120
- return rb_ca_hold_forward(self, axis);
118
+ return rb_ca_hold_forward(self, ca_normalize_axis_arg(raxis, ca->ndim, NULL));
121
119
  }
122
120
 
123
121
  /* first / last: the reduction sibling of hold. Reduce each fiber to its
@@ -222,7 +220,7 @@ rb_ca_last (int argc, VALUE *argv, VALUE self)
222
220
  void
223
221
  Init_carray_hold (void)
224
222
  {
225
- rb_define_private_method(rb_cCArray, "__hold__", rb_ca_hold_method, 1);
223
+ rb_define_private_method(rb_cCArray, "hold_forward", rb_ca_hold_method, 1);
226
224
  rb_define_method(rb_cCArray, "first", rb_ca_first, -1);
227
225
  rb_define_method(rb_cCArray, "last", rb_ca_last, -1);
228
226
  }