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
@@ -14,6 +14,7 @@
14
14
 
15
15
  #include "ruby.h"
16
16
  #include "carray.h"
17
+ #include "carray_internal.h" /* ca_normalize_axis_arg */
17
18
  #include "ca_kernel_iterator.h" /* CA_FOR_EACH_FIBER_INOUT */
18
19
  #include "ca_obj_face.h" /* CA_FACE_LIFT_IF_FACE */
19
20
  #include "ca_sort_kernels.h" /* ca_partition_quick_* / ca_partition_nan_* */
@@ -23,7 +24,6 @@
23
24
  /* External entries reached at link time (extern declarations rather than
24
25
  carray.h additions to keep the public header lean): */
25
26
  extern VALUE rb_ca_remap_new (VALUE cary, VALUE rmapper); /* ca_obj_remap.c */
26
- extern VALUE rb_ca_partition_addr_ki (VALUE self, VALUE vaxis, VALUE vkth); /* carray_kernels.c (generated, bind_ruby: false) */
27
27
  /* _mp ("masked position") twin: explicit masked_last, used by `partition`
28
28
  / `partition_copy` to pass masked_position: through (see MASKED_POSITION
29
29
  rev1 in mkkernel.rb's MkKernel.sort doc). */
@@ -111,7 +111,21 @@ ca_quickselect_bytes (char *buf, ca_size_t lo, ca_size_t hi,
111
111
  #undef QSCMP
112
112
  }
113
113
 
114
- /* partition_copy(kth, axis: 0) — eager counterpart to `partition(kth,
114
+ /* The kth of a partition along a fiber of length n: an Integer in
115
+ -n <= kth < n, negative counting from the end. */
116
+ static ca_size_t
117
+ partition_kth (ca_size_t n, VALUE vkth)
118
+ {
119
+ ca_size_t raw = (ca_size_t) ca_integer_arg(vkth, "kth", NULL);
120
+ ca_size_t kth = ( raw < 0 ) ? raw + n : raw;
121
+ if ( kth < 0 || kth >= n ) {
122
+ rb_raise(rb_eArgError, "%s: kth %lld out of range for length %lld",
123
+ ca_calling_method_name(), (long long) raw, (long long) n);
124
+ }
125
+ return kth;
126
+ }
127
+
128
+ /* partition_copy(kth, axis:) — eager counterpart to `partition(kth,
115
129
  * axis:)`. Returns a fresh entity CArray with the kth fiber-local
116
130
  * position holding the kth-smallest value. Average O(n) per fiber via
117
131
  * quickselect. Mask handling, axis kwarg, kth validation: identical to
@@ -141,22 +155,10 @@ rb_ca_partition_copy_c (VALUE self, VALUE vkth, VALUE vaxis)
141
155
  }
142
156
 
143
157
  /* Normalize axis. */
144
- int axis = NUM2INT(vaxis);
145
- if ( axis < 0 ) axis += cat->ndim;
146
- if ( axis < 0 || axis >= cat->ndim ) {
147
- rb_raise(rb_eArgError, "partition_copy: axis %d out of range for ndim %d",
148
- NUM2INT(vaxis), cat->ndim);
149
- }
158
+ int axis = ca_normalize_axis_arg(vaxis, cat->ndim, NULL);
150
159
 
151
- /* Normalize kth (-dim[axis] <= kth < dim[axis], negative counts from end). */
152
160
  ca_size_t fiber_n = cat->dim[axis];
153
- ca_size_t kth = (ca_size_t) NUM2SSIZET(vkth);
154
- if ( kth < 0 ) kth += fiber_n;
155
- if ( kth < 0 || kth >= fiber_n ) {
156
- rb_raise(rb_eArgError,
157
- "partition_copy: kth %ld out of range for axis %d (dim=%ld)",
158
- (long) NUM2SSIZET(vkth), axis, (long) fiber_n);
159
- }
161
+ ca_size_t kth = partition_kth(fiber_n, vkth);
160
162
 
161
163
  /* CA_OBJECT branch: partition_index_ki carries the rb_funcall(<=>)
162
164
  * comparator. Build the entity via partition_index_ki ->
@@ -164,14 +166,9 @@ rb_ca_partition_copy_c (VALUE self, VALUE vkth, VALUE vaxis)
164
166
  * but the cost is the per-pair rb_funcall, not an architectural
165
167
  * penalty. */
