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
@@ -965,6 +965,139 @@ address_basis_tier (VALUE module, VALUE object)
965
965
  return INT2NUM(tier_for(ca));
966
966
  }
967
967
 
968
+ /* ------------------------------------------------------------------- */
969
+
970
+ /*
971
+ * call-seq:
972
+ * CArray::AddressBasis.sweep(function, fsync, arrays, *parts) -> nil
973
+ *
974
+ * Runs ca_call_cslab_N_r over `arrays` with the slab function at the address
975
+ * `function`, and hands it as `userdata` a table of pointers to the bytes of
976
+ * each of `parts`, in order.
977
+ *
978
+ * This is what a consumer did through Fiddle: copy the parts into memory
979
+ * from malloc, write the table in front of them, and call the family member
980
+ * for the arity. The copy was there because a String's bytes may be moved
981
+ * by GC compaction, and the sweep allocates -- so a collection can run
982
+ * between taking an address and the slab reading it. It is not needed
983
+ * here: every part is also held in an array on the machine stack for the
984
+ * length of this call, and an object referenced from there is pinned. The
985
+ * VM stack is not enough by itself -- a splat of 128 or more arguments
986
+ * reaches a C method as a heap array, whose elements compaction moves.
987
+ * The machine stack is why the parts are limited to 1024.
988
+ *
989
+ * A part that is not frozen is the slab's to write (an error slot), and is
990
+ * made unshared first so the write lands in that String alone. A frozen
991
+ * part is read only. Each part has to start on an 8-byte boundary, since a
992
+ * slab reads doubles and int64s out of them.
993
+ */
994
+ static VALUE
995
+ address_basis_sweep (int argc, VALUE *argv, VALUE module)
996
+ {
997
+ volatile VALUE rfunction, rfsync, rarrays;
998
+ ca_cslab_r_t function;
999
+ const char *fsync;
1000
+ VALUE vholder = 0;
1001
+ void **table;
1002
+ VALUE *arrays;
1003
+ volatile VALUE *parts;
1004
+ int i, n, nparts;
1005
+
1006
+ rb_check_arity(argc, 3, UNLIMITED_ARGUMENTS);
1007
+ rfunction = argv[0];
1008
+ rfsync = argv[1];
1009
+ rarrays = argv[2];
1010
+ nparts = argc - 3;
1011
+
1012
+ if ( nparts > 1024 ) {
1013
+ rb_raise(rb_eArgError, "%s: a sweep takes at most 1024 parts, got %d",
1014
+ ca_calling_method_name(), nparts);
1015
+ }
1016
+ /* Held on the machine stack, which the GC scans conservatively and so
1017
+ pins. argv is not written: it may be the storage of a heap array. */
1018
+ parts = ALLOCA_N(VALUE, nparts > 0 ? nparts : 1);
1019
+ for ( i = 0; i < nparts; i++ ) {
1020
+ parts[i] = argv[3 + i];
1021
+ }
1022
+
1023
+ Check_Type(rarrays, T_ARRAY);
1024
+ n = (int) RARRAY_LEN(rarrays);
1025
+ if ( n < 1 || n > 7 ) {
1026
+ rb_raise(rb_eArgError, "%s: a sweep takes 1 to 7 arrays, got %d",
1027
+ ca_calling_method_name(), n);
1028
+ }
1029
+ fsync = StringValueCStr(rfsync);
1030
+ if ( (int) strlen(fsync) != n ) {
1031
+ rb_raise(rb_eArgError, "%s: fsync has %d characters for %d arrays",
1032
+ ca_calling_method_name(), (int) strlen(fsync), n);
1033
+ }
1034
+ for ( i = 0; i < n; i++ ) {
1035
+ if ( fsync[i] != '0' && fsync[i] != '1' ) {
1036
+ rb_raise(rb_eArgError,
1037
+ "%s: fsync character %d is '%c', not '0' (read) or '1' (written)",
1038
+ ca_calling_method_name(), i, fsync[i]);
1039
+ }
1040
+ }
1041
+ function = (ca_cslab_r_t) (uintptr_t) NUM2ULL(rfunction);
1042
+ if ( ! function ) {
1043
+ rb_raise(rb_eArgError, "%s: the slab function's address is zero",
1044
+ ca_calling_method_name());
1045
+ }
1046
+
1047
+ arrays = RARRAY_PTR(rarrays);
1048
+ for ( i = 0; i < n; i++ ) {
1049
+ if ( ! rb_obj_is_kind_of(arrays[i], rb_cCArray) ) {
1050
+ rb_raise(rb_eTypeError, "%s: array %d is not a CArray",
1051
+ ca_calling_method_name(), i);
1052
+ }
1053
+ }
1054
+
1055
+ for ( i = 0; i < nparts; i++ ) {
1056
+ VALUE part = parts[i];
1057
+ StringValue(part);
1058
+ parts[i] = part;
1059
+ if ( ! OBJ_FROZEN(part) ) {
1060
+ rb_str_modify(part);
1061
+ }
1062
+ if ( (uintptr_t) RSTRING_PTR(part) & 7 ) {
1063
+ rb_raise(rb_eArgError, "%s: part %d does not start on an 8-byte boundary",
1064
+ ca_calling_method_name(), i);
1065
+ }
1066
+ }
1067
+
1068
+ /* Taken after every check, so a refusal has nothing to free. The sweep
1069
+ itself can raise (a shape that will not broadcast); then the table is
1070
+ left to ALLOCV's own holder, which the GC reclaims. */
1071
+ table = ALLOCV_N(void *, vholder, nparts > 0 ? nparts : 1);
1072
+ for ( i = 0; i < nparts; i++ ) {
1073
+ table[i] = RSTRING_PTR(parts[i]);
1074
+ }
1075
+
1076
+ switch ( n ) {
1077
+ case 1: ca_call_cslab_1_r(function, fsync, arrays[0], table); break;
1078
+ case 2: ca_call_cslab_2_r(function, fsync, arrays[0], arrays[1], table); break;
1079
+ case 3: ca_call_cslab_3_r(function, fsync, arrays[0], arrays[1], arrays[2],
1080
+ table); break;
1081
+ case 4: ca_call_cslab_4_r(function, fsync, arrays[0], arrays[1], arrays[2],
1082
+ arrays[3], table); break;
1083
+ case 5: ca_call_cslab_5_r(function, fsync, arrays[0], arrays[1], arrays[2],
1084
+ arrays[3], arrays[4], table); break;
1085
+ case 6: ca_call_cslab_6_r(function, fsync, arrays[0], arrays[1], arrays[2],
1086
+ arrays[3], arrays[4], arrays[5], table); break;
1087
+ case 7: ca_call_cslab_7_r(function, fsync, arrays[0], arrays[1], arrays[2],
1088
+ arrays[3], arrays[4], arrays[5], arrays[6],
1089
+ table); break;
1090
+ }
1091
+
1092
+ ALLOCV_END(vholder);
1093
+ for ( i = 0; i < nparts; i++ ) {
1094
+ RB_GC_GUARD(parts[i]);
1095
+ }
1096
+ RB_GC_GUARD(rarrays);
1097
+ RB_GC_GUARD(rfsync);
1098
+ return Qnil;
1099
+ }
1100
+
968
1101
  /* ------------------------------------------------------------------- */
