carray 3.0.1 → 3.0.3

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +824 -0
  3. data/README.md +5 -6
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_dispatch.c +258 -4
  6. data/ext/ca_axis_group.c +368 -184
  7. data/ext/ca_binop_dispatch.c +54 -32
  8. data/ext/ca_binop_dispatch.h +1 -0
  9. data/ext/ca_categorical_iterator.c +90 -41
  10. data/ext/ca_compare.c +8 -2
  11. data/ext/ca_for_buffer.h +21 -68
  12. data/ext/ca_group_iter.c +27 -11
  13. data/ext/ca_kernel_iterator.c +960 -245
  14. data/ext/ca_kernel_iterator.h +352 -181
  15. data/ext/ca_monop_dispatch.c +4 -4
  16. data/ext/ca_monop_dispatch.h +4 -0
  17. data/ext/ca_obj_array.c +194 -42
  18. data/ext/ca_obj_bincmp.c +152 -121
  19. data/ext/ca_obj_binop.c +107 -210
  20. data/ext/ca_obj_bitarray.c +37 -24
  21. data/ext/ca_obj_bitfield.c +95 -62
  22. data/ext/ca_obj_block.c +5 -4
  23. data/ext/ca_obj_byte_swap.c +40 -40
  24. data/ext/ca_obj_const_string.c +180 -50
  25. data/ext/ca_obj_face.c +428 -62
  26. data/ext/ca_obj_face.h +107 -47
  27. data/ext/ca_obj_fake.c +21 -50
  28. data/ext/ca_obj_farray.c +1 -0
  29. data/ext/ca_obj_field.c +16 -3
  30. data/ext/ca_obj_fixlen_string.c +39 -26
  31. data/ext/ca_obj_grid.c +181 -124
  32. data/ext/ca_obj_meld.c +235 -55
  33. data/ext/ca_obj_moncmp.c +61 -61
  34. data/ext/ca_obj_monop.c +125 -107
  35. data/ext/ca_obj_object.c +551 -233
  36. data/ext/ca_obj_record.c +51 -16
  37. data/ext/ca_obj_reduce.c +5 -8
  38. data/ext/ca_obj_refer.c +117 -33
  39. data/ext/ca_obj_remap.c +57 -17
  40. data/ext/ca_obj_repeat.c +21 -5
  41. data/ext/ca_obj_roll.c +115 -11
  42. data/ext/ca_obj_select.c +88 -75
  43. data/ext/ca_obj_select_axis.c +58 -60
  44. data/ext/ca_obj_shift.c +22 -102
  45. data/ext/ca_obj_stack.c +223 -123
  46. data/ext/ca_obj_stride.c +267 -35
  47. data/ext/ca_obj_string.c +25 -22
  48. data/ext/ca_obj_tile.c +32 -16
  49. data/ext/ca_obj_time.c +23 -25
  50. data/ext/ca_obj_timedelta.c +21 -23
  51. data/ext/ca_obj_transpose.c +12 -3
  52. data/ext/ca_obj_triop.c +110 -117
  53. data/ext/ca_obj_window.c +157 -29
  54. data/ext/ca_op_ipower.c +25 -13
  55. data/ext/ca_op_powi.h +57 -30
  56. data/ext/ca_pow5_table.h +656 -0
  57. data/ext/ca_rng_normal.h +42 -0
  58. data/ext/ca_rng_xoshiro256pp.h +105 -0
  59. data/ext/ca_sort_kernels.h +70 -0
  60. data/ext/ca_sweep_engine.c +385 -198
  61. data/ext/ca_sweep_engine.h +31 -23
  62. data/ext/ca_triop_dispatch.c +4 -1
  63. data/ext/ca_triop_dispatch.h +5 -2
  64. data/ext/caframe_csv_reader.c +463 -0
  65. data/ext/carray.h +90 -28
  66. data/ext/carray_access.c +487 -231
  67. data/ext/carray_address_basis.c +731 -0
  68. data/ext/carray_attribute.c +45 -3
  69. data/ext/carray_bincount.c +32 -2
  70. data/ext/carray_broadcast.c +49 -17
  71. data/ext/carray_call_cfunc.c +667 -511
  72. data/ext/carray_cast.c +1556 -247
  73. data/ext/carray_cast_func.rb +34 -21
  74. data/ext/carray_conversion.c +197 -73
  75. data/ext/carray_copy.c +84 -38
  76. data/ext/carray_core.c +591 -119
  77. data/ext/carray_count.c +148 -96
  78. data/ext/carray_element.c +18 -27
  79. data/ext/carray_factorize.c +604 -291
  80. data/ext/carray_generate.c +76 -40
  81. data/ext/carray_histogram.c +152 -94
  82. data/ext/carray_hold.c +2 -1
  83. data/ext/carray_index_classifier.c +63 -96
  84. data/ext/carray_internal.h +400 -1
  85. data/ext/carray_lazy.c +834 -79
  86. data/ext/carray_loop.c +88 -66
  87. data/ext/carray_mask.c +705 -324
  88. data/ext/carray_math_kernel.h +1 -0
  89. data/ext/carray_median_percentile.c +263 -63
  90. data/ext/carray_memory_view.c +254 -248
  91. data/ext/carray_operator.c +1093 -363
  92. data/ext/carray_order.c +133 -69
  93. data/ext/carray_partition.c +102 -56
  94. data/ext/carray_random.c +582 -204
  95. data/ext/carray_scatter.c +308 -65
  96. data/ext/carray_segment.c +257 -0
  97. data/ext/carray_slab.c +183 -70
  98. data/ext/carray_sort.c +235 -240
  99. data/ext/carray_sort_kernel.c +8 -1
  100. data/ext/carray_struct.c +99 -21
  101. data/ext/carray_test.c +167 -64
  102. data/ext/carray_time_text.c +1182 -0
  103. data/ext/carray_utils.c +363 -98
  104. data/ext/extconf.rb +27 -2
  105. data/ext/mk_call_cfunc.rb +103 -118
  106. data/ext/mk_pow5_table.rb +35 -0
  107. data/ext/mkkernel.rb +1349 -851
  108. data/ext/ruby_carray.c +17 -2
  109. data/ext/version.h +4 -4
  110. data/ext/version.rb +4 -2
  111. data/lib/carray/attribute.rb +39 -0
  112. data/lib/carray/autoload_carray.rb +24 -3
  113. data/lib/carray/autoload_method_extension.rb +18 -0
  114. data/lib/carray/axis_group.rb +245 -20
  115. data/lib/carray/basics.rb +95 -25
  116. data/lib/carray/bincount_nd.rb +6 -0
  117. data/lib/carray/block_iterator.rb +200 -54
  118. data/lib/carray/boolean_reduce.rb +21 -29
  119. data/lib/carray/categorical.rb +244 -59
  120. data/lib/carray/categorical_iterator.rb +391 -757
  121. data/lib/carray/complex.rb +36 -29
  122. data/lib/carray/conditional.rb +94 -7
  123. data/lib/carray/const_string.rb +177 -27
  124. data/lib/carray/construct.rb +40 -0
  125. data/lib/carray/data_type_extension.rb +3 -0
  126. data/lib/carray/data_type_limits.rb +91 -0
  127. data/lib/carray/fixlen_string.rb +1 -1
  128. data/lib/carray/frame/concat.rb +157 -6
  129. data/lib/carray/frame/convert.rb +13 -7
  130. data/lib/carray/frame/csv_parser.rb +590 -76
  131. data/lib/carray/frame/describe.rb +79 -0
  132. data/lib/carray/frame/frame.rb +205 -35
  133. data/lib/carray/frame/group.rb +199 -40
  134. data/lib/carray/frame/io.rb +452 -60
  135. data/lib/carray/frame/join.rb +134 -46
  136. data/lib/carray/frame/records.rb +54 -19
  137. data/lib/carray/frame/reshape.rb +448 -0
  138. data/lib/carray/frame/sort.rb +26 -2
  139. data/lib/carray/frame/verbs.rb +726 -56
  140. data/lib/carray/frame.rb +2 -0
  141. data/lib/carray/fuse_source.rb +111 -2
  142. data/lib/carray/fusion.rb +229 -38
  143. data/lib/carray/inspect.rb +71 -20
  144. data/lib/carray/iterator.rb +157 -2
  145. data/lib/carray/lazy.rb +54 -67
  146. data/lib/carray/mask_gap_fill.rb +66 -50
  147. data/lib/carray/math.rb +32 -19
  148. data/lib/carray/meld_reduce.rb +40 -7
  149. data/lib/carray/methods/align_addr.rb +8 -4
  150. data/lib/carray/methods/bincount.rb +2 -2
  151. data/lib/carray/methods/bit_string.rb +14 -3
  152. data/lib/carray/methods/composition.rb +16 -10
  153. data/lib/carray/methods/discovery_along.rb +74 -0
  154. data/lib/carray/methods/factorize.rb +50 -0
  155. data/lib/carray/methods/gather_nd.rb +13 -2
  156. data/lib/carray/methods/insert_block.rb +9 -14
  157. data/lib/carray/methods/is_in.rb +130 -6
  158. data/lib/carray/methods/join.rb +1 -1
  159. data/lib/carray/methods/locate_addr.rb +235 -21
  160. data/lib/carray/methods/mask_duplicates.rb +35 -1
  161. data/lib/carray/methods/mode.rb +18 -1
  162. data/lib/carray/methods/nunique.rb +22 -1
  163. data/lib/carray/methods/repeat.rb +91 -0
  164. data/lib/carray/methods/resize.rb +21 -23
  165. data/lib/carray/methods/snap.rb +34 -12
  166. data/lib/carray/methods/unique.rb +52 -3
  167. data/lib/carray/record_order.rb +208 -0
  168. data/lib/carray/rng.rb +86 -0
  169. data/lib/carray/runtime.rb +14 -11
  170. data/lib/carray/segment_iterator.rb +990 -0
  171. data/lib/carray/serialize.rb +197 -27
  172. data/lib/carray/slab_iterator.rb +109 -40
  173. data/lib/carray/stack.rb +10 -4
  174. data/lib/carray/string_operation_extension.rb +9 -4
  175. data/lib/carray/struct.rb +142 -51
  176. data/lib/carray/struct_builder.rb +110 -14
  177. data/lib/carray/table.rb +2 -2
  178. data/lib/carray/time.rb +535 -105
  179. data/lib/carray/window_iterator.rb +259 -82
  180. data/lib/carray.rb +4 -2
  181. data/yard-stubs/ca_obj_array.rb +4 -4
  182. data/yard-stubs/ca_obj_bitarray.rb +7 -0
  183. data/yard-stubs/ca_obj_bitfield.rb +23 -12
  184. data/yard-stubs/ca_obj_block.rb +2 -7
  185. data/yard-stubs/ca_obj_fake.rb +1 -1
  186. data/yard-stubs/ca_obj_field.rb +1 -1
  187. data/yard-stubs/ca_obj_refer.rb +3 -3
  188. data/yard-stubs/ca_obj_roll.rb +0 -1
  189. data/yard-stubs/ca_obj_stride.rb +10 -7
  190. data/yard-stubs/ca_obj_transpose.rb +1 -1
  191. data/yard-stubs/ca_obj_window.rb +11 -4
  192. data/yard-stubs/carray_access.rb +6 -5
  193. data/yard-stubs/carray_broadcast.rb +2 -2
  194. data/yard-stubs/carray_cast.rb +78 -43
  195. data/yard-stubs/carray_conversion.rb +13 -1
  196. data/yard-stubs/carray_copy.rb +8 -3
  197. data/yard-stubs/carray_core.rb +3 -83
  198. data/yard-stubs/carray_count.rb +16 -2
  199. data/yard-stubs/carray_lazy.rb +210 -1
  200. data/yard-stubs/carray_loop.rb +4 -1
  201. data/yard-stubs/carray_mask.rb +34 -10
  202. data/yard-stubs/carray_math.rb +1499 -4
  203. data/yard-stubs/carray_median_percentile.rb +26 -8
  204. data/yard-stubs/carray_order.rb +43 -82
  205. data/yard-stubs/carray_scatter.rb +10 -3
  206. data/yard-stubs/carray_segment.rb +72 -0
  207. data/yard-stubs/carray_slab.rb +11 -8
  208. data/yard-stubs/carray_sort.rb +50 -8
  209. data/yard-stubs/carray_test.rb +10 -0
  210. data/yard-stubs/carray_utils.rb +0 -26
  211. metadata +19 -19
  212. data/ext/ca_for_each_element.h +0 -239
  213. data/ext/carray_build_flags.h +0 -3
  214. data/ext/carray_config.h +0 -28
  215. data/ext/carray_kernels_bincmp.c +0 -4446
  216. data/ext/carray_kernels_binop.c +0 -11001
  217. data/ext/carray_kernels_init.c +0 -1131
  218. data/ext/carray_kernels_map.c +0 -3467
  219. data/ext/carray_kernels_moncmp.c +0 -2097
  220. data/ext/carray_kernels_monop.c +0 -18313
  221. data/ext/carray_kernels_reduce_aggregate.c +0 -25837
  222. data/ext/carray_kernels_reduce_boolean.c +0 -330
  223. data/ext/carray_kernels_reduce_cumulative.c +0 -14593
  224. data/ext/carray_kernels_reduce_extreme.c +0 -16948
  225. data/ext/carray_kernels_reduce_variance.c +0 -3910
  226. data/ext/carray_kernels_scan.c +0 -3693
  227. data/ext/carray_kernels_search.c +0 -32138
  228. data/ext/carray_kernels_sort.c +0 -10626
  229. data/ext/carray_kernels_triop.c +0 -1392
