carray 3.0.3 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +469 -0
  3. data/README.md +3 -2
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_array_pool.c +25 -1
  6. data/ext/ca_axis_descriptor.h +27 -24
  7. data/ext/ca_axis_dispatch.c +14 -26
  8. data/ext/ca_axis_group.c +27 -27
  9. data/ext/ca_binop_dispatch.c +1 -29
  10. data/ext/ca_binop_dispatch.h +0 -1
  11. data/ext/ca_categorical_iterator.c +231 -153
  12. data/ext/ca_compare.c +9 -20
  13. data/ext/ca_composite_dispatch.c +9 -9
  14. data/ext/ca_group_iter.c +16 -17
  15. data/ext/ca_kernel_iterator.c +1240 -2000
  16. data/ext/ca_kernel_iterator.h +502 -519
  17. data/ext/ca_monop_dispatch.c +82 -59
  18. data/ext/ca_monop_dispatch.h +1 -0
  19. data/ext/ca_obj_array.c +152 -45
  20. data/ext/ca_obj_bincmp.c +25 -21
  21. data/ext/ca_obj_binop.c +16 -26
  22. data/ext/ca_obj_bitarray.c +8 -3
  23. data/ext/ca_obj_bitfield.c +63 -49
  24. data/ext/ca_obj_block.c +18 -9
  25. data/ext/ca_obj_byte_swap.c +7 -7
  26. data/ext/ca_obj_const_string.c +188 -22
  27. data/ext/ca_obj_face.c +280 -58
  28. data/ext/ca_obj_face.h +19 -0
  29. data/ext/ca_obj_fake.c +15 -29
  30. data/ext/ca_obj_farray.c +6 -3
  31. data/ext/ca_obj_field.c +30 -8
  32. data/ext/ca_obj_fixlen_string.c +2 -3
  33. data/ext/ca_obj_grid.c +455 -134
  34. data/ext/ca_obj_meld.c +172 -34
  35. data/ext/ca_obj_moncmp.c +23 -8
  36. data/ext/ca_obj_monop.c +113 -67
  37. data/ext/ca_obj_object.c +210 -52
  38. data/ext/ca_obj_record.c +15 -7
  39. data/ext/ca_obj_reduce.c +17 -8
  40. data/ext/ca_obj_refer.c +42 -35
  41. data/ext/ca_obj_remap.c +30 -9
  42. data/ext/ca_obj_repeat.c +9 -10
  43. data/ext/ca_obj_roll.c +31 -10
  44. data/ext/ca_obj_select.c +48 -14
  45. data/ext/ca_obj_select_axis.c +15 -47
  46. data/ext/ca_obj_shift.c +41 -7
  47. data/ext/ca_obj_stack.c +180 -34
  48. data/ext/ca_obj_stride.c +190 -134
  49. data/ext/ca_obj_string.c +80 -4
  50. data/ext/ca_obj_tile.c +32 -11
  51. data/ext/ca_obj_time.c +22 -6
  52. data/ext/ca_obj_timedelta.c +22 -6
  53. data/ext/ca_obj_transpose.c +13 -7
  54. data/ext/ca_obj_triop.c +26 -32
  55. data/ext/ca_obj_window.c +267 -74
  56. data/ext/ca_op_ipower.c +4 -4
  57. data/ext/ca_sort_kernels.h +6 -3
  58. data/ext/ca_sweep_engine.c +2 -2
  59. data/ext/caframe_csv_reader.c +80 -1
  60. data/ext/carray.h +214 -75
  61. data/ext/carray_access.c +200 -99
  62. data/ext/carray_address_basis.c +343 -87
  63. data/ext/carray_attribute.c +113 -6
  64. data/ext/carray_bincount.c +10 -8
  65. data/ext/carray_broadcast.c +13 -8
  66. data/ext/carray_build_flags.h +3 -0
  67. data/ext/carray_call_cfunc.c +108 -0
  68. data/ext/carray_cast.c +375 -96
  69. data/ext/carray_cast_func.rb +90 -20
  70. data/ext/carray_class.c +4 -3
  71. data/ext/carray_config.h +28 -0
  72. data/ext/carray_conversion.c +18 -9
  73. data/ext/carray_copy.c +51 -14
  74. data/ext/carray_core.c +150 -55
  75. data/ext/carray_count.c +56 -20
  76. data/ext/carray_element.c +81 -33
  77. data/ext/carray_factorize.c +138 -84
  78. data/ext/carray_generate.c +199 -52
  79. data/ext/carray_histogram.c +63 -18
  80. data/ext/carray_hold.c +12 -15
  81. data/ext/carray_index_classifier.c +388 -176
  82. data/ext/carray_internal.h +348 -29
  83. data/ext/carray_kernels_bincmp.c +4453 -0
  84. data/ext/carray_kernels_binop.c +11368 -0
  85. data/ext/carray_kernels_init.c +1734 -0
  86. data/ext/carray_kernels_moncmp.c +2104 -0
  87. data/ext/carray_kernels_monop.c +18369 -0
  88. data/ext/carray_kernels_reduce_aggregate.c +23818 -0
  89. data/ext/carray_kernels_reduce_boolean.c +406 -0
  90. data/ext/carray_kernels_reduce_cumulative.c +10086 -0
  91. data/ext/carray_kernels_reduce_extreme.c +17634 -0
  92. data/ext/carray_kernels_reduce_variance.c +3849 -0
  93. data/ext/carray_kernels_scan.c +4302 -0
  94. data/ext/carray_kernels_search.c +33829 -0
  95. data/ext/carray_kernels_sort.c +10897 -0
  96. data/ext/carray_kernels_triop.c +1864 -0
  97. data/ext/carray_key_windows.c +220 -0
  98. data/ext/carray_lazy.c +170 -111
  99. data/ext/carray_mask.c +337 -94
  100. data/ext/carray_median_percentile.c +82 -28
  101. data/ext/carray_memory_view.c +669 -561
  102. data/ext/carray_operator.c +129 -52
  103. data/ext/carray_order.c +604 -77
  104. data/ext/carray_partition.c +28 -27
  105. data/ext/carray_random.c +85 -31
  106. data/ext/carray_round.c +273 -0
  107. data/ext/carray_scatter.c +87 -45
  108. data/ext/carray_segment.c +3 -3
  109. data/ext/carray_slab.c +123 -37
  110. data/ext/carray_sort.c +259 -51
  111. data/ext/carray_sort_kernel.c +5 -7
  112. data/ext/carray_struct.c +54 -61
  113. data/ext/carray_test.c +26 -5
  114. data/ext/carray_time_text.c +4 -2
  115. data/ext/carray_undef.c +4 -0
  116. data/ext/carray_utils.c +309 -66
  117. data/ext/mk_call_cfunc.rb +19 -2
  118. data/ext/mkkernel.rb +403 -350
  119. data/ext/ruby_carray.c +10 -4
  120. data/ext/version.h +4 -4
  121. data/lib/carray/attribute.rb +139 -22
  122. data/lib/carray/autoload_carray.rb +8 -31
  123. data/lib/carray/autoload_method_extension.rb +14 -5
  124. data/lib/carray/axis_group.rb +255 -106
  125. data/lib/carray/basics.rb +105 -17
  126. data/lib/carray/bincount_nd.rb +12 -2
  127. data/lib/carray/block_iterator.rb +126 -23
  128. data/lib/carray/boolean_reduce.rb +17 -17
  129. data/lib/carray/categorical.rb +195 -59
  130. data/lib/carray/categorical_iterator.rb +132 -29
  131. data/lib/carray/complex.rb +5 -5
  132. data/lib/carray/conditional.rb +67 -18
  133. data/lib/carray/const_string.rb +24 -5
  134. data/lib/carray/construct.rb +15 -11
  135. data/lib/carray/data_type_extension.rb +9 -1
  136. data/lib/carray/distance_limit.rb +77 -0
  137. data/lib/carray/fixlen_string.rb +48 -3
  138. data/lib/carray/frame/column_verbs.rb +71 -0
  139. data/lib/carray/frame/concat.rb +17 -3
  140. data/lib/carray/frame/convert.rb +69 -0
  141. data/lib/carray/frame/csv_parser.rb +111 -17
  142. data/lib/carray/frame/describe.rb +3 -2
  143. data/lib/carray/frame/frame.rb +252 -28
  144. data/lib/carray/frame/group.rb +603 -101
  145. data/lib/carray/frame/io.rb +117 -28
  146. data/lib/carray/frame/join.rb +312 -51
  147. data/lib/carray/frame/records.rb +83 -7
  148. data/lib/carray/frame/reshape.rb +42 -35
  149. data/lib/carray/frame/sort.rb +7 -19
  150. data/lib/carray/frame/verbs.rb +188 -48
  151. data/lib/carray/frame/windows.rb +117 -0
  152. data/lib/carray/frame.rb +2 -0
  153. data/lib/carray/fuse_source.rb +42 -6
  154. data/lib/carray/fusion.rb +40 -16
  155. data/lib/carray/histogram.rb +6 -1
  156. data/lib/carray/inspect.rb +31 -8
  157. data/lib/carray/iterator.rb +85 -7
  158. data/lib/carray/key_windows.rb +620 -0
  159. data/lib/carray/lazy.rb +217 -183
  160. data/lib/carray/mask_gap_fill.rb +63 -57
  161. data/lib/carray/meld_reduce.rb +12 -14
  162. data/lib/carray/methods/bin.rb +26 -18
  163. data/lib/carray/methods/bincount.rb +16 -0
  164. data/lib/carray/methods/bit_string.rb +1 -1
  165. data/lib/carray/methods/choose.rb +16 -3
  166. data/lib/carray/methods/composition.rb +3 -1
  167. data/lib/carray/methods/gather_nd.rb +14 -5
  168. data/lib/carray/methods/insert_block.rb +2 -2
  169. data/lib/carray/methods/is_between.rb +59 -0
  170. data/lib/carray/methods/is_in.rb +61 -37
  171. data/lib/carray/methods/join.rb +1 -6
  172. data/lib/carray/methods/lag.rb +49 -0
  173. data/lib/carray/methods/locate_addr.rb +47 -51
  174. data/lib/carray/methods/mode.rb +1 -1
  175. data/lib/carray/methods/nunique.rb +11 -6
  176. data/lib/carray/methods/resize.rb +3 -3
  177. data/lib/carray/methods/value_counts.rb +4 -11
  178. data/lib/carray/record_order.rb +3 -3
  179. data/lib/carray/rng.rb +3 -0
  180. data/lib/carray/runtime.rb +53 -8
  181. data/lib/carray/segment_iterator.rb +323 -88
  182. data/lib/carray/serialize.rb +45 -14
  183. data/lib/carray/slab_iterator.rb +50 -0
  184. data/lib/carray/stack.rb +15 -12
  185. data/lib/carray/string.rb +113 -5
  186. data/lib/carray/string_operation_extension.rb +21 -6
  187. data/lib/carray/struct.rb +9 -21
  188. data/lib/carray/struct_builder.rb +24 -11
  189. data/lib/carray/time.rb +819 -158
  190. data/lib/carray/window_iterator.rb +122 -16
  191. data/lib/carray.rb +7 -0
  192. data/yard-stubs/ca_obj_bitfield.rb +1 -1
  193. data/yard-stubs/ca_obj_field.rb +4 -0
  194. data/yard-stubs/ca_obj_grid.rb +21 -10
  195. data/yard-stubs/ca_obj_refer.rb +2 -1
  196. data/yard-stubs/ca_obj_roll.rb +2 -2
  197. data/yard-stubs/ca_obj_shift.rb +5 -1
  198. data/yard-stubs/ca_obj_tile.rb +1 -1
  199. data/yard-stubs/ca_obj_transpose.rb +5 -4
  200. data/yard-stubs/ca_obj_window.rb +8 -3
  201. data/yard-stubs/carray_access.rb +6 -1
  202. data/yard-stubs/carray_attribute.rb +3 -6
  203. data/yard-stubs/carray_cast.rb +12 -0
  204. data/yard-stubs/carray_conversion.rb +7 -2
  205. data/yard-stubs/carray_copy.rb +4 -2
  206. data/yard-stubs/carray_count.rb +4 -4
  207. data/yard-stubs/carray_element.rb +17 -10
  208. data/yard-stubs/carray_generate.rb +21 -1
  209. data/yard-stubs/carray_mask.rb +32 -3
  210. data/yard-stubs/carray_math.rb +41 -5
  211. data/yard-stubs/carray_median_percentile.rb +5 -2
  212. data/yard-stubs/carray_memory_view.rb +40 -23
  213. data/yard-stubs/carray_order.rb +129 -22
  214. data/yard-stubs/carray_random.rb +13 -4
  215. data/yard-stubs/carray_scatter.rb +17 -10
  216. data/yard-stubs/carray_slab.rb +9 -2
  217. data/yard-stubs/carray_sort.rb +6 -5
  218. data/yard-stubs/carray_test.rb +5 -3
  219. metadata +25 -3
  220. data/lib/carray/arrow_tensor.rb +0 -401
  221. data/lib/carray/table.rb +0 -108