969
1102
  /* Init_carray_address_basis */
970
1103
  /* ------------------------------------------------------------------- */
@@ -978,6 +1111,7 @@ Init_carray_address_basis (void)
978
1111
  rb_define_singleton_method(mAddressBasis, "classify",
979
1112
  address_basis_classify, 1);
980
1113
  rb_define_singleton_method(mAddressBasis, "tier", address_basis_tier, 1);
1114
+ rb_define_singleton_method(mAddressBasis, "sweep", address_basis_sweep, -1);
981
1115
 
982
1116
  rb_define_const(mAddressBasis, "TIER_ENTITY", INT2NUM(TIER_ENTITY));
983
1117
  rb_define_const(mAddressBasis, "TIER_STRIDE", INT2NUM(TIER_STRIDE));
@@ -223,6 +223,14 @@ ca_is_readonly (void *ap)
223
223
  return 1;
224
224
  }
225
225
  }
226
+ if ( ca_test_flag(ca, CA_FLAG_FOLDED) ) {
227
+ /* a folded reshape: its source is not on the parent chain */
228
+ CArray *src = ca_fold_source(ca);
229
+ if ( src && ca_is_readonly(src) ) {
230
+ ca_set_flag(ca, CA_FLAG_READ_ONLY);
231
+ return 1;
232
+ }
233
+ }
226
234
  return 0; /* all test -> false */