@@ -9,6 +9,7 @@
9
9
 
10
10
  #include "ruby.h"
11
11
  #include "carray.h"
12
+ #include "carray_internal.h" /* ca_attach_window, ca_axis_integer */
12
13
 
13
14
  /* ----------------------------------------------------------------- */
14
15
 
@@ -32,7 +33,7 @@ rb_ca_where (VALUE self)
32
33
 
33
34
  TypedData_Get_Struct(bool0, CArray, &carray_data_type, ca);
34
35
 
35
- ca_attach(ca);
36
+ ca_attach(ca); /* window: nothing raises inside */
36
37
 
37
38
  /* calculate elements of output array */
38
39
  p = (boolean8_t *) ca->ptr;
@@ -179,16 +180,10 @@ ca_seq_resolve_axis (CArray *ca, VALUE raxis)
179
180
  }
180
181
  if ( TYPE(raxis) == T_ARRAY ) {
181
182
  rb_raise(rb_eArgError,
182
- "seq axis must be a single integer (multi-axis seq is not supported)");
183
- }
184
- axis = NUM2INT(raxis);
185
- if ( axis < 0 ) {
186
- axis += ca->ndim;
187
- }
188
- if ( axis < 0 || axis >= ca->ndim ) {
189
- rb_raise(rb_eArgError,
190
- "axis out of range for seq (0...%d)", ca->ndim);
183
+ "%s: axis must be a single Integer (a seq over several axes is not supported)",
184
+ ca_calling_method_name());
191
185
  }
