carray 3.0.5 → 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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +233 -0
  3. data/README.md +1 -1
  4. data/carray.gemspec +3 -2
  5. data/ext/ca_axis_dispatch.c +6 -0
  6. data/ext/ca_axis_group.c +1 -1
  7. data/ext/ca_categorical_iterator.c +7 -7
  8. data/ext/ca_kernel_iterator.c +116 -231
  9. data/ext/ca_kernel_iterator.h +410 -254
  10. data/ext/ca_obj_bincmp.c +9 -1
  11. data/ext/ca_obj_binop.c +10 -1
  12. data/ext/ca_obj_bitfield.c +2 -0
  13. data/ext/ca_obj_byte_swap.c +2 -0
  14. data/ext/ca_obj_face.c +2 -0
  15. data/ext/ca_obj_fake.c +3 -1
  16. data/ext/ca_obj_grid.c +167 -12
  17. data/ext/ca_obj_meld.c +69 -113
  18. data/ext/ca_obj_moncmp.c +9 -1
  19. data/ext/ca_obj_monop.c +40 -2
  20. data/ext/ca_obj_object.c +54 -20
  21. data/ext/ca_obj_reduce.c +15 -1
  22. data/ext/ca_obj_refer.c +65 -20
  23. data/ext/ca_obj_remap.c +69 -10
  24. data/ext/ca_obj_roll.c +1 -0
  25. data/ext/ca_obj_select.c +4 -1
  26. data/ext/ca_obj_select_axis.c +1 -0
  27. data/ext/ca_obj_shift.c +1 -0
  28. data/ext/ca_obj_stack.c +310 -111
  29. data/ext/ca_obj_stride.c +131 -45
  30. data/ext/ca_obj_string.c +18 -2
  31. data/ext/ca_obj_tile.c +1 -0
  32. data/ext/ca_obj_triop.c +9 -1
  33. data/ext/ca_obj_window.c +1 -0
  34. data/ext/ca_op_ipower.c +8 -8
  35. data/ext/caframe_csv_reader.c +1 -1
  36. data/ext/carray.h +2 -1
  37. data/ext/carray_access.c +27 -64
  38. data/ext/carray_address_basis.c +134 -0
  39. data/ext/carray_attribute.c +8 -0
  40. data/ext/carray_broadcast.c +3 -4
  41. data/ext/carray_build_flags.h +1 -1
  42. data/ext/carray_cast.c +8 -11
  43. data/ext/carray_conversion.c +9 -5
  44. data/ext/carray_core.c +811 -72
  45. data/ext/carray_element.c +13 -9
  46. data/ext/carray_histogram.c +25 -3
  47. data/ext/carray_internal.h +147 -12
  48. data/ext/carray_kernels_bincmp.c +2007 -3
  49. data/ext/carray_kernels_binop.c +25365 -5199
  50. data/ext/carray_kernels_init.c +8 -8
  51. data/ext/carray_kernels_monop.c +10696 -3678
  52. data/ext/carray_kernels_reduce_aggregate.c +4429 -702
  53. data/ext/carray_kernels_reduce_boolean.c +1533 -15
  54. data/ext/carray_kernels_reduce_cumulative.c +1808 -248
  55. data/ext/carray_kernels_reduce_extreme.c +4508 -511
  56. data/ext/carray_kernels_reduce_variance.c +2284 -152
  57. data/ext/carray_kernels_scan.c +240 -240
  58. data/ext/carray_kernels_search.c +4211 -264
  59. data/ext/carray_kernels_sort.c +367 -450
  60. data/ext/carray_lazy.c +47 -0
  61. data/ext/carray_loop.c +1 -1
  62. data/ext/carray_mask.c +130 -139
  63. data/ext/carray_median_percentile.c +4 -4
  64. data/ext/carray_memory_view.c +13 -7
  65. data/ext/carray_operator.c +147 -44
  66. data/ext/carray_order.c +3 -2
  67. data/ext/carray_random.c +4 -1
  68. data/ext/carray_slab.c +97 -21
  69. data/ext/carray_sort.c +1 -1
  70. data/ext/carray_test.c +74 -19
  71. data/ext/carray_time_text.c +2 -2
  72. data/ext/extconf.rb +11 -0
  73. data/ext/mkkernel.rb +346 -94
  74. data/ext/ruby_carray.c +4 -1
  75. data/ext/version.h +4 -4
  76. data/lib/carray/attribute.rb +25 -1
  77. data/lib/carray/autoload_carray.rb +3 -3
  78. data/lib/carray/autoload_method_extension.rb +5 -3
  79. data/lib/carray/axis_group.rb +13 -7
  80. data/lib/carray/basics.rb +1 -1
  81. data/lib/carray/block_iterator.rb +17 -3
  82. data/lib/carray/categorical.rb +6 -8
  83. data/lib/carray/categorical_iterator.rb +2 -2
  84. data/lib/carray/complex.rb +2 -2
  85. data/lib/carray/conditional.rb +3 -2
  86. data/lib/carray/frame/column_verbs.rb +45 -14
  87. data/lib/carray/frame/convert.rb +19 -0
  88. data/lib/carray/frame/csv_parser.rb +32 -32
  89. data/lib/carray/frame/describe.rb +4 -2
  90. data/lib/carray/frame/frame.rb +399 -78
  91. data/lib/carray/frame/group.rb +679 -53
  92. data/lib/carray/frame/io.rb +209 -71
  93. data/lib/carray/frame/join.rb +146 -37
  94. data/lib/carray/frame/records.rb +3 -3
  95. data/lib/carray/frame/reshape.rb +89 -11
  96. data/lib/carray/frame/sort.rb +57 -9
  97. data/lib/carray/frame/verbs.rb +384 -49
  98. data/lib/carray/frame/windows.rb +44 -6
  99. data/lib/carray/inspect.rb +7 -2
  100. data/lib/carray/iterator.rb +32 -0
  101. data/lib/carray/lazy.rb +17 -8
  102. data/lib/carray/mask_gap_fill.rb +37 -17
  103. data/lib/carray/meld_reduce.rb +1 -1
  104. data/lib/carray/methods/choose.rb +3 -2
  105. data/lib/carray/methods/meshgrid.rb +3 -1
  106. data/lib/carray/runtime.rb +47 -8
  107. data/lib/carray/segment_iterator.rb +23 -8
  108. data/lib/carray/serialize.rb +34 -17
  109. data/lib/carray/stack.rb +18 -6
  110. data/lib/carray/time.rb +5 -0
  111. data/lib/carray/window_iterator.rb +16 -4
  112. data/yard-stubs/ca_obj_array.rb +26 -1
  113. data/yard-stubs/carray_cast.rb +8 -5
  114. data/yard-stubs/carray_conversion.rb +8 -2
  115. data/yard-stubs/carray_mask.rb +20 -1
  116. data/yard-stubs/carray_math.rb +31 -16
  117. data/yard-stubs/carray_memory_view.rb +7 -0
  118. data/yard-stubs/carray_test.rb +7 -4
  119. metadata +18 -4
