carray 3.0.4 → 3.0.6

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +438 -0
  3. data/README.md +1 -1
  4. data/carray.gemspec +3 -2
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_dispatch.c +19 -20
  7. data/ext/ca_axis_group.c +1 -1
  8. data/ext/ca_categorical_iterator.c +34 -27
  9. data/ext/ca_compare.c +4 -4
  10. data/ext/ca_composite_dispatch.c +9 -9
  11. data/ext/ca_kernel_iterator.c +122 -237
  12. data/ext/ca_kernel_iterator.h +522 -337
  13. data/ext/ca_obj_array.c +69 -19
  14. data/ext/ca_obj_bincmp.c +10 -1
  15. data/ext/ca_obj_binop.c +11 -1
  16. data/ext/ca_obj_bitarray.c +5 -1
  17. data/ext/ca_obj_bitfield.c +60 -43
  18. data/ext/ca_obj_byte_swap.c +4 -1
  19. data/ext/ca_obj_const_string.c +15 -3
  20. data/ext/ca_obj_face.c +44 -1
  21. data/ext/ca_obj_fake.c +3 -1
  22. data/ext/ca_obj_field.c +13 -3
  23. data/ext/ca_obj_grid.c +219 -17
  24. data/ext/ca_obj_meld.c +69 -113
  25. data/ext/ca_obj_moncmp.c +9 -1
  26. data/ext/ca_obj_monop.c +86 -12
  27. data/ext/ca_obj_object.c +118 -32
  28. data/ext/ca_obj_record.c +3 -0
  29. data/ext/ca_obj_reduce.c +19 -1
  30. data/ext/ca_obj_refer.c +80 -26
  31. data/ext/ca_obj_remap.c +69 -10
  32. data/ext/ca_obj_roll.c +27 -6
  33. data/ext/ca_obj_select.c +38 -6
  34. data/ext/ca_obj_select_axis.c +1 -0
  35. data/ext/ca_obj_shift.c +32 -7
  36. data/ext/ca_obj_stack.c +311 -111
  37. data/ext/ca_obj_stride.c +159 -64
  38. data/ext/ca_obj_string.c +27 -2
  39. data/ext/ca_obj_tile.c +28 -7
  40. data/ext/ca_obj_transpose.c +8 -4
  41. data/ext/ca_obj_triop.c +12 -1
  42. data/ext/ca_obj_window.c +80 -50
  43. data/ext/ca_op_ipower.c +12 -12
  44. data/ext/ca_sort_kernels.h +6 -3
  45. data/ext/caframe_csv_reader.c +1 -1
  46. data/ext/carray.h +35 -1
  47. data/ext/carray_access.c +43 -67
  48. data/ext/carray_address_basis.c +134 -0
  49. data/ext/carray_attribute.c +32 -0
  50. data/ext/carray_broadcast.c +3 -4
  51. data/ext/carray_build_flags.h +1 -1
  52. data/ext/carray_cast.c +251 -93
  53. data/ext/carray_cast_func.rb +56 -26
  54. data/ext/carray_conversion.c +11 -7
  55. data/ext/carray_core.c +814 -72
  56. data/ext/carray_count.c +6 -0
  57. data/ext/carray_element.c +22 -13
  58. data/ext/carray_factorize.c +20 -20
  59. data/ext/carray_generate.c +8 -2
  60. data/ext/carray_histogram.c +26 -4
  61. data/ext/carray_index_classifier.c +4 -4
  62. data/ext/carray_internal.h +159 -12
  63. data/ext/carray_kernels_bincmp.c +2174 -170
  64. data/ext/carray_kernels_binop.c +25653 -5487
  65. data/ext/carray_kernels_init.c +8 -8
  66. data/ext/carray_kernels_moncmp.c +96 -96
  67. data/ext/carray_kernels_monop.c +12253 -5235
  68. data/ext/carray_kernels_reduce_aggregate.c +6150 -2423
  69. data/ext/carray_kernels_reduce_boolean.c +1533 -15
  70. data/ext/carray_kernels_reduce_cumulative.c +2442 -882
  71. data/ext/carray_kernels_reduce_extreme.c +5658 -1661
  72. data/ext/carray_kernels_reduce_variance.c +2534 -402
  73. data/ext/carray_kernels_scan.c +368 -368
  74. data/ext/carray_kernels_search.c +4551 -604
  75. data/ext/carray_kernels_sort.c +659 -751
  76. data/ext/carray_kernels_triop.c +114 -114
  77. data/ext/carray_key_windows.c +4 -0
  78. data/ext/carray_lazy.c +47 -0
  79. data/ext/carray_loop.c +1 -1
  80. data/ext/carray_mask.c +175 -161
  81. data/ext/carray_median_percentile.c +4 -4
  82. data/ext/carray_memory_view.c +15 -9
  83. data/ext/carray_operator.c +152 -49
  84. data/ext/carray_order.c +230 -10
  85. data/ext/carray_random.c +22 -19
  86. data/ext/carray_scatter.c +24 -7
  87. data/ext/carray_slab.c +128 -29
  88. data/ext/carray_sort.c +224 -16
  89. data/ext/carray_sort_kernel.c +5 -7
  90. data/ext/carray_struct.c +35 -43
  91. data/ext/carray_test.c +74 -19
  92. data/ext/carray_time_text.c +6 -4
  93. data/ext/carray_utils.c +63 -21
  94. data/ext/extconf.rb +11 -0
  95. data/ext/mkkernel.rb +546 -199
  96. data/ext/ruby_carray.c +4 -1
  97. data/ext/version.h +4 -4
  98. data/lib/carray/attribute.rb +42 -5
  99. data/lib/carray/autoload_carray.rb +3 -3
  100. data/lib/carray/autoload_method_extension.rb +5 -3
  101. data/lib/carray/axis_group.rb +13 -7
  102. data/lib/carray/basics.rb +28 -8
  103. data/lib/carray/block_iterator.rb +17 -3
  104. data/lib/carray/categorical.rb +35 -23
  105. data/lib/carray/categorical_iterator.rb +8 -8
  106. data/lib/carray/complex.rb +2 -2
  107. data/lib/carray/conditional.rb +3 -2
  108. data/lib/carray/const_string.rb +10 -0
  109. data/lib/carray/data_type_extension.rb +8 -1
  110. data/lib/carray/fixlen_string.rb +41 -2
  111. data/lib/carray/frame/column_verbs.rb +48 -16
  112. data/lib/carray/frame/concat.rb +17 -3
  113. data/lib/carray/frame/convert.rb +19 -0
  114. data/lib/carray/frame/csv_parser.rb +32 -32
  115. data/lib/carray/frame/describe.rb +4 -2
  116. data/lib/carray/frame/frame.rb +405 -85
  117. data/lib/carray/frame/group.rb +777 -64
  118. data/lib/carray/frame/io.rb +212 -72
  119. data/lib/carray/frame/join.rb +146 -37
  120. data/lib/carray/frame/records.rb +3 -3
  121. data/lib/carray/frame/reshape.rb +89 -11
  122. data/lib/carray/frame/sort.rb +57 -9
  123. data/lib/carray/frame/verbs.rb +384 -49
  124. data/lib/carray/frame/windows.rb +44 -6
  125. data/lib/carray/fuse_source.rb +31 -2
  126. data/lib/carray/inspect.rb +7 -2
  127. data/lib/carray/iterator.rb +32 -0
  128. data/lib/carray/lazy.rb +52 -8
  129. data/lib/carray/mask_gap_fill.rb +37 -17
  130. data/lib/carray/meld_reduce.rb +1 -1
  131. data/lib/carray/methods/choose.rb +3 -2
  132. data/lib/carray/methods/is_in.rb +8 -1
  133. data/lib/carray/methods/meshgrid.rb +3 -1
  134. data/lib/carray/runtime.rb +47 -8
  135. data/lib/carray/segment_iterator.rb +35 -16
  136. data/lib/carray/serialize.rb +53 -19
  137. data/lib/carray/stack.rb +33 -18
  138. data/lib/carray/string.rb +8 -0
  139. data/lib/carray/string_operation_extension.rb +13 -5
  140. data/lib/carray/struct_builder.rb +5 -3
  141. data/lib/carray/time.rb +112 -68
  142. data/lib/carray/window_iterator.rb +16 -4
  143. data/yard-stubs/ca_obj_array.rb +26 -1
  144. data/yard-stubs/ca_obj_transpose.rb +5 -4
  145. data/yard-stubs/carray_attribute.rb +3 -1
  146. data/yard-stubs/carray_cast.rb +10 -5
  147. data/yard-stubs/carray_conversion.rb +13 -3
  148. data/yard-stubs/carray_element.rb +7 -6
  149. data/yard-stubs/carray_mask.rb +28 -4
  150. data/yard-stubs/carray_math.rb +45 -20
  151. data/yard-stubs/carray_memory_view.rb +7 -0
  152. data/yard-stubs/carray_order.rb +100 -4
  153. data/yard-stubs/carray_scatter.rb +7 -5
  154. data/yard-stubs/carray_test.rb +7 -4
  155. metadata +18 -4
