cumo 0.5.3 → 0.5.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/3rd_party/mkmf-cu/lib/mkmf-cu/cli.rb +5 -2
  3. data/3rd_party/mkmf-cu/lib/mkmf-cu/nvcc.rb +1 -1
  4. data/CHANGELOG.md +39 -0
  5. data/ext/cumo/include/cumo/narray.h +4 -0
  6. data/ext/cumo/include/cumo/reduce_kernel.h +84 -0
  7. data/ext/cumo/include/cumo/types/int16.h +5 -2
  8. data/ext/cumo/include/cumo/types/int32.h +0 -1
  9. data/ext/cumo/include/cumo/types/int64.h +0 -1
  10. data/ext/cumo/include/cumo/types/int8.h +1 -2
  11. data/ext/cumo/include/cumo/types/uint16.h +5 -2
  12. data/ext/cumo/include/cumo/types/uint32.h +0 -1
  13. data/ext/cumo/include/cumo/types/uint64.h +0 -1
  14. data/ext/cumo/include/cumo/types/uint8.h +1 -2
  15. data/ext/cumo/include/cumo/types/xint_macro.h +2 -0
  16. data/ext/cumo/include/cumo.h +1 -1
  17. data/ext/cumo/narray/array.c +18 -24
  18. data/ext/cumo/narray/data.c +1 -7
  19. data/ext/cumo/narray/gen/cogen.rb +1 -1
  20. data/ext/cumo/narray/gen/narray_def.rb +4 -0
  21. data/ext/cumo/narray/gen/spec.rb +14 -6
  22. data/ext/cumo/narray/gen/tmpl/accum_arg.c +120 -0
  23. data/ext/cumo/narray/gen/tmpl/accum_arg_kernel.cu +66 -0
  24. data/ext/cumo/narray/gen/tmpl/accum_binary.c +4 -0
  25. data/ext/cumo/narray/gen/tmpl/cast.c +7 -0
  26. data/ext/cumo/narray/gen/tmpl_bit/binary.c +6 -0
  27. data/ext/cumo/narray/gen/tmpl_bit/bit_count_cpu.c +6 -0
  28. data/ext/cumo/narray/gen/tmpl_bit/bit_reduce.c +1 -1
  29. data/ext/cumo/narray/gen/tmpl_bit/store_bit.c +7 -2
  30. data/ext/cumo/narray/gen/tmpl_bit/unary.c +4 -0
  31. data/ext/cumo/narray/index.c +9 -0
  32. data/ext/cumo/narray/narray.c +2 -2
  33. data/ext/cumo/narray/ndloop.c +2 -2
  34. data/lib/cumo/narray/extra.rb +54 -7
  35. data/test/bit_test.rb +37 -0
  36. data/test/narray_test.rb +65 -0
  37. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ea033fff4a77a42e911f54418e264dd3467372c41ffebcfb693e45b3f5f6faf
4
- data.tar.gz: 7cdc86588d27d4819aaba0b994ed178f9d028cc4441c557c1b403a9570b56b0e
3
+ metadata.gz: 96a38fa0ad4be223020cef21720e30e9a32fcd2901798279293924df8bfd0f92
4
+ data.tar.gz: c826e49bea46001d6764c7d0f8ad124e5b6072543eb97a07990a26453dd71bf7
5
5
  SHA512:
6
- metadata.gz: f2ed5c87fcee89596b0ed404169fe82ad514da4cdcb23b3e8b200415d2fe1092d450c88e8a7f109c7ff786b58ffe2a52b12485eb7d0e2844e28fcc18d2303c0c
7
- data.tar.gz: 215bbcab440ff133bd13aa9e4f133cddb8da783003dccddfd8546e072adf49a6d68d93ecd9f97221aca4f09348eaf5b5657437f614d94e0c0fc15dbcf924ded9
6
+ metadata.gz: 1dba1ea3cb5a9c93044d222a9d03c975809c5b03d7925702aa3357a0244752d532cb9421b0632e71808944685c3ca44e7a0fc6032ca8c39d8083c279596dce61
7
+ data.tar.gz: 81c933a8f07f862b22a0c6be5e397000d4ea9476139203353907ba7de21a7aae418264fa8425b197d6302861a2788d262af2d2ecd2e34100900d2293706439f4
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "English"
3
4
  require "mkmf"
4
5
  require "open3"
5
6
  require_relative "nvcc"
@@ -28,8 +29,10 @@ module MakeMakefileCuda
28
29
  # private
29
30
 
30
31
  def run_command!(*args)
31
- puts colorize(:green, args.join(' '))
32
- exit system(*args)
32
+ command = args.join(' ')
33
+ puts colorize(:green, command)
34
+ system(command)
35
+ exit($CHILD_STATUS.exitstatus)
33
36
  end
34
37
 
35
38
  # TODO(sonots): Make it possible to configure "nvcc" and additional arguments
@@ -114,7 +114,7 @@ module MakeMakefileCuda
114
114
  if opt_h["--mkmf-cu-ext"][0] == "c"
115
115
  " --compiler-bindir " + ENV.fetch("NVCC_CCBIN", RbConfig::CONFIG["CC"])
116
116
  elsif opt_h["--mkmf-cu-ext"][0] == "cxx"
117
- " --compiler-bindir " + ENV.fetch("NVCC_CCBIN", RbConfig::CONFIG["CXX"])
117
+ " --compiler-bindir " + ENV.fetch("NVCC_CCBIN", RbConfig::CONFIG["CXX"]).split.first
118
118
  end
119
119
  end
120
120
 
