cumo 0.5.4 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0aea399ff1a36438f62f47a0a1c0350366971c34000343eb20376e8d3d448297
4
- data.tar.gz: 8f8f8fab9df42cf544131dc38ac2a9ff9c2eda218a3be11eb2a887c26e86fac1
3
+ metadata.gz: 96a38fa0ad4be223020cef21720e30e9a32fcd2901798279293924df8bfd0f92
4
+ data.tar.gz: c826e49bea46001d6764c7d0f8ad124e5b6072543eb97a07990a26453dd71bf7
5
5
  SHA512:
6
- metadata.gz: d57caea8974f8d7c8be8d62c0c5d52004bb414092e178459d29a5e5d3566999ce03899a5cdd82d5b3cdc0d4b690f4c1e9991cdeb40ec8a7eec5f6bd33157ec7b
7
- data.tar.gz: 7cb0cd15e20c826806209ed91279694f41cc17f54aade1043ed3defd62fc9a9bdccadc0bc9345d1f802302399b915adc7fac1c2059bded270991644babce6d1a
6
+ metadata.gz: 1dba1ea3cb5a9c93044d222a9d03c975809c5b03d7925702aa3357a0244752d532cb9421b0632e71808944685c3ca44e7a0fc6032ca8c39d8083c279596dce61
7
+ data.tar.gz: 81c933a8f07f862b22a0c6be5e397000d4ea9476139203353907ba7de21a7aae418264fa8425b197d6302861a2788d262af2d2ecd2e34100900d2293706439f4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
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
+
1
9
  # 0.5.4 (2026/05/30)
2
10
 
3
11
  Fixes:
@@ -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
@@ -10,7 +10,7 @@ extern "C" {
10
10
  #endif
11
11
  #endif
12
12
 
13
- #define CUMO_VERSION "0.5.4"
13
+ #define CUMO_VERSION "0.5.5"
14
14
  #define CUMO_VERSION_CODE 51
15
15
 
16
16
  bool cumo_compatible_mode_enabled_p();
@@ -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
@@ -333,6 +333,8 @@ if is_comparable
333
333
  accum "ptp", "dtype", "cT"
334
334
  accum_index "max_index"
335
335
  accum_index "min_index"
336
+ accum_arg "argmax"
337
+ accum_arg "argmin"
336
338
  def_method "minmax"
337
339
  def_module_function "maximum", "ewcomp", n_arg:2
338
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 %>
@@ -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
  }
@@ -473,8 +473,10 @@ module Cumo
473
473
  arrays.each do |a|
474
474
  fst = lst
475
475
  lst = fst + (a.shape[axis - nd] || 1)
476
- refs[axis] = fst...lst
477
- result[*refs] = a
476
+ if lst > fst
477
+ refs[axis] = fst...lst
478
+ result[*refs] = a
479
+ end
478
480
  end
479
481
  result
480
482
  end
@@ -654,13 +656,17 @@ module Cumo
654
656
  result = self.class.zeros(*self_shape)
655
657
  lst = shape[axis]
656
658
  refs = [true] * ndim
657
- refs[axis] = 0...lst
658
- result[*refs] = self
659
+ if lst > 0
660
+ refs[axis] = 0...lst
661
+ result[*refs] = self
662
+ end
659
663
  arrays.each do |a|
660
664
  fst = lst
661
665
  lst = fst + (a.shape[axis - ndim] || 1)
662
- refs[axis] = fst...lst
663
- result[*refs] = a
666
+ if lst > fst
667
+ refs[axis] = fst...lst
668
+ result[*refs] = a
669
+ end
664
670
  end
665
671
  result
666
672
  end
data/test/narray_test.rb CHANGED
@@ -344,11 +344,21 @@ 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]] }
354
364
  assert { a.percentile(0) == 1.0 }
@@ -716,6 +726,8 @@ class NArrayTest < Test::Unit::TestCase
716
726
  [4, 1, 6]]]
717
727
  assert { a.max_index(2) == [[1, 5, 8], [9, 12, 17]] }
718
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]] }
719
731
 
720
732
  unless [Cumo::UInt64, Cumo::UInt32, Cumo::UInt16, Cumo::UInt8].include?(dtype)
721
733
  a = dtype[[[-6, -8, -5],
@@ -839,4 +851,40 @@ class NArrayTest < Test::Unit::TestCase
839
851
  assert { Cumo::SComplex[1].rms == 1.0 }
840
852
  assert { Cumo::DComplex[1].rms == 1.0 }
841
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
842
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.4
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.10
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