data/ext/carray_order.c CHANGED
@@ -242,7 +242,13 @@ rb_ca_project (int argc, VALUE *argv, VALUE self)
242
242
  char *lfval, *ufval;
243
243
  int self_is_face;
244
244
 
245
- rb_scan_args(argc, argv, "12", (VALUE *)&ridx, (VALUE *) &vlfval, (VALUE *) &vufval);
245
+ {
246
+ VALUE ropt = Qnil;
247
+ /* project takes no keyword: one given was read as a fill value. */
248
+ rb_scan_args(argc, argv, "12:", (VALUE *)&ridx, (VALUE *) &vlfval,
249
+ (VALUE *) &vufval, &ropt);
250
+ rb_scan_options(ropt, "");
251
+ }
246
252
 
247
253
  TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
248
254
  self_is_face = ca_is_face(ca);
@@ -721,13 +727,14 @@ rb_ca_range_method (VALUE self)
721
727
 
722
728
  /* ---- nlargest / nsmallest family ------------------------------------- */
723
729
 
724
- /* The partition picks the right values but, among cells that tie with the
725
- last one picked, any of them. The answer is the cells first in the
726
- order (value, then NaN, then masked; the values descending for the
727
- largest) with ties broken by position, as `order` breaks them. So the
728
- tied candidates are replaced by the earliest cells that tie, and the
729
- candidates are sorted by (order, position): O(n) per fiber besides the
730
- sort of the candidates. */
730
+ /* The answer is the cells first in the order (value, then NaN, then
731
+ masked; the values descending for the largest) with ties broken by
732
+ position, as `order` breaks them. Fewer cells than the fiber are found
733
+ by the buffered walk below. The other routes (the whole fiber, and the
734
+ keys the walk does not read) sort or partition every cell, which picks
735
+ the right values but, among cells that tie with the last one picked,
736
+ any of them; ca_topk_stable replaces the tied candidates by the
737
+ earliest cells that tie and sorts the candidates by (order, position). */
731
738
 
