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 +4 -4
- data/CHANGELOG.md +8 -0
- data/ext/cumo/include/cumo/reduce_kernel.h +84 -0
- data/ext/cumo/include/cumo.h +1 -1
- data/ext/cumo/narray/gen/narray_def.rb +4 -0
- data/ext/cumo/narray/gen/spec.rb +2 -0
- data/ext/cumo/narray/gen/tmpl/accum_arg.c +120 -0
- data/ext/cumo/narray/gen/tmpl/accum_arg_kernel.cu +66 -0
- data/ext/cumo/narray/index.c +9 -0
- data/lib/cumo/narray/extra.rb +12 -6
- data/test/narray_test.rb +48 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 96a38fa0ad4be223020cef21720e30e9a32fcd2901798279293924df8bfd0f92
|
|
4
|
+
data.tar.gz: c826e49bea46001d6764c7d0f8ad124e5b6072543eb97a07990a26453dd71bf7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
data/ext/cumo/include/cumo.h
CHANGED
data/ext/cumo/narray/gen/spec.rb
CHANGED
|
@@ -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 %>
|
data/ext/cumo/narray/index.c
CHANGED
|
@@ -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
|
}
|
data/lib/cumo/narray/extra.rb
CHANGED
|
@@ -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
|
-
|
|
477
|
-
|
|
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
|
-
|
|
658
|
-
|
|
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
|
-
|
|
663
|
-
|
|
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
|
+
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.
|
|
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
|