carray 3.0.6 → 3.0.7

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +110 -0
  3. data/README.md +24 -3
  4. data/carray.gemspec +1 -1
  5. data/ext/ca_axis_group.c +6 -6
  6. data/ext/ca_binop_dispatch.c +8 -0
  7. data/ext/ca_binop_dispatch.h +1 -0
  8. data/ext/ca_categorical_iterator.c +7 -7
  9. data/ext/ca_kernel_iterator.h +6 -4
  10. data/ext/ca_obj_array.c +4 -4
  11. data/ext/ca_obj_bincmp.c +19 -3
  12. data/ext/ca_obj_binop.c +36 -11
  13. data/ext/ca_obj_bitarray.c +2 -4
  14. data/ext/ca_obj_bitfield.c +86 -4
  15. data/ext/ca_obj_byte_swap.c +2 -4
  16. data/ext/ca_obj_const_string.c +422 -257
  17. data/ext/ca_obj_face.c +71 -33
  18. data/ext/ca_obj_fake.c +112 -13
  19. data/ext/ca_obj_farray.c +7 -1
  20. data/ext/ca_obj_fixlen_string.c +51 -17
  21. data/ext/ca_obj_grid.c +12 -7
  22. data/ext/ca_obj_meld.c +5 -5
  23. data/ext/ca_obj_monop.c +65 -39
  24. data/ext/ca_obj_object.c +9 -9
  25. data/ext/ca_obj_reduce.c +2 -4
  26. data/ext/ca_obj_refer.c +104 -10
  27. data/ext/ca_obj_repeat.c +1 -1
  28. data/ext/ca_obj_roll.c +2 -4
  29. data/ext/ca_obj_select.c +8 -6
  30. data/ext/ca_obj_select_axis.c +8 -6
  31. data/ext/ca_obj_stack.c +5 -5
  32. data/ext/ca_obj_stride.c +46 -8
  33. data/ext/ca_obj_string.c +2 -2
  34. data/ext/ca_obj_tile.c +2 -4
  35. data/ext/ca_obj_triop.c +15 -12
  36. data/ext/ca_obj_window.c +22 -15
  37. data/ext/ca_op_ipower.c +63 -15
  38. data/ext/ca_op_powi.h +6 -29
  39. data/ext/ca_sort_kernels.h +3 -0
  40. data/ext/ca_sweep_engine.c +90 -23
  41. data/ext/ca_sweep_engine.h +5 -6
  42. data/ext/caframe_csv_reader.c +1 -1
  43. data/ext/carray.h +3 -1
  44. data/ext/carray_access.c +98 -39
  45. data/ext/carray_address_basis.c +98 -24
  46. data/ext/carray_broadcast.c +2 -2
  47. data/ext/carray_call_cfunc.c +5 -8
  48. data/ext/carray_cast.c +311 -37
  49. data/ext/carray_cast_func.rb +37 -5
  50. data/ext/carray_conversion.c +56 -2
  51. data/ext/carray_copy.c +24 -0
  52. data/ext/carray_core.c +69 -6
  53. data/ext/carray_count.c +28 -9
  54. data/ext/carray_element.c +9 -3
  55. data/ext/carray_factorize.c +11 -11
  56. data/ext/carray_histogram.c +2 -2
  57. data/ext/carray_index_classifier.c +7 -5
  58. data/ext/carray_internal.h +94 -0
  59. data/ext/carray_kernels_binop.c +55 -55
  60. data/ext/carray_kernels_init.c +14 -14
  61. data/ext/carray_kernels_monop.c +90 -140
  62. data/ext/carray_lazy.c +16 -1
  63. data/ext/carray_loop.c +9 -2
  64. data/ext/carray_mask.c +118 -11
  65. data/ext/carray_median_percentile.c +13 -8
  66. data/ext/carray_memory_view.c +41 -22
  67. data/ext/carray_operator.c +72 -11
  68. data/ext/carray_order.c +52 -9
  69. data/ext/carray_partition.c +1 -1
  70. data/ext/carray_random.c +1 -1
  71. data/ext/carray_round.c +24 -1
  72. data/ext/carray_scatter.c +4 -0
  73. data/ext/carray_segment.c +1 -1
  74. data/ext/carray_slab.c +13 -4
  75. data/ext/carray_sort.c +6 -3
  76. data/ext/carray_sort_kernel.c +24 -0
  77. data/ext/carray_struct.c +21 -6
  78. data/ext/carray_test.c +85 -39
  79. data/ext/carray_time_text.c +6 -0
  80. data/ext/carray_utils.c +124 -54
  81. data/ext/mk_call_cfunc.rb +6 -11
  82. data/ext/mkkernel.rb +37 -27
  83. data/ext/version.h +4 -4
  84. data/lib/carray/axis_group.rb +9 -6
  85. data/lib/carray/basics.rb +26 -8
  86. data/lib/carray/bincount_nd.rb +8 -2
  87. data/lib/carray/block_iterator.rb +48 -21
  88. data/lib/carray/categorical.rb +21 -8
  89. data/lib/carray/categorical_iterator.rb +2 -1
  90. data/lib/carray/conditional.rb +52 -4
  91. data/lib/carray/const_string.rb +74 -0
  92. data/lib/carray/construct.rb +2 -2
  93. data/lib/carray/core_extensions.rb +19 -68
  94. data/lib/carray/data_type_extension.rb +1 -0
  95. data/lib/carray/fixlen_string.rb +83 -1
  96. data/lib/carray/frame/column_verbs.rb +61 -6
  97. data/lib/carray/frame/concat.rb +50 -6
  98. data/lib/carray/frame/csv_parser.rb +13 -4
  99. data/lib/carray/frame/frame.rb +38 -6
  100. data/lib/carray/frame/group.rb +67 -40
  101. data/lib/carray/frame/io.rb +10 -5
  102. data/lib/carray/frame/join.rb +20 -6
  103. data/lib/carray/frame/records.rb +6 -4
  104. data/lib/carray/frame/reshape.rb +25 -5
  105. data/lib/carray/frame/verbs.rb +78 -25
  106. data/lib/carray/frame/windows.rb +30 -6
  107. data/lib/carray/fuse_source.rb +4 -2
  108. data/lib/carray/iterator.rb +8 -0
  109. data/lib/carray/key_windows.rb +10 -4
  110. data/lib/carray/lazy.rb +12 -17
  111. data/lib/carray/methods/bin.rb +3 -0
  112. data/lib/carray/methods/composition.rb +1 -1
  113. data/lib/carray/methods/factorize.rb +2 -0
  114. data/lib/carray/methods/gather_nd.rb +4 -1
  115. data/lib/carray/methods/is_in.rb +23 -3
  116. data/lib/carray/methods/locate_addr.rb +63 -12
  117. data/lib/carray/methods/repeat.rb +11 -1
  118. data/lib/carray/record_order.rb +35 -6
  119. data/lib/carray/runtime.rb +10 -0
  120. data/lib/carray/segment_iterator.rb +19 -16
  121. data/lib/carray/serialize.rb +22 -0
  122. data/lib/carray/slab_iterator.rb +1 -1
  123. data/lib/carray/stack.rb +3 -3
  124. data/lib/carray/string.rb +6 -6
  125. data/lib/carray/string_operation_extension.rb +25 -4
  126. data/lib/carray/struct_builder.rb +4 -1
  127. data/lib/carray/time.rb +190 -46
  128. data/lib/carray/window_iterator.rb +48 -12
  129. data/yard-stubs/ca_obj_bitfield.rb +4 -1
  130. data/yard-stubs/ca_obj_refer.rb +3 -0
  131. data/yard-stubs/ca_obj_window.rb +2 -1
  132. data/yard-stubs/carray_access.rb +4 -2
  133. data/yard-stubs/carray_cast.rb +6 -0
  134. data/yard-stubs/carray_count.rb +6 -3
  135. data/yard-stubs/carray_math.rb +5 -0
  136. data/yard-stubs/carray_order.rb +6 -0
  137. data/yard-stubs/carray_scatter.rb +2 -1
  138. data/yard-stubs/carray_test.rb +18 -5
  139. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7012a2c73c33e52e9b5dd18d5fd0e7c02b4c741bb650a41cefbfea117449da2f