732
739
  typedef struct {
733
740
  const char *v; /* the fiber's values, contiguous */
@@ -892,8 +899,9 @@ ca_topk_stable (VALUE self, VALUE picked, long axis, int desc)
892
899
  for (k = 0; k < ndim; k++) inv[NUM2INT(perm[k])] = INT2FIX(k);
893
900
  }
894
901
  /* An entity whose fibers already lie along its last axis is read in
895
- place; anything else is copied into that layout. */
896
- if ( last && ca_is_entity(cv) ) {
902
+ place; anything else is copied into that layout, as is an entity
903
+ that leaves ptr NULL at rest (a CASource). */
904
+ if ( last && ca_is_entity(cv) && cv->ptr ) {
897
905
  vals = key;
898
906
  ca_update_mask(cv);
899
907
  }
@@ -936,6 +944,206 @@ ca_topk_has_cells_after_numbers (VALUE self, CArray *ca)
936
944
  return 0;
937
945
  }
938
946
 
947
+ /* ---- the buffered walk ------------------------------------------------
948
+ Each fiber is read once. The cells that come before the cut (the last
949
+ of the cap cells kept so far, in (order, position)) are collected in a
950
+ buffer of a few times cap; when it fills, a selection keeps the first
951
+ cap and the cut moves up. The work area is the buffer, whatever the
952
+ length of the fiber, and a fiber in order costs one selection per
953
+ bufferful instead of a heap update per cell.
954
+
955
+ The walk is written once as a macro over three others: CLASS(i) (0 a
956
+ value, 1 NaN, 2 masked), AFTER(i, j) (cell i comes after cell j in
957
+ (order, position)) and ENTERS(j) (cell j comes before the cut), and
958
+ instantiated per type so that the comparisons
959
+ are inline. The fixlen type takes the generic comparison. */
960
+
961
+ /* Rearranges b[0..nb) so that b[0..cap) hold the cap cells first in
962
+ (order, position): quickselect with median-of-three pivots; past a
963
+ depth limit the remaining range is sorted (tmp holds nb positions). */
964
+ #define CA_TOPK_SELECT(AFTER) \
965
+ do { \
966
+ lo = 0; hi = nb; \
967
+ depth = 2; \
968
+ for (s = nb; s > 1; s >>= 1) depth += 2; \
969
+ while ( hi - lo > 16 ) { \
970
+ mid = lo + ( hi - lo ) / 2; last = hi - 1; \
971
+ if ( depth-- == 0 ) break; \
972
+ if ( AFTER(b[lo], b[mid]) ) { t = b[lo]; b[lo] = b[mid]; b[mid] = t; } \
973
+ if ( AFTER(b[mid], b[last]) ) { t = b[mid]; b[mid] = b[last]; b[last] = t; } \
974
+ if ( AFTER(b[lo], b[mid]) ) { t = b[lo]; b[lo] = b[mid]; b[mid] = t; } \
975
+ t = b[mid]; b[mid] = b[last]; b[last] = t; \
976
+ for (s = lo, i = lo; i < last; i++) { \
977
+ if ( AFTER(b[last], b[i]) ) { t = b[s]; b[s] = b[i]; b[i] = t; s++; } \
978
+ } \
979
+ t = b[s]; b[s] = b[last]; b[last] = t; \
980
+ if ( s == cap || s + 1 == cap ) { lo = hi; break; } \
981
+ if ( cap < s ) hi = s; \
982
+ else lo = s + 1; \
983
+ } \
984
+ if ( hi > lo ) ca_topk_sort(f, b + lo, tmp, hi - lo); \
985
+ } while (0)
986
+
987
+ #define CA_TOPK_DEFINE_BUF(NAME, T, CLASS, AFTER, ENTERS) \
988
+ static void \
989
+ NAME (const ca_topk_fiber_t *f, ca_size_t len, ca_size_t cap, \
990
+ ca_size_t *b, ca_size_t *tmp, ca_size_t size) \
991
+ { \
992
+ const T *v_ = (const T *) f->v; \
993
+ ca_size_t j, nb = 0, cut = 0, lo, hi, i, s, t, mid, last; \
994
+ int rc_ = 3, depth; \
995
+ T rv_; \
996
+ (void) v_; \
997
+ memset(&rv_, 0, sizeof(rv_)); \
998
+ for (j = 0; j < len; j++) { \
999
+ if ( rc_ != 3 && ! ( ENTERS(j) ) ) continue; \
1000
+ b[nb++] = j; \
1001
+ if ( nb == size ) { \
1002
+ CA_TOPK_SELECT(AFTER); \
1003
+ nb = cap; \
1004
+ } \
1005
+ else if ( ! ( nb == cap && rc_ == 3 ) ) { /* the first cap cells */ \
1006
+ continue; \
1007
+ } \
1008
+ cut = b[0]; \
1009
+ for (i = 1; i < cap; i++) if ( AFTER(b[i], cut) ) cut = b[i]; \
1010
+ rc_ = CLASS(cut); \
1011
+ if ( rc_ == 0 ) memcpy(&rv_, f->v + cut * f->bytes, sizeof(rv_)); \
1012
+ } \
1013
+ if ( nb > cap ) CA_TOPK_SELECT(AFTER); \
1014
+ ca_topk_sort(f, b, tmp, cap); \
1015
+ }
1016
+
1017
+ /* The typed comparisons. A cell enters when it comes before the cut;
1018
+ one that ties the cut does not, it lies later. */
1019
+ #define CA_TOPK_CLASS_INT(i) ( ( f->m && f->m[i] ) ? 2 : 0 )
1020
+ #define CA_TOPK_CLASS_FLT(i) ( ( f->m && f->m[i] ) ? 2 : ( isnan(v_[i]) ? 1 : 0 ) )
1021
+ #define CA_TOPK_AFTER_V(CLASS, i, j) \
1022
+ ( CLASS(i) != CLASS(j) ? CLASS(i) > CLASS(j) \
1023
+ : ( CLASS(i) == 0 && v_[i] != v_[j] ) \
1024
+ ? ( f->desc ? v_[i] < v_[j] : v_[i] > v_[j] ) \
1025
+ : (i) > (j) )
1026
+ #define CA_TOPK_AFTER_INT(i, j) CA_TOPK_AFTER_V(CA_TOPK_CLASS_INT, i, j)
1027
+ #define CA_TOPK_AFTER_FLT(i, j) CA_TOPK_AFTER_V(CA_TOPK_CLASS_FLT, i, j)
1028
+ #define CA_TOPK_ENTERS_V(CLASS, j) \
1029
+ ( CLASS(j) < rc_ || \
1030
+ ( CLASS(j) == 0 && rc_ == 0 && \
1031
+ ( f->desc ? v_[j] > rv_ : v_[j] < rv_ ) ) )
1032
+ #define CA_TOPK_ENTERS_INT(j) CA_TOPK_ENTERS_V(CA_TOPK_CLASS_INT, j)
1033
+ #define CA_TOPK_ENTERS_FLT(j) CA_TOPK_ENTERS_V(CA_TOPK_CLASS_FLT, j)
1034
+
1035
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_u8, uint8_t, CA_TOPK_CLASS_INT, CA_TOPK_AFTER_INT, CA_TOPK_ENTERS_INT)
1036
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_i8, int8_t, CA_TOPK_CLASS_INT, CA_TOPK_AFTER_INT, CA_TOPK_ENTERS_INT)
1037
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_i16, int16_t, CA_TOPK_CLASS_INT, CA_TOPK_AFTER_INT, CA_TOPK_ENTERS_INT)
1038
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_u16, uint16_t, CA_TOPK_CLASS_INT, CA_TOPK_AFTER_INT, CA_TOPK_ENTERS_INT)
1039
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_i32, int32_t, CA_TOPK_CLASS_INT, CA_TOPK_AFTER_INT, CA_TOPK_ENTERS_INT)
1040
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_u32, uint32_t, CA_TOPK_CLASS_INT, CA_TOPK_AFTER_INT, CA_TOPK_ENTERS_INT)
1041
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_i64, int64_t, CA_TOPK_CLASS_INT, CA_TOPK_AFTER_INT, CA_TOPK_ENTERS_INT)
1042
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_u64, uint64_t, CA_TOPK_CLASS_INT, CA_TOPK_AFTER_INT, CA_TOPK_ENTERS_INT)
1043
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_f32, float, CA_TOPK_CLASS_FLT, CA_TOPK_AFTER_FLT, CA_TOPK_ENTERS_FLT)
1044
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_f64, double, CA_TOPK_CLASS_FLT, CA_TOPK_AFTER_FLT, CA_TOPK_ENTERS_FLT)
1045
+
1046
+ /* fixlen: the generic comparison; v_ is unused. */
1047
+ #define CA_TOPK_CLASS_GEN(i) ca_topk_class(f, i)
1048
+ #define CA_TOPK_AFTER_GEN(i, j) ca_topk_after(f, i, j)
1049
+ #define CA_TOPK_ENTERS_GEN(j) ( ca_topk_cmp(f, j, cut) < 0 )
1050
+
1051
+ /* Whether cell i comes after cell j in (order, position). */
1052
+ static int
1053
+ ca_topk_after (const ca_topk_fiber_t *f, ca_size_t i, ca_size_t j)
1054
+ {
1055
+ int r = ca_topk_cmp(f, i, j);
1056
+ return r > 0 || ( r == 0 && i > j );
1057
+ }
1058
+
1059
+ CA_TOPK_DEFINE_BUF(ca_topk_buf_gen, char, CA_TOPK_CLASS_GEN, CA_TOPK_AFTER_GEN, CA_TOPK_ENTERS_GEN)
1060
+
1061
+ #undef CA_TOPK_DEFINE_BUF
1062
+ #undef CA_TOPK_SELECT
1063
+ #undef CA_TOPK_CLASS_INT
1064
+ #undef CA_TOPK_CLASS_FLT
1065
+ #undef CA_TOPK_AFTER_V
1066
+ #undef CA_TOPK_AFTER_INT
1067
+ #undef CA_TOPK_AFTER_FLT
1068
+ #undef CA_TOPK_ENTERS_V
1069
+ #undef CA_TOPK_ENTERS_INT
1070
+ #undef CA_TOPK_ENTERS_FLT
1071
+ #undef CA_TOPK_CLASS_GEN
1072
+ #undef CA_TOPK_AFTER_GEN
1073
+ #undef CA_TOPK_ENTERS_GEN
1074
+
1075
+ /* The first cap cells of one fiber in (order, position), sorted, into
1076
+ b[0..cap). b and tmp hold size positions, cap < size <= len. */
1077
+ static void
1078
+ ca_topk_buf_fiber (const ca_topk_fiber_t *f, ca_size_t len, ca_size_t cap,
1079
+ ca_size_t *b, ca_size_t *tmp, ca_size_t size)
1080
+ {
1081
+ switch ( f->type ) {
1082
+ case CA_BOOLEAN:
1083
+ case CA_UINT8: ca_topk_buf_u8(f, len, cap, b, tmp, size); break;
1084
+ case CA_INT8: ca_topk_buf_i8(f, len, cap, b, tmp, size); break;
1085
+ case CA_INT16: ca_topk_buf_i16(f, len, cap, b, tmp, size); break;
1086
+ case CA_UINT16: ca_topk_buf_u16(f, len, cap, b, tmp, size); break;
1087
+ case CA_INT32: ca_topk_buf_i32(f, len, cap, b, tmp, size); break;
1088
+ case CA_UINT32: ca_topk_buf_u32(f, len, cap, b, tmp, size); break;
1089
+ case CA_INT64: ca_topk_buf_i64(f, len, cap, b, tmp, size); break;
1090
+ case CA_UINT64: ca_topk_buf_u64(f, len, cap, b, tmp, size); break;
1091
+ case CA_FLOAT32: ca_topk_buf_f32(f, len, cap, b, tmp, size); break;
1092
+ case CA_FLOAT64: ca_topk_buf_f64(f, len, cap, b, tmp, size); break;
1093
+ default: ca_topk_buf_gen(f, len, cap, b, tmp, size); break;
1094
+ }
1095
+ }
1096
+
1097
+ /* Per-axis top-k positions of `key` (an order key: not object, not
1098
+ complex) by the buffered walk, for cap < the length of the axis. The
1099
+ fibers come in the row-major order of the other axes, so the answer is
1100
+ filled with the axis last and moved into place at the end (cap cells
1101
+ per fiber). */
1102
+ static VALUE
1103
+ ca_topk_buffered_positions (VALUE key, long cap, long axis, int desc)
1104
+ {
1105
+ volatile VALUE holder = 0, out;
1106
+ VALUE perm[CA_RANK_MAX];
1107
+ ca_size_t odim[CA_RANK_MAX];
1108
+ CArray *ck, *co;
1109
+ ca_iter_state st;
1110
+ ca_topk_fiber_t f;
1111
+ ca_size_t *buf, *tmp, n, o = 0, k, len, size;
1112
+ int64_t *op;
1113
+ boolean8_t *m;
1114
+ char *p;
1115
+ int ndim, i, j = 0;
1116
+
1117
+ GetCArray(key, ck);
1118
+ ndim = ck->ndim;
1119
+ for (i = 0; i < ndim; i++) if ( i != axis ) odim[j++] = ck->dim[i];
1120
+ odim[ndim - 1] = cap;
1121
+ len = ck->dim[axis];
1122
+ out = rb_carray_new(CA_INT64, ndim, odim, 0, NULL);
1123
+ GetCArray(out, co);
1124
+ op = (int64_t *) co->ptr;
1125
+
1126
+ f.type = ck->data_type;
1127
+ f.bytes = ck->bytes;
1128
+ f.desc = desc;
1129
+ size = ( len < 4 * cap + 256 ) ? len : 4 * cap + 256;
1130
+ buf = ALLOCV_N(ca_size_t, holder, 2 * size);
1131
+ tmp = buf + size;
1132
+ CA_FOR_EACH_FIBER_MASKED(st, ck, axis, 0, p, n, m) {
1133
+ f.v = p;
1134
+ f.m = m;
1135
+ ca_topk_buf_fiber(&f, n, cap, buf, tmp, size);
1136
+ for (k = 0; k < cap; k++) op[o * cap + k] = (int64_t) buf[k];
1137
+ o++;
1138
+ }
1139
+ ALLOCV_END(holder);
1140
+ if ( axis == ndim - 1 ) return out;
1141
+ for (i = 0; i < ndim; i++) {
1142
+ perm[i] = INT2FIX( i < axis ? i : ( i == axis ? ndim - 1 : i - 1 ) );
1143
+ }
1144
+ return rb_ca_copy(rb_funcallv(out, rb_intern("transpose"), ndim, perm));
1145
+ }
1146
+
939
1147
  /* Per-axis top-k positions (cap clamped, axis normalized).
940
1148
  * Called by rb_ca_topk_index below. */