227
235
  }
228
236
  }
@@ -85,13 +85,12 @@ ca_broadcast_to_destination (VALUE dst, volatile VALUE *src)
85
85
  for ( i = 0; agree && i < dst_ndim; i++ ) {
86
86
  if ( dst_dim[i] != src_dim[i] ) agree = 0;
87
87
  }
88
- if ( ! agree ) ca_broadcast_refuse_write(dst, *src);
89
- return;
88
+ if ( agree ) return;
90
89
  }
91
90
 
92
91
  /* A size-1 axis repeated onto an axis of length 0 leaves the source
93
- larger than an empty destination; the axes say it is a repeat all
94
- the same. */
92
+ larger than an empty destination, or as large when it is empty too
93
+ ((1,0) onto (2,0)); the axes say it is a repeat all the same. */
95
94
  if ( ( cs->elements < cd->elements || cd->elements == 0 )
96
95
  && cs->ndim == cd->ndim ) {
97
96
  int i;
@@ -1,3 +1,3 @@
1
1
  /* GENERATED by extconf.rb: the flags this build's arithmetic
2
2
  was compiled with. See CArray::BUILD_FLAGS. */
3
- #define CA_BUILD_FLAGS "-O3 -fno-fast-math -fwrapv -fopenmp-simd -march=native"
3
+ #define CA_BUILD_FLAGS "-O3 -fno-fast-math -fwrapv -fno-math-errno -fopenmp-simd -march=native"
data/ext/carray_cast.c CHANGED
@@ -1609,7 +1609,6 @@ static VALUE
1609
1609
  rb_ca_as_type_internal (int argc, VALUE *argv, VALUE self)
1610
1610
  {
1611
1611
  volatile VALUE obj, rtype = Qnil, ropt, rbytes = Qnil;
1612
- CArray *ca;
1613
1612
  int8_t data_type;
1614
1613
  ca_size_t bytes;
1615
1614
 
@@ -1618,14 +1617,12 @@ rb_ca_as_type_internal (int argc, VALUE *argv, VALUE self)
1618
1617
 
1619
1618
  rb_ca_guess_type_and_bytes(rtype, rbytes, &data_type, &bytes);
1620
1619
 
1621
- TypedData_Get_Struct(self, CArray, &carray_data_type, ca);
1622
- if ( ca->data_type == data_type ) {
1623
- if ( ! ca_is_fixlen_type(ca) ) {
1624
- return self;
1625
- }
1626
- }
1620
+ rb_check_carray_object(self);
1621
+
1622
+ /* A view also when the data_type is the receiver's own: what is done to
1623
+ it (an attribute, a freeze) stays with it.
1627
1624
 
1628
- /* Natural-width cast: dispatch via helper (CAMonOp for numeric,
1625
+ Natural-width cast: dispatch via helper (CAMonOp for numeric,
1629
1626
  CAFake for CA_FIXLEN sizing / CA_OBJECT / class-rtype). */
1630
1627
  if ( bytes == (ca_size_t) ca_sizeof[data_type] ) {
1631
1628
  obj = ca_type_adapt_view(self, rtype, data_type, CA_ADAPT_VIEW);
@@ -3434,7 +3431,7 @@ rb_ca_read_text_as_number (int argc, VALUE *argv, VALUE self)
3434
3431
  if ( ca->data_type != CA_OBJECT ) {
3435
3432
  rb_raise(rb_eArgError, "decimal reading needs an object array");
3436
3433
  }
3437
- if ( ! ca_is_entity(ca) ) {
3434
+ if ( ! ca_is_entity(ca) || ! ca->ptr ) {
3438
3435
  src = rb_ca_copy(src);
3439
3436
  TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
3440
3437
  }
@@ -3571,7 +3568,7 @@ rb_ca_infer_number_type_of_text (VALUE self)
3571
3568
  if ( ca->data_type != CA_OBJECT ) {
3572
3569
  rb_raise(rb_eArgError, "type inference needs an object array");
3573
3570
  }
3574
- if ( ! ca_is_entity(ca) ) {
3571
+ if ( ! ca_is_entity(ca) || ! ca->ptr ) {
3575
3572
  src = rb_ca_copy(src);
3576
3573
  TypedData_Get_Struct(src, CArray, &carray_data_type, ca);
3577
3574
  }
@@ -3634,7 +3631,7 @@ ca_const_string_buffer_and_ranges (VALUE cs, VALUE *buffer, CArray **ranges)
3634
3631
  *buffer = rb_funcall(cs, rb_intern("buffer"), 0);
3635
3632
  vranges = rb_ca_parent(cs);
3636
3633
  TypedData_Get_Struct(vranges, CArray, &carray_data_type, *ranges);
3637
- if ( ! ca_is_entity(*ranges) ) {
3634
+ if ( ! ca_is_entity(*ranges) || ! (*ranges)->ptr ) {
3638
3635
  vranges = rb_ca_copy(vranges);
3639
3636
  TypedData_Get_Struct(vranges, CArray, &carray_data_type, *ranges);
3640
3637
  }
@@ -369,7 +369,8 @@ rb_ca_convert (int argc, VALUE *argv, VALUE self)
369
369
 
370
370
  list[0] = c.ca;
371
371
  list[1] = c.co;
372
- ca_attach_window(2, list, "rw", ca_convert_body, (VALUE) &c);
372
+ ca_attach_window_yielding(rb_assoc_new(self, obj), 2, list, "rw",
373
+ ca_convert_body, (VALUE) &c);
373
374
 
374
375
  return obj;
375
376
  }
@@ -417,9 +418,11 @@ rb_ca_dump_binary (int argc, VALUE *argv, VALUE self)
417
418
  ca_size_t total = ca_length(ca);
418
419
  GetOpenFile(io, iop);
419
420
  rb_io_check_writable(iop);
420
- if ( ca_is_entity(ca) ) {
421
+ if ( ca_is_entity(ca) && ca->ptr ) {
421
422
  /* Owned ca->ptr: write through the IO buffer machinery so peak
422
- stays at ca_length instead of doubling via a Ruby String. */
423
+ stays at ca_length instead of doubling via a Ruby String. An
424
+ entity that leaves ptr NULL at rest (a CASource) takes the
425
+ gather below. */
423
426
  ssize_t n = rb_io_bufwrite(io, ca->ptr, (size_t) total);
424
427
  if ( n < 0 || (ca_size_t) n != total ) {
425
428
  rb_raise(rb_eRuntimeError,
@@ -428,7 +431,8 @@ rb_ca_dump_binary (int argc, VALUE *argv, VALUE self)
428
431
  }
429
432
  }
430
433
  else {
431
- /* View: no chunked gather API, so materialise into one buffer. */
434
+ /* View, or entity without a ptr: no chunked gather API, so
435
+ materialise into one buffer. */
432
436
  volatile VALUE buf = rb_str_new(NULL, total);
433
437
  ca_copy_data(ca, RSTRING_PTR(buf));
434
438
  rb_io_write(io, buf);
@@ -545,7 +549,7 @@ rb_ca_load_binary (VALUE self, VALUE io)
545
549
  }
546
550
 
547
551
  /* The double nearest to the shortest decimal that reads back as x, the
548
- float32 value, as from_csv reads text into float32: strtod, then the cast
552
+ float32 value, as read_csv reads text into float32: strtod, then the cast
549
553
  to float. Its digits are those of the decimal (at most 9, which a double
550
554
  holds), so Float#to_s writes them. */
551
555
  static double