data/CHANGELOG.md CHANGED
@@ -1,3 +1,42 @@
1
+ # 0.5.5 (2026/07/11)
2
+
3
+ Fixes:
4
+
5
+ * Backport: rename method: min_arg, max_arg => argmin, argmax
6
+ * Backport: fix NArray#concatenate: avoid exception when concatenating empty arrays
7
+ * Backport: fix boolean indexing in each axis
8
+
9
+ # 0.5.4 (2026/05/30)
10
+
11
+ Fixes:
12
+
13
+ * Backport: Fix to use rb_funcallv_kw in Ruby 2.7 and later
14
+ * Backport: define id_pow as "**" for all types except Bit
15
+ * Backport: define id_minus as "-@" for RObject
16
+ * Backport: duplicated id_eq and id_ne for RObject
17
+ * Backport: follow the change of INIT_PTR_BIT_IDX
18
+ * Backport: add test for empty bit array
19
+ * Backport: fix NArray::Bit#count_true/false: empty array should return zero
20
+ * Fix backport error
21
+ * Backport: minor fixes
22
+ * Backport: fix RObject#sum,prod
23
+ * Backport: NArray#from_binary: allow zero dimension
24
+ * Backport: Added test cases
25
+ * Backport: fix NArray#store: drop automatic 'to_a' conversion
26
+ * Backport: Numo::NArray.cast tries to convert to Array when it has to_a method
27
+ * Backport: use rb_respond_to()
28
+ * Backport: improve discrimination between int32/64
29
+ * Backport: missing declaration of id_ge
30
+ * Backport: support casting any object that responds to 'to_a'
31
+ * Backport: fix the range of int32 as -2**31 .. 2**31-1
32
+ * Backport: if int32_max is Bignum, it should be protected from GC
33
+ * fix: handle compiler flags included in RbConfig::CONFIG properly (#157)
34
+ * Backport: Added more percentile tests
35
+ * Backport: Use File.write in cogen to ensure file is closed
36
+ * Backport: Added percentile method
37
+ * Backport: Use INT2FIX to define m_data_to_num for 8 or 16-bit Int.
38
+ * Backport: raise error if compiler does not support 8 or 4-byte integer
39
+
1
40
  # 0.5.3 (2026/04/26)
2
41
 
3
42
  Fixes:
@@ -99,6 +99,8 @@ extern "C" {
99
99
  # ifndef PRIu64
100
100
  # define PRIu64 "llu"
101
101
  # endif
102
+ #else
103
+ # error ---->> numo/narray requires 8-byte integer. <<----
102
104
  #endif
103
105
 
104
106
  #if SIZEOF_LONG==4
@@ -139,6 +141,8 @@ extern "C" {
139
141
  # ifndef PRIu32
140
142
  # define PRIu32 "u"
141
143
  # endif
144
+ #else
145
+ # error ---->> numo/narray requires 4-byte integer. <<----
142
146
  #endif
143
147
 
144
148
  #if SIZEOF_LONG > 4
@@ -86,6 +86,67 @@ __global__ static void reduction_kernel(cumo_na_reduction_arg_t arg, int out_blo
86
86
  }
87
87
  }
88
88
 
89
+ // Variant of reduction_kernel for arg-reductions (argmax/argmin).
90
+ //
91
+ // Unlike reduction_kernel, which passes the flat 1-d index of an input element
92
+ // (i.e. index of input elements, same as (min|max)_index), this passes the
93
+ // index along the reduction axis (i_reduce) to the reduction impl. This matches
94
+ // the spec of arg(min|max) which returns indices along the axis.
95
+ template <typename TypeIn, typename TypeOut, typename ReductionImpl>
96
+ __global__ static void reduction_arg_kernel(cumo_na_reduction_arg_t arg, int out_block_size, int reduce_block_size, ReductionImpl impl) {
97
+ cumo_na_iarray_t& in_iarray = arg.in;
98
+ cumo_na_iarray_t& out_iarray = arg.out;
99
+ cumo_na_indexer_t& in_indexer = arg.in_indexer;
100
+ cumo_na_indexer_t& out_indexer = arg.out_indexer;
101
+
102
+ using TypeReduce = decltype(impl.Identity(0));
103
+
104
+ extern __shared__ __align__(8) char sdata_raw[];
105
+ TypeReduce* sdata = reinterpret_cast<TypeReduce*>(sdata_raw);
106
+ unsigned int tid = threadIdx.x;
107
+
108
+ int64_t reduce_indexer_total_size = in_indexer.total_size / out_indexer.total_size;
109
+ int64_t reduce_offset = tid / out_block_size; // # of cols == # of elems
110
+
111
+ int64_t out_offset = tid % out_block_size; // # of rows
112
+ int64_t out_base = blockIdx.x * out_block_size; // # of rows
113
+ int64_t out_stride = gridDim.x * out_block_size; // # of rows
114
+
115
+ for (int64_t i_out = out_base + out_offset; i_out < out_indexer.total_size; i_out += out_stride) {
116
+ cumo_na_indexer_set_dim(&out_indexer, i_out);
117
+ int64_t i_in = i_out * reduce_indexer_total_size + reduce_offset;
118
+
119
+ // Note that arg(min|max) returns the index along the reduction axis.
120
+ TypeReduce accum = impl.Identity(reduce_offset);
121
+
122
+ for (int64_t i_reduce = reduce_offset; i_reduce < reduce_indexer_total_size; i_reduce += reduce_block_size, i_in += reduce_block_size) {
123
+ cumo_na_indexer_set_dim(&in_indexer, i_in);
124
+ TypeIn* in_ptr = reinterpret_cast<TypeIn*>(cumo_na_iarray_at_dim(&in_iarray, &in_indexer));
125
+ impl.Reduce(impl.MapIn(*in_ptr, i_reduce), accum);
126
+ }
127
+
128
+ if (out_block_size <= max_block_size / 2) {
129
+ sdata[tid] = accum;
130
+ __syncthreads();
131
+ // NOTE: Compiler optimizes to unroll this loop
132
+ for (int stride = max_block_size / 2; stride > 0; stride >>= 1) {
133
+ if (out_block_size <= stride) {
134
+ if (tid < stride) {
135
+ impl.Reduce(sdata[tid + stride], sdata[tid]);
136
+ }
137
+ __syncthreads();
138
+ }
139
+ }
140
+ accum = sdata[tid];
141
+ __syncthreads();
142
+ }
143
+ if (reduce_offset == 0 && i_out < out_indexer.total_size) {
144
+ TypeOut* out_ptr = reinterpret_cast<TypeOut*>(cumo_na_iarray_at_dim(&out_iarray, &out_indexer));
145
+ *out_ptr = impl.MapOut(accum);
146
+ }
147
+ }
148
+ }
149
+
89
150
  } // cumo_detail
90
151
 
91
152
  // TODO(sonots): Optimize indexer by squashing (or reducing) dimensions
@@ -110,4 +171,27 @@ void cumo_reduce(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
110
171
  cumo_detail::reduction_kernel<TypeIn,TypeOut,ReductionImpl><<<grid_size, block_size, shared_mem_size>>>(arg, out_block_size, reduce_block_size, impl);
111
172
  }
112
173
 
174
+ // Variant of cumo_reduce for arg-reductions (argmax/argmin), which returns
175
+ // indices along the reduction axis. See reduction_arg_kernel above.
176
+ template <typename TypeIn, typename TypeOut, typename ReductionImpl>
177
+ void cumo_reduce_arg(cumo_na_reduction_arg_t arg, ReductionImpl&& impl) {
178
+ cumo_na_indexer_t& in_indexer = arg.in_indexer;
179
+ cumo_na_indexer_t& out_indexer = arg.out_indexer;
180
+
181
+ if (out_indexer.total_size == 0) {
182
+ return;
183
+ }
184
+
185
+ int64_t reduce_total_size_pow2 = cumo_detail::round_up_to_power_of_2(std::max(size_t{1}, in_indexer.total_size / out_indexer.total_size));
186
+ int64_t reduce_block_size = std::min(cumo_detail::max_block_size, reduce_total_size_pow2);
187
+ int64_t out_block_size = cumo_detail::max_block_size / reduce_block_size;
188
+ int64_t out_block_num = (out_indexer.total_size + out_block_size - 1) / out_block_size;
189
+
190
+ int64_t block_size = cumo_detail::max_block_size;
191
+ int64_t grid_size = std::min(cumo_detail::max_grid_size, out_block_num);
192
+ int64_t shared_mem_size = sizeof(decltype(impl.Identity(0))) * block_size;
193
+
194
+ cumo_detail::reduction_arg_kernel<TypeIn,TypeOut,ReductionImpl><<<grid_size, block_size, shared_mem_size>>>(arg, out_block_size, reduce_block_size, impl);
195
+ }
196
+
113
197
  #endif // CUMO_REDUCE_KERNEL_H
@@ -4,8 +4,11 @@ typedef int16_t rtype;
4
4
  #define cRT cT
5
5
 
6
6
  #define m_num_to_data(x) ((dtype)NUM2INT(x))
7
- #define m_data_to_num(x) INT2NUM((int)(x))
8
- #define m_extract(x) INT2NUM((int)*(dtype*)(x))
7
+ #if SIZEOF_INT > 2
8
+ #define m_data_to_num(x) INT2FIX(x)
9
+ #else
10
+ #define m_data_to_num(x) INT2NUM(x)
11
+ #endif
9
12
  #define m_sprintf(s,x) sprintf(s,"%d",(int)(x))
10
13
 
11
14
  #ifndef INT16_MIN
@@ -5,7 +5,6 @@ typedef int32_t rtype;
5
5
 
6
6
  #define m_num_to_data(x) ((dtype)NUM2INT32(x))
7
7
  #define m_data_to_num(x) INT322NUM((int32_t)(x))
8
- #define m_extract(x) INT322NUM((int32_t)*(dtype*)(x))
9
8
  #define m_sprintf(s,x) sprintf(s,"%"PRId32,(int32_t)(x))
10
9
 
11
10
  #ifndef INT32_MIN
@@ -5,7 +5,6 @@ typedef int64_t rtype;
5
5
 
6
6
  #define m_num_to_data(x) ((dtype)NUM2INT64(x))
7
7
  #define m_data_to_num(x) INT642NUM((int64_t)(x))
8
- #define m_extract(x) INT642NUM((int64_t)*(dtype*)(x))
9
8
  #define m_sprintf(s,x) sprintf(s,"%"PRId64,(int64_t)(x))
10
9
 
11
10
  #ifndef INT64_MIN
@@ -4,8 +4,7 @@ typedef int8_t rtype;
4
4
  #define cRT cT
5
5
 
6
6
  #define m_num_to_data(x) ((dtype)NUM2INT(x))
7
- #define m_data_to_num(x) INT2NUM((int)(x))
8
- #define m_extract(x) INT2NUM((int)*(dtype*)(x))
7
+ #define m_data_to_num(x) INT2FIX(x)
9
8
  #define m_sprintf(s,x) sprintf(s,"%d",(int)(x))
10
9
 
11
10
  #ifndef INT8_MIN
@@ -4,8 +4,11 @@ typedef u_int16_t rtype;
4
4
  #define cRT cT
5
5
 
6
6
  #define m_num_to_data(x) ((dtype)NUM2UINT(x))
7
- #define m_data_to_num(x) UINT2NUM((unsigned int)(x))
8
- #define m_extract(x) UINT2NUM((unsigned int)*(dtype*)(x))
7
+ #if SIZEOF_INT > 2
8
+ #define m_data_to_num(x) INT2FIX(x)
9
+ #else
10
+ #define m_data_to_num(x) UINT2NUM(x)
11
+ #endif
9
12
  #define m_sprintf(s,x) sprintf(s,"%u",(unsigned int)(x))
10
13
 
11
14
  #ifndef UINT16_MIN
@@ -5,7 +5,6 @@ typedef u_int32_t rtype;
5
5
 
6
6
  #define m_num_to_data(x) ((dtype)NUM2UINT32(x))
7
7
  #define m_data_to_num(x) UINT322NUM((u_int32_t)(x))
8
- #define m_extract(x) UINT322NUM((u_int32_t)*(dtype*)(x))
9
8
  #define m_sprintf(s,x) sprintf(s,"%"PRIu32,(u_int32_t)(x))
10
9
 
11
10
  #ifndef UINT32_MIN
@@ -5,7 +5,6 @@ typedef u_int64_t rtype;
5
5
 
6
6
  #define m_num_to_data(x) ((dtype)NUM2UINT64(x))
7
7
  #define m_data_to_num(x) UINT642NUM((u_int64_t)(x))
8
- #define m_extract(x) UINT642NUM((u_int64_t)*(dtype*)(x))
9
8
  #define m_sprintf(s,x) sprintf(s,"%"PRIu64,(u_int64_t)(x))
10
9
 
11
10
  #ifndef UINT64_MIN
@@ -4,8 +4,7 @@ typedef u_int8_t rtype;
4
4
  #define cRT cT
5
5
 
6
6
  #define m_num_to_data(x) ((dtype)NUM2UINT(x))
7
- #define m_data_to_num(x) UINT2NUM((unsigned int)(x))
8
- #define m_extract(x) UINT2NUM((unsigned int)*(dtype*)(x))
7
+ #define m_data_to_num(x) INT2FIX(x)
9
8
  #define m_sprintf(s,x) sprintf(s,"%u",(unsigned int)(x))
10
9
 
11
10
  #ifndef UINT8_MIN
@@ -1,6 +1,8 @@
1
1
  #define m_zero 0
2
2
  #define m_one 1
3
3
 
4
+ #define m_extract(x) m_data_to_num(*(dtype*)(x))
5
+
4
6
  /* Handle negative values consistently across platforms for unsigned integer types */
5
7
  #define m_from_double(x) ((x) < 0 ? (dtype)((long long)(x)) : (dtype)(x))
6
8
  #define m_from_real(x) ((x) < 0 ? (dtype)((long long)(x)) : (dtype)(x))
@@ -10,7 +10,7 @@ extern "C" {
10
10
  #endif
11
11
  #endif
12
12
 
13
- #define CUMO_VERSION "0.5.3"
13
+ #define CUMO_VERSION "0.5.5"
14
14
  #define CUMO_VERSION_CODE 51
15
15
 
16
16
  bool cumo_compatible_mode_enabled_p();
@@ -25,16 +25,16 @@ static ID cumo_id_step;
25
25
  static ID cumo_id_abs;
26
26
  static ID cumo_id_cast;
27
27
  static ID cumo_id_le;
28
+ #if SIZEOF_LONG <= 4
29
+ static ID cumo_id_ge;
30
+ #endif
28
31
  static ID cumo_id_Complex;
29
-
32
+ static VALUE cumo_int32_max = Qnil;
33
+ static VALUE cumo_int32_min = Qnil;
30
34
 
31
35
  static VALUE
32
36
  cumo_na_object_type(int type, VALUE v)
33
37
  {
34
- static VALUE int32_max = Qnil;
35
- if (NIL_P(int32_max))
36
- int32_max = ULONG2NUM(2147483647);
37
-
38
38
  switch(TYPE(v)) {
39
39
 
40
40
  case T_TRUE:
@@ -43,15 +43,15 @@ static VALUE
43
43
  return CUMO_NA_BIT;
44
44
  return type;
45
45
 
46
- #if SIZEOF_LONG == 4
46
+ #if SIZEOF_LONG <= 4
47
47
  case T_FIXNUM:
48
48
  if (type<CUMO_NA_INT32)
49
49
  return CUMO_NA_INT32;
50
50
  return type;
51
51
  case T_BIGNUM:
52
52
  if (type<CUMO_NA_INT64) {
53
- v = rb_funcall(v,cumo_id_abs,0);
54
- if (RTEST(rb_funcall(v,cumo_id_le,1,int32_max))) {
53
+ if (RTEST(rb_funcall(v,cumo_id_le,1,int32_max)) &&
54
+ RTEST(rb_funcall(v,cumo_id_ge,1,int32_min))) {
55
55
  if (type<CUMO_NA_INT32)
56
56
  return CUMO_NA_INT32;
57
57
  } else {
@@ -59,13 +59,12 @@ static VALUE
59
59
  }
60
60
  }
61
61
  return type;
62
-
63
- #elif SIZEOF_LONG == 8
62
+ #else
64
63
  case T_FIXNUM:
65
64
  if (type<CUMO_NA_INT64) {
66
65
  long x = NUM2LONG(v);
67
66
  if (x<0) x=-x;
68
- if (x<=2147483647) {
67
+ if (x<=2147483647L && x>=-2147483648L) {
69
68
  if (type<CUMO_NA_INT32)
70
69
  return CUMO_NA_INT32;
71
70
  } else {
@@ -77,19 +76,6 @@ static VALUE
77
76
  if (type<CUMO_NA_INT64)
78
77
  return CUMO_NA_INT64;
79
78
  return type;
80
- #else
81
- case T_FIXNUM:
82
- case T_BIGNUM:
83
- if (type<CUMO_NA_INT64) {
84
- v = rb_funcall(v,cumo_id_abs,0);
85
- if (RTEST(rb_funcall(v,cumo_id_le,1,int32_max))) {
86
- if (type<CUMO_NA_INT32)
87
- return CUMO_NA_INT32;
88
- } else {
89
- return CUMO_NA_INT64;
90
- }
91
- }
92
- return type;
93
79
  #endif
94
80
 
95
81
  case T_FLOAT:
@@ -642,5 +628,13 @@ Init_cumo_na_array(void)
642
628
  cumo_id_cast = rb_intern("cast");
643
629
  cumo_id_abs = rb_intern("abs");
644
630
  cumo_id_le = rb_intern("<=");
631
+ #if SIZEOF_LONG <= 4
632
+ cumo_id_ge = rb_intern(">=");
633
+ #endif
645
634
  cumo_id_Complex = rb_intern("Complex");
635
+
636
+ rb_global_variable(&cumo_int32_max);
637
+ cumo_int32_max = INT2NUM(2147483647);
638
+ rb_global_variable(&cumo_int32_min);
639
+ cumo_int32_min = INT2NUM(-2147483648);
646
640
  }
@@ -5,9 +5,7 @@
5
5
  #include "cumo/narray.h"
6
6
  #include "cumo/template.h"
7
7
 
8
- static VALUE cumo_sym_mulsum;
9
8
  static ID cumo_id_mulsum;
10
- static ID cumo_id_respond_to_p;
11
9
  static ID cumo_id_store;
12
10
  static ID cumo_id_swap_byte;
13
11
 
@@ -932,12 +930,10 @@ cumo_na_new_dimension_for_dot(VALUE self, int pos, int len, bool transpose)
932
930
  static VALUE
933
931
  cumo_na_dot(VALUE self, VALUE other)
934
932
  {
935
- VALUE test;
936
933
  volatile VALUE a1=self, a2=other;
937
934
  cumo_narray_t *na1, *na2;
938
935
 
939
- test = rb_funcall(a1, cumo_id_respond_to_p, 1, cumo_sym_mulsum);
940
- if (!RTEST(test)) {
936
+ if (!rb_respond_to(a1, cumo_id_mulsum)) {
941
937
  rb_raise(rb_eNoMethodError,"requires mulsum method for dot method");
942
938
  }
943
939
  CumoGetNArray(a1,na1);
@@ -994,8 +990,6 @@ Init_cumo_na_data(void)
994
990
  //rb_define_method(cNArray, "dot", cumo_na_dot, 1);
995
991
 
996
992
  cumo_id_mulsum = rb_intern("mulsum");
997
- cumo_sym_mulsum = ID2SYM(cumo_id_mulsum);
998
- cumo_id_respond_to_p = rb_intern("respond_to?");
999
993
  cumo_id_store = rb_intern("store");
1000
994
  cumo_id_swap_byte = rb_intern("swap_byte");
1001
995
  }
@@ -54,7 +54,7 @@ code = DefLib.new do
54
54
  end.result
55
55
 
56
56
  if $output
57
- open($output, "w").write(code)
57
+ File.write($output, code)
58
58
  else
59
59
  $stdout.write(code)
60
60
  end
@@ -63,6 +63,10 @@ module NArrayMethod
63
63
  def_method(meth, "accum_index")
64
64
  end
65
65
 
66
+ def accum_arg(meth)
67
+ def_method(meth, "accum_arg")
68
+ end
69
+
66
70
  def cum(meth, cmacro)
67
71
  def_method(meth, "cum", cmacro:cmacro)
68
72
  end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  def_id "cast"
4
- def_id "eq"
5
- def_id "ne"
6
- def_id "pow"
7
4
  def_id "mulsum"
5
+ def_id "to_a"
8
6
  if is_complex
9
7
  def_id "real"
10
8
  def_id "imag"
@@ -34,7 +32,6 @@ if is_object
34
32
  def_id "bit_xor"
35
33
  def_id "bit_not"
36
34
  def_id "abs"
37
- def_id "minus"
38
35
  def_id "reciprocal"
39
36
  def_id "square"
40
37
  def_id "floor"
@@ -44,6 +41,7 @@ if is_object
44
41
  def_id "nan?"
45
42
  def_id "infinite?"
46
43
  def_id "finite?"
44
+ def_id "-@", "minus"
47
45
  def_id "==", "eq"
48
46
  def_id "!=", "ne"
49
47
  def_id ">" , "gt"
@@ -51,6 +49,9 @@ if is_object
51
49
  def_id "<" , "lt"
52
50
  def_id "<=", "le"
53
51
  def_id "<=>", "ufo"
52
+ else
53
+ def_id "eq"
54
+ def_id "ne"
54
55
  end
55
56
  if (is_float || is_complex) && !is_object
56
57
  def_id "gemm"
@@ -203,7 +204,12 @@ if !is_complex
203
204
  binary2 "divmod"
204
205
  end
205
206
 
206
- pow
207
+
208
+ if !is_bit
209
+ pow
210
+ def_id "**","pow"
211
+ def_alias "pow","**"
212
+ end
207
213
 
208
214
  unary "minus", "-@"
209
215
  unary "reciprocal"
@@ -297,7 +303,7 @@ if is_float
297
303
  cond_unary "isfinite"
298
304
  end
299
305
 
300
- if is_int
306
+ if is_int && !is_object
301
307
  if is_unsigned
302
308
  accum "sum", "u_int64_t", "cumo_cUInt64"
303
309
  accum "prod", "u_int64_t", "cumo_cUInt64"
@@ -327,6 +333,8 @@ if is_comparable
327
333
  accum "ptp", "dtype", "cT"
328
334
  accum_index "max_index"
329
335
  accum_index "min_index"
336
+ accum_arg "argmax"
337
+ accum_arg "argmin"
330
338
  def_method "minmax"
331
339
  def_module_function "maximum", "ewcomp", n_arg:2
332
340
  def_module_function "minimum", "ewcomp", n_arg:2
@@ -0,0 +1,120 @@
1
+ <% (is_float ? ["","_nan"] : [""]).each do |nan| %>
2
+
3
+ <% [64,32].each do |i| %>
4
+ <% unless type_name == 'robject' %>
5
+ void cumo_<%=type_name%>_<%=name%>_int<%=i%>_kernel_launch(cumo_na_reduction_arg_t* arg);
6
+ <% end %>
7
+
8
+ #define idx_t int<%=i%>_t
9
+ static void
10
+ <%=c_iter%>_arg<%=i%><%=nan%>(cumo_na_loop_t *const lp)
11
+ {
12
+ // TODO(sonots): Support nan in CUDA
13
+ <% if type_name == 'robject' || nan == '_nan' %>
14
+ {
15
+ size_t n, idx;
16
+ char *d_ptr, *o_ptr;
17
+ ssize_t d_step;
18
+
19
+ CUMO_INIT_COUNTER(lp, n);
20
+ CUMO_INIT_PTR(lp, 0, d_ptr, d_step);
21
+ o_ptr = CUMO_NDL_PTR(lp,1);
22
+
23
+ CUMO_SHOW_SYNCHRONIZE_FIXME_WARNING_ONCE("<%=name%><%=nan%>", "<%=type_name%>");
24
+ idx = f_<%=name[3..5]%>_index<%=nan%>(n,d_ptr,d_step);
25
+ *(idx_t*)o_ptr = (idx_t)idx;
26
+ }
27
+ <% else %>
28
+ {
29
+ cumo_na_reduction_arg_t arg = cumo_na_make_reduction_arg(lp);
30
+ cumo_<%=type_name%>_<%=name%>_int<%=i%>_kernel_launch(&arg);
31
+ }
32
+ <% end %>
33
+ }
34
+ #undef idx_t
35
+ <% end;end %>
36
+
37
+ /*
38
+ <%=name%>. Returns an index of the <%=name[3..5]%>imum value along the axis. See also `<%=name[3..5]%>_index`.
39
+ <% if is_float %>
40
+ @overload <%=name%>(axis:nil, nan:false)
41
+ @param [TrueClass] nan If true, apply NaN-aware algorithm (return NaN posision if exist).
42
+ <% else %>
43
+ @overload <%=name%>(axis:nil)
44
+ <% end %>
45
+ @param [Numeric,Array,Range] axis Finds <%=name[3..5]%>imum values along the axis and returns indices along the axis.
46
+ @return [Integer,Cumo::Int] returns result indices.
47
+ @example
48
+ Cumo::NArray[3,4,1,2].<%=name%> => <% if name == 'argmin' %>2<% else %>1<% end %>
49
+ */
50
+ static VALUE
51
+ <%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
52
+ {
53
+ <% if type_name == 'robject' %>
54
+ {
55
+ cumo_narray_t *na;
56
+ VALUE reduce;
57
+ cumo_ndfunc_arg_in_t ain[2] = {{Qnil,0},{cumo_sym_reduce,0}};
58
+ cumo_ndfunc_arg_out_t aout[1] = {{0,0,0}};
59
+ cumo_ndfunc_t ndf = {0, CUMO_STRIDE_LOOP_NIP|CUMO_NDF_FLAT_REDUCE|CUMO_NDF_EXTRACT, 2,1, ain,aout};
60
+
61
+ CumoGetNArray(self,na);
62
+ if (na->ndim==0) {
63
+ return INT2FIX(0);
64
+ }
65
+ if (na->size > (~(u_int32_t)0)) {
66
+ aout[0].type = cumo_cInt64;
67
+ ndf.func = <%=c_iter%>_arg64;
68
+ reduce = cumo_na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
69
+ } else {
70
+ aout[0].type = cumo_cInt32;
71
+ ndf.func = <%=c_iter%>_arg32;
72
+ reduce = cumo_na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
73
+ }
74
+
75
+ return cumo_na_ndloop(&ndf, 2, self, reduce);
76
+ }
77
+ <% else %>
78
+ {
79
+ cumo_narray_t *na;
80
+ VALUE reduce, ret;
81
+ cumo_ndfunc_arg_in_t ain[2] = {{Qnil,0},{cumo_sym_reduce,0}};
82
+ cumo_ndfunc_arg_out_t aout[1] = {{0,0,0}};
83
+ cumo_ndfunc_t ndf = {0, CUMO_STRIDE_LOOP_NIP|CUMO_NDF_FLAT_REDUCE|CUMO_NDF_EXTRACT|CUMO_NDF_INDEXER_LOOP, 2,1, ain,aout};
84
+
85
+ CumoGetNArray(self,na);
86
+ if (na->ndim==0) {
87
+ return INT2FIX(0);
88
+ }
89
+ if (na->size > (~(u_int32_t)0)) {
90
+ aout[0].type = cumo_cInt64;
91
+ ndf.func = <%=c_iter%>_arg64;
92
+ <% if is_float %>
93
+ reduce = cumo_na_reduce_dimension(argc, argv, 1, &self, &ndf, <%=c_iter%>_arg64_nan);
94
+ <% else %>
95
+ reduce = cumo_na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
96
+ <% end %>
97
+ } else {
98
+ aout[0].type = cumo_cInt32;
99
+ ndf.func = <%=c_iter%>_arg32;
100
+ <% if is_float %>
101
+ reduce = cumo_na_reduce_dimension(argc, argv, 1, &self, &ndf, <%=c_iter%>_arg32_nan);
102
+ <% else %>
103
+ reduce = cumo_na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
104
+ <% end %>
105
+ }
106
+
107
+ if (cumo_na_has_idx_p(self)) {
108
+ VALUE copy = cumo_na_copy(self); // reduction does not support idx, make contiguous
109
+ ret = cumo_na_ndloop(&ndf, 2, copy, reduce);
110
+ } else {
111
+ ret = cumo_na_ndloop(&ndf, 2, self, reduce);
112
+ }
113
+ if (cumo_compatible_mode_enabled_p()) {
114
+ return rb_funcall(ret, rb_intern("extract_cpu"), 0);
115
+ } else {
116
+ return ret;
117
+ }
118
+ }
119
+ <% end %>
120
+ }
@@ -0,0 +1,66 @@
1
+ <% unless defined?($cumo_narray_gen_tmpl_accum_arg_kernel_included) %>
2
+ <% $cumo_narray_gen_tmpl_accum_arg_kernel_included = 1 %>
3
+ <% unless type_name == 'robject' %>
4
+
5
+ <% [64,32].each do |i| %>
6
+ #define idx_t int<%=i%>_t
7
+
8
+ #if defined(__cplusplus)
9
+ #if 0
10
+ { /* satisfy cc-mode */
11
+ #endif
12
+ } /* extern "C" { */
13
+ #endif
14
+
15
+ struct cumo_<%=type_name%>_argmin_int<%=i%>_impl {
16
+ struct MinAndArgMin {
17
+ dtype min;
18
+ idx_t argmin;
19
+ };
20
+ __device__ MinAndArgMin Identity(idx_t index) { return {DATA_MAX, index}; }
21
+ __device__ MinAndArgMin MapIn(dtype in, idx_t index) { return {in, index}; }
22
+ __device__ void Reduce(MinAndArgMin next, MinAndArgMin& accum) {
23
+ if (accum.min > next.min) {
24
+ accum = next;
25
+ }
26
+ }
27
+ __device__ idx_t MapOut(MinAndArgMin accum) { return accum.argmin; }
28
+ };
29
+
30
+ struct cumo_<%=type_name%>_argmax_int<%=i%>_impl {
31
+ struct MaxAndArgMax {
32
+ dtype max;
33
+ idx_t argmax;
34
+ };
35
+ __device__ MaxAndArgMax Identity(idx_t index) { return {DATA_MIN, index}; }
36
+ __device__ MaxAndArgMax MapIn(dtype in, idx_t index) { return {in, index}; }
37
+ __device__ void Reduce(MaxAndArgMax next, MaxAndArgMax& accum) {
38
+ if (accum.max < next.max) {
39
+ accum = next;
40
+ }
41
+ }
42
+ __device__ idx_t MapOut(MaxAndArgMax accum) { return accum.argmax; }
43
+ };
44
+
45
+ #if defined(__cplusplus)
46
+ extern "C" {
47
+ #if 0
48
+ } /* satisfy cc-mode */
49
+ #endif
50
+ #endif
51
+
52
+ void cumo_<%=type_name%>_argmin_int<%=i%>_kernel_launch(cumo_na_reduction_arg_t* arg)
53
+ {
54
+ cumo_reduce_arg<dtype, idx_t, cumo_<%=type_name%>_argmin_int<%=i%>_impl>(*arg, cumo_<%=type_name%>_argmin_int<%=i%>_impl{});
55
+ }
56
+
57
+ void cumo_<%=type_name%>_argmax_int<%=i%>_kernel_launch(cumo_na_reduction_arg_t* arg)
58
+ {
59
+ cumo_reduce_arg<dtype, idx_t, cumo_<%=type_name%>_argmax_int<%=i%>_impl>(*arg, cumo_<%=type_name%>_argmax_int<%=i%>_impl{});
60
+ }
61
+
62
+ #undef idx_t
63
+ <% end %>
64
+
65
+ <% end %>
66
+ <% end %>
@@ -115,7 +115,11 @@ static VALUE
115
115
  return <%=c_func%>_self(argc, argv, self);
116
116
  } else {
117
117
  v = rb_funcall(klass, cumo_id_cast, 1, self);
118
+ //<% if Gem::Version.create(RUBY_VERSION) < Gem::Version.create('2.7.0') %>
118
119
  return rb_funcall2(v, rb_intern("<%=name%>"), argc, argv);
120
+ //<% else %>
121
+ return rb_funcallv_kw(v, rb_intern("<%=name%>"), argc, argv, RB_PASS_CALLED_KEYWORDS);
122
+ //<% end %>
119
123
  }
120
124
  //<% end %>
121
125
  }
@@ -35,6 +35,13 @@ static VALUE
35
35
  }
36
36
  return v;
37
37
  }
38
+ if (rb_respond_to(obj,cumo_id_to_a)) {
39
+ obj = rb_funcall(obj,cumo_id_to_a,0);
40
+ if (TYPE(obj)!=T_ARRAY) {
41
+ rb_raise(rb_eTypeError, "`to_a' did not return Array");
42
+ }
43
+ return <%=find_tmpl("cast_array").c_func%>(obj);
44
+ }
38
45
  <% if is_object %>
39
46
  return robject_new_dim0(obj);
40
47
  <% else %>
@@ -25,6 +25,12 @@ static void
25
25
  CUMO_STORE_BIT_STEP(a3, p3, s3, idx3, x);
26
26
  }
27
27
  } else {
28
+ a1 += p1/CUMO_NB;
29
+ p1 %= CUMO_NB;
30
+ a2 += p2/CUMO_NB;
31
+ p2 %= CUMO_NB;
32
+ a3 += p3/CUMO_NB;
33
+ p3 %= CUMO_NB;
28
34
  o1 = p1-p3;
29
35
  o2 = p2-p3;
30
36
  l1 = CUMO_NB+o1;
@@ -78,10 +78,16 @@ static VALUE
78
78
  <%=c_func(-1)%>(int argc, VALUE *argv, VALUE self)
79
79
  {
80
80
  VALUE v, reduce;
81
+ cumo_narray_t *na;
82
+
81
83
  cumo_ndfunc_arg_in_t ain[3] = {{cT,0},{cumo_sym_reduce,0},{cumo_sym_init,0}};
82
84
  cumo_ndfunc_arg_out_t aout[1] = {{cumo_cInt64,0}};
83
85
  cumo_ndfunc_t ndf = { <%=c_iter%>, CUMO_FULL_LOOP_NIP, 3, 1, ain, aout };
84
86
 
87
+ CumoGetNArray(self,na);
88
+ if (CUMO_NA_SIZE(na)==0) {
89
+ return INT2FIX(0);
90
+ }
85
91
  reduce = cumo_na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
86
92
  v = cumo_na_ndloop(&ndf, 3, self, reduce, INT2FIX(0));
87
93
  return rb_funcall(v,rb_intern("extract_cpu"),0);
@@ -118,7 +118,7 @@ static VALUE
118
118
 
119
119
  CumoGetNArray(self,na);
120
120
  if (CUMO_NA_SIZE(na)==0) {
121
- return INT2FIX(0);
121
+ return Qfalse;
122
122
  }
123
123
  reduce = cumo_na_reduce_dimension(argc, argv, 1, &self, &ndf, 0);
124
124
  v = cumo_na_ndloop(&ndf, 3, self, reduce, INT2FIX(<%=init_bit%>));
@@ -1,8 +1,9 @@
1
+ #include <stdio.h>
1
2
  static void
2
3
  <%=c_iter%>(cumo_na_loop_t *const lp)
3
4
  {
4
5
  size_t n;
5
- size_t p1, p3;
6
+ ssize_t p1, p3;
6
7
  ssize_t s1, s3;
7
8
  size_t *idx1, *idx3;
8
9
  int o1, l1, r1, len;
@@ -22,6 +23,10 @@ static void
22
23
  CUMO_STORE_BIT_STEP(a3, p3, s3, idx3, x);
23
24
  }
24
25
  } else {
26
+ a1 += p1/CUMO_NB;
27
+ p1 %= CUMO_NB;
28
+ a3 += p3/CUMO_NB;
29
+ p3 %= CUMO_NB;
25
30
  o1 = p1-p3;
26
31
  l1 = CUMO_NB+o1;
27
32
  r1 = CUMO_NB-o1;
@@ -30,7 +35,7 @@ static void
30
35
  if ((int)n<len) len=n;
31
36
  if (o1>=0) x = *a1>>o1;
32
37
  else x = *a1<<-o1;
33
- if (p1+len>CUMO_NB) x |= *(a1+1)<<r1;
38
+ if (p1+len>(ssize_t)CUMO_NB) x |= *(a1+1)<<r1;
34
39
  a1++;
35
40
  *a3 = (x & (CUMO_SLB(len)<<p3)) | (*a3 & ~(CUMO_SLB(len)<<p3));
36
41
  a3++;
@@ -24,6 +24,10 @@ static void
24
24
  CUMO_STORE_BIT_STEP(a3, p3, s3, idx3, y);
25
25
  }
26
26
  } else {
27
+ a1 += p1/CUMO_NB;
28
+ p1 %= CUMO_NB;
29
+ a3 += p3/CUMO_NB;
30
+ p3 %= CUMO_NB;
27
31
  o1 = p1-p3;
28
32
  l1 = CUMO_NB+o1;
29
33
  r1 = CUMO_NB-o1;
@@ -63,6 +63,7 @@ static ID cumo_id_dup;
63
63
  static ID cumo_id_bracket;
64
64
  static ID cumo_id_shift_left;
65
65
  static ID cumo_id_mask;
66
+ static ID cumo_id_where;
66
67
 
67
68
 
68
69
  static void
@@ -159,6 +160,13 @@ cumo_na_parse_narray_index(VALUE a, int orig_dim, ssize_t size, cumo_na_index_ar
159
160
  if (CUMO_NA_NDIM(na) != 1) {
160
161
  rb_raise(rb_eIndexError, "should be 1-d NArray");
161
162
  }
163
+ if (rb_obj_class(a) == cumo_cBit) {
164
+ if (CUMO_NA_SIZE(na) != (size_t)size) {
165
+ rb_raise(rb_eIndexError, "Bit-NArray size mismatch");
166
+ }
167
+ a = rb_funcall(a, cumo_id_where, 0);
168
+ CumoGetNArray(a,na);
169
+ }
162
170
  n = CUMO_NA_SIZE(na);
163
171
  idx = cumo_na_new(cIndex,1,&n);
164
172
  cumo_na_store(idx,a);
@@ -1138,4 +1146,5 @@ Init_cumo_na_index()
1138
1146
  cumo_id_bracket = rb_intern("[]");
1139
1147
  cumo_id_shift_left = rb_intern("<<");
1140
1148
  cumo_id_mask = rb_intern("mask");
1149
+ cumo_id_where = rb_intern("where");
1141
1150
  }
@@ -1346,8 +1346,8 @@ cumo_na_s_from_binary(int argc, VALUE *argv, VALUE type)
1346
1346
  break;
1347
1347
  case T_ARRAY:
1348
1348
  nd = RARRAY_LEN(vshape);
1349
- if (nd == 0 || nd > CUMO_NA_MAX_DIMENSION) {
1350
- rb_raise(cumo_na_eDimensionError,"too long or empty shape (%d)", nd);
1349
+ if (nd > CUMO_NA_MAX_DIMENSION) {
1350
+ rb_raise(cumo_na_eDimensionError,"shape exceeds max dimension");
1351
1351
  }
1352
1352
  shape = ALLOCA_N(size_t,nd);
1353
1353
  len = 1;
@@ -164,7 +164,7 @@ print_ndloop(cumo_na_md_loop_t *lp) {
164
164
  for (i=0; i<lp->user.ndim; i++) {
165
165
  printf(" &user.args[%d].iter[%d] = 0x%"SZF"x\n", j,i, (size_t)&lp->user.args[j].iter[i]);
166
166
  printf(" user.args[%d].iter[%d].pos = %"SZF"u\n", j,i, lp->user.args[j].iter[i].pos);
167
- printf(" user.args[%d].iter[%d].step = %"SZF"u\n", j,i, lp->user.args[j].iter[i].step);
167
+ printf(" user.args[%d].iter[%d].step = %"SZF"d\n", j,i, lp->user.args[j].iter[i].step);
168
168
  printf(" user.args[%d].iter[%d].idx = 0x%"SZF"x (cuda:%d)\n", j,i, (size_t)lp->user.args[j].iter[i].idx, cumo_cuda_runtime_is_device_memory(lp->user.args[j].iter[i].idx));
169
169
  // printf(" user.args[%d].iter[%d].idx = 0x%"SZF"x\n", j,i, (size_t)lp->user.args[j].iter[i].idx);
170
170
  }
@@ -175,7 +175,7 @@ print_ndloop(cumo_na_md_loop_t *lp) {
175
175
  for (i=0; i<=nd; i++) {
176
176
  printf(" &xargs[%d].iter[%d] = 0x%"SZF"x\n", j,i, (size_t)&LITER(lp,i,j));
177
177
  printf(" xargs[%d].iter[%d].pos = %"SZF"u\n", j,i, LITER(lp,i,j).pos);
178
- printf(" xargs[%d].iter[%d].step = %"SZF"u\n", j,i, LITER(lp,i,j).step);
178
+ printf(" xargs[%d].iter[%d].step = %"SZF"d\n", j,i, LITER(lp,i,j).step);
179
179
  printf(" xargs[%d].iter[%d].idx = 0x%"SZF"x (cuda:%d)\n", j,i, (size_t)LITER(lp,i,j).idx, cumo_cuda_runtime_is_device_memory(LITER(lp,i,j).idx));
180
180
  // printf(" xargs[%d].iter[%d].idx = 0x%"SZF"x\n", j,i, (size_t)LITER(lp,i,j).idx);
181
181
  }
@@ -108,7 +108,19 @@ module Cumo
108
108
 
109
109
  # Convert the argument to an narray if not an narray.
110
110
  def self.cast(a)
111
- a.kind_of?(NArray) ? a : NArray.array_type(a).cast(a)
111
+ case a
112
+ when NArray
113
+ a
114
+ when Array,Numeric
115
+ NArray.array_type(a).cast(a)
116
+ else
117
+ if a.respond_to?(:to_a)
118
+ a = a.to_a
119
+ NArray.array_type(a).cast(a)
120
+ else
121
+ raise TypeError,"invalid type for NArray"
122
+ end
123
+ end
112
124
  end
113
125
 
114
126
  def self.asarray(a)
@@ -461,8 +473,10 @@ module Cumo
461
473
  arrays.each do |a|
462
474
  fst = lst
463
475
  lst = fst + (a.shape[axis - nd] || 1)
464
- refs[axis] = fst...lst
465
- result[*refs] = a
476
+ if lst > fst
477
+ refs[axis] = fst...lst
478
+ result[*refs] = a
479
+ end
466
480
  end
467
481
  result
468
482
  end
@@ -642,13 +656,17 @@ module Cumo
642
656
  result = self.class.zeros(*self_shape)
643
657
  lst = shape[axis]
644
658
  refs = [true] * ndim
645
- refs[axis] = 0...lst
646
- result[*refs] = self
659
+ if lst > 0
660
+ refs[axis] = 0...lst
661
+ result[*refs] = self
662
+ end
647
663
  arrays.each do |a|
648
664
  fst = lst
649
665
  lst = fst + (a.shape[axis - ndim] || 1)
650
- refs[axis] = fst...lst
651
- result[*refs] = a
666
+ if lst > fst
667
+ refs[axis] = fst...lst
668
+ result[*refs] = a
669
+ end
652
670
  end
653
671
  result
654
672
  end
@@ -1186,6 +1204,35 @@ module Cumo
1186
1204
  end
1187
1205
  end
1188
1206
 
1207
+ # Percentile
1208
+ #
1209
+ # @param q [Numo::NArray]
1210
+ # @param axis [Integer] applied axis
1211
+ # @return [Numo::NArray] return percentile
1212
+ def percentile(q, axis: nil)
1213
+ raise ArgumentError, "q is out of range" if q < 0 || q > 100
1214
+
1215
+ x = self
1216
+ unless axis
1217
+ axis = 0
1218
+ x = x.flatten
1219
+ end
1220
+
1221
+ sorted = x.sort(axis: axis)
1222
+ x = q / 100.0 * (sorted.shape[axis] - 1)
1223
+ r = x % 1
1224
+ i = x.floor
1225
+ refs = [true] * sorted.ndim
1226
+ refs[axis] = i
1227
+ if i == sorted.shape[axis] - 1
1228
+ sorted[*refs]
1229
+ else
1230
+ refs_upper = refs.dup
1231
+ refs_upper[axis] = i + 1
1232
+ sorted[*refs] + r * (sorted[*refs_upper] - sorted[*refs])
1233
+ end
1234
+ end
1235
+
1189
1236
  # Kronecker product of two arrays.
1190
1237
  #
1191
1238
  # kron(a,b)[k_0, k_1, ...] = a[i_0, i_1, ...] * b[j_0, j_1, ...]
data/test/bit_test.rb CHANGED
@@ -139,6 +139,37 @@ class BitTest < Test::Unit::TestCase
139
139
  end
140
140
  end
141
141
 
142
+ procs = [
143
+ [proc{|tp,a| tp[*a] },""],
144
+ ]
145
+ procs.each do |init, ref|
146
+
147
+ test "#{dtype},[]#{ref}" do
148
+ src = []
149
+ n = src.size
150
+ a = init.call(dtype, src)
151
+
152
+ assert { a == src }
153
+ assert { (a & 0) == [0] * n }
154
+ assert { (a & 1) == src }
155
+ assert { (a | 0) == src }
156
+ assert { (a | 1) == [1] * n }
157
+ assert { (a ^ 0) == src.map {|x| x ^ 0 } }
158
+ assert { (a ^ 1) == src.map {|x| x ^ 1 } }
159
+ assert { ~a == src.map {|x| 1 - x } }
160
+
161
+ assert { a.count_true == 0 }
162
+ assert { a.count_false == 0 }
163
+ assert { a.where == [] }
164
+ assert { a.where2 == [[], []] }
165
+ assert { a.mask(Cumo::DFloat[]) == [] }
166
+ assert { !a.all? }
167
+ assert { !a.any? }
168
+ assert { a.none? }
169
+ end
170
+
171
+ end
172
+
142
173
  test "store to view" do
143
174
  n = 14
144
175
  x = Cumo::Bit.zeros(n + 2, n + 2, 3)
@@ -154,4 +185,10 @@ class BitTest < Test::Unit::TestCase
154
185
  assert { (~y[1..-2, 1..-2, 0]).where.size == 0 }
155
186
  assert { y[true, true, 1].where.size == 0 }
156
187
  end
188
+
189
+ test "assign nil" do
190
+ x = Cumo::RObject.cast([1, 2, 3])
191
+ x[Cumo::Bit.cast([0, 1, 0])] = nil
192
+ assert { x.to_a == [1, nil, 3] }
193
+ end
157
194
  end
data/test/narray_test.rb CHANGED
@@ -344,13 +344,35 @@ class NArrayTest < Test::Unit::TestCase
344
344
  assert { a.min_index(axis: 0) == [0, 1, 2] }
345
345
  assert { a.max_index(axis: 1) == [2, 5] }
346
346
  assert { a.max_index(axis: 0) == [3, 4, 5] }
347
+ assert { a.argmin == 0 }
348
+ assert { a.argmax == 5 }
349
+ assert { a.argmin(axis: 1) == [0, 0] }
350
+ assert { a.argmin(axis: 0) == [0, 0, 0] }
351
+ assert { a.argmax(axis: 1) == [2, 2] }
352
+ assert { a.argmax(axis: 0) == [1, 1, 1] }
347
353
  assert { (a >= 3) == [[0, 0, 1], [1, 1, 1]] }
348
354
  assert { (a > 3) == [[0, 0, 0], [1, 1, 1]] }
349
355
  assert { (a <= 3) == [[1, 1, 1], [0, 0, 0]] }
350
356
  assert { (a < 3) == [[1, 1, 0], [0, 0, 0]] }
351
357
  assert { (a.eq 3) == [[0, 0, 1], [0, 0, 0]] }
358
+ assert { a[a.ne 3] == [1, 2, 5, 7, 11] }
359
+ assert { a[a[true, 2] < 5, true] == [[1, 2, 3]] }
360
+ assert { a[true, a[1, true] > 5] == [[2, 3], [7, 11]] }
361
+ assert { a[:*, (a[0, :*] % 2).eq(1)] == [[1, 3], [5, 11]] }
352
362
  assert { a.sort == src }
353
363
  assert { a.sort_index == [[0, 1, 2], [3, 4, 5]] }
364
+ assert { a.percentile(0) == 1.0 }
365
+ assert { a.percentile(50) == 4.0 }
366
+ assert { a.percentile(90) == 9.0 }
367
+ assert { a.percentile(100) == 11.0 }
368
+ assert { a.percentile(0, axis: 0) == [1, 2, 3] }
369
+ assert { a.percentile(50, axis: 0) == [3, 4.5, 7] }
370
+ assert { a.percentile(90, axis: 0) == [4.6, 6.5, 10.2] }
371
+ assert { a.percentile(100, axis: 0) == [5, 7, 11] }
372
+ assert { a.percentile(0, axis: 1) == [1, 5] }
373
+ assert { a.percentile(50, axis: 1) == [2, 7] }
374
+ assert { a.percentile(90, axis: 1) == [2.8, 10.2] }
375
+ assert { a.percentile(100, axis: 1) == [3, 11] }
354
376
  end
355
377
  assert { a.dup.fill(12) == [[12] * 3] * 2 }
356
378
  assert { (a + 1) == [[2, 3, 4], [6, 8, 12]] }
@@ -704,6 +726,8 @@ class NArrayTest < Test::Unit::TestCase
704
726
  [4, 1, 6]]]
705
727
  assert { a.max_index(2) == [[1, 5, 8], [9, 12, 17]] }
706
728
  assert { a.max(2) == [[8, 6, 5], [7, 9, 6]] }
729
+ assert { a.argmax(2) == [[1, 2, 2], [0, 0, 2]] }
730
+ assert { a.argmin(2) == [[2, 0, 0], [2, 2, 1]] }
707
731
 
708
732
  unless [Cumo::UInt64, Cumo::UInt32, Cumo::UInt16, Cumo::UInt8].include?(dtype)
709
733
  a = dtype[[[-6, -8, -5],
@@ -796,6 +820,11 @@ class NArrayTest < Test::Unit::TestCase
796
820
  end
797
821
  end
798
822
 
823
+ test "cast any object that responds to to_a" do
824
+ object = Struct.new(:to_a).new([1, 2, 3])
825
+ assert { Cumo::NArray.cast(object) == [1, 2, 3] }
826
+ end
827
+
799
828
  test "Cumo::DFloat.cast(Cumo::RObject[1, nil, 3])" do
800
829
  assert_equal(Cumo::DFloat[1, Float::NAN, 3].format_to_a,
801
830
  Cumo::DFloat.cast(Cumo::RObject[1, nil, 3]).format_to_a)
@@ -822,4 +851,40 @@ class NArrayTest < Test::Unit::TestCase
822
851
  assert { Cumo::SComplex[1].rms == 1.0 }
823
852
  assert { Cumo::DComplex[1].rms == 1.0 }
824
853
  end
854
+
855
+ test "concatenate with empty arrays" do
856
+ a = Cumo::DFloat[1, 2, 3]
857
+ empty = Cumo::DFloat[]
858
+ assert { Cumo::NArray.concatenate([empty, a]) == [1, 2, 3] }
859
+ assert { Cumo::NArray.concatenate([a, empty]) == [1, 2, 3] }
860
+ assert { Cumo::NArray.concatenate([empty, empty]) == [] }
861
+ assert { a.concatenate(empty) == [1, 2, 3] }
862
+ assert { empty.concatenate(a) == [1, 2, 3] }
863
+ assert { empty.concatenate(empty) == [] }
864
+ end
865
+
866
+ test "argmax/argmin" do
867
+ [Cumo::DFloat, Cumo::Int32, Cumo::UInt8].each do |dtype|
868
+ a = dtype[3, 4, 1, 2]
869
+ assert { a.argmax == 1 }
870
+ assert { a.argmin == 2 }
871
+
872
+ b = dtype[[3, 4, 1], [2, 0, 5]]
873
+ assert { b.argmax == 5 }
874
+ assert { b.argmin == 4 }
875
+ assert { b.argmax(axis: 1) == [1, 2] }
876
+ assert { b.argmax(axis: 0) == [0, 0, 1] }
877
+ assert { b.argmin(axis: 1) == [2, 1] }
878
+ assert { b.argmin(axis: 0) == [1, 1, 0] }
879
+ assert { b.at(b.argmax(axis: 0), 0..-1) == [3, 4, 5] }
880
+ assert { b.at(b.argmin(axis: 0), 0..-1) == [2, 0, 1] }
881
+ end
882
+
883
+ # NaN-aware (nan:true returns the NaN position; nan:false ignores NaN)
884
+ c = Cumo::DFloat[3.0, Float::NAN, 1.0, 5.0]
885
+ assert { c.argmax == 3 }
886
+ assert { c.argmax(nan: true) == 1 }
887
+ assert { c.argmin == 2 }
888
+ assert { c.argmin(nan: true) == 1 }
889
+ end
825
890
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cumo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.5.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naotoshi Seo
@@ -157,6 +157,8 @@ files:
157
157
  - ext/cumo/narray/gen/narray_def.rb
158
158
  - ext/cumo/narray/gen/spec.rb
159
159
  - ext/cumo/narray/gen/tmpl/accum.c
160
+ - ext/cumo/narray/gen/tmpl/accum_arg.c
161
+ - ext/cumo/narray/gen/tmpl/accum_arg_kernel.cu
160
162
  - ext/cumo/narray/gen/tmpl/accum_binary.c
161
163
  - ext/cumo/narray/gen/tmpl/accum_binary_kernel.cu
162
164
  - ext/cumo/narray/gen/tmpl/accum_index.c
@@ -331,7 +333,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
331
333
  - !ruby/object:Gem::Version
332
334
  version: '0'
333
335
  requirements: []
334
- rubygems_version: 4.0.6
336
+ rubygems_version: 4.0.15
335
337
  specification_version: 4
336
338
  summary: Cumo is CUDA aware numerical library whose interface is highly compatible
337
339
  with Ruby Numo