4
- data.tar.gz: 5731ca96689f1d87d9c4e1e6a4764893eac0e39f8126f91695b2042581ae198f
3
+ metadata.gz: dc1e09cd60b311255af53d363b340440aa899193bbe93cd314abc5211dcd81b2
4
+ data.tar.gz: 3cb15673d7396b64a4fe4ccfa5956862c96b8f7c772194adf4059aff5086c4eb
5
5
  SHA512:
6
- metadata.gz: 1e05efbfc29639882cc08753c9394400abb707df063025a7ae5bfed6c006979721d8b0030ae17a4eab1397c89c7c3803bf9fa2ec62fa7aa9d8c56e1adb38bd79
7
- data.tar.gz: 21baa2d1fac6d2c45a1ed47b4235e9f1832beb4063e93491743470ac77805c266210139d7af834ca1d014ec410ae43191228679a72004c14af6c2fa91eb88eba
6
+ metadata.gz: 8d1077b9d4602707efa889976e1d60908303d7525b5238faf090aa22dd5b21d7c3b5a534775c7290dd88aa7be0db1ad2472da4a6f73d8d75d5c9fdefafcf7cb5
7
+ data.tar.gz: 1715c2a8f1dcf6dc16439f2aedde45cae012d6a9cc1713f0b84ed8be1930d1e3114f41c3100c363888fbd8395feeedbf2f96eae7443dba2495cac85dab2fb04e
data/CHANGELOG.md CHANGED
@@ -34,6 +34,116 @@ and a newer one. The 1.x history, up to the 2.0.0 release, is in
34
34
  neighbour ("as well", "the producer above") or leave unnamed the
35
35
  method, class or keyword it is about. -->
36
36
 