186
+ axis = rb_ca_normalize_axis_for_ndim(ca_axis_integer(raxis, NULL), ca->ndim, NULL);
192
187
  return axis;
193
188
  }
194
189
 
@@ -208,23 +203,30 @@ ca_seq_geometry (CArray *ca, int axis,
208
203
  *outer = out;
209
204
  }
210
205
 
206
+ /* The object fill calls Ruby per cell (`+`, or the method given as the
207
+ step), which can raise part way, so it runs in a window that attaches:
208
+ the cells filled before the raise then reach the parent with the rest
209
+ left as they were, as they would for an entity. */
210
+
211
+ typedef struct {
212
+ CArray *ca;
213
+ VALUE roffset;
214
+ VALUE rstep;
215
+ VALUE rmethod;
216
+ int axis;
217
+ } ca_seq_ctx_t;
218
+
211
219
  static VALUE
212
- rb_ca_seq_bang_object (VALUE self, VALUE roffset, VALUE rstep, int axis)
220
+ ca_seq_bang_object_body (VALUE arg)
213
221
  {
214
- volatile VALUE rval, rmethod = Qnil;
215
- CArray *ca;
222
+ ca_seq_ctx_t *c = (ca_seq_ctx_t *) arg;
223
+ CArray *ca = c->ca;
224
+ volatile VALUE rval;
225
+ VALUE roffset = c->roffset, rstep = c->rstep, rmethod = c->rmethod;
226
+ int axis = c->axis;
216
227
  VALUE *p;
217
228
  ca_size_t i;
218
229
 
219
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
220
-
221
- if ( TYPE(rstep) == T_SYMBOL ) { /* e.g. a.seq("a", :succ) */
222
- rmethod = rstep;
223
- rstep = Qnil;
224
- }
225
-
226
- ca_allocate(ca);
227
-
228
230
  if ( ca_has_mask(ca) ) {
229
231
  ca_clear_mask(ca); /* clear all mask */
230
232
  }
@@ -318,12 +320,54 @@ rb_ca_seq_bang_object (VALUE self, VALUE roffset, VALUE rstep, int axis)
318
320
  }