166
168
  if ( cat->data_type == CA_OBJECT ) {
167
- static ID id_partition_index_ki = 0;
168
- static ID id_take_along_axis = 0;
169
- static ID id_axis_sym = 0;
170
- if ( !id_partition_index_ki ) {
171
- id_partition_index_ki = rb_intern("partition_index_ki");
172
- id_take_along_axis = rb_intern("take_along_axis");
173
- id_axis_sym = rb_intern("axis");
174
- }
169
+ ID id_partition_index_ki = rb_intern("partition_index_ki");
170
+ ID id_take_along_axis = rb_intern("take_along_axis");
171
+ ID id_axis_sym = rb_intern("axis");
175
172
  VALUE idx = rb_funcall(target, id_partition_index_ki, 2,
176
173
  INT2NUM(axis), SIZET2NUM(kth));
177
174
  VALUE kw = rb_hash_new();
@@ -193,8 +190,10 @@ rb_ca_partition_copy_c (VALUE self, VALUE vkth, VALUE vaxis)
193
190
  INT2NUM((int) fbytes));
194
191
  CArray *cao;
195
192
  TypedData_Get_Struct(vout, CArray, &carray_data_type, cao);
196
- char *swap_tmp = ALLOCA_N(char, fbytes);
197
- char *pivot = ALLOCA_N(char, fbytes);
193
+ /* Two cells of scratch. ALLOCV, not the stack: a cell can be wide. */
194
+ volatile VALUE scratch_holder = 0;
195
+ char *swap_tmp = ALLOCV_N(char, scratch_holder, 2 * (size_t) fbytes);
196
+ char *pivot = swap_tmp + fbytes;
198
197
  ca_iter_state st_in, st_out;
199
198
  char *pi, *po;
200
199
  ca_size_t n;
@@ -205,15 +204,16 @@ rb_ca_partition_copy_c (VALUE self, VALUE vkth, VALUE vaxis)
205
204
  ca_quickselect_bytes(po, 0, n - 1, kth, fbytes, NULL, swap_tmp, pivot);
206
205
  }
207
206
  }
207
+ ALLOCV_END(scratch_holder);
208
208
  return vout;
209
209
  }
210
210
 
211
211
  if ( cat->data_type != CA_BOOLEAN &&
212
212
  (cat->data_type < CA_INT8 || cat->data_type > CA_FLOAT64) ) {
213
213
  rb_raise(rb_eCADataTypeError,
214
- "partition_copy: data_type %d not supported "
215
- "(expected one of: bool, i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, object)",
216
- cat->data_type);
214
+ "partition_copy: source data_type :%s not supported "
215
+ "(expected boolean, an integer or float type, or object)",
216
+ ca_type_name[cat->data_type]);
217
217
  }
218
218
 