37
+ ## 3.0.7
38
+
39
+ - New: `CATime` and `CATimedelta` take the word forms of their operators
40
+ (`add`, `sub`; on a duration also `mul`, `div`, `neg`). A duration array
41
+ divided by one duration gives the ratios as numbers, a number may stand
42
+ left of a duration (`2 * d`), a duration element has `-@` and `abs`, and
43
+ a duration array has `to_seconds`. A duration's comparisons and stores
44
+ take a String such as `"3 days"`.
45
+
46
+ - New: `pmax` and `pmin` (with `maximum`, `minimum`, `fmax`, `fmin`) on
47
+ `CATimedelta`, `CAFixlenString` and `CAConstString`. `CAConstString`
48
+ also has `match`, `bsearch`, `bsearch_addr`, `search_addr`, `min_addr`
49
+ and `max_addr`.
50
+
51
+ - New: a `CAFixlenString` carries the encoding of its text
52
+ (`a.encoding`), and its cells read in that encoding: UTF-8 when the
53
+ strings were ASCII, `BINARY` when they disagreed. `to_const_string`
54
+ keeps it, so non-ASCII text comes back from `to_fixlen_string`. Two
55
+ arrays of different text encodings no longer stack.
56
+
57
+ - New: `CAFrame#resample` takes a `CArray` as `by:`, and a windowed
58
+ reduction takes a Hash of column name to value as `fill_value:`.
59
+ `CACategorical#count` takes the keywords of `CArray#count`, and the
60
+ `all` and `any` of a categorical iterator take `axis:`.
61
+
62
+ - New: `CArray.from_memory_view` and `wrap_memory_view` take an item of
63
+ several members (a record) as raw bytes, a `fixlen` array of the item's
64
+ size.
65
+
66
+ - Change: a Float is refused as a shape, a size or a count
67
+ (`CArray.int32(2.5)`, `blocks(2.5)`, the counts of `repeat`), whole or
68
+ not; it was cut down to an Integer. A Float key of `[]` still reads as a
69
+ position.
70
+
71
+ - Change: a data type name must match whole. `:complex128`, `:float16` or
72
+ `:int128` raise `ArgumentError`; they were read as the type whose name
73
+ they begin with (`:complex128` gave `cmplx64`). Write `:cmplx128`.
74
+ `CArray::Complex64::TypeSymbol` and `CArray::Complex128::TypeSymbol` are
75
+ `:cmplx64` and `:cmplx128`.
76
+
77
+ - Change: a keyword given with a String key (`a.sum("axis" => 0)`) raises
78
+ `ArgumentError`; it was ignored. Write `axis: 0`.
79
+
80
+ - Change: storing complex cells into a real array raises; the imaginary
81
+ parts were dropped. Convert with `to_type` first.
82
+
83
+ - Change: an object or boolean array given where addresses are expected
84
+ (`project`, `scatter_add!` and the other `scatter_*!`, `addr2index`)
85
+ raises `IndexError`. A boolean array still selects in `[]`.
86
+
87
+ - Change: a value a numeric or boolean array cannot hold (`nil`, a String,
88
+ a Symbol, another object) is answered alike for every data type: an
89
+ operator raises `TypeError`, an ordering (`<`, `pmax` and its kin)
90
+ raises `ArgumentError`, and `eq`, `ne`, `count`, `search` and `is_in`
91
+ find no cell. `search("2")` on a numeric array used to read the text.
92
+ `true` and `false` are 1 and 0, so `count(true)` counts the cells
93
+ holding 1. An object array still looks such values up as values.
94
+
95
+ - Change: `UNDEF` beside an array in an operation is a masked scalar of the
96
+ array's own type, so `CA_INT32([1, 2]) + UNDEF` is an all-masked `int32`
97
+ array; integer, boolean and fixlen arrays gave an object array.
98
+
99
+ - Change: `to_type` to an integer type gives `UNDEF` for an object Float,
100
+ Rational, BigDecimal or Complex the type cannot hold, and keeps the low
101
+ bytes of an object Integer wider than 64 bits, as `int64` to `int8` does.
102
+ A store and a view still refuse such values.
103
+
104
+ - Change: `x ** k` with an Integer `k` from -2 to 4 is computed by at most
105
+ two multiplications or divisions (`x ** 2` is `x * x`), and other Integer
106
+ exponents through `pow`, for a scalar and an array exponent alike,
107
+ eagerly and lazily. Float and complex results can differ from 3.0.6 in
108
+ the last bit.
109
+
110
+ - Change: a time or a date with a year past four digits is written with
111
+ its sign (`"+12345-01-01"`), in `to_s` and in CSV, so it reads back.
112
+
113
+ - Change: `join`, `join_asof`, `align`, `CAFrame.concatenate`, `stack` and
114
+ `stack_columns` refuse integers that the float type they meet would
115
+ round (past 2**53 beside `float64`), in a key or in the pieces of a
116
+ column; such integers matched or merged with neighbouring values. Cast
117
+ one side to the other's type first.
118
+
119
+ - Change: the frames that `GroupedFrame`, the windows and a frame's own
120
+ verbs return hold a copy of the index, so a write to the result's index
121
+ does not reach the source frame.
122
+
123
+ - Change: `CAFrame` refuses, with an `ArgumentError` that names the verb,
124
+ a `GroupedFrame#table` or `#filter` without a block, a `lag` step that is
125
+ not an Integer, a `columns:` Range that selects no column, a
126
+ `fill_value:` Hash naming no column, a row-wise group verb with no column
127
+ left to compute, and a splice of a frame without an index into one with
128
+ an index.
129
+
130
+ - Change: CSV type inference reads a column as text when a float would
131
+ round one of its integers, and an object column of Integers past 2**53
132
+ beside a Float is not inferred as `float64`.
133
+
134
+ - Change: a walk into object cells (`unique`, `hash`, `Marshal.dump`,
135
+ computations over the cells) raises past 256 levels of nesting. A cell
136
+ holding a lazy expression over the array that holds the cell made these
137
+ run without end.
138
+
139
+ - Change: a String Face (`CAString`, `CAFixlenString`, `CAConstString`)
140
+ refuses an ordering with a value that is not a String, and a Face
141
+ refuses a single Ruby object as the operand of an operator the Face does
142
+ not define.
143
+
144
+ - Change (C extensions and carray-jit): `CArray::AddressBasis.sweep` and
145
+ the sweep bridge refuse a `CScalar` output beside an array operand.
146
+
37
147
  ## 3.0.6
38
148
 
39
149
  - New: `CAFrame` answers the column reductions itself, as a frame of one
data/README.md CHANGED
@@ -109,18 +109,39 @@ b.strip_mask(Float::NAN).sum(axis: 0)
109
109
 
110
110
  ## Documentation
111
111
 
112
+ #### Basics
113
+
112
114
  * [Introduction](guides/users/introduction.md) — what Ruby/CArray is
113
115
  * [Getting started](guides/users/00_getting_started.md) — install, and a first array
114
116
  * [Creating arrays](guides/users/01_creating_arrays.md) — constructors, data types, filling
115
117
  * [Indexing and slicing](guides/users/02_indexing_and_slicing.md) — elements, rows, blocks, conditions
116
- * [Indexer reference](guides/users/16_indexer_reference.md) — every form `[]` accepts
117
118
  * [Element-wise operations](guides/users/03_elementwise.md) — arithmetic and mathematical functions