319
321
  }
320
322
 
321
- ca_sync(ca);
322
- ca_detach(ca);
323
+ return Qnil;
324
+ }
325
+
326
+ static VALUE
327
+ rb_ca_seq_bang_object (VALUE self, VALUE roffset, VALUE rstep, int axis)
328
+ {
329
+ ca_seq_ctx_t c;
330
+
331
+ TypedData_Get_Struct(self, CArray, &carray_data_type, c.ca);
332
+
333
+ c.rmethod = Qnil;
334
+ if ( TYPE(rstep) == T_SYMBOL ) { /* e.g. a.seq("a", :succ) */
335
+ c.rmethod = rstep;
336
+ rstep = Qnil;
337
+ }
338
+ c.roffset = roffset;
339
+ c.rstep = rstep;
340
+ c.axis = axis;
341
+
342
+ ca_attach_window(1, &c.ca, "w", ca_seq_bang_object_body, (VALUE) &c);
323
343
 
324
344
  return self;
325
345
  }
326
346
 
347
+ /* The numeric fill converts offset and step before it writes a cell, so
348
+ a raise there leaves nothing to push back: an allocate window. */
349
+ static VALUE
350
+ ca_seq_bang_numeric_body (VALUE arg)
351
+ {
352
+ ca_seq_ctx_t *c = (ca_seq_ctx_t *) arg;
353
+ CArray *ca = c->ca;
354
+ VALUE roffset = c->roffset, rstep = c->rstep;
355
+
356
+ if ( ca_has_mask(ca) ) {
357
+ ca_clear_mask(ca); /* clear all mask */
358
+ }
359
+
360
+ if ( c->axis < 0 ) {
361
+ seq_bang_switch(proc_seq_bang);
362
+ }
363
+ else {
364
+ ca_size_t len, inner_size, outer_size;
365
+ ca_seq_geometry(ca, c->axis, &len, &inner_size, &outer_size);
366
+ seq_bang_switch(proc_seq_bang_axis);
367
+ }
368
+ return Qnil;
369
+ }
370
+
327
371
  /* CArray#seq!(init_val=0, step=1, axis: nil) -- arithmetic-progression
328
372
  fill, in place. Without `axis:` the fill runs in row-major order
329
373
  over the whole array; with `axis: k` the progression runs along axis
@@ -353,24 +397,16 @@ rb_ca_seq_bang_method (int argc, VALUE *argv, VALUE self)
353
397
  return rb_ca_seq_bang_object(self, roffset, rstep, axis);
354
398
  }
355
399
 
356
- ca_allocate(ca);
357
-
358
- if ( ca_has_mask(ca) ) {
359
- ca_clear_mask(ca); /* clear all mask */
400
+ {
401
+ ca_seq_ctx_t c;
402
+ c.ca = ca;
403
+ c.roffset = roffset;
404
+ c.rstep = rstep;
405
+ c.rmethod = Qnil;
406
+ c.axis = axis;
407
+ ca_attach_window(1, &ca, "a", ca_seq_bang_numeric_body, (VALUE) &c);
360
408
  }