219
219
  volatile VALUE vout = rb_ca_template_with_type(target,
@@ -289,6 +289,12 @@ rb_ca_partition_copy_c_mp (VALUE self, VALUE vkth, VALUE vaxis, int masked_last)
289
289
  if ( ! ca_has_mask(ca) ) {
290
290
  return rb_ca_partition_copy_c(self, vkth, vaxis);
291
291
  }
292
+ /* Check axis and kth here, so a bad one is reported as partition_copy's
293
+ rather than as the partition this delegates to. */
294
+ {
295
+ int axis = ca_normalize_axis_arg(vaxis, ca->ndim, NULL);
296
+ partition_kth(ca->dim[axis], vkth);
297
+ }
292
298
  /* rb_ca_partitioned_view's rb_scan_args "1:" pattern needs call-frame
293
299
  keyword-splat state, only set by full Ruby method dispatch -- a raw
294
300
  C call segfaults/misparses (same constraint documented on
@@ -307,34 +313,60 @@ rb_ca_partition_copy_c_mp (VALUE self, VALUE vkth, VALUE vaxis, int masked_last)
307
313
  return obj;
308
314
  }
309
315
 
310
- /* Ruby entry: partition_copy(kth, axis: 0, masked_position: :last) */
316
+ /* Ruby entry: partition_copy(kth, axis: nil, masked_position: :last).
317
+ No axis means the whole array, as for sort_copy: flatten first. */
311
318
  static VALUE
312
- rb_ca_partition_copy (int argc, VALUE *argv, VALUE self)
319
+ rb_ca_partition_copy_body (int argc, VALUE *argv, VALUE self)
313
320
  {
314
321
  VALUE vkth, rkw = Qnil;
315
- VALUE vaxis = INT2NUM(0);
322
+ VALUE vaxis = Qnil;
316
323
  VALUE vmasked_position = Qnil;
317
324
  rb_scan_args(argc, argv, "1:", &vkth, &rkw);
318
325
  rb_scan_options(rkw, "axis,masked_position", &vaxis, &vmasked_position);
326
+ if ( NIL_P(vaxis) ) {
327
+ self = rb_ca_flatten(self);
328
+ vaxis = INT2NUM(0);
329
+ }
319
330
 
320
- int masked_last = 1;
321
- if ( !NIL_P(vmasked_position) ) {
322
- static ID sym_first = 0, sym_last = 0;
323
- if ( !sym_first ) sym_first = rb_intern("first");
324
- if ( !sym_last ) sym_last = rb_intern("last");
325
- ID mp_id = SYM2ID(vmasked_position);
326
- if ( mp_id == sym_last ) masked_last = 1;
327
- else if ( mp_id == sym_first ) masked_last = 0;
328
- else {
329
- rb_raise(rb_eArgError,
330
- "partition_copy: unknown masked_position %s (expected :first or :last)",
331
- rb_id2name(mp_id));
331
+ int masked_last = NIL_P(vmasked_position) ? 1
332
+ : ca_symbol_choice(vmasked_position, "masked_position", "first", "last", NULL);
333
+
334
+ /* Face gate, the same policy as the sort family's. An ORDERABLE Face
335
+ is selected on its storage and put back on the result. A Face that
336
+ orders by itself (ca_face_orders_by_itself) is partitioned by the view,
337
+ which orders by that order (ca_order_key), and its copy is the answer.
338
+ Any other Face raises. */
339
+ volatile VALUE face = Qnil;
340
+ {
341
+ CArray *ca;
342
+ TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
343
+ if ( ca_is_face(ca) ) {
344
+ if ( ca_face_orders_by_itself(self) ) {
345
+ VALUE kw = rb_hash_new();
346
+ VALUE pv_argv[2];
347
+ rb_hash_aset(kw, ID2SYM(rb_intern("axis")), vaxis);
348
+ rb_hash_aset(kw, ID2SYM(rb_intern("masked_position")),
349
+ masked_last ? ID2SYM(rb_intern("last")) : ID2SYM(rb_intern("first")));
350
+ pv_argv[0] = vkth;
351
+ pv_argv[1] = kw;
352
+ return rb_ca_copy(rb_funcallv_kw(self, rb_intern("partition"), 2, pv_argv,
353
+ RB_PASS_KEYWORDS));
354
+ }
355
+ ca_face_require_orderable(self, "partition_copy", "order");
356
+ face = self;
357
+ self = rb_ca_strip_face_value(self);
332
358
  }
333
359
  }
334
- return rb_ca_partition_copy_c_mp(self, vkth, vaxis, masked_last);
360
+
361
+ VALUE out = rb_ca_partition_copy_c_mp(self, vkth, vaxis, masked_last);
362
+
363
+ if ( face != Qnil ) {
364
+ out = ca_face_relift_entity(face, out);
365
+ }
366
+ return out;
335
367
  }
336
368
 
337
- /* partition(kth, axis: 0, masked_position: :last)
369
+ /* partition(kth, axis: nil, masked_position: :last)
338
370
  *
339
371
  * Returns a CARemap view of +self+ partitioned along +axis+ such that
340
372
  * the cell at the kth fiber-local position contains the kth-smallest
@@ -344,7 +376,7 @@ rb_ca_partition_copy (int argc, VALUE *argv, VALUE self)
344
376
  * :partition).
345
377
  *
346
378
  * Signature mirrors rb_ca_sorted_view: positional kth + optional axis: /
347
- * masked_position: kwargs (default 0 / :last). Mask handling mirrors
379
+ * masked_position: kwargs (default nil = whole array / :last). Mask handling mirrors
348
380
  * {sort}: masked cells are an incomparable sentinel clustered at
349
381
  * masked_position:, excluded from the kth-selection; a kth landing in
350
382
  * the masked cluster needs no selection (unspecified order, same
@@ -356,33 +388,27 @@ static VALUE
356
388
  rb_ca_partitioned_view (int argc, VALUE *argv, VALUE self)
357
389
  {
358
390
  VALUE vkth, rkw = Qnil;
359
- VALUE vaxis = INT2NUM(0);
391
+ VALUE vaxis = Qnil;
360
392
  VALUE vmasked_position = Qnil;
361
393
 
362
394
  rb_scan_args(argc, argv, "1:", &vkth, &rkw);
363
395
  rb_scan_options(rkw, "axis,masked_position", &vaxis, &vmasked_position);
364
396
 
365
- int masked_last = 1;
366
- if ( !NIL_P(vmasked_position) ) {
367
- static ID sym_first = 0, sym_last = 0;
368
- if ( !sym_first ) sym_first = rb_intern("first");
369
- if ( !sym_last ) sym_last = rb_intern("last");
370
- ID mp_id = SYM2ID(vmasked_position);
371
- if ( mp_id == sym_last ) masked_last = 1;
372
- else if ( mp_id == sym_first ) masked_last = 0;
373
- else {
374
- rb_raise(rb_eArgError,
375
- "partition: unknown masked_position %s (expected :first or :last)",
376
- rb_id2name(mp_id));
377
- }
378
- }
397
+ int masked_last = NIL_P(vmasked_position) ? 1
398
+ : ca_symbol_choice(vmasked_position, "masked_position", "first", "last", NULL);
379
399
 
380
400
  CArray *ca;
381
401
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
382
402
 
383
403
  /* CA_FIXLEN flows through the same partition_addr_ki fixlen dialect
384
- as numeric; masked_position: applies uniformly across data types. */
385
- VALUE target = self;
404
+ as numeric; masked_position: applies uniformly across data types.
405
+ No axis means the whole array, as for sort: partition the flattened
406
+ view. */
407
+ volatile VALUE target = self;
408
+ if ( NIL_P(vaxis) ) {
409
+ target = rb_ca_flatten(self);
410
+ vaxis = INT2NUM(0);
411
+ }
386
412
 
387
413
  /* partition_addr_ki_mp validates axis + kth, splits masked cells to
388
414
  masked_position:, and quickselects per fiber over the unmasked
@@ -390,7 +416,8 @@ rb_ca_partitioned_view (int argc, VALUE *argv, VALUE self)
390
416
  suitable for direct ca_remap_new wrap; the remap gather carries
391
417
  target's mask bits through so masked cells stay masked at their
392
418
  clustered position (no extra output-mask step needed here). */
393
- volatile VALUE sigma_addr = rb_ca_partition_addr_ki_mp(target, vaxis, vkth, masked_last);
419
+ volatile VALUE sigma_addr =
420
+ rb_ca_partition_addr_ki_mp(target, vaxis, vkth, masked_last);
394
421
  {
395
422
  VALUE obj = rb_ca_remap_new(target, sigma_addr);
396
423
  CA_FACE_LIFT_IF_FACE(obj, self, ca);
@@ -400,6 +427,26 @@ rb_ca_partitioned_view (int argc, VALUE *argv, VALUE self)
400
427
 
401
428
  /* ----------------------------------------------------------------------- */
402
429
 
430
+
431
+ typedef struct { int argc; VALUE *argv; VALUE self; } pc_call_t;
432
+
433
+ static VALUE
434
+ pc_answer_body (VALUE p)
435
+ {
436
+ pc_call_t *c = (pc_call_t *) p;
437
+ return rb_ca_partition_copy_body(c->argc, c->argv, c->self);
438
+ }
439
+
440
+ /* An error raised by the methods this one calls names this one. */
441
+ static VALUE
442
+ rb_ca_partition_copy (int argc, VALUE *argv, VALUE self)
443
+ {
444
+ pc_call_t c = { argc, argv, self };
445
+ VALUE out = ca_answer_as_caller(pc_answer_body, (VALUE) &c);
446
+ rb_ca_inherit_attr(out, self);
447
+ return out;
448
+ }
449
+
403
450
  void
404
451
  Init_carray_partition (void)
405
452
  {