118
- * [Broadcasting](guides/users/07_broadcasting.md) — shapes that differ
119
- * [Views](guides/users/06_views.md) — referring to data without copying
120
119
  * [Reduction and statistics](guides/users/04_reduction_and_statistics.md) — summaries, whole or per axis
121
120
  * [Masks and missing values](guides/users/05_masks.md) — undefined elements, and how calculations treat them
121
+ * [Views](guides/users/06_views.md) — referring to data without copying
122
+ * [Broadcasting](guides/users/07_broadcasting.md) — shapes that differ
123
+
124
+ #### Using arrays
125
+
126
+ * [Indexer reference](guides/users/16_indexer_reference.md) — every form `[]` accepts
127
+
128
+ #### Data that is not plain numbers
129
+
130
+ * [Object arrays](guides/users/13_object_arrays.md) — arrays whose cells hold Ruby objects
131
+ * [Faces](guides/users/12_faces.md) — arrays that read their data as times, categories or strings
132
+
133
+ #### Processing along axes
134
+
135
+ * [Slab iteration](guides/users/11_slab_iteration.md) — running a Ruby block on each slab along an axis
136
+
137
+ #### Data frames
138
+
122
139
  * [Data frames](guides/dataframe/README.md) — tables of named columns, each column a CArray
123
140
 
141
+ #### Appendix
142
+
143
+ * [Vocabulary](guides/users/08_vocabulary.md) — the terms used in these documents
144
+
124
145
  ## Contributing
125
146
 
126
147
  Bug reports and feature requests are welcome — please open an issue.
data/carray.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "carray"
3
- s.version = "3.0.6"
3
+ s.version = "3.0.7"
4
4
  s.authors = ["himotoyoshi"]
5
5
  s.email = ["himotoyoshi@users.noreply.github.com"]
6
6
  s.summary = "Multi-dimensional numerical array class for Ruby"
data/ext/ca_axis_group.c CHANGED
@@ -377,8 +377,8 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
377
377
  ca_size_t k = (ca_size_t) NUM2LONG(RARRAY_AREF(bundle, 1));
378
378
  VALUE vbaxes = RARRAY_AREF(bundle, 2);
379
379
  Check_Type(vbaxes, T_ARRAY);