361
409
 
362
- if ( axis < 0 ) {
363
- seq_bang_switch(proc_seq_bang);
364
- }
365
- else {
366
- ca_size_t len, inner_size, outer_size;
367
- ca_seq_geometry(ca, axis, &len, &inner_size, &outer_size);
368
- seq_bang_switch(proc_seq_bang_axis);
369
- }
370
-
371
- ca_sync(ca);
372
- ca_detach(ca);
373
-
374
410
  return self;
375
411
  }
376
412
 
@@ -23,13 +23,15 @@
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. */
29
+ /* Resolve `redges` to a 1-D float64 CArray of at least two edges. The
30
+ caller copies the edges out (ca_xfer_all into its own buffer) rather
31
+ than attaching them: the walk that follows reads the caller's array,
32
+ and a raise there must not leave the edges attached. */
31
33
  static CArray *
32
- histbin_attach_edges (VALUE self, VALUE redges, double **ep_out, ca_size_t *ne_out)
34
+ histbin_resolve_edges (VALUE self, VALUE redges)
33
35
  {
34
36
  CArray *ce;
35
37
 
@@ -49,9 +51,6 @@ histbin_attach_edges (VALUE self, VALUE redges, double **ep_out, ca_size_t *ne_o
49
51
  rb_raise(rb_eArgError, "histbin_ki: edges needs at least 2 values");
50
52
  }
51
53
 
52
- ca_attach(ce);
53
- *ep_out = (double *) ce->ptr;
54
- *ne_out = ce->elements;
55
54
  return ce;
56
55
  }