data/ext/carray_test.c CHANGED
@@ -274,10 +274,23 @@ eql_## type (const char *a, const char *b, ca_size_t bytes) \
274
274
  return ( *(const type*)a == *(const type*)b ); \
275
275
  }
276
276
 
277
+ /* == compares contents: a NaN equals a NaN (whatever its payload), as the
278
+ same array read back or copied holds the same NaN; -0.0 equals 0.0 as
279
+ values do. eql? stays bitwise. */
280
+ static int
281
+ ca_object_cells_equal (VALUE x, VALUE y)
282
+ {
283
+ if ( RB_FLOAT_TYPE_P(x) && RB_FLOAT_TYPE_P(y) &&
284
+ isnan(RFLOAT_VALUE(x)) && isnan(RFLOAT_VALUE(y)) ) {
285
+ return 1;
286
+ }
287
+ return RTEST(rb_funcall(x, id_equal, 1, y)) ? 1 : 0;
288
+ }
289
+
277
290
  static int
278
291
  eql_VALUE (const char *a, const char *b, ca_size_t bytes)
279
292
  {
280
- return RTEST(rb_funcall(*(const VALUE*)a, id_equal, 1, *(const VALUE*)b)) ? 1 : 0;
293
+ return ca_object_cells_equal(*(const VALUE*)a, *(const VALUE*)b);
281
294
  }
282
295
 
283
296
  static int
@@ -295,10 +308,28 @@ eql_type(int32_t)
295
308
  eql_type(uint32_t)
296
309
  eql_type(int64_t)
297
310
  eql_type(uint64_t)
298
- eql_type(float32_t)
299
- eql_type(float64_t)
300
- eql_type(cmplx64_t)
301
- eql_type(cmplx128_t)
311
+ #define eql_float(type) \
312
+ static int \
313
+ eql_## type (const char *a, const char *b, ca_size_t bytes) \
314
+ { \
315
+ type x = *(const type*)a, y = *(const type*)b; \
316
+ return ( x == y ) || ( isnan(x) && isnan(y) ); \
317
+ }
318
+
319
+ #define eql_cmplx(type, part) \
320
+ static int \
321
+ eql_## type (const char *a, const char *b, ca_size_t bytes) \
322
+ { \
323
+ type x = *(const type*)a, y = *(const type*)b; \
324
+ part xr = creal(x), xi = cimag(x), yr = creal(y), yi = cimag(y); \
325
+ return ( ( xr == yr ) || ( isnan(xr) && isnan(yr) ) ) && \
326
+ ( ( xi == yi ) || ( isnan(xi) && isnan(yi) ) ); \
327
+ }
328
+
329
+ eql_float(float32_t)
330
+ eql_float(float64_t)
331
+ eql_cmplx(cmplx64_t, float)
332
+ eql_cmplx(cmplx128_t, double)
302
333
 