380
- if ( k <= 0 ) {
381
- rb_raise(rb_eArgError, "axis_group_reduce: bundle k must be positive");
380
+ if ( k < 0 ) {
381
+ rb_raise(rb_eArgError, "axis_group_reduce: bundle k must not be negative");
382
382
  }
383
383
 
384
384
  /* The code table is copied out and the source let go of at once, rather
@@ -390,7 +390,7 @@ rb_ca_axis_group_reduce (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
390
390
  that the unwind collects. Not a String: a String held only by `keep`
391
391
  can be moved by compaction, taking the bytes under bundle_codes with
392
392
  it. */
393
- VALUE v32 = rb_ca_wrap_readonly(vcodes, INT2NUM(CA_INT32));
393
+ volatile VALUE v32 = rb_ca_wrap_readonly(vcodes, INT2NUM(CA_INT32));
394
394
  rb_ary_push((VALUE) keep, v32);
395
395
  GetCArray(v32, bundle_ca[bi]);
396
396
  h_codes[bi] = 0;
@@ -1212,8 +1212,8 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1212
1212
  ca_size_t k = (ca_size_t) NUM2LONG(RARRAY_AREF(bundle, 1));
1213
1213
  VALUE vbaxes = RARRAY_AREF(bundle, 2);
1214
1214
  Check_Type(vbaxes, T_ARRAY);
1215
- if ( k <= 0 ) {
1216
- rb_raise(rb_eArgError, "axis_group_scan: bundle k must be positive");
1215
+ if ( k < 0 ) {
1216
+ rb_raise(rb_eArgError, "axis_group_scan: bundle k must not be negative");
1217
1217
  }
1218
1218
 
1219
1219
  /* The code table is copied out and the source let go of at once, rather
@@ -1225,7 +1225,7 @@ rb_ca_axis_group_scan (VALUE self, VALUE vgaxes, VALUE vbundles, VALUE vop)
1225
1225
  that the unwind collects. Not a String: a String held only by `keep`
1226
1226
  can be moved by compaction, taking the bytes under bundle_codes with
1227
1227
  it. */
1228
- VALUE v32 = rb_ca_wrap_readonly(vcodes, INT2NUM(CA_INT32));
1228
+ volatile VALUE v32 = rb_ca_wrap_readonly(vcodes, INT2NUM(CA_INT32));
1229
1229
  rb_ary_push((VALUE) keep, v32);
1230
1230
  GetCArray(v32, bundle_ca[bi]);
1231
1231
  h_codes[bi] = 0;
@@ -79,6 +79,14 @@ ca_binop_op_id_of_table (ca_binop_func_t table[])
79
79
  return -1;
80
80
  }
81
81
 
82
+ /* pmax, pmin, maximum and minimum pick one operand by order. */
83
+ int
84
+ ca_binop_picks_by_order (int op_id)
85
+ {
86
+ return op_id == CA_BINOP_PMAX || op_id == CA_BINOP_PMIN ||
87
+ op_id == CA_BINOP_MAXIMUM || op_id == CA_BINOP_MINIMUM;
88
+ }
89
+
82
90
  /* ------------------------------------------------------------------- */
83
91
  /* output data_type rule */
84
92
  /* ------------------------------------------------------------------- */
@@ -148,5 +148,6 @@ void ca_binop_kernel_input_data_types (uint16_t op_id, int8_t l_dt, int8_t r_dt,
148
148
  a slab mask to the kernel so masked cells are skipped (otherwise
149
149
  masked-zero divisors crash with SIGFPE). See §3.4 rev3. */
150
150
  int ca_binop_op_id_of_table (ca_binop_func_t table[]);
151
+ int ca_binop_picks_by_order (int op_id);
151
152
 
152
153
  #endif /* CA_BINOP_DISPATCH_H */
@@ -46,7 +46,7 @@
46
46
  } while (0)
47
47
 
48
48
  static VALUE
49
- rb_ca_addresses_by_category (VALUE self, VALUE rcursor, VALUE rk, VALUE rnvalid)
49
+ rb_ca_addresses_by_category (VALUE self, volatile VALUE rcursor, VALUE rk, VALUE rnvalid)
50
50
  {
51
51
  CArray *codes, *cursor, *result;
52
52
  VALUE rresult;
@@ -264,7 +264,7 @@ rb_ca_addresses_by_category (VALUE self, VALUE rcursor, VALUE rk, VALUE rnvalid)
264
264
 
265
265
  static VALUE
266
266
  rb_ca_reduceat_moments (VALUE self, VALUE roffsets, VALUE rcounts,
267
- VALUE rsums, VALUE rmins, VALUE rmaxs)
267
+ VALUE rsums, volatile VALUE rmins, volatile VALUE rmaxs)
268
268
  {
269
269
  CArray *grouped, *offsets, *counts, *sums, *mins, *maxs;
270
270
  int64_t k, *offs, *countp;
@@ -397,7 +397,7 @@ ca_nth_element_double (double *a, ca_size_t n, ca_size_t kth)
397
397
  } while (0)
398
398
 
399
399
  static VALUE
400
- rb_ca_reduceat_percentile (VALUE self, VALUE roffsets, VALUE rp, VALUE rout)
400
+ rb_ca_reduceat_percentile (VALUE self, volatile VALUE roffsets, VALUE rp, volatile VALUE rout)
401
401
  {
402
402
  CArray *grouped, *offsets, *out;
403
403
  int64_t k, *offs;
@@ -503,7 +503,7 @@ rb_ca_reduceat_percentile (VALUE self, VALUE roffsets, VALUE rp, VALUE rout)
503
503
 
504
504
  static VALUE
505
505
  rb_ca_reduceat_variance (VALUE self, VALUE roffsets, VALUE rmeans,
506
- VALUE rcounts, VALUE rout, VALUE rddof)
506
+ VALUE rcounts, volatile VALUE rout, VALUE rddof)
507
507
  {
508
508
  int64_t ddof = NUM2LL(rddof);
509
509
  CArray *grouped, *offsets, *means, *counts, *out;
@@ -649,7 +649,7 @@ rb_ca_reduceat_prod (VALUE self, VALUE roffsets, VALUE rout)
649
649
  } while (0)
650
650
 
651
651
  static VALUE
652
- rb_ca_reduceat_argminmax (VALUE self, VALUE roffsets, VALUE rminidx, VALUE rmaxidx)
652
+ rb_ca_reduceat_argminmax (VALUE self, VALUE roffsets, volatile VALUE rminidx, volatile VALUE rmaxidx)
653
653
  {
654
654
  CArray *grouped, *offsets, *minidx, *maxidx;
655
655
  int64_t k, *offs, *minp, *maxp;
@@ -871,8 +871,8 @@ rb_ca_reduceat_quantile (VALUE self, VALUE roffsets, VALUE rp0, VALUE rp25,
871
871
  } while (0)
872
872
 
873
873
  static VALUE
874
- rb_ca_reduceat_wsum_wmean (VALUE self, VALUE roffsets, VALUE rwg,
875
- VALUE rwsum, VALUE rwmean)
874
+ rb_ca_reduceat_wsum_wmean (VALUE self, VALUE roffsets, volatile VALUE rwg,
875
+ VALUE rwsum, volatile VALUE rwmean)
876
876
  {
877
877
  CArray *grouped, *offsets, *wg, *wsum, *wmean;
878
878
  int64_t k, *offs;
@@ -1792,10 +1792,12 @@ ca_slab_is_flat (const ca_iter_state *st, const ca_size_t *strides,
1792
1792
  * producing the value to reduce (typically `((ACC_T)(x))`), so the
1793
1793
  * caller controls the per-src cast without embedding it in a REDUCE
1794
1794
  * statement. Reassoc across the 8 lanes is the same ε-close license
1795
- * as _MIN_EX / _MAX_EX / _STAR_EX (bit-exact not guaranteed; min/max
1796
- * are strictly associative + commutative so the 8-way tree gives the
1797
- * same result modulo NaN handling which stays identical to the
1798
- * single-accumulator case).
1795
+ * as _MIN_EX / _MAX_EX / _STAR_EX (bit-exact not guaranteed). min / max
1796
+ * pick the same value as the single-accumulator walk, and handle NaN
1797
+ * alike, but of two values equal under `<` (0.0 and -0.0) the one kept
1798
+ * depends on the lane it fell in: the sign of a zero answer can differ
1799
+ * from the single-accumulator walk and between a contiguous and a
1800
+ * strided fiber. Which of the two min / max answers is not specified.
1799
1801
  */
1800
1802
  #define CA_SLAB_REDUCE_MIN8_EX(T, ACC_T, st, p, m, acc, INIT, EXPR, masked_cnt) do { \
1801
1803
  typedef T __ca_u_T CA_UNALIGNED; \
data/ext/ca_obj_array.c CHANGED
@@ -958,7 +958,7 @@ ca_scan_construct_args (int argc, VALUE *argv, int8_t *data_type,
958
958
  CA_CHECK_RANK_GIVEN(RARRAY_LEN(rdim)); /* before dim[] is filled */
959
959
  *ndim = RARRAY_LEN(rdim);
960
960
  for (i=0; i<*ndim; i++) {
961
- dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
961
+ dim[i] = ca_integer_arg(rb_ary_entry(rdim, i), "a dimension", NULL);
962
962
  }
963
963
  }
964
964
 
@@ -1244,7 +1244,7 @@ rb_ca_initialize_copy (VALUE self, VALUE other)
1244
1244
  a copy of a mask is still a mask (its class, CArrayMask, says so) and
1245
1245
  can no more hold a mask of its own than the original. */
1246
1246
  static void
1247
- ca_dup_keep_state (VALUE self, VALUE other)
1247
+ ca_dup_keep_state (VALUE self, volatile VALUE other)
1248
1248
  {
1249
1249
  CArray *ca, *cs;
1250
1250
  if ( ! rb_obj_is_kind_of(other, rb_cCArray) ) {
@@ -1356,7 +1356,7 @@ rb_ca_s_wrap (int argc, VALUE *argv, VALUE self)
1356
1356
  CA_CHECK_RANK_GIVEN(RARRAY_LEN(rdim)); /* before dim[] is filled */
1357
1357
  ndim = RARRAY_LEN(rdim);
1358
1358
  for (i=0; i<ndim; i++) {
1359
- dim[i] = NUM2SIZE(rb_ary_entry(rdim, i));
1359
+ dim[i] = ca_integer_arg(rb_ary_entry(rdim, i), "a dimension", NULL);
1360
1360
  }
1361
1361
 
1362
1362
  target = rb_yield_values(0);
@@ -1661,7 +1661,7 @@ rb_ca_s_alloc_uninit (VALUE klass, VALUE rtype, VALUE rshape)
1661
1661
  Check_Type(rshape, T_ARRAY);
1662
1662
  CA_CHECK_RANK_GIVEN(RARRAY_LEN(rshape)); /* before dim[] is filled */
1663
1663
  ndim = (int8_t) RARRAY_LEN(rshape);
1664
- for (i = 0; i < ndim; i++) dim[i] = NUM2SIZE(rb_ary_entry(rshape, i));
1664
+ for (i = 0; i < ndim; i++) dim[i] = ca_integer_arg(rb_ary_entry(rshape, i), "a dimension", NULL);
1665
1665
  return rb_carray_new(data_type, ndim, dim, bytes, NULL);
1666
1666
  }
1667
1667
 
data/ext/ca_obj_bincmp.c CHANGED
@@ -142,7 +142,7 @@ ca_bincmp_setup (CABinCmp *ca, CArray *left, CArray *right, uint16_t op_id,
142
142
  ca->nosync = 0;
143
143
  ca->right = right;
144
144
  ca->op_id = op_id;
145
- ca->right_is_scalar = ( right->elements == 1 && left->elements > 1 ) ? 1 : 0;
145
+ ca->right_is_scalar = ( right->elements == 1 ) ? 1 : 0;
146
146
  /* Builder has already cast both operands to common data_type. */
147
147
  ca->common_dt = left->data_type;
148
148
  ca->sign_fix = 0;
@@ -622,6 +622,7 @@ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
622
622
  {
623
623
  CArray *l, *r;
624
624
  int8_t l_in_dt, r_in_dt;
625
+ int left_scalar;
625
626
  int signed_side = 0;
626
627
  volatile VALUE l_resolved, r_resolved;
627
628
 
@@ -642,6 +643,20 @@ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
642
643
  break;
643
644
  }
644
645
 
646
+ /* A value the array can not hold matches no cell in eq / ne, and an
647
+ ordering with it is refused, as the eager comparison answers. */
648
+ if ( ! rb_obj_is_carray(r_resolved) && rb_obj_is_carray(l_resolved) ) {
649
+ CArray *lc;
650
+ GetCArray(l_resolved, lc);
651
+ if ( ( op_id == CA_BINCMP_EQ || op_id == CA_BINCMP_NE ) &&
652
+ ca_query_matches_nothing(lc, r_resolved) ) {
653
+ return ca_bincmp_no_match(l_resolved, op_id == CA_BINCMP_NE);
654
+ }
655
+ if ( op_id <= CA_BINCMP_GE && ! ca_is_complex_type(lc) ) {
656
+ ca_refuse_foreign_order(r_resolved, l_resolved);
657
+ }
658
+ }
659
+
645
660
  /* A scalar beside the array (a Ruby value or a CScalar) is wrapped and
646
661
  promoted as the eager comparison does it. */
647
662
  if ( ! rb_obj_is_carray(l_resolved) || ! rb_obj_is_carray(r_resolved) ||
@@ -687,8 +702,9 @@ rb_ca_bincmp_build (VALUE l_cary, VALUE r_cary, uint16_t op_id, double eps)
687
702
  TypedData_Get_Struct(l_resolved, CArray, &carray_data_type, l);
688
703
  TypedData_Get_Struct(r_resolved, CArray, &carray_data_type, r);
689
704
 
690
- if ( l->elements != r->elements ) {
691
- if ( r->elements == 1 ) {
705
+ left_scalar = ca_is_scalar(l) && ! ca_is_scalar(r);
706
+ if ( l->elements != r->elements || left_scalar ) {
707
+ if ( r->elements == 1 && ! left_scalar ) {
692
708
  /* CScalar right: handled via right_is_scalar */
693
709
  }
694
710
  else if ( l->elements == 1 ) {
data/ext/ca_obj_binop.c CHANGED
@@ -153,12 +153,13 @@ ca_binop_setup (CABinOp *ca, CArray *left, CArray *right, uint16_t op_id)
153
153
  ca->operands[1] = right;
154
154
  ca->parents = ca->operands;
155
155
  ca->n_parents = 2;
156
- /* right_is_scalar fast path: when right holds a single element,
157
- xfer_stride pulls only that cell into scratch and walks the
158
- kernel with element-stride 0 (broadcast). The symmetric
156
+ /* right_is_scalar: a right of one cell is pulled once and walked with
157
+ element-stride 0, also when left has one cell too -- a view over this
158
+ node can ask for that one cell several times, and a CScalar right has
159
+ fewer axes than the request. The symmetric
159
160
  left_is_scalar case is currently handled by wrapping left in
160
161
  a broadcast view of right's shape (correct but slower). */
161
- ca->right_is_scalar = ( right->elements == 1 && left->elements > 1 ) ? 1 : 0;
162
+ ca->right_is_scalar = ( right->elements == 1 ) ? 1 : 0;
162
163
 
163
164
  memcpy(ca->dim, left->dim, left->ndim * sizeof(ca_size_t));
164
165
 
@@ -454,9 +455,10 @@ ca_binop_func_fill_data (void *ap, void *ptr)
454
455
 
455
456
  Boolean AND / OR are three-valued (Kleene): a masked cell is resolved by
456
457
  the *known* side (`unknown | true = true`, `unknown & false = false`), so
457
- it is NOT masked in the result. The blind value the value kernel writes
458
- is already correct on a resolved cell because the absorbing element (true
459
- for OR, false for AND) dominates whatever sits on the masked side. */
458
+ it is NOT masked in the result. The value the kernel writes is already
459
+ right on a resolved cell: the absorbing element (true for OR, false for
460
+ AND) decides it whatever byte sits on the masked side, and the boolean
461
+ OR kernel writes 1, not the OR of the bytes. */
460
462
  static void
461
463
  ca_binop_func_create_mask (void *ap)
462
464
  {
@@ -554,6 +556,7 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
554
556
  {
555
557
  CArray *l, *r;
556
558
  int8_t l_in_dt, r_in_dt;
559
+ int left_scalar;
557
560
  volatile VALUE l_resolved, r_resolved;
558
561
 
559
562
  /* Collapse markers on both sides. */
@@ -568,6 +571,22 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
568
571
  data_type the eager binop gives it, and the pair is promoted as the
569
572
  eager binop promotes it. An integer power keeps its int64 exponent
570
573
  (ca_binop_kernel_input_data_types). */
574
+ if ( ! rb_obj_is_carray(r_resolved) && rb_obj_is_carray(l_resolved) &&
575
+ ca_binop_picks_by_order(op_id) ) {
576
+ CArray *lc;
577
+ GetCArray(l_resolved, lc);
578
+ /* a boolean array picks as its 0 / 1 int64 numbers */
579
+ if ( ca_binop_kernel_lookup_vv(op_id,
580
+ lc->data_type == CA_BOOLEAN ? CA_INT64 : lc->data_type)
581
+ != ca_binop_not_implement ) {
582
+ ca_refuse_foreign_order(r_resolved, l_resolved);
583
+ }
584
+ else {
585
+ /* an array the op is not defined for says so, whatever the operand */
586
+ ca_op_refuse_unimplemented(l_resolved, lc->data_type, rb_eCADataTypeError);
587
+ }
588
+ }
589
+
571
590
  if ( op_id != CA_BINOP_IPOWER &&
572
591
  ( ! rb_obj_is_carray(l_resolved) || ! rb_obj_is_carray(r_resolved) ||
573
592
  rb_obj_is_cscalar(l_resolved) || rb_obj_is_cscalar(r_resolved) ) ) {
@@ -633,14 +652,20 @@ rb_ca_binop_build (VALUE l_cary, VALUE r_cary, uint16_t op_id)
633
652
  op commutes (ADD / MUL / BIT_*). Non-commutative +
634
653
  left scalar wraps left in a broadcast view of right's
635
654
  shape so the kernel sees matched shapes; cost is N
636
- reads of the scalar cell with stride 0. */
637
- if ( l->elements != r->elements ) {
638
- if ( r->elements == 1 ) {
655
+ reads of the scalar cell with stride 0.
656
+ A left CScalar is taken here also beside a one-cell array, whose
657
+ shape is the answer's. */
658
+ left_scalar = ca_is_scalar(l) && ! ca_is_scalar(r);
659
+ if ( l->elements != r->elements || left_scalar ) {
660
+ if ( r->elements == 1 && ! left_scalar ) {
639
661
  /* CScalar-vs-array, right. xfer_stride handles this with
640
662
  right_step = 0. */
641
663
  }
642
664
  else if ( l->elements == 1 ) {
643
- int commutes = ( op_id == CA_BINOP_ADD ||
665
+ /* An object cell answers an operator for itself, so which operand
666
+ receives it is part of the expression. */
667
+ int commutes = l->data_type != CA_OBJECT &&
668
+ ( op_id == CA_BINOP_ADD ||
644
669
  op_id == CA_BINOP_MUL ||
645
670
  op_id == CA_BINOP_BIT_AND ||
646
671
  op_id == CA_BINOP_BIT_OR ||
@@ -399,16 +399,14 @@ static void
399
399
  ca_bitarray_func_allocate (void *ap)
400
400
  {
401
401
  CABitarray *ca = (CABitarray *) ap;
402
- ca_attach(ca->parent);
403
- ca->ptr = ca_alloc_cells((CArray *) ca);
402
+ ca->ptr = ca_alloc_cells_then_attach((CArray *) ca, 1, &ca->parent);
404
403
  }
405
404
 
406
405
  static void
407
406
  ca_bitarray_func_attach (void *ap)
408
407
  {
409
408
  CABitarray *ca = (CABitarray *) ap;
410
- ca_attach(ca->parent);
411
- ca->ptr = ca_alloc_cells((CArray *) ca);
409
+ ca->ptr = ca_alloc_cells_then_attach((CArray *) ca, 1, &ca->parent);
412
410
  ca_bitarray_attach(ca);
413
411
  }
414
412
 
@@ -290,6 +290,90 @@ ca_bitfield_setup (CABitfield *ca, CArray *parent,
290
290
  return 0;
291
291
  }
292
292
 
293
+ /* The bit field view whose cells `ca` is, of the same data type: ca itself,
294
+ or the bit field at the end of a chain of single-parent views that keep
295
+ the type (a slice, a grid, a mask selection of the field). A view of
296
+ several parents (a stack or a meld) has one when every parent has a field
297
+ of the same width and sign beneath it, so that a value is kept the same
298
+ way whichever parent its cell lands in. NULL when there is none. */
299
+ CArray *
300
+ ca_bitfield_beneath (CArray *ca)
301
+ {
302
+ while ( ca && ! ca_is_entity(ca) ) {
303
+ CArray *parent;
304
+ if ( ca->obj_type == CA_OBJ_BITFIELD ) {
305
+ return ca;
306
+ }
307
+ if ( ca_test_flag(ca, CA_FLAG_MULTI_PARENTS) ) {
308
+ CAMultiParent *mp = (CAMultiParent *) ca;
309
+ CABitfield *first = NULL;
310
+ int32_t k;
311
+ for (k=0; k<mp->n_parents; k++) {
312
+ CArray *p = mp->parents[k];
313
+ CABitfield *f;
314
+ if ( ! p || p->data_type != ca->data_type ) {
315
+ return NULL;
316
+ }
317
+ f = (CABitfield *) ca_bitfield_beneath(p);
318
+ if ( ! f || ( first && ( f->bit_length != first->bit_length ||
319
+ f->sign_extend != first->sign_extend ) ) ) {
320
+ return NULL;
321
+ }
322
+ if ( ! first ) {
323
+ first = f;
324
+ }
325
+ }
326
+ return (CArray *) first;
327
+ }
328
+ parent = ((CAView *) ca)->parent;
329
+ if ( ! parent || parent->data_type != ca->data_type ) {
330
+ return NULL;
331
+ }
332
+ ca = parent;
333
+ }
334
+ return NULL;
335
+ }
336
+
337
+ /* A value stored into a field keeps its low `bits` bits, as the bits of a
338
+ wider integer written into the field would. */
339
+ VALUE
340
+ ca_integer_wrap_bits (VALUE v, int bits, int sign_extend)
341
+ {
342
+ VALUE integer, modulus;
343
+ if ( RB_TYPE_P(v, T_STRING) ) {
344
+ int64_t x;
345
+ ca_decimal_string_store(v, CA_INT64, &x);
346
+ integer = LL2NUM(x);
347
+ }
348
+ else {
349
+ integer = RB_INTEGER_TYPE_P(v) ? v : rb_Integer(v);
350
+ }
351
+ if ( FIXNUM_P(integer) && bits < 62 ) {
352
+ long x = FIX2LONG(integer);
353
+ long m = 1L << bits;
354
+ x &= m - 1;
355
+ if ( sign_extend && x >= ( m >> 1 ) ) {
356
+ x -= m;
357
+ }
358
+ return LONG2FIX(x);
359
+ }
360
+ modulus = rb_funcall(INT2FIX(1), rb_intern("<<"), 1, INT2FIX(bits));
361
+ integer = rb_funcall(integer, '%', 1, modulus);
362
+ if ( sign_extend &&
363
+ RTEST(rb_funcall(rb_funcall(integer, '*', 1, INT2FIX(2)),
364
+ rb_intern(">="), 1, modulus)) ) {
365
+ integer = rb_funcall(integer, '-', 1, modulus);
366
+ }
367
+ return integer;
368
+ }
369
+
370
+ VALUE
371
+ ca_bitfield_wrap_integer (CArray *ca, VALUE v)
372
+ {
373
+ CABitfield *cb = (CABitfield *) ca;
374
+ return ca_integer_wrap_bits(v, (int) cb->bit_length, cb->sign_extend);
375
+ }
376
+
293
377
  CABitfield *
294
378
  ca_bitfield_new (CArray *parent, ca_size_t offset, ca_size_t bitlen,
295
379
  int8_t data_type)
@@ -462,16 +546,14 @@ static void
462
546
  ca_bitfield_func_allocate (void *ap)
463
547
  {
464
548
  CABitfield *ca = (CABitfield *) ap;
465
- ca_attach(ca->parent);
466
- ca->ptr = ca_alloc_cells((CArray *) ca);
549
+ ca->ptr = ca_alloc_cells_then_attach((CArray *) ca, 1, &ca->parent);
467
550
  }
468
551
 
469
552
  static void
470
553
  ca_bitfield_func_attach (void *ap)
471
554
  {
472
555
  CABitfield *ca = (CABitfield *) ap;
473
- ca_attach(ca->parent);
474
- ca->ptr = ca_alloc_cells((CArray *) ca);
556
+ ca->ptr = ca_alloc_cells_then_attach((CArray *) ca, 1, &ca->parent);
475
557
  ca_bitfield_attach(ca);
476
558
  }
477
559
 
@@ -462,16 +462,14 @@ static void
462
462
  ca_byte_swap_func_allocate (void *ap)
463
463
  {
464
464
  CAByteSwap *ca = (CAByteSwap *) ap;
465
- ca_attach(ca->parent);
466
- ca->ptr = ca_alloc_cells((CArray *) ca);
465
+ ca->ptr = ca_alloc_cells_then_attach((CArray *) ca, 1, &ca->parent);
467
466
  }
468
467
 
469
468
  static void
470
469
  ca_byte_swap_func_attach (void *ap)
471
470
  {
472
471
  CAByteSwap *ca = (CAByteSwap *) ap;
473
- ca_attach(ca->parent);
474
- ca->ptr = ca_alloc_cells((CArray *) ca);
472
+ ca->ptr = ca_alloc_cells_then_attach((CArray *) ca, 1, &ca->parent);
475
473
  memcpy(ca->ptr, ca->parent->ptr, ca_length(ca));
476
474
  ca_byte_swap_apply(ca, ca->ptr);
477
475
  }