57
56
 
@@ -105,19 +104,24 @@ histbin_index (const histbin_axis_t *ax, double v)
105
104
  }
106
105
 
107
106
  static void
108
- histbin_axis_setup (histbin_axis_t *ax, CArray *ce, int include_max)
107
+ histbin_axis_setup (histbin_axis_t *ax, const double *ep, ca_size_t ne,
108
+ int include_max)
109
109
  {
110
- ca_size_t ne = ce->elements, kk;
110
+ ca_size_t kk;
111
111
  double dx, tol;
112
112
 
113
- ax->ep = (const double *) ce->ptr;
113
+ ax->ep = ep;
114
114
  ax->n = ne - 1;
115
115
  ax->lo = ax->ep[0];
116
116
  ax->hi = ax->ep[ne - 1];
117
117
  dx = (ax->hi - ax->lo) / (double) ax->n;
118
118
  tol = fabs(dx) * 1e-9 + 1e-12;
119
- ax->uniform = 1;
120
- for ( kk = 0; kk <= ax->n; kk++ ) {
119
+ /* The linearised index needs a width and its reciprocal that are both
120
+ finite and nonzero: edges spanning more than a double holds make the
121
+ width infinite, and a subnormal width makes the reciprocal infinite.
122
+ Either turns the position into NaN, which has no integer. */
123
+ ax->uniform = isfinite(dx) && dx != 0.0 && isfinite(1.0 / dx);
124
+ for ( kk = 0; ax->uniform && kk <= ax->n; kk++ ) {
121
125
  if ( fabs(ax->ep[kk] - (ax->lo + (double) kk * dx)) > tol ) { ax->uniform = 0; break; }
122
126
  }
123
127
  ax->inv_dx = (dx != 0.0) ? 1.0 / dx : 0.0;
@@ -129,8 +133,8 @@ rb_ca_histbin_ki (VALUE self, VALUE redges, VALUE rinclude_max)
129
133
  {
130
134
  CArray *ca, *co, *ce;
131
135
  VALUE vout;
136
+ volatile VALUE hedges = 0;
132
137
  double *ep;
133
- ca_size_t ne;
134
138
  histbin_axis_t ax;
135
139
 
136
140
  GetCArray(self, ca);
@@ -140,9 +144,10 @@ rb_ca_histbin_ki (VALUE self, VALUE redges, VALUE rinclude_max)
140
144
  ca_type_name[ca->data_type]);
141
145
  }
142
146
 
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));
147
+ ce = histbin_resolve_edges(self, redges);
148
+ ep = ALLOCV_N(double, hedges, ce->elements);
149
+ ca_xfer_all(ce, ep, CA_XFER_GET);
150
+ histbin_axis_setup(&ax, ep, ce->elements, RTEST(rinclude_max));
146
151
 
147
152
  /* output: fresh contiguous int64, same shape as self. */
148
153
  vout = rb_carray_new(CA_INT64, ca->ndim, ca->dim, 0, NULL);
@@ -179,7 +184,7 @@ rb_ca_histbin_ki (VALUE self, VALUE redges, VALUE rinclude_max)
179
184
  }
180
185
  }
181
186
 
182
- ca_detach(ce);
187
+ ALLOCV_END(hedges);
183
188
 
184
189
  return vout;
185
190
  }
@@ -201,6 +206,125 @@ rb_ca_histbin_ki (VALUE self, VALUE redges, VALUE rinclude_max)
201
206
  off = fiber_base + Σ_k histbin_index(axis_k, v_{a,k}) * ext_stride[k]
202
207
  counts[off] += 1 (or += weight when weighted)