941
1149
  static VALUE
@@ -946,6 +1154,18 @@ rb_ca_topk_positions (VALUE self, long cap, long axis_norm, int desc)
946
1154
  long dim_axis = (long) ca->dim[axis_norm];
947
1155
  VALUE raxis_norm = LONG2NUM(axis_norm);
948
1156
 
1157
+ /* The buffered walk reads any key but an object (its cells compare in
1158
+ Ruby) or a complex one (no order), and keeps cap cells per fiber. */
1159
+ if ( ca->data_type != CA_OBJECT && ! ca_is_complex_type(ca) ) {
1160
+ VALUE key = ca_order_key(self, desc ? "nlargest" : "nsmallest");
1161
+ CArray *ck;
1162
+ GetCArray(key, ck);
1163
+ if ( ck->data_type != CA_OBJECT && ! ca_is_complex_type(ck) &&
1164
+ cap < dim_axis ) {
1165
+ return ca_topk_buffered_positions(key, cap, axis_norm, desc);
1166
+ }
1167
+ }
1168
+
949
1169
  /* The largest: reversing the ascending order would put the NaN and the
950
1170
  masked cells first, so rank them descending (NaN, then the masked
951
1171
  cells, last) when there are any. An object array is ranked by
data/ext/carray_random.c CHANGED
@@ -165,7 +165,7 @@ ca_random_bang_fill (VALUE arg)
165
165
  ca_rng_bind(&c->source);
166
166
  switch (ca->data_type) {
167
167
  case CA_FLOAT64: {
168
- double *p = (double *)ca->ptr;
168
+ CA_U(double) *p = (CA_U(double) *)ca->ptr;
169
169
  if (is_default) {
170
170
  for (i = 0; i < n; i++)
171
171
  p[i] = ca_random_real(&c->source);
@@ -177,7 +177,7 @@ ca_random_bang_fill (VALUE arg)
177
177
  break;
178
178
  }
179
179
  case CA_FLOAT32: {
180
- float *p = (float *)ca->ptr;
180
+ CA_U(float) *p = (CA_U(float) *)ca->ptr;
181
181
  if (is_default) {
182
182
  for (i = 0; i < n; i++)
183
183
  p[i] = (float)ca_random_real(&c->source);
@@ -189,7 +189,7 @@ ca_random_bang_fill (VALUE arg)
189
189
  break;
190
190
  }
191
191
  case CA_CMPLX128: {
192
- double complex *p = (double complex *)ca->ptr;
192
+ ca_u_cmplx128_t *p = (ca_u_cmplx128_t *)ca->ptr;
193
193
  if (is_default) {
194
194
  for (i = 0; i < n; i++)
195
195
  p[i] = ca_random_real(&c->source) + ca_random_real(&c->source) * I;
@@ -202,7 +202,7 @@ ca_random_bang_fill (VALUE arg)
202
202
  break;
203
203
  }
204
204
  case CA_CMPLX64: {
205
- float complex *p = (float complex *)ca->ptr;
205
+ ca_u_cmplx64_t *p = (ca_u_cmplx64_t *)ca->ptr;
206
206
  if (is_default) {
207
207
  for (i = 0; i < n; i++)
208
208
  p[i] = (float)ca_random_real(&c->source) + (float)ca_random_real(&c->source) * I;
@@ -242,37 +242,37 @@ ca_random_bang_fill (VALUE arg)
242
242
  break;
243
243
  }
244
244
  case CA_INT16: {
245
- int16_t *p = (int16_t *)ca->ptr;
245
+ CA_U(int16_t) *p = (CA_U(int16_t) *)ca->ptr;
246
246
  for (i = 0; i < n; i++)
247
247
  p[i] = (int16_t)(low_long + ca_random_ulong_limited(&c->source, limit));
248
248
  break;
249
249
  }
250
250
  case CA_UINT16: {
251
- uint16_t *p = (uint16_t *)ca->ptr;
251
+ CA_U(uint16_t) *p = (CA_U(uint16_t) *)ca->ptr;
252
252
  for (i = 0; i < n; i++)
253
253
  p[i] = (uint16_t)(low_long + ca_random_ulong_limited(&c->source, limit));
254
254
  break;
255
255
  }
256
256
  case CA_INT32: {
257
- int32_t *p = (int32_t *)ca->ptr;
257
+ CA_U(int32_t) *p = (CA_U(int32_t) *)ca->ptr;
258
258
  for (i = 0; i < n; i++)
259
259
  p[i] = (int32_t)(low_long + ca_random_ulong_limited(&c->source, limit));
260
260
  break;
261
261
  }
262
262
  case CA_UINT32: {
263
- uint32_t *p = (uint32_t *)ca->ptr;
263
+ CA_U(uint32_t) *p = (CA_U(uint32_t) *)ca->ptr;
264
264
  for (i = 0; i < n; i++)
265
265
  p[i] = (uint32_t)(low_long + ca_random_ulong_limited(&c->source, limit));
266
266
  break;
267
267
  }
268
268
  case CA_INT64: {
269
- int64_t *p = (int64_t *)ca->ptr;
269
+ CA_U(int64_t) *p = (CA_U(int64_t) *)ca->ptr;
270
270
  for (i = 0; i < n; i++)
271
271
  p[i] = (int64_t)(low_long + ca_random_ulong_limited(&c->source, limit));
272
272
  break;
273
273
  }
274
274
  case CA_UINT64: {
275
- uint64_t *p = (uint64_t *)ca->ptr;
275
+ CA_U(uint64_t) *p = (CA_U(uint64_t) *)ca->ptr;
276
276
  for (i = 0; i < n; i++)
277
277
  p[i] = (uint64_t)(low_long + ca_random_ulong_limited(&c->source, limit));
278
278
  break;
@@ -483,19 +483,19 @@ ca_randomn_bang_fill (VALUE arg)
483
483
  if (c->source.kind == CA_RNG_OWN) {
484
484
  switch (ca->data_type) {
485
485
  case CA_FLOAT64: {
486
- double *p = (double *)ca->ptr;
486
+ CA_U(double) *p = (CA_U(double) *)ca->ptr;
487
487
  for (i = 0; i < n; i++)
488
488
  p[i] = ca_random_normal(&c->source);
489
489
  break;
490
490
  }
491
491
  case CA_FLOAT32: {
492
- float *p = (float *)ca->ptr;
492
+ CA_U(float) *p = (CA_U(float) *)ca->ptr;
493
493
  for (i = 0; i < n; i++)
494
494
  p[i] = (float) ca_random_normal(&c->source);
495
495
  break;
496
496
  }
497
497
  case CA_CMPLX128: {
498
- double complex *p = (double complex *)ca->ptr;
498
+ ca_u_cmplx128_t *p = (ca_u_cmplx128_t *)ca->ptr;
499
499
  for (i = 0; i < n; i++) {
500
500
  /* Into locals first: C does not say which order a call's
501
501
  arguments are evaluated in, and these two advance a state. */