@@ -0,0 +1,220 @@
1
+ /* ---------------------------------------------------------------------------
2
+
3
+ Key windows: the rows each row's window holds when the window is bounded by
4
+ a width of a key (a time or a number) rather than by a count of cells.
5
+ Backing primitive for `windows(on:)` (lib/carray/key_windows.rb).
6
+
7
+ The Ruby side sorts the rows by (group, key), drops the rows whose key or
8
+ group is masked, and hands the sorted keys and group codes here. One walk
9
+ with two pointers gives each row the range [lo, hi) of sorted positions in
10
+ its window: within a group the key does not decrease, so both bounds of the
11
+ window only move forward.
12
+
13
+ With points given (`windows(at:)`), the windows sit at the points instead
14
+ of at the rows: the walk goes over the sorted points, one window each, and
15
+ the two pointers move over the sorted keys of a single group.
16
+
17
+ ---------------------------------------------------------------------------- */
18
+
19
+ #include <stdint.h>
20
+ #include <math.h>
21
+ #include "ruby.h"
22
+ #include "carray.h"
23
+
24
+ /* Whether key k lies inside the window of an anchor t:
25
+ lower bound t - before, upper bound t + after,
26
+ each bound excluded when the matching flag is set. */
27
+ #define KW_ABOVE_LOWER(k, lo_b, ex_lo) ((ex_lo) ? ((k) > (lo_b)) : ((k) >= (lo_b)))
28
+ #define KW_BELOW_UPPER(k, hi_b, ex_hi) ((ex_hi) ? ((k) < (hi_b)) : ((k) <= (hi_b)))
29
+
30
+ /* The walk, written once for an int64 key and once for a float64 key. ON_GRID
31
+ tells whether key k lies on the interval grid that starts at anchor t.
32
+ BOUNDS sets lo_b and hi_b, and lo_open / hi_open when a bound lies beyond
33
+ the range of T, so that every key of the group is inside it. */
34
+ #define KW_WALK(T, ON_GRID, BOUNDS) \
35
+ { \
36
+ const T *key = (const T *) ck->ptr; \
37
+ const T before = (T) vbefore, after = (T) vafter, iv = (T) viv; \
38
+ ca_size_t lo = 0, hi = 0, gstart = 0; \
39
+ for (ca_size_t i = 0; i < n; i++) { \
40
+ if ( i > 0 && grp[i] != grp[i-1] ) { \
41
+ gstart = i; lo = i; hi = i; \
42
+ } \
43
+ else if ( i > 0 && key[i] < key[i-1] ) { \
44
+ rb_raise(rb_eArgError, \
45
+ "windows: the keys are not sorted within a group"); \
46
+ } \
47
+ if ( lo < gstart ) lo = gstart; \
48
+ if ( hi < lo ) hi = lo; \
49
+ const T t = key[i]; \
50
+ T lo_b, hi_b; \
51
+ int lo_open, hi_open; \
52
+ BOUNDS; \
53
+ while ( lo < n && grp[lo] == grp[i] && !lo_open && \
54
+ !KW_ABOVE_LOWER(key[lo], lo_b, ex_lo) ) lo++; \
55
+ if ( hi < lo ) hi = lo; \
56
+ while ( hi < n && grp[hi] == grp[i] && \
57
+ ( hi_open || KW_BELOW_UPPER(key[hi], hi_b, ex_hi) ) ) hi++; \
58
+ plo[i] = lo; \
59
+ phi[i] = hi; \
60
+ if ( pcomplete ) { \
61
+ int64_t distinct = 0; \
62
+ int ok = 1; \
63
+ for (ca_size_t j = lo; j < hi; j++) { \
64
+ const T k = key[j]; \
65
+ if ( j == lo || k != key[j-1] ) distinct++; \
66
+ if ( !(ON_GRID) ) { ok = 0; break; } \
67
+ } \
68
+ pcomplete[i] = ( ok && distinct == nexp ) ? 1 : 0; \
69
+ } \
70
+ } \
71
+ }
72
+
73
+ /* The walk over points: the window of point t holds the keys within its
74
+ bounds. The keys form one group (at: refuses by:), and both the keys and
75
+ the points are sorted, so both pointers only move forward. */
76
+ #define KW_WALK_AT(T, ON_GRID, BOUNDS) \
77
+ { \
78
+ const T *key = (const T *) ck->ptr; \
79
+ const T *pts = (const T *) cp->ptr; \
80
+ const T before = (T) vbefore, after = (T) vafter, iv = (T) viv; \
81
+ ca_size_t lo = 0, hi = 0; \
82
+ for (ca_size_t j = 1; j < n; j++) { \
83
+ if ( key[j] < key[j-1] ) { \
84
+ rb_raise(rb_eArgError, "windows: the keys are not sorted"); \
85
+ } \
86
+ } \
87
+ for (ca_size_t i = 0; i < nout; i++) { \
88
+ if ( i > 0 && pts[i] < pts[i-1] ) { \
89
+ rb_raise(rb_eArgError, "windows: the points are not sorted"); \
90
+ } \
91
+ const T t = pts[i]; \
92
+ T lo_b, hi_b; \
93
+ int lo_open, hi_open; \
94
+ BOUNDS; \
95
+ while ( lo < n && !lo_open && !KW_ABOVE_LOWER(key[lo], lo_b, ex_lo) ) \
96
+ lo++; \
97
+ if ( hi < lo ) hi = lo; \
98
+ while ( hi < n && ( hi_open || KW_BELOW_UPPER(key[hi], hi_b, ex_hi) ) ) \
99
+ hi++; \
100
+ plo[i] = lo; \
101
+ phi[i] = hi; \
102
+ if ( pcomplete ) { \
103
+ int64_t distinct = 0; \
104
+ int ok = 1; \
105
+ for (ca_size_t j = lo; j < hi; j++) { \
106
+ const T k = key[j]; \
107
+ if ( j == lo || k != key[j-1] ) distinct++; \
108
+ if ( !(ON_GRID) ) { ok = 0; break; } \
109
+ } \
110
+ pcomplete[i] = ( ok && distinct == nexp ) ? 1 : 0; \
111
+ } \
112
+ } \
113
+ }
114
+
115
+ /* CArray.__find_key_window_row_ranges__(keys, groups, before, after,
116
+ exclude_lower, exclude_upper,
117
+ interval, expected, points)
118
+ keys: int64 or float64 entity, sorted within each group
119
+ groups: int64 entity, the group code of each row (rows of a group adjacent)
120
+ interval: nil, or the grid step for the completeness test
121
+ expected: the number of grid points a complete window holds
122
+ points: nil for a window at each row; or an entity of the keys' data type,
123
+ sorted, for a window at each point (groups must then be one group)
124
+ Returns [lo, hi, complete]: int64 positions into the sorted rows, one per
125
+ row or per point, and a boolean array (nil when no interval was given). */
126
+ static VALUE
127
+ rb_ca_s_key_window_ranges (VALUE self, VALUE vkeys, VALUE vgroups,
128
+ VALUE rbefore, VALUE rafter,
129
+ VALUE rex_lo, VALUE rex_hi,
130
+ VALUE rinterval, VALUE rexpected, VALUE vpoints)
131
+ {
132
+ CArray *ck, *cg, *cp = NULL, *clo, *chi, *cc = NULL;
133
+ volatile VALUE vlo, vhi, vcomplete = Qnil;
134
+ ca_size_t n, nout;
135
+ int64_t *plo, *phi;
136
+ boolean8_t *pcomplete = NULL;
137
+ int ex_lo = RTEST(rex_lo), ex_hi = RTEST(rex_hi);
138
+ int64_t nexp = 0;
139
+ const int64_t *grp;
140
+
141
+ if ( !rb_obj_is_kind_of(vkeys, rb_cCArray) ||
142
+ !rb_obj_is_kind_of(vgroups, rb_cCArray) ) {
143
+ rb_raise(rb_eTypeError, "__find_key_window_row_ranges__: CArray arguments expected");
144
+ }
145
+ GetCArray(vkeys, ck);
146
+ GetCArray(vgroups, cg);
147
+ if ( ck->obj_type != CA_OBJ_ARRAY || cg->obj_type != CA_OBJ_ARRAY ||
148
+ ck->ndim != 1 || cg->ndim != 1 || cg->data_type != CA_INT64 ||
149
+ ck->elements != cg->elements || ca_has_mask(ck) || ca_has_mask(cg) ||
150
+ ( ck->data_type != CA_INT64 && ck->data_type != CA_FLOAT64 ) ) {
151
+ rb_raise(rb_eArgError, "__find_key_window_row_ranges__: unexpected arguments");
152
+ }
153
+ /* The completeness test takes the key difference modulo the interval. */
154
+ if ( !NIL_P(rinterval) && !(NUM2DBL(rinterval) > 0) ) {
155
+ rb_raise(rb_eArgError, "__find_key_window_row_ranges__: interval should be positive");
156
+ }
157
+ n = ck->elements;
158
+ grp = (const int64_t *) cg->ptr;
159
+ nout = n;
160
+ if ( !NIL_P(vpoints) ) {
161
+ if ( !rb_obj_is_kind_of(vpoints, rb_cCArray) ) {
162
+ rb_raise(rb_eTypeError, "__find_key_window_row_ranges__: CArray arguments expected");
163
+ }
164
+ GetCArray(vpoints, cp);
165
+ if ( cp->obj_type != CA_OBJ_ARRAY || cp->ndim != 1 || ca_has_mask(cp) ||
166
+ cp->data_type != ck->data_type ) {
167
+ rb_raise(rb_eArgError, "__find_key_window_row_ranges__: unexpected arguments");
168
+ }
169
+ nout = cp->elements;
170
+ }
171
+
172
+ vlo = rb_carray_new(CA_INT64, 1, &nout, 0, NULL);
173
+ vhi = rb_carray_new(CA_INT64, 1, &nout, 0, NULL);
174
+ GetCArray(vlo, clo);
175
+ GetCArray(vhi, chi);
176
+ plo = (int64_t *) clo->ptr;
177
+ phi = (int64_t *) chi->ptr;
178
+ if ( !NIL_P(rinterval) ) {
179
+ vcomplete = rb_carray_new(CA_BOOLEAN, 1, &nout, 0, NULL);
180
+ GetCArray(vcomplete, cc);
181
+ pcomplete = (boolean8_t *) cc->ptr;
182
+ nexp = NUM2LL(rexpected);
183
+ }
184
+
185
+ if ( ck->data_type == CA_INT64 ) {
186
+ int64_t vbefore = NUM2LL(rbefore), vafter = NUM2LL(rafter);
187
+ int64_t viv = NIL_P(rinterval) ? 1 : NUM2LL(rinterval);
188
+ int64_t d;
189
+ /* before and after are not negative, so an overflow of t - before is
190
+ below every key and one of t + after above every key. A difference
191
+ k - t that overflows is not taken as on the grid. */
192
+ #define KW_INT_ON_GRID (!__builtin_sub_overflow(k, t, &d) && d % iv == 0)
193
+ #define KW_INT_BOUNDS (lo_open = __builtin_sub_overflow(t, before, &lo_b), \
194
+ hi_open = __builtin_add_overflow(t, after, &hi_b))
195
+ if ( cp ) KW_WALK_AT(int64_t, KW_INT_ON_GRID, KW_INT_BOUNDS)
196
+ else KW_WALK(int64_t, KW_INT_ON_GRID, KW_INT_BOUNDS)
197
+ #undef KW_INT_ON_GRID
198
+ #undef KW_INT_BOUNDS
199
+ }
200
+ else {
201
+ double vbefore = NUM2DBL(rbefore), vafter = NUM2DBL(rafter);
202
+ double viv = NIL_P(rinterval) ? 1.0 : NUM2DBL(rinterval);
203
+ #define KW_DBL_ON_GRID (fabs((k - t) / iv - nearbyint((k - t) / iv)) <= \
204
+ 1e-9 * fmax(1.0, fabs((k - t) / iv)))
205
+ #define KW_DBL_BOUNDS (lo_b = t - before, hi_b = t + after, lo_open = 0, hi_open = 0)
206
+ if ( cp ) KW_WALK_AT(double, KW_DBL_ON_GRID, KW_DBL_BOUNDS)
207
+ else KW_WALK(double, KW_DBL_ON_GRID, KW_DBL_BOUNDS)
208
+ #undef KW_DBL_ON_GRID
209
+ #undef KW_DBL_BOUNDS
210
+ }
211
+
212
+ return rb_ary_new3(3, vlo, vhi, vcomplete);
213
+ }
214
+
215
+ void
216
+ Init_carray_key_windows (void)
217
+ {
218
+ rb_define_singleton_method(rb_cCArray, "__find_key_window_row_ranges__",
219
+ rb_ca_s_key_window_ranges, 9);
220
+ }