203
208
  =========================================================================== */
209
+ /* histogram_scatter_ki reads its edges inside an attach window and walks
210
+ the samples (and the weights) with two kernel iterators, whose states
211
+ live here, outside the walk: a sample view that raises as it is read --
212
+ a lazy source meeting a cell it cannot compute -- leaves neither the
213
+ edges nor the other walk open. */
214
+ typedef struct {
215
+ ca_iter_state states[2]; /* the samples, the weights */
216
+ CArray *ca, *cc, *cw;
217
+ long M, nf;
218
+ int weighted;
219
+ CArray **edge_ca;
220
+ VALUE rincmax;
221
+ histbin_axis_t *axes;
222
+ ca_size_t *ext_stride;
223
+ ca_size_t *fiber_stride;
224
+ } histogram_scatter_t;
225
+
226
+ static VALUE
227
+ histogram_scatter_walk (VALUE arg)
228
+ {
229
+ histogram_scatter_t *c = (histogram_scatter_t *) arg;
230
+ CArray *ca = c->ca, *cc = c->cc, *cw = c->cw;
231
+ long M = c->M, k;
232
+ int weighted = c->weighted;
233
+ histbin_axis_t *axes = c->axes;
234
+ ca_size_t *ext_stride = c->ext_stride;
235
+ ca_size_t *fiber_stride = c->fiber_stride;
236
+ #define st (c->states[0])
237
+ #define stw (c->states[1])
238
+ int64_t *cpi = (int64_t *) cc->ptr; /* unweighted */
239
+ double *cpd = (double *) cc->ptr; /* weighted */
240
+ char *p, *pw = NULL;
241
+ boolean8_t *m, *mw = NULL;
242
+ ca_size_t cur_outer_idx[CA_RANK_MAX];
243
+ int8_t slab_axes[2] = { (int8_t)(ca->ndim - 2), (int8_t)(ca->ndim - 1) };
244
+ int8_t w_slab_axes[1] = { (int8_t)(ca->ndim - 2) }; /* weights sample axis */
245
+ int8_t mm;
246
+ int rc;
247
+
248
+ rc = ca_iter_state_init_l2(&st, ca, CA_SLAB_AXES, slab_axes, 2, 0);
249
+ if ( rc != CA_ITER_OK ) {
250
+ rb_raise(rb_eRuntimeError, "histogram_scatter_ki: iter init failed rc=%d", rc);
251
+ }
252
+ if ( weighted ) {
253
+ rc = ca_iter_state_init_l2(&stw, cw, CA_SLAB_AXES, w_slab_axes, 1, 0);
254
+ if ( rc != CA_ITER_OK ) {
255
+ rb_raise(rb_eRuntimeError, "histogram_scatter_ki: weights iter init failed rc=%d", rc);
256
+ }
257
+ }
258
+ for ( mm = 0; mm < st.outer_ndim; mm++ ) cur_outer_idx[mm] = 0;
259
+
260
+ while ( ca_iter_state_next_slab_axes(&st, &p, &m) ) {
261
+ ca_size_t fiber_base = 0;
262
+ ca_size_t A, a, kk;
263
+ ca_size_t ss, cs, sms, cms, ws = 0, wms = 0;
264
+
265
+ if ( weighted && ! ca_iter_state_next_slab_axes(&stw, &pw, &mw) ) break;
266
+
267
+ for ( mm = 0; mm < st.outer_ndim; mm++ )
268
+ fiber_base += cur_outer_idx[mm] * fiber_stride[mm];
269
+
270
+ A = st.slab_dims[0]; /* samples */
271
+ ss = st.slab_strides[0]; /* sample byte stride */
272
+ cs = st.slab_strides[1]; /* channel byte stride */
273
+ sms = st.slab_mask_strides[0];
274
+ cms = st.slab_mask_strides[1];
275
+ if ( weighted ) {
276
+ ws = stw.slab_strides[0];
277
+ wms = stw.slab_mask_strides[0];
278
+ }
279
+
280
+ for ( a = 0; a < A; a++ ) {
281
+ ca_size_t off = fiber_base;
282
+ int masked = 0;
283
+ for ( kk = 0; kk < (ca_size_t) M; kk++ ) {
284
+ double v = *(const double *)(p + a * ss + kk * cs);
285
+ if ( (m && m[a * sms + kk * cms]) || isnan(v) ) { masked = 1; break; }
286
+ off += histbin_index(&axes[kk], v) * ext_stride[kk];
287
+ }
288
+ if ( masked ) continue;
289
+ if ( weighted ) {
290
+ double w = *(const double *)(pw + a * ws);
291
+ if ( (mw && mw[a * wms]) || isnan(w) ) continue; /* skip masked / NaN weight */
292
+ cpd[off] += w;
293
+ }
294
+ else {
295
+ cpi[off] += 1;
296
+ }
297
+ }
298
+
299
+ for ( mm = (int8_t)(st.outer_ndim - 1); mm >= 0; mm-- ) {
300
+ if ( ++cur_outer_idx[mm] < st.outer_dims[mm] ) break;
301
+ cur_outer_idx[mm] = 0;
302
+ }
303
+ }
304
+ ca_iter_state_finish(&st);
305
+ if ( weighted ) ca_iter_state_finish(&stw);
306
+ #undef st
307
+ #undef stw
308
+ (void) k;
309
+ return Qnil;
310
+ }
311
+
312
+ static VALUE
313
+ histogram_scatter_edges (VALUE arg)
314
+ {
315
+ histogram_scatter_t *c = (histogram_scatter_t *) arg;
316
+ long k;
317
+ for ( k = 0; k < c->M; k++ ) {
318
+ histbin_axis_setup(&c->axes[k], (const double *) c->edge_ca[k]->ptr,
319
+ c->edge_ca[k]->elements,
320
+ RTEST(RARRAY_AREF(c->rincmax, k)));
321
+ }
322
+ if ( c->ca->elements > 0 ) {
323
+ ca_iter_ensure(2, c->states, histogram_scatter_walk, arg);
324
+ }
325
+ return Qnil;
326
+ }
327
+
204
328
  static VALUE