303
334
  /* Placeholder for CA_FLOAT128 / CA_CMPLX256 slots (ca_valid[12] =
304
335
  ca_valid[15] = 0, so never invoked). */
@@ -371,8 +402,8 @@ ca_compare_body (VALUE arg)
371
402
  comparison is bitwise (= NaN.eql?(NaN) yields true since their bit
372
403
  patterns match), so memcmp gives the right semantics. For non-strict
373
404
  (==) of numeric data_types, type-equality is byte-equality EXCEPT for
374
- floats where -0.0 == +0.0 (different bit pattern, same value) and
375
- NaN != NaN (same bit pattern, unequal value) -- so we must keep the
405
+ floats where -0.0 == +0.0 (different bit pattern, same value) and any
406
+ NaN equals any NaN (payloads may differ) -- so we must keep the
376
407
  per-element comparator there.
377
408
 
378
409
  Integer / bool / fixlen data_types are byte-exact, so memcmp matches both
@@ -380,13 +411,14 @@ ca_compare_body (VALUE arg)
380
411
  the comparator. */
381
412
  if ( ! masked_a && ! masked_b ) {
382
413
  if ( is_object ) {
383
- ID id = strict ? id_eql : id_equal;
384
414
  VALUE *va = (VALUE *) pa;
385
415
  VALUE *vb = (VALUE *) pb;
386
416
  for (i=0; i<ca->elements; i++) {
387
417
  volatile VALUE x = va[i];
388
418
  volatile VALUE y = vb[i];
389
- if ( ! RTEST(rb_funcall(x, id, 1, y)) ) {
419
+ int eq = strict ? RTEST(rb_funcall(x, id_eql, 1, y))
420
+ : ca_object_cells_equal(x, y);
421
+ if ( ! eq ) {
390
422
  flag = 0;
391
423
  break;
392
424
  }
@@ -427,8 +459,8 @@ ca_compare_body (VALUE arg)
427
459
  if ( is_object ) {
428
460
  volatile VALUE x = *(VALUE *) pa;
429
461
  volatile VALUE y = *(VALUE *) pb;
430
- ID id = strict ? id_eql : id_equal;
431
- eq = RTEST(rb_funcall(x, id, 1, y));
462
+ eq = strict ? RTEST(rb_funcall(x, id_eql, 1, y))
463
+ : ca_object_cells_equal(x, y);
432
464
  }
433
465
  else if ( strict
434
466
  || ca->data_type <= CA_UINT64
@@ -451,6 +483,19 @@ ca_compare_body (VALUE arg)
451
483
  return Qnil;
452
484
  }
453
485
 
486
+ typedef struct {
487
+ CArray **list;
488
+ ca_compare_ctx_t *c;
489
+ } ca_compare_run_t;
490
+
491
+ static VALUE
492
+ ca_compare_run (VALUE arg)
493
+ {
494
+ ca_compare_run_t *r = (ca_compare_run_t *) arg;
495
+ ca_attach_window(2, r->list, "rr", ca_compare_body, (VALUE) r->c);
496
+ return Qnil;
497
+ }
498
+
454
499
  /* ca_compare_common(a, b, strict) — shared body of ca_equal (==) and
455
500
  * ca_eql_strict (eql?). Returns 1 if arrays match under the selected
456
501
  * semantics, else 0.
@@ -461,7 +506,7 @@ ca_compare_body (VALUE arg)
461
506
  * four masked/unmasked combinations.
462
507
  *
463
508
  * The only difference is the per-element comparator:
464
- * == : ca_eql[data_type] (type-specific, so float NaN != NaN)
509
+ * == : ca_eql[data_type] (by value: NaN equals NaN, -0.0 equals 0.0)
465
510
  * eql?: memcmp for numeric, rb_funcall(:eql?) for CA_OBJECT
466
511
  *
467
512
  * The unmasked-unmasked branch takes a bulk memcmp or per-cell
@@ -503,8 +548,14 @@ ca_compare_common (void *ap, void *bp, int strict)
503
548
  c.flag = 1;
504
549
  list[0] = ca;
505
550
  list[1] = cb;
506
- /* The object lane calls #== / #eql? with both arrays attached. */
507
- ca_attach_window(2, list, "rr", ca_compare_body, (VALUE) &c);
551
+ /* The object lane calls #== / #eql? with both arrays attached, and
552
+ recorded as compared over (ca_computing_run), so a cell holding one
553
+ of them is refused as cyclic rather than compared again without
554
+ end. */
555
+ ca_compare_run_t r;
556
+ r.list = list;
557
+ r.c = &c;
558
+ ca_computing_run(2, list, ca_compare_run, (VALUE) &r);
508
559
  return c.flag;
509
560
  }
510
561
  }
@@ -522,9 +573,10 @@ ca_eql_storage (void *ap, void *bp)
522
573
  }
523
574
 
524
575
  /* CArray#==(other) — elementwise equality returning true / false.
525
- * data_class, data_type, shape, and mask state must all match; NaN
526
- * compares unequal per IEEE semantics. Non-CArray other returns
527
- * false. */
576
+ * data_class, data_type, shape, and mask state must all match. It asks
577
+ * whether the contents are the same, so a NaN equals a NaN and -0.0
578
+ * equals 0.0; the IEEE comparison of each element is #eq. Non-CArray
579
+ * other returns false. */
528
580
  static VALUE
529
581
  rb_ca_equal (VALUE self, VALUE other)
530
582
  {
@@ -795,7 +847,8 @@ without_read_only_ensure (VALUE arg)
795
847
  * the bridge owns.
796
848
  *
797
849
  * Mechanics: clears CA_FLAG_READ_ONLY on self and on its mask for the
798
- * duration of the block; rb_ensure restores both on normal return AND on
850
+ * duration of the block, except on a mask that is a wrap: that mask borrows
851
+ * its bits from a producer (wrap_memory_view's mask:), which set the flag; rb_ensure restores both on normal return AND on
799
852
  * raise, setting the flag on whatever mask self has by then. (A read-only
800
853
  * array's mask carries the flag once CArray#mask has handed it out.) Frozen
801
854
  * objects still raise FrozenError. Does not walk parent chains.
@@ -822,7 +875,9 @@ rb_ca_without_read_only_flag (VALUE self)
822
875
  s.was_readonly = ca_test_flag(ca, CA_FLAG_READ_ONLY);
823
876
  if (s.was_readonly) {
824
877
  ca_unset_flag(ca, CA_FLAG_READ_ONLY);
825
- if (ca->mask) {
878
+ /* A mask that is a wrap borrows its bits (the mask: of
879
+ wrap_memory_view); its flag is the lender's and stays. */
880
+ if (ca->mask && ca->mask->obj_type != CA_OBJ_ARRAY_WRAP) {
826
881
  ca_unset_flag(ca->mask, CA_FLAG_READ_ONLY);
827
882
  }
828
883
  }
@@ -383,7 +383,7 @@ rb_ca_parse_time_text (int argc, VALUE *argv, VALUE self)
383
383
  if ( ca->data_type != CA_OBJECT ) {
384
384
  rb_raise(rb_eArgError, "time text reading needs an object array");
385
385
  }
386
- if ( ! ca_is_entity(ca) ) {
386
+ if ( ! ca_is_entity(ca) || ! ca->ptr ) {
387
387
  src = rb_ca_copy(src);
388
388
  TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
389
389
  }
@@ -1077,7 +1077,7 @@ rb_ca_strptime_fields (VALUE self, VALUE rformat, VALUE rstrict)
1077
1077
  if ( ca->data_type != CA_OBJECT ) {
1078
1078
  rb_raise(rb_eArgError, "strptime reading needs an object array");
1079
1079
  }
1080
- if ( ! ca_is_entity(ca) ) {
1080
+ if ( ! ca_is_entity(ca) || ! ca->ptr ) {
1081
1081
  src = rb_ca_copy(src);
1082
1082
  TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
1083
1083
  }
data/ext/extconf.rb CHANGED
@@ -118,6 +118,17 @@ if try_compile("int main(void) { return 0; }", "-fwrapv")
118
118
  $carray_build_flags << "-fwrapv"
119
119
  end
120
120
 
121
+ # --- math functions do not set errno (`-fno-math-errno`)
122
+ #
123
+ # Nothing in carray reads errno after a math call. With errno kept, GCC
124
+ # must call sqrt() for every cell instead of using the vector square root,
125
+ # so `sqrt` ran 2-4x slower than it could. The values do not change.
126
+ # Apple clang already defaults to this.
127
+ if try_compile("int main(void) { return 0; }", "-fno-math-errno")
128
+ $CFLAGS += " -fno-math-errno"
129
+ $carray_build_flags << "-fno-math-errno"
130
+ end
131
+
121
132
  # --- probe for `-fopenmp-simd` (SL.1.0, PROPOSAL_REDUCTION_SIMD_LICENSE)
122
133
  #
123
134
  # `-fopenmp-simd` enables `#pragma omp simd` (and its `reduction(+:acc)`