@@ -506,7 +506,7 @@ ca_randomn_bang_fill (VALUE arg)
506
506
  break;
507
507
  }
508
508
  case CA_CMPLX64: {
509
- float complex *p = (float complex *)ca->ptr;
509
+ ca_u_cmplx64_t *p = (ca_u_cmplx64_t *)ca->ptr;
510
510
  for (i = 0; i < n; i++) {
511
511
  double re = ca_random_normal(&c->source);
512
512
  double im = ca_random_normal(&c->source);
@@ -522,10 +522,13 @@ ca_randomn_bang_fill (VALUE arg)
522
522
 
523
523
  switch (ca->data_type) {
524
524
  case CA_FLOAT64: {
525
- double *p = (double *)ca->ptr;
525
+ CA_U(double) *p = (CA_U(double) *)ca->ptr;
526
526
  ca_size_t pairs = n / 2;
527
527
  for (i = 0; i < pairs; i++) {
528
- box_muller_pair(&c->source, &p[2*i], &p[2*i+1]);
528
+ double r1, r2;
529
+ box_muller_pair(&c->source, &r1, &r2);
530
+ p[2*i] = r1;
531
+ p[2*i+1] = r2;
529
532
  }
530
533
  if (n % 2 == 1) {
531
534
  double r1, r2;
@@ -535,7 +538,7 @@ ca_randomn_bang_fill (VALUE arg)
535
538
  break;
536
539
  }
537
540
  case CA_FLOAT32: {
538
- float *p = (float *)ca->ptr;
541
+ CA_U(float) *p = (CA_U(float) *)ca->ptr;
539
542
  ca_size_t pairs = n / 2;
540
543
  for (i = 0; i < pairs; i++) {
541
544
  double r1, r2;
@@ -551,7 +554,7 @@ ca_randomn_bang_fill (VALUE arg)
551
554
  break;
552
555
  }
553
556
  case CA_CMPLX128: {
554
- double complex *p = (double complex *)ca->ptr;
557
+ ca_u_cmplx128_t *p = (ca_u_cmplx128_t *)ca->ptr;
555
558
  for (i = 0; i < n; i++) {
556
559
  double r1, r2;
557
560
  box_muller_pair(&c->source, &r1, &r2);
@@ -560,7 +563,7 @@ ca_randomn_bang_fill (VALUE arg)
560
563
  break;
561
564
  }
562
565
  case CA_CMPLX64: {
563
- float complex *p = (float complex *)ca->ptr;
566
+ ca_u_cmplx64_t *p = (ca_u_cmplx64_t *)ca->ptr;
564
567
  for (i = 0; i < n; i++) {
565
568
  double r1, r2;
566
569
  box_muller_pair(&c->source, &r1, &r2);
data/ext/carray_scatter.c CHANGED
@@ -13,7 +13,8 @@
13
13
  min / max: real numeric only (complex has no order)
14
14
  (boolean / object / fixlen → CADataTypeError; the bang
15
15
  cannot widen self, same rationale as fma! / fms!)
16
- replace: numeric or boolean (assignment, no widening)
16
+ replace: any type (assignment, no widening); an object or
17
+ fixlen array is written through the indexer
17
18
  scalar any Numeric, true / false, or UNDEF; converted to self's
18
19
  type as the indexer's store converts it (a value that does
19
20
  not fit raises, as `self[i] = v` does)
@@ -63,7 +64,7 @@ typedef union {
63
64
  #define LOOP_SCALAR(T, APPLY) LOOP_SCALAR_V(T, APPLY, SCALAR_REAL(T))
64
65
 
65
66
  #define LOOP_SCALAR_V(T, APPLY, VS) do { \
66
- T *q = (T *) qbase; \
67
+ CA_U(T) *q = (CA_U(T) *) qbase; \
67
68
  T vs = VS; \
68
69
  if ( mself ) { \
69
70
  for (i = 0; i < n; i++) { \
@@ -85,8 +86,8 @@ typedef union {
85
86
  } while (0)
86
87
 
87
88
  #define LOOP_VEC(T, APPLY) do { \
88
- T *q = (T *) qbase; \
89
- T *r = (T *) cv->ptr; \
89
+ CA_U(T) *q = (CA_U(T) *) qbase; \
90
+ CA_U(T) *r = (CA_U(T) *) cv->ptr; \
90
91
  if ( mself ) { \
91
92
  for (i = 0; i < n; i++) { \
92
93
  if ( maddrs && maddrs[i] ) continue; \
@@ -120,7 +121,7 @@ typedef union {
120
121
  #define LOOP_SCALAR_REPLACE(T) LOOP_SCALAR_REPLACE_V(T, SCALAR_REAL(T))
121
122
 
122
123
  #define LOOP_SCALAR_REPLACE_V(T, VS) do { \
123
- T *q = (T *) qbase; \
124
+ CA_U(T) *q = (CA_U(T) *) qbase; \
124
125
  T vs = VS; \
125
126
  for (i = 0; i < n; i++) { \
126
127
  if ( maddrs && maddrs[i] ) continue; \
@@ -136,8 +137,8 @@ typedef union {
136
137
  } while (0)
137
138
 
138
139
  #define LOOP_VEC_REPLACE(T) do { \
139
- T *q = (T *) qbase; \
140
- T *r = (T *) cv->ptr; \
140
+ CA_U(T) *q = (CA_U(T) *) qbase; \
141
+ CA_U(T) *r = (CA_U(T) *) cv->ptr; \
141
142
  for (i = 0; i < n; i++) { \
142
143
  if ( maddrs && maddrs[i] ) continue; \
143
144
  addr = p[i]; \
@@ -592,6 +593,22 @@ AT_BODY(ca_scatter_replace_body, DISPATCH_NUMERIC_REPLACE())
592
593
  static VALUE
593
594
  rb_ca_scatter_replace_bang (VALUE self, VALUE raddrs, VALUE rvals)
594
595
  {
596
+ /* An object or fixlen array takes the assignment through the indexer,
597
+ which reads and writes its cells by their own rules (a VALUE kept
598
+ visible to the GC, a fixlen value fitted to the cell); the kernel
599
+ below is for the numeric and boolean cells. */
600
+ {
601
+ CArray *cs;
602
+ TypedData_Get_Struct(self, CArray, &carray_data_type, cs);
603
+ if ( cs->data_type == CA_OBJECT || cs->data_type == CA_FIXLEN ) {
604
+ rb_ca_modify(self);
605
+ if ( RB_TYPE_P(raddrs, T_ARRAY) ) { /* a list of addresses */
606
+ raddrs = rb_ca_wrap_readonly(raddrs, INT2NUM(CA_SIZE));
607
+ }
608
+ rb_funcall(rb_ca_flatten(self), rb_intern("[]="), 2, raddrs, rvals);
609
+ return self;
610
+ }
611
+ }
595
612
  /* Pre-scan: if vals is a masked CArray and self isn't yet masked,
596
613
  promote self so the kernel can flip target cells to masked (indexer
597
614
  `self[addrs] = vals` establishes self.mask lazily the same way). */