205
329
  rb_ca_histogram_scatter_ki (VALUE self, VALUE rcounts, VALUE redges,
206
330
  VALUE rincmax, VALUE rweights)
@@ -258,8 +382,6 @@ rb_ca_histogram_scatter_ki (VALUE self, VALUE rcounts, VALUE redges,
258
382
  for ( k = 0; k < M; k++ ) {
259
383
  VALUE e = RARRAY_AREF(redges, k);
260
384
  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)));
263
385
  }
264
386
 
265
387
  /* ext strides (row-major within the trailing M bin axes of counts). */
@@ -275,83 +397,19 @@ rb_ca_histogram_scatter_ki (VALUE self, VALUE rcounts, VALUE redges,
275
397
  s *= cc->dim[k];
276
398
  }
277
399
 
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);
400
+ {
401
+ histogram_scatter_t c;
402
+ char modes[CA_RANK_MAX + 1];
403
+ for ( k = 0; k < M; k++ ) modes[k] = 'r';
404
+ modes[M] = '\0';
405
+ c.ca = ca; c.cc = cc; c.cw = cw;
406
+ c.M = M; c.nf = nf; c.weighted = weighted;
407
+ c.edge_ca = edge_ca; c.rincmax = rincmax; c.axes = axes;
408
+ c.ext_stride = ext_stride; c.fiber_stride = fiber_stride;
409
+ ca_attach_window((int32_t) M, edge_ca, modes, histogram_scatter_edges,
410
+ (VALUE) &c);
351
411
  }
352
412
 
353
- for ( k = 0; k < M; k++ ) ca_detach(edge_ca[k]);
354
-
355
413
  return rcounts;
356
414
  }
357
415
 
data/ext/carray_hold.c CHANGED
@@ -49,7 +49,8 @@ rb_ca_hold_forward (VALUE self, int axis)
49
49
  if ( rc != CA_ITER_OK ) {
50
50
  rb_raise(rb_eRuntimeError, "__hold__: input init failed rc=%d", rc);
51
51
  }
52
- rc = ca_iter_state_init_l2(&st_out, co, CA_SLAB_AXES, slab_axes, 1,
52
+ rc = ca_iter_state_init_l2_paired(&st_out, &st_in, co, CA_SLAB_AXES,
53
+ slab_axes, 1,
53
54
  CA_KERNEL_WRITE);
54
55
  if ( rc != CA_ITER_OK ) {
55
56
  ca_iter_state_finish(&st_in);