1
0
mirror of https://github.com/exaloop/codon.git synced 2025-06-03 15:03:52 +08:00
codon/stdlib/numpy/reductions.codon
A. R. Shajii b8c1eeed36
2025 updates (#619)
* 2025 updates

* Update ci.yml
2025-01-29 15:41:43 -05:00

2935 lines
90 KiB
Python

# Copyright (C) 2022-2025 Exaloop Inc. <https://exaloop.io>
from .ndarray import ndarray
from .routines import asarray, broadcast_to, full, copyto, round, moveaxis, concatenate, take, atleast_1d
from .ndmath import isnan as math_isnan, floor, ceil, subtract, add, true_divide
from .lib.arraysetops import unique
import util
newaxis = None
def _check_out(out, shape):
if not isinstance(out, ndarray):
compile_error("output must be an array")
if out.ndim != staticlen(shape):
compile_error("output parameter has the wrong number of dimensions")
if out.shape != shape:
raise ValueError("output parameter has incorrect shape")
def _float(x):
T = type(x)
if (T is float or T is float32 or T is float16 or T is complex
or T is complex64):
return x
else:
return util.cast(x, float)
def _nan(T: type):
if T is float or T is float32 or T is float16:
return util.nan(T)
elif T is complex:
return complex(util.nan64(), util.nan64())
elif T is complex64:
return complex64(util.nan32(), util.nan32())
else:
compile_error("[internal error] no nan for type " + T.__name__)
def _isnan(x):
T = type(x)
if T is float or T is float32 or T is float16:
return util.isnan(x)
else:
return math_isnan(x)
def _supports_nan(T: type):
return (T is float or T is float32 or T is float16 or T is float128
or T is bfloat16 or T is complex or T is complex64)
def _nan_to_back(v: Ptr[T], n: int, T: type):
if _supports_nan(T):
fill_index = 0
while fill_index < n and not _isnan(v[fill_index]):
fill_index += 1
for i in range(fill_index + 1, n):
e = v[i]
if not _isnan(e):
v[fill_index] = e
fill_index += 1
return fill_index
else:
return n
def _make_reducer(R, ans_type: type, dtype: type, conv_to_float: Static[int],
bool_to_int: Static[int], **kwargs):
if dtype is NoneType:
if conv_to_float:
ftype = type(_float(ans_type()))
return R(ftype, **kwargs)
elif bool_to_int and ans_type is bool:
return R(int, **kwargs)
else:
return R(ans_type, **kwargs)
else:
if conv_to_float:
ftype = type(_float(dtype()))
return R(ftype, **kwargs)
else:
return R(dtype, **kwargs)
def _cast_elem(e0, dtype: type, conv_to_float: Static[int]):
if dtype is not NoneType:
e1 = util.cast(e0, dtype)
else:
e1 = e0
if conv_to_float:
e2 = _float(e1)
else:
e2 = e1
return e2
def _increment_ptr(p: Ptr[T], stride: int, T: type):
return Ptr[T](p.as_byte() + stride)
def _where_to_array(where, arr):
if where is None or isinstance(where, util._NoValue):
return None
else:
return broadcast_to(asarray(where), arr.shape)
def _pairwise_sum_complex(a: Ptr[C], n: int, stride: int, C: type):
PW_BLOCKSIZE: Static[int] = 128
T = type(C().real)
sz = T.__elemsize__
p = a.as_byte()
if n < 8:
rr = T(-0.0)
ri = T(-0.0)
for i in range(0, n, 2):
rr += Ptr[T](p + i * stride + 0)[0]
ri += Ptr[T](p + i * stride + sz)[0]
return C(rr, ri)
elif n <= PW_BLOCKSIZE:
r0 = Ptr[T](p + 0 * stride)[0]
r1 = Ptr[T](p + 0 * stride + sz)[0]
r2 = Ptr[T](p + 2 * stride)[0]
r3 = Ptr[T](p + 2 * stride + sz)[0]
r4 = Ptr[T](p + 4 * stride)[0]
r5 = Ptr[T](p + 4 * stride + sz)[0]
r6 = Ptr[T](p + 6 * stride)[0]
r7 = Ptr[T](p + 6 * stride + sz)[0]
i = 8
while i < n - (n & 7):
(p + (i + 512//sz)*stride).__prefetch_r3__()
r0 += Ptr[T](p + (i + 0) * stride)[0]
r1 += Ptr[T](p + (i + 0) * stride + sz)[0]
r2 += Ptr[T](p + (i + 2) * stride)[0]
r3 += Ptr[T](p + (i + 2) * stride + sz)[0]
r4 += Ptr[T](p + (i + 4) * stride)[0]
r5 += Ptr[T](p + (i + 4) * stride + sz)[0]
r6 += Ptr[T](p + (i + 6) * stride)[0]
r7 += Ptr[T](p + (i + 6) * stride + sz)[0]
i += 8
rr = (r0 + r2) + (r4 + r6)
ri = (r1 + r3) + (r5 + r7)
while i < n:
rr += Ptr[T](p + i * stride + 0)[0]
ri += Ptr[T](p + i * stride + sz)[0]
i += 2
return C(rr, ri)
else:
n2 = n >> 1
n2 -= n2 & 7
return (_pairwise_sum_complex(a, n2, stride) +
_pairwise_sum_complex(Ptr[C](p + n2 * stride), n - n2, stride))
def _pairwise_sum(a: Ptr[T], n: int, stride: int, T: type, dtype: type = NoneType):
if T is complex or T is complex64:
return _pairwise_sum_complex(a, n << 1, stride >> 1)
if dtype is NoneType:
return _pairwise_sum(a, n, stride, dtype=T)
PW_BLOCKSIZE: Static[int] = 128
p = a.as_byte()
if n < 8:
res = util.cast(T(-0.0), dtype)
for i in range(n):
res += util.cast(Ptr[T](p + i * stride)[0], dtype)
return res
elif n <= PW_BLOCKSIZE:
r0 = util.cast(Ptr[T](p + 0 * stride)[0], dtype)
r1 = util.cast(Ptr[T](p + 1 * stride)[0], dtype)
r2 = util.cast(Ptr[T](p + 2 * stride)[0], dtype)
r3 = util.cast(Ptr[T](p + 3 * stride)[0], dtype)
r4 = util.cast(Ptr[T](p + 4 * stride)[0], dtype)
r5 = util.cast(Ptr[T](p + 5 * stride)[0], dtype)
r6 = util.cast(Ptr[T](p + 6 * stride)[0], dtype)
r7 = util.cast(Ptr[T](p + 7 * stride)[0], dtype)
i = 8
while i < n - (n & 7):
(p + (i + 512//T.__elemsize__)*stride).__prefetch_r3__()
r0 += util.cast(Ptr[T](p + (i + 0) * stride)[0], dtype)
r1 += util.cast(Ptr[T](p + (i + 1) * stride)[0], dtype)
r2 += util.cast(Ptr[T](p + (i + 2) * stride)[0], dtype)
r3 += util.cast(Ptr[T](p + (i + 3) * stride)[0], dtype)
r4 += util.cast(Ptr[T](p + (i + 4) * stride)[0], dtype)
r5 += util.cast(Ptr[T](p + (i + 5) * stride)[0], dtype)
r6 += util.cast(Ptr[T](p + (i + 6) * stride)[0], dtype)
r7 += util.cast(Ptr[T](p + (i + 7) * stride)[0], dtype)
i += 8
res = ((r0 + r1) + (r2 + r3)) + ((r4 + r5) + (r6 + r7))
while i < n:
res += util.cast(Ptr[T](p + i * stride)[0], dtype)
i += 1
return res
else:
n2 = n >> 1
n2 -= n2 & 7
return (_pairwise_sum(a, n2, stride, dtype=dtype) +
_pairwise_sum(Ptr[T](p + n2 * stride), n - n2, stride, dtype=dtype))
def _empty_like(arr, shape, dtype: type):
fcontig = arr._should_transpose()
p = Ptr[dtype](util.count(shape))
return ndarray(shape, p, fcontig=fcontig)
def _reduce_all(arr,
R,
empty,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
where=util._NoValue(),
conv_to_float: Static[int] = False,
bool_to_int: Static[int] = False,
**kwargs):
if out is not None:
if keepdims:
_check_out(out, (1, ) * arr.ndim)
else:
_check_out(out, ())
n = arr.size
p = arr.data
shape = arr.shape
strides = arr.strides
if empty is not None:
if n == 0:
empty(**kwargs)
where = _where_to_array(where, arr)
redux = _make_reducer(R, arr.dtype, dtype, conv_to_float, bool_to_int, **kwargs)
i = 0
if where is None:
if arr.ndim == 1:
stride = strides[0]
if hasattr(redux, "loop"):
redux.loop(p, n, stride, partial=False)
i = n
else:
while i < n:
e = _cast_elem(p[0], dtype, conv_to_float)
redux.accept(e, i)
if redux.done():
break
p = _increment_ptr(p, stride)
i += 1
else:
if arr._is_contig:
if hasattr(redux, "loop"):
redux.loop(p, n, arr.itemsize, partial=False)
i = n
else:
while i < n:
e = _cast_elem(p[i], dtype, conv_to_float)
redux.accept(e, i)
if redux.done():
break
i += 1
else:
if hasattr(redux, "loop") and arr.ndim > 0:
loop_axis = -1
min_abs_stride = 0x7FFFFFFFFFFFFFFF
for i in staticrange(staticlen(arr.ndim)):
stride = strides[i]
if stride:
abs_stride = abs(stride)
if abs_stride < min_abs_stride:
loop_axis = i
min_abs_stride = abs_stride
if loop_axis == -1:
loop_axis = arr.ndim - 1
outer_loop_shape = util.tuple_delete(shape, loop_axis)
loop_size = util.tuple_get(shape, loop_axis)
loop_stride = util.tuple_get(strides, loop_axis)
for idx in util.multirange(outer_loop_shape):
idx1 = util.tuple_insert(idx, loop_axis, 0)
q = arr._ptr(idx1)
redux.loop(q, loop_size, loop_stride, partial=True)
i = loop_size * util.count(outer_loop_shape)
else:
A = arr.T if arr._should_transpose() else arr
for idx in util.multirange(A.shape):
e = _cast_elem(A._ptr(idx)[0], dtype, conv_to_float)
redux.accept(e, i)
if redux.done():
break
i += 1
else:
if arr._contig_match(where):
w = where.data
for k in range(n):
if not w[k]:
continue
e = _cast_elem(p[k], dtype, conv_to_float)
redux.accept(e, i)
if redux.done():
break
i += 1
else:
transpose = arr._should_transpose(where)
A = arr
W = where
if transpose:
A = A.T
W = W.T
for idx in util.multirange(A.shape):
if not W._ptr(idx)[0]:
continue
e = _cast_elem(A._ptr(idx)[0], dtype, conv_to_float)
redux.accept(e, i)
if redux.done():
break
i += 1
ans = redux.result(i)
if out is not None:
out.data[0] = util.cast(ans, out.dtype)
return out
else:
if keepdims:
return asarray(ans).reshape((1, ) * arr.ndim)
else:
return ans
@tuple
class _GradualFunctor:
redux: R
k: int
kwargs: KW
dtype: type
conv_to_float: Static[int]
R: type
KW: type
def __new__(redux: R,
k: int,
dtype: type,
conv_to_float: Static[int],
kwargs: KW,
R: type,
KW: type) -> _GradualFunctor[dtype, conv_to_float, R, KW]:
return (redux, k, kwargs)
def __call__(self, q, p):
e = _cast_elem(p[0], self.dtype, self.conv_to_float)
q[0] = util.cast(
self.redux.gradual_accept(q[0], e, self.k, **self.kwargs), type(q[0]))
def _reduce_gradual(arr,
R,
empty,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
conv_to_float: Static[int] = False,
bool_to_int: Static[int] = False,
**kwargs):
data = arr.data
shape = arr.shape
strides = arr.strides
ax = axis
redux = _make_reducer(R, arr.dtype, dtype, conv_to_float,
bool_to_int, **kwargs)
if hasattr(redux, "gradual_init"):
init_value = redux.gradual_init(**kwargs)
else:
init_value = None
if staticlen(ax) == 1:
ax0 = ax[0]
length = util.tuple_get(shape, ax0)
stride = util.tuple_get(arr.strides, ax0)
iter_shape = util.tuple_delete(shape, ax0)
sub_strides = util.tuple_delete(arr.strides, ax0)
if keepdims:
ans_shape = util.tuple_set(shape, ax0, 1)
else:
ans_shape = iter_shape
if out is None:
out_type = type(redux.result(0))
ans = _empty_like(arr, iter_shape, out_type)
else:
_check_out(out, ans_shape)
if keepdims:
sub_ans_strides = util.tuple_delete(out.strides, ax0)
ans = ndarray(iter_shape, sub_ans_strides, out.data)
else:
ans = out
if init_value is not None:
for i in range(ans.size):
ans.data[i] = util.cast(init_value, ans.dtype)
for k in range(length):
sub_arr_ptr = _increment_ptr(arr.data, k * stride)
sub_arr = ndarray(iter_shape, sub_strides, sub_arr_ptr)
fn = _GradualFunctor(redux, k, dtype, conv_to_float, kwargs)
ndarray._loop((ans, sub_arr), fn, broadcast='none')
if hasattr(redux, "gradual_result"):
ans.map(lambda e: redux.gradual_result(e, length), inplace=True)
if out is not None:
return out
elif keepdims:
return ans.reshape(ans_shape)
elif ans.ndim == 0:
return ans.item()
else:
return ans
new_shape = (0, ) * (staticlen(shape) - staticlen(ax))
idx_bound = (0, ) * staticlen(ax)
out_strides = (0, ) * (staticlen(shape) - staticlen(ax))
sub_strides = (0, ) * staticlen(ax)
mask = (False, ) * staticlen(shape)
ptr_new_shape = Ptr[int](__ptr__(new_shape).as_byte())
ptr_idx_bound = Ptr[int](__ptr__(idx_bound).as_byte())
ptr_out_strides = Ptr[int](__ptr__(out_strides).as_byte())
ptr_sub_strides = Ptr[int](__ptr__(sub_strides).as_byte())
ptr_mask = Ptr[bool](__ptr__(mask).as_byte())
shape_size = 1
bound_size = 1
a = 0
b = 0
for i in staticrange(staticlen(shape)):
s = shape[i]
stride = strides[i]
if i in ax:
bound_size *= s
ptr_idx_bound[a] = s
ptr_sub_strides[a] = stride
ptr_mask[i] = False
a += 1
else:
shape_size *= s
ptr_new_shape[b] = s
ptr_out_strides[b] = stride
ptr_mask[i] = True
b += 1
if keepdims:
ones = (1, ) * staticlen(idx_bound)
ans_shape = util.reconstruct_index(new_shape, ones, mask)
else:
ans_shape = new_shape
redux = _make_reducer(R, arr.dtype, dtype, conv_to_float, bool_to_int, **kwargs)
k = 0
if out is None:
out_type = type(redux.result(0))
ans = _empty_like(arr, new_shape, out_type)
else:
_check_out(out, ans_shape)
if keepdims:
sub_ans_strides = (0, ) * staticlen(new_shape)
ptr_sub_ans_strides = Ptr[int](__ptr__(sub_ans_strides).as_byte())
a = 0
for i in staticrange(out.ndim):
if i not in ax:
ptr_sub_ans_strides[a] = out.strides[i]
a += 1
ans = ndarray(new_shape, sub_ans_strides, out.data)
else:
ans = out
if init_value is not None:
for i in range(ans.size):
ans.data[i] = util.cast(init_value, ans.dtype)
if arr._should_transpose():
idx_bound = idx_bound[::-1]
sub_strides = sub_strides[::-1]
for t2 in util.multirange(idx_bound):
offset = 0
for i in staticrange(staticlen(sub_strides)):
offset += sub_strides[i] * t2[i]
sub_arr_ptr = _increment_ptr(arr.data, offset)
sub_arr = ndarray(new_shape, out_strides, sub_arr_ptr)
fn = _GradualFunctor(redux, k, dtype, conv_to_float, kwargs)
ndarray._loop((ans, sub_arr), fn, broadcast='none')
k += 1
if hasattr(redux, "gradual_result"):
ans.map(lambda e: redux.gradual_result(e, bound_size), inplace=True)
if out is not None:
return out
elif keepdims:
return ans.reshape(ans_shape)
elif ans.ndim == 0:
return ans.item()
else:
return ans
def _reduce(arr,
R,
empty,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
where=util._NoValue(),
conv_to_float: Static[int] = False,
bool_to_int: Static[int] = False,
**kwargs):
data = arr.data
shape = arr.shape
strides = arr.strides
# Strangely, NumPy supports this, so we do too...
if arr.ndim == 0 and isinstance(axis, int):
if axis != 0 and axis != -1:
util.normalize_axis_index(axis=axis, ndim=0) # raises error
return _reduce(arr,
R=R,
empty=empty,
axis=None,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where,
conv_to_float=conv_to_float,
bool_to_int=bool_to_int,
**kwargs)
if axis is None:
ax = util.tuple_range(arr.ndim)
elif isinstance(axis, int):
ax = (util.normalize_axis_index(axis, arr.ndim), )
else:
ax = util.normalize_axis_tuple(axis, arr.ndim)
if staticlen(ax) == staticlen(shape):
return _reduce_all(arr,
R=R,
empty=empty,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where,
conv_to_float=conv_to_float,
bool_to_int=bool_to_int,
**kwargs)
if empty is not None:
if arr.size == 0:
empty(**kwargs)
new_shape = (0, ) * (staticlen(shape) - staticlen(ax))
idx_bound = (0, ) * staticlen(ax)
out_strides = (0, ) * (staticlen(shape) - staticlen(ax))
sub_strides = (0, ) * staticlen(ax)
mask = (False, ) * staticlen(shape)
ptr_new_shape = Ptr[int](__ptr__(new_shape).as_byte())
ptr_idx_bound = Ptr[int](__ptr__(idx_bound).as_byte())
ptr_out_strides = Ptr[int](__ptr__(out_strides).as_byte())
ptr_sub_strides = Ptr[int](__ptr__(sub_strides).as_byte())
ptr_mask = Ptr[bool](__ptr__(mask).as_byte())
shape_size = 1
bound_size = 1
min_stride_bound = -1
min_stride_shape = -1
a = 0
b = 0
for i in staticrange(staticlen(shape)):
s = shape[i]
stride = strides[i]
if i in ax:
bound_size *= s
ptr_idx_bound[a] = s
ptr_sub_strides[a] = stride
ptr_mask[i] = False
if (stride and
(min_stride_bound == -1 or abs(stride) < min_stride_bound)):
min_stride_bound = stride
a += 1
else:
shape_size *= s
ptr_new_shape[b] = s
ptr_out_strides[b] = stride
ptr_mask[i] = True
if (stride and
(min_stride_shape == -1 or abs(stride) < min_stride_shape)):
min_stride_shape = stride
b += 1
if hasattr(type(
_make_reducer(R, arr.dtype, dtype, conv_to_float,
bool_to_int, **kwargs)), "gradual_init"):
if (out is None and (where is None or isinstance(where, util._NoValue)) and arr.ndim > 1 and
min_stride_shape > 0 and min_stride_shape < min_stride_bound):
return _reduce_gradual(arr,
R=R,
empty=empty,
axis=ax,
dtype=dtype,
out=out,
keepdims=keepdims,
conv_to_float=conv_to_float,
bool_to_int=bool_to_int,
**kwargs)
if keepdims:
ones = (1, ) * staticlen(idx_bound)
ans_shape = util.reconstruct_index(new_shape, ones, mask)
else:
ans_shape = new_shape
if out is None:
out_type = type(
_make_reducer(R, arr.dtype, dtype, conv_to_float,
bool_to_int, **kwargs).result(0))
ans = _empty_like(arr, new_shape, out_type)
else:
_check_out(out, ans_shape)
if keepdims:
if staticlen(ax) == 1:
sub_ans_strides = util.tuple_delete(out.strides, ax[0])
else:
sub_ans_strides = (0, ) * staticlen(new_shape)
ptr_sub_ans_strides = Ptr[int](__ptr__(sub_ans_strides).as_byte())
a = 0
for i in staticrange(out.ndim):
if i not in ax:
ptr_sub_ans_strides[a] = out.strides[i]
a += 1
ans = ndarray(new_shape, sub_ans_strides, out.data)
else:
ans = out
where = _where_to_array(where, arr)
where_out_shape = (0, ) * (staticlen(shape) - staticlen(ax))
where_sub_shape = (0, ) * staticlen(ax)
where_out_strides = (0, ) * (staticlen(shape) - staticlen(ax))
where_sub_strides = (0, ) * staticlen(ax)
if where is not None and staticlen(shape) > 0:
ptr_where_out_shape = Ptr[int](__ptr__(where_out_shape).as_byte())
ptr_where_sub_shape = Ptr[int](__ptr__(where_sub_shape).as_byte())
ptr_where_out_strides = Ptr[int](__ptr__(where_out_strides).as_byte())
ptr_where_sub_strides = Ptr[int](__ptr__(where_sub_strides).as_byte())
a = 0
b = 0
for i in staticrange(staticlen(shape)):
if i in ax:
ptr_where_sub_shape[a] = where.shape[i]
ptr_where_sub_strides[a] = where.strides[i]
a += 1
else:
ptr_where_out_shape[b] = where.shape[i]
ptr_where_out_strides[b] = where.strides[i]
b += 1
if arr._should_transpose():
new_shape = new_shape[::-1]
out_strides = out_strides[::-1]
where_out_strides = where_out_strides[::-1]
ans1 = ndarray(ans.shape, ans.strides[::-1], ans.data)
else:
ans1 = ans
for idx in util.multirange(new_shape):
offset = 0
for i in staticrange(staticlen(out_strides)):
offset += out_strides[i] * idx[i]
sub_arr_ptr = _increment_ptr(arr.data, offset)
sub_arr = ndarray(idx_bound, sub_strides, sub_arr_ptr)
if where is None:
sub_where = None
else:
offset = 0
for i in staticrange(staticlen(where_out_strides)):
offset += where_out_strides[i] * idx[i]
sub_where_ptr = _increment_ptr(where.data, offset)
sub_where = ndarray(where_sub_shape, where_sub_strides, sub_where_ptr)
sub_rdx = _reduce_all(sub_arr,
R=R,
empty=None,
dtype=dtype,
out=None,
keepdims=False,
where=sub_where,
conv_to_float=conv_to_float,
bool_to_int=bool_to_int,
**kwargs)
ans1._ptr(idx)[0] = util.cast(sub_rdx, ans.dtype)
if out is not None:
return out
elif keepdims:
return ans.reshape(ans_shape)
elif ans.ndim == 0:
return ans.item()
else:
return ans
class _FlattenFunctor:
buffer: Ptr[dtype]
k: int
dtype: type
def __init__(self, buffer: Ptr[dtype]):
self.buffer = buffer
self.k = 0
def __call__(self, x):
self.buffer[self.k] = x[0]
self.k += 1
class _FlattenWhereFunctor:
buffer: Ptr[dtype]
k: int
dtype: type
def __init__(self, buffer: Ptr[dtype]):
self.buffer = buffer
self.k = 0
def __call__(self, x, w):
if w[0]:
self.buffer[self.k] = x[0]
self.k += 1
def _reduce_buffered(arr,
reducer,
dtype: type,
axis=None,
out=None,
overwrite_input: bool = False,
force_contig: bool = True,
keepdims: Static[int] = False,
where=util._NoValue(),
**kwargs):
data = arr.data
shape = arr.shape
strides = arr.strides
where = _where_to_array(where, arr)
if axis is None:
ax = util.tuple_range(arr.ndim)
elif isinstance(axis, int):
ax = (util.normalize_axis_index(axis, arr.ndim), )
else:
ax = util.normalize_axis_tuple(axis, arr.ndim)
if staticlen(ax) == staticlen(shape):
sz = arr.size
if arr._is_contig and overwrite_input and where is None:
result = reducer(arr.data, util.sizeof(arr.dtype), sz, dtype,
**kwargs)
else:
buffer = Ptr[arr.dtype](sz)
if where is None:
fn = _FlattenFunctor(buffer)
ndarray._loop((arr,), fn, broadcast='none')
n = sz
else:
fn = _FlattenWhereFunctor(buffer)
ndarray._loop((arr, where), fn, broadcast='none')
n = fn.k
result = reducer(buffer, util.sizeof(arr.dtype), n, dtype,
**kwargs)
util.free(buffer)
if out is None:
if keepdims:
return asarray(result).reshape((1, ) * arr.ndim)
else:
return result
else:
if keepdims:
_check_out(out, (1, ) * arr.ndim)
else:
_check_out(out, ())
out.data[0] = util.cast(result, out.dtype)
return out
new_shape = (0, ) * (staticlen(shape) - staticlen(ax))
idx_bound = (0, ) * staticlen(ax)
out_strides = (0, ) * (staticlen(shape) - staticlen(ax))
stride_bound = (0, ) * staticlen(ax)
mask = (False, ) * staticlen(shape)
ptr_new_shape = Ptr[int](__ptr__(new_shape).as_byte())
ptr_idx_bound = Ptr[int](__ptr__(idx_bound).as_byte())
ptr_out_strides = Ptr[int](__ptr__(out_strides).as_byte())
ptr_stride_bound = Ptr[int](__ptr__(stride_bound).as_byte())
ptr_mask = Ptr[bool](__ptr__(mask).as_byte())
shape_size = 1
bound_size = 1
a = 0
b = 0
for i in staticrange(staticlen(shape)):
s = shape[i]
stride = strides[i]
if i in ax:
bound_size *= s
ptr_idx_bound[a] = s
ptr_stride_bound[a] = stride
ptr_mask[i] = False
a += 1
else:
shape_size *= s
ptr_new_shape[b] = s
ptr_out_strides[b] = stride
ptr_mask[i] = True
b += 1
if keepdims:
ones = (1, ) * staticlen(idx_bound)
ans_shape = util.reconstruct_index(new_shape, ones, mask)
else:
ans_shape = new_shape
if out is None:
out_type = type(reducer(Ptr[arr.dtype](), 0, 0, dtype, **kwargs))
ans = _empty_like(arr, new_shape, out_type)
else:
_check_out(out, ans_shape)
if keepdims:
if staticlen(ax) == 1:
sub_ans_strides = util.tuple_delete(out.strides, ax[0])
else:
sub_ans_strides = (0, ) * staticlen(new_shape)
ptr_sub_ans_strides = Ptr[int](__ptr__(sub_ans_strides).as_byte())
a = 0
for i in staticrange(out.ndim):
if i not in ax:
ptr_sub_ans_strides[a] = out.strides[i]
a += 1
ans = ndarray(new_shape, sub_ans_strides, out.data)
else:
ans = out
inplace = False
stride = 0
if where is not None or not overwrite_input:
inplace = False
stride = util.sizeof(arr.dtype)
else:
if staticlen(ax) == 1:
inplace = True
stride = stride_bound[0]
else:
if stride_bound == util.strides(idx_bound, False, arr.dtype):
inplace = True
stride = stride_bound[-1]
elif stride_bound == util.strides(idx_bound, True, arr.dtype):
inplace = True
stride = stride_bound[0]
else:
inplace = False
stride = util.sizeof(arr.dtype)
if force_contig and stride != util.sizeof(arr.dtype):
inplace = False
stride = util.sizeof(arr.dtype)
where_out_shape = (0, ) * (staticlen(shape) - staticlen(ax))
where_sub_shape = (0, ) * staticlen(ax)
where_out_strides = (0, ) * (staticlen(shape) - staticlen(ax))
where_sub_strides = (0, ) * staticlen(ax)
if where is not None and staticlen(shape) > 0:
ptr_where_out_shape = Ptr[int](__ptr__(where_out_shape).as_byte())
ptr_where_sub_shape = Ptr[int](__ptr__(where_sub_shape).as_byte())
ptr_where_out_strides = Ptr[int](__ptr__(where_out_strides).as_byte())
ptr_where_sub_strides = Ptr[int](__ptr__(where_sub_strides).as_byte())
a = 0
b = 0
for i in staticrange(staticlen(shape)):
if i in ax:
ptr_where_sub_shape[a] = where.shape[i]
ptr_where_sub_strides[a] = where.strides[i]
a += 1
else:
ptr_where_out_shape[b] = where.shape[i]
ptr_where_out_strides[b] = where.strides[i]
b += 1
buffer = Ptr[arr.dtype]() if inplace else Ptr[arr.dtype](bound_size)
if arr._should_transpose():
new_shape = new_shape[::-1]
out_strides = out_strides[::-1]
where_out_strides = where_out_strides[::-1]
ans1 = ndarray(ans.shape, ans.strides[::-1], ans.data)
else:
ans1 = ans
for idx in util.multirange(new_shape):
n = bound_size
offset = 0
for i in staticrange(staticlen(out_strides)):
offset += out_strides[i] * idx[i]
sub_arr_ptr = _increment_ptr(arr.data, offset)
if inplace:
data_ptr = sub_arr_ptr
else:
sub_arr = ndarray(idx_bound, stride_bound, sub_arr_ptr)
if where is None:
fn = _FlattenFunctor(buffer)
ndarray._loop((sub_arr,), fn, broadcast='none')
else:
offset = 0
for i in staticrange(staticlen(where_out_strides)):
offset += where_out_strides[i] * idx[i]
sub_where_ptr = _increment_ptr(where.data, offset)
sub_where = ndarray(where_sub_shape, where_sub_strides, sub_where_ptr)
fn = _FlattenWhereFunctor(buffer)
ndarray._loop((sub_arr, sub_where), fn, broadcast='none')
n = fn.k
data_ptr = buffer
result = reducer(data_ptr, stride, n, dtype, **kwargs)
ans1._ptr(idx)[0] = util.cast(result, ans.dtype)
if not inplace:
util.free(buffer)
if out is not None:
return out
elif keepdims:
return ans.reshape(ans_shape)
elif ans.ndim == 0:
return ans.item()
else:
return ans
def _reduce_buffered_multi(arr,
reducer,
multi_num: int,
dtype: type,
axis=None,
out=None,
overwrite_input: bool = False,
force_contig: bool = True,
keepdims: Static[int] = False,
where=util._NoValue(),
**kwargs):
data = arr.data
shape = arr.shape
strides = arr.strides
where = _where_to_array(where, arr)
if axis is None:
ax = util.tuple_range(arr.ndim)
elif isinstance(axis, int):
ax = (util.normalize_axis_index(axis, arr.ndim), )
else:
ax = util.normalize_axis_tuple(axis, arr.ndim)
new_shape = (0, ) * (staticlen(shape) - staticlen(ax))
idx_bound = (0, ) * staticlen(ax)
stride_bound = (0, ) * staticlen(ax)
mask = (False, ) * staticlen(shape)
ptr_new_shape = Ptr[int](__ptr__(new_shape).as_byte())
ptr_idx_bound = Ptr[int](__ptr__(idx_bound).as_byte())
ptr_stride_bound = Ptr[int](__ptr__(stride_bound).as_byte())
ptr_mask = Ptr[bool](__ptr__(mask).as_byte())
shape_size = 1
bound_size = 1
a = 0
b = 0
for i in staticrange(staticlen(shape)):
s = shape[i]
if i in ax:
bound_size *= s
ptr_idx_bound[a] = s
ptr_stride_bound[a] = strides[i]
ptr_mask[i] = False
a += 1
else:
shape_size *= s
ptr_new_shape[b] = s
ptr_mask[i] = True
b += 1
if keepdims:
ones = (1, ) * staticlen(idx_bound)
ans_shape = (multi_num, ) + util.reconstruct_index(
new_shape, ones, mask)
else:
ans_shape = (multi_num, ) + new_shape
if out is None:
ans = _empty_like(arr, ans_shape, dtype)
else:
_check_out(out, ans_shape)
ans = out
if staticlen(ax) == staticlen(shape):
sz = arr.size
if arr._is_contig and overwrite_input and where is None:
reducer(arr.data, util.sizeof(arr.dtype), sz, ans.data, dtype,
**kwargs)
else:
buffer = Ptr[arr.dtype](sz)
k = 0
for idx in util.multirange(shape):
if where is not None:
if not where._ptr(idx)[0]:
continue
buffer[k] = arr._ptr(idx)[0]
k += 1
n = sz if where is None else k
reducer(buffer, util.sizeof(arr.dtype), n, ans.data, dtype,
**kwargs)
util.free(buffer)
return ans
inplace = False
stride = 0
if where is not None or not overwrite_input:
inplace = False
stride = util.sizeof(arr.dtype)
else:
if staticlen(ax) == 1:
inplace = True
stride = stride_bound[0]
else:
if stride_bound == util.strides(idx_bound, False, arr.dtype):
inplace = True
stride = stride_bound[-1]
elif stride_bound == util.strides(idx_bound, True, arr.dtype):
inplace = True
stride = stride_bound[0]
else:
inplace = False
stride = util.sizeof(arr.dtype)
if force_contig and stride != util.sizeof(arr.dtype):
inplace = False
stride = util.sizeof(arr.dtype)
buffer = Ptr[arr.dtype]() if inplace else Ptr[arr.dtype](bound_size)
out_buffer = Ptr[ans.dtype](multi_num)
for t1 in util.multirange(new_shape):
n = bound_size
if inplace:
idx = util.reconstruct_index(t1, (0, ) * staticlen(idx_bound),
mask)
subdata = arr._ptr(idx)
else:
k = 0
for t2 in util.multirange(idx_bound):
idx = util.reconstruct_index(t1, t2, mask)
if where is not None:
if not where._ptr(idx)[0]:
continue
e = arr._ptr(idx)[0]
buffer[k] = e
k += 1
subdata = buffer
if where is not None:
n = k
reducer(subdata, stride, n, out_buffer, dtype, **kwargs)
if keepdims:
zeros = (0, ) * staticlen(idx_bound)
t3 = util.reconstruct_index(t1, zeros, mask)
else:
t3 = t1
for i in range(multi_num):
ans._ptr((i, ) + t3)[0] = util.cast(out_buffer[i], ans.dtype)
if not inplace:
util.free(buffer)
util.free(out_buffer)
return ans
class SumRedux:
total: T
T: type
def create(T: type, **kwargs):
return SumRedux[T](**kwargs)
def __init__(self, **kwargs):
initial = kwargs.get("initial", T())
self.total = util.cast(initial, T)
def accept(self, item, index: int):
self.total += util.cast(item, T)
def result(self, count: int):
return self.total
def empty(**kwargs):
pass
def done(self):
return False
def gradual_init(self, **kwargs):
return util.cast(kwargs.get("initial", T()), T)
def gradual_accept(self, curr, item, index: int, **kwargs):
return curr + util.cast(item, T)
def _loop(a: Ptr[S], n: int, stride: int, S: type):
ans = T()
if (T is float or T is float32 or T is float16 or
T is complex or T is complex64):
ans += _pairwise_sum(a, n, stride, dtype=T)
else:
for i in range(n):
item = _increment_ptr(a, i * stride)[0]
ans += util.cast(item, T)
return ans
def loop(self, a: Ptr[S], n: int, stride: int, partial: Static[int], S: type):
self.total += SumRedux[T]._loop(a, n, stride, S)
class NanSumRedux:
total: T
T: type
def create(T: type, **kwargs):
return NanSumRedux[T](**kwargs)
def __init__(self, **kwargs):
initial = kwargs.get("initial", T())
self.total = util.cast(initial, T)
def accept(self, item, index: int):
if not _isnan(item):
self.total += util.cast(item, T)
def result(self, count: int):
return self.total
def empty(**kwargs):
pass
def done(self):
return False
def gradual_init(self, **kwargs):
return util.cast(kwargs.get("initial", T()), T)
def gradual_accept(self, curr, item, index: int, **kwargs):
return curr if _isnan(item) else curr + util.cast(item, T)
def loop(self, a: Ptr[S], n: int, stride: int, partial: Static[int], S: type):
ans = T()
for i in range(n):
item = _increment_ptr(a, i * stride)[0]
if not _isnan(item):
ans += util.cast(item, T)
self.total += ans
class ProdRedux:
total: T
T: type
def create(T: type, **kwargs):
return ProdRedux[T](**kwargs)
def __init__(self, **kwargs):
initial = kwargs.get("initial", T(1))
self.total = util.cast(initial, T)
def accept(self, item, index: int):
self.total *= util.cast(item, T)
def result(self, count: int):
return self.total
def empty(**kwargs):
pass
def done(self):
return False
def gradual_init(self, **kwargs):
return util.cast(kwargs.get("initial", T(1)), T)
def gradual_accept(self, curr, item, index: int, **kwargs):
return curr * util.cast(item, T)
def loop(self, a: Ptr[S], n: int, stride: int, partial: Static[int], S: type):
ans = T(1)
for i in range(n):
item = _increment_ptr(a, i * stride)[0]
ans *= util.cast(item, T)
self.total *= ans
class NanProdRedux:
total: T
T: type
def create(T: type, **kwargs):
return NanProdRedux[T](**kwargs)
def __init__(self, **kwargs):
initial = kwargs.get("initial", T(1))
self.total = util.cast(initial, T)
def accept(self, item, index: int):
if not _isnan(item):
self.total *= util.cast(item, T)
def result(self, count: int):
return self.total
def empty(**kwargs):
pass
def done(self):
return False
def gradual_init(self, **kwargs):
return util.cast(kwargs.get("initial", T(1)), T)
def gradual_accept(self, curr, item, index: int, **kwargs):
return curr if _isnan(item) else curr * util.cast(item, T)
def loop(self, a: Ptr[S], n: int, stride: int, partial: Static[int], S: type):
ans = T(1)
for i in range(n):
item = _increment_ptr(a, i * stride)[0]
if not _isnan(item):
ans *= util.cast(item, T)
self.total *= ans
class MeanRedux:
total: T
T: type
def create(T: type, **kwargs):
return MeanRedux[T](**kwargs)
def __init__(self, **kwargs):
self.total = T()
def accept(self, item: T, index: int):
self.total += item
def result(self, count: int):
return self.total / T(count) if count else _nan(T)
def empty(**kwargs):
pass
def done(self):
return False
def gradual_init(self, **kwargs):
return T()
def gradual_accept(self, curr, item, index: int, **kwargs):
return curr + util.cast(item, T)
def gradual_result(self, curr, count: int):
return curr / T(count) if count else _nan(T)
def loop(self, a: Ptr[S], n: int, stride: int, partial: Static[int], S: type):
self.total += SumRedux[T]._loop(a, n, stride, S)
class NanMeanRedux:
total: T
T: type
nan_count: int
def create(T: type, **kwargs):
return NanMeanRedux[T](**kwargs)
def __init__(self, **kwargs):
self.total = T()
self.nan_count = 0
def accept(self, item: T, index: int):
if not _isnan(item):
self.total += item
else:
self.nan_count += 1
def result(self, count: int):
count -= self.nan_count
return self.total / T(count) if count else _nan(T)
def empty(**kwargs):
pass
def done(self):
return False
def loop(self, a: Ptr[S], n: int, stride: int, partial: Static[int], S: type):
ans = T()
nan_count = 0
for i in range(n):
item = _increment_ptr(a, i * stride)[0]
if _isnan(item):
nan_count += 1
else:
ans += util.cast(item, T)
self.total += ans
self.nan_count += nan_count
class MinRedux:
m: Optional[T]
T: type
def create(T: type, **kwargs):
return MinRedux[T](**kwargs)
def __init__(self, **kwargs):
initial = kwargs.get("initial", util._NoValue())
if isinstance(initial, util._NoValue):
self.m = None
else:
self.m = util.cast(initial, T)
def accept(self, item: T, index: int):
if self.m is None:
self.m = item
else:
self.m = MinRedux[T]._min(self.m, item)
def result(self, count: int) -> T:
return self.m
def empty(**kwargs):
if isinstance(kwargs.get("initial", util._NoValue()), util._NoValue):
raise ValueError(
"zero-size array to reduction operation minimum which has no identity"
)
def done(self):
return False
def gradual_init(self, **kwargs):
initial = kwargs.get("initial", util._NoValue())
if isinstance(initial, util._NoValue):
return None
else:
return util.cast(initial, T)
def gradual_accept(self, curr, item, index: int, **kwargs):
item = util.cast(item, T)
initial = kwargs.get("initial", util._NoValue())
if isinstance(initial, util._NoValue):
if index == 0:
return item
return MinRedux[T]._min(curr, item)
def _min(m: T, x):
x = util.cast(x, T)
if T is float or T is float32 or T is float16:
return util.fmin(m, x)
else:
return x if x < m else m
def loop(self, a: Ptr[S], n: int, stride: int, partial: Static[int], S: type):
if self.m is None:
m: T = util.cast(a[0], T)
a = _increment_ptr(a, stride)
n -= 1
else:
m: T = self.m
for i in range(n):
m = MinRedux[T]._min(m, a[0])
a = _increment_ptr(a, stride)
if partial:
self.accept(m, 0)
else:
self.m = m
class MaxRedux:
m: Optional[T]
T: type
def create(T: type, **kwargs):
return MaxRedux[T](**kwargs)
def __init__(self, **kwargs):
initial = kwargs.get("initial", util._NoValue())
if isinstance(initial, util._NoValue):
self.m = None
else:
self.m = util.cast(initial, T)
def accept(self, item: T, index: int):
if self.m is None:
self.m = item
else:
self.m = MaxRedux[T]._max(self.m, item)
def result(self, count: int) -> T:
return self.m
def empty(**kwargs):
if isinstance(kwargs.get("initial", util._NoValue()), util._NoValue):
raise ValueError(
"zero-size array to reduction operation maximum which has no identity"
)
def done(self):
return False
def gradual_init(self, **kwargs):
initial = kwargs.get("initial", util._NoValue())
if isinstance(initial, util._NoValue):
return None
else:
return util.cast(initial, T)
def gradual_accept(self, curr, item, index: int, **kwargs):
item = util.cast(item, T)
initial = kwargs.get("initial", util._NoValue())
if isinstance(initial, util._NoValue):
if index == 0:
return item
return MaxRedux[T]._max(curr, item)
def _max(m: T, x):
x = util.cast(x, T)
if T is float or T is float32 or T is float16:
return util.fmax(m, x)
else:
return x if x > m else m
def loop(self, a: Ptr[S], n: int, stride: int, partial: Static[int], S: type):
if self.m is None and n > 0:
m: T = util.cast(a[0], T)
a = _increment_ptr(a, stride)
n -= 1
else:
m: T = self.m
for i in range(n):
m = MaxRedux[T]._max(m, a[0])
a = _increment_ptr(a, stride)
if partial:
self.accept(m, 0)
else:
self.m = m
class PTPRedux:
hi: Optional[T]
lo: Optional[T]
T: type
def create(T: type, **kwargs):
return PTPRedux[T](**kwargs)
def __init__(self, **kwargs):
self.hi = None
self.lo = None
def accept(self, item: T, index: int):
if self.hi is None:
self.hi = item
else:
self.hi = MaxRedux[T]._max(self.hi, item)
if self.lo is None:
self.lo = item
else:
self.lo = MinRedux[T]._min(self.lo, item)
def result(self, count: int) -> T:
return self.hi - self.lo
def empty(**kwargs):
raise ValueError(
"zero-size array to reduction operation maximum which has no identity"
)
def done(self):
return False
def loop(self, a: Ptr[S], n: int, stride: int, partial: Static[int], S: type):
# n must be >0 here or we would've thrown an exception earlier
m = util.cast(a[0], T)
M = m
a = _increment_ptr(a, stride)
n -= 1
for i in range(n):
m = MinRedux[T]._min(m, a[0])
M = MaxRedux[T]._max(M, a[0])
a = _increment_ptr(a, stride)
if partial:
if self.hi is None or (M > self.hi):
self.hi = M
if self.lo is None or (m < self.lo):
self.lo = m
else:
self.hi = M
self.lo = m
class ArgMinRedux:
m: Optional[T]
i: int
T: type
def create(T: type, **kwargs):
return ArgMinRedux[T](**kwargs)
def __init__(self, **kwargs):
self.m = None
self.i = 0
def accept(self, item: T, index: int):
if self.m is None or (item < self.m):
self.m = item
self.i = index
def result(self, count: int):
return self.i
def empty(**kwargs):
raise ValueError("attempt to get argmin of an empty sequence")
def done(self):
return False
class ArgMaxRedux:
m: Optional[T]
i: int
T: type
def create(T: type, **kwargs):
return ArgMaxRedux[T](**kwargs)
def __init__(self, **kwargs):
self.m = None
self.i = 0
def accept(self, item: T, index: int):
if self.m is None or (item > self.m):
self.m = item
self.i = index
def result(self, count: int):
return self.i
def empty(**kwargs):
raise ValueError("attempt to get argmax of an empty sequence")
def done(self):
return False
class AnyRedux:
a: bool
T: type
def create(T: type, **kwargs):
return AnyRedux[T](**kwargs)
def __init__(self, **kwargs):
self.a = False
def accept(self, item: T, index: int):
if item:
self.a = True
def result(self, count: int):
return self.a
def empty(**kwargs):
pass
def done(self):
return self.a
class AllRedux:
a: bool
T: type
def create(T: type, **kwargs):
return AllRedux[T](**kwargs)
def __init__(self, **kwargs):
self.a = True
def accept(self, item: T, index: int):
if not item:
self.a = False
def result(self, count: int):
return self.a
def empty(**kwargs):
pass
def done(self):
return not self.a
class NonZeroRedux:
nonzero: int
T: type
def create(T: type, **kwargs):
return NonZeroRedux[T](**kwargs)
def __init__(self, **kwargs):
self.nonzero = 0
def accept(self, item: T, index: int):
if item:
self.nonzero += 1
def result(self, count: int):
return self.nonzero
def empty(**kwargs):
pass
def done(self):
return False
def gradual_init(self, **kwargs):
return 0
def gradual_accept(self, curr, item, index: int, **kwargs):
if item:
curr += 1
return curr
def sum(
a,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
initial=0,
where=util._NoValue(),
):
a = asarray(a)
return _reduce(
a,
R=SumRedux.create,
empty=SumRedux.empty,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where,
initial=initial,
bool_to_int=True,
)
def nansum(
a,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
initial=0,
where=util._NoValue(),
):
a = asarray(a)
return _reduce(
a,
R=NanSumRedux.create,
empty=NanSumRedux.empty,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where,
initial=initial,
bool_to_int=True,
)
def prod(
a,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
initial=1,
where=util._NoValue(),
):
a = asarray(a)
return _reduce(
a,
R=ProdRedux.create,
empty=ProdRedux.empty,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where,
initial=initial,
bool_to_int=True,
)
def nanprod(
a,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
initial=1,
where=util._NoValue(),
):
a = asarray(a)
return _reduce(
a,
R=NanProdRedux.create,
empty=NanProdRedux.empty,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where,
initial=initial,
bool_to_int=True,
)
def mean(
a,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
where=util._NoValue(),
):
a = asarray(a)
return _reduce(
a,
R=MeanRedux.create,
empty=MeanRedux.empty,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where,
conv_to_float=True,
)
def nanmean(
a,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
where=util._NoValue(),
):
a = asarray(a)
return _reduce(
a,
R=NanMeanRedux.create,
empty=NanMeanRedux.empty,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where,
conv_to_float=True,
)
def _var_reducer(p: Ptr[T], s: int, n: int, dtype: type, T: type, **kwargs):
if dtype is NoneType:
zero = _cast_elem(util.zero(T), dtype, conv_to_float=True)
else:
zero = _cast_elem(util.zero(dtype), dtype, conv_to_float=True)
Z = type(zero)
u = zero
q = p
u = _pairwise_sum(p, n, s, dtype=Z)
u /= util.cast(n, Z)
if Z is complex:
v = 0.0
elif Z is complex64:
v = float32(0.0)
else:
v = zero
q = p
for _ in range(n):
t = util.cast(q[0], Z) - u
if Z is complex or Z is complex64:
r = abs(t)
v += r * r
else:
v += t * t
q = _increment_ptr(q, s)
v /= util.cast(n - kwargs['ddof'], type(v))
return v
def var(
a,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
where=util._NoValue(),
):
a = asarray(a)
return _reduce_buffered(a,
_var_reducer,
dtype=dtype,
axis=axis,
out=out,
overwrite_input=True,
force_contig=False,
keepdims=keepdims,
where=where,
ddof=ddof)
def _nanvar_reducer(p: Ptr[T], s: int, n: int, dtype: type, T: type, **kwargs):
if dtype is NoneType:
zero = _cast_elem(util.zero(T), dtype, conv_to_float=True)
else:
zero = _cast_elem(util.zero(dtype), dtype, conv_to_float=True)
Z = type(zero)
u = zero
q = p
nans = 0
for _ in range(n):
e = util.cast(q[0], Z)
if _isnan(e):
nans += 1
else:
u += e
q = _increment_ptr(q, s)
u /= util.cast(n - nans, Z)
if Z is complex:
v = 0.0
elif Z is complex64:
v = float32(0.0)
else:
v = zero
q = p
for _ in range(n):
e = util.cast(q[0], Z)
if not _isnan(e):
t = util.cast(q[0], Z) - u
if Z is complex or Z is complex64:
r = abs(t)
v += r * r
else:
v += t * t
q = _increment_ptr(q, s)
v /= util.cast(n - nans - kwargs['ddof'], type(v))
return v
def nanvar(
a,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
where=util._NoValue(),
):
a = asarray(a)
return _reduce_buffered(a,
_nanvar_reducer,
dtype=dtype,
axis=axis,
out=out,
overwrite_input=True,
force_contig=False,
keepdims=keepdims,
where=where,
ddof=ddof)
def _std_reducer(p: Ptr[T], s: int, n: int, dtype: type, T: type, **kwargs):
x = _var_reducer(p=p, s=s, n=n, dtype=dtype, T=T, **kwargs)
return util.sqrt(x)
def std(
a,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
where=util._NoValue(),
):
a = asarray(a)
return _reduce_buffered(a,
_std_reducer,
dtype=dtype,
axis=axis,
out=out,
overwrite_input=True,
force_contig=False,
keepdims=keepdims,
where=where,
ddof=ddof)
def _nanstd_reducer(p: Ptr[T], s: int, n: int, dtype: type, T: type, **kwargs):
x = _nanvar_reducer(p=p, s=s, n=n, dtype=dtype, T=T, **kwargs)
return util.sqrt(x)
def nanstd(
a,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
where=util._NoValue(),
):
a = asarray(a)
return _reduce_buffered(a,
_nanstd_reducer,
dtype=dtype,
axis=axis,
out=out,
overwrite_input=True,
force_contig=False,
keepdims=keepdims,
where=where,
ddof=ddof)
def min(
a,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
initial=util._NoValue(),
where=util._NoValue(),
):
if not isinstance(where, util._NoValue) and isinstance(
initial, util._NoValue):
compile_error(
"reduction operation 'minimum' does not have an identity, so to use a where mask one has to specify 'initial'"
)
a = asarray(a)
return _reduce(
a,
R=MinRedux.create,
empty=MinRedux.empty,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where,
initial=initial,
)
def max(
a,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
initial=util._NoValue(),
where=util._NoValue(),
):
if not isinstance(where, util._NoValue) and isinstance(
initial, util._NoValue):
compile_error(
"reduction operation 'maximum' does not have an identity, so to use a where mask one has to specify 'initial'"
)
a = asarray(a)
return _reduce(
a,
R=MaxRedux.create,
empty=MaxRedux.empty,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where,
initial=initial,
)
def ptp(a, axis=None, out=None, keepdims: Static[int] = False):
a = asarray(a)
return _reduce(
a,
R=PTPRedux.create,
empty=PTPRedux.empty,
axis=axis,
out=out,
keepdims=keepdims,
)
def argmin(a, axis=None, out=None, keepdims: Static[int] = False):
a = asarray(a)
return _reduce(
a,
R=ArgMinRedux.create,
empty=ArgMinRedux.empty,
axis=axis,
out=out,
keepdims=keepdims,
)
def argmax(a, axis=None, out=None, keepdims: Static[int] = False):
a = asarray(a)
return _reduce(
a,
R=ArgMaxRedux.create,
empty=ArgMaxRedux.empty,
axis=axis,
out=out,
keepdims=keepdims,
)
def any(a,
axis=None,
out=None,
keepdims: Static[int] = False,
where=util._NoValue()):
a = asarray(a)
return _reduce(
a,
R=AnyRedux.create,
empty=AnyRedux.empty,
axis=axis,
out=out,
keepdims=keepdims,
where=where,
)
def all(a,
axis=None,
out=None,
keepdims: Static[int] = False,
where=util._NoValue()):
a = asarray(a)
return _reduce(
a,
R=AllRedux.create,
empty=AllRedux.empty,
axis=axis,
out=out,
keepdims=keepdims,
where=where,
)
def count_nonzero(a, axis=None, keepdims: Static[int] = False):
a = asarray(a)
return _reduce(a,
R=NonZeroRedux.create,
empty=NonZeroRedux.empty,
axis=axis,
keepdims=keepdims)
def _median_reducer_no_nan(v: Ptr[T], s: int, n: int, dtype: type, T: type,
**kwargs):
if n == 0:
if T is complex or T is complex64:
return _nan(T)
else:
return _nan(float)
m1, m2 = util.median(v, n)
if n & 1 == 0:
if T is complex:
return (m1 + m2) / 2.0
elif T is complex64:
return (m1 + m2) / float32(2.0)
else:
return (util.cast(m1, float) + util.cast(m2, float)) / 2.0
else:
if T is complex or T is complex64:
return m1
else:
return util.cast(m1, float)
def _median_reducer(v: Ptr[T], s: int, n: int, dtype: type, T: type, **kwargs):
if _supports_nan(T):
for i in range(n):
if _isnan(v[i]):
if T is complex or T is complex64:
return _nan(T)
else:
return _nan(float)
return _median_reducer_no_nan(v, s, n, dtype, T, **kwargs)
def median(a,
axis=None,
out=None,
overwrite_input: bool = False,
keepdims: Static[int] = False):
a = asarray(a)
return _reduce_buffered(a,
_median_reducer,
dtype=a.dtype,
axis=axis,
out=out,
overwrite_input=overwrite_input,
force_contig=True,
keepdims=keepdims,
where=None)
def _nanmedian_reducer(v: Ptr[T], s: int, n: int, dtype: type, T: type,
**kwargs):
n = _nan_to_back(v, n)
return _median_reducer_no_nan(v, s, n, dtype, T, **kwargs)
def nanmedian(a,
axis=None,
out=None,
overwrite_input: bool = False,
keepdims: Static[int] = False):
a = asarray(a)
return _reduce_buffered(a,
_nanmedian_reducer,
dtype=a.dtype,
axis=axis,
out=out,
overwrite_input=overwrite_input,
force_contig=True,
keepdims=keepdims,
where=None)
def _sorted(ar):
if isinstance(ar, ndarray):
x = ar.flatten()
x.sort()
return x
else:
x = asarray(ar).ravel()
x.sort()
return x
def _check_interpolation_as_method(method, interpolation):
if method != "linear":
# sanity check, we assume this basically never happens
raise TypeError(
"You shall not pass both `method` and `interpolation`!\n"
"(`interpolation` is Deprecated in favor of `method`)")
return interpolation
def _quantile_is_valid(q):
# avoid expensive reductions, relevant for arrays with < O(1000) elements
if staticlen(q.shape) == 1 and q.size < 10:
for i in range(q.size):
if not (0.0 <= q[i] <= 1.0):
return False
else:
for idx in util.multirange(q.shape):
if not ((0.0 <= q._ptr(idx)[0]) and (q._ptr(idx)[0] <= 1.0)):
return False
return True
def _get_gamma_mask(shape, default_value, conditioned_value, where):
out = full(shape, default_value)
copyto(out, conditioned_value, where=where)
return out
def _discret_interpolation_to_boundaries(index, gamma_condition_fun):
if not isinstance(index, ndarray):
shape = ()
else:
shape = index.shape
previous = floor(index)
next = previous + 1
gamma = index - previous
res = _get_gamma_mask(shape=shape,
default_value=next,
conditioned_value=previous,
where=gamma_condition_fun(gamma, index)).astype(int)
# Some methods can lead to out-of-bound integers so we clip them
res[res < 0] = 0
return res
def _inverted_cdf(n, quantiles):
gamma_fun = lambda gamma, _: (gamma == 0)
return _discret_interpolation_to_boundaries((n * quantiles) - 1, gamma_fun)
def _closest_observation(n, quantiles):
gamma_fun = lambda gamma, index: (gamma == 0) & (floor(index) % 2 == 0)
return _discret_interpolation_to_boundaries((n * quantiles) - 1 - 0.5,
gamma_fun)
def _compute_virtual_index(n, quantiles, alpha: float, beta: float):
return n * quantiles + (alpha + quantiles * (1 - alpha - beta)) - 1
def _get_indexes(arr, virtual_indexes, valid_values_count, supports_nan: bool):
previous_indexes = asarray(floor(virtual_indexes))
next_indexes = asarray(previous_indexes + 1)
indexes_above_bounds = virtual_indexes >= valid_values_count - 1
# When indexes is above max index, take the max value of the array
if indexes_above_bounds.any():
previous_indexes[indexes_above_bounds] = -1
next_indexes[indexes_above_bounds] = -1
# When indexes is below min index, take the min value of the array
indexes_below_bounds = virtual_indexes < 0
if indexes_below_bounds.any():
previous_indexes[indexes_below_bounds] = 0
next_indexes[indexes_below_bounds] = 0
if supports_nan:
# After the sort, slices having NaNs will have for last element a NaN
virtual_indexes_nans = _isnan(virtual_indexes)
if isinstance(virtual_indexes_nans, bool):
if virtual_indexes_nans:
previous_indexes[()] = -1
next_indexes[()] = -1
elif isinstance(virtual_indexes_nans, ndarray):
if virtual_indexes_nans.any():
previous_indexes[virtual_indexes_nans] = -1
next_indexes[virtual_indexes_nans] = -1
previous_indexes = previous_indexes.astype(int)
next_indexes = next_indexes.astype(int)
return previous_indexes, next_indexes
def _lerp(a, b, t, out=None):
diff_b_a = subtract(b, a)
lerp_interpolation = asarray(add(a, diff_b_a * t, out=out))
subtract(b, diff_b_a * (1 - t), out=lerp_interpolation, where=t >= 0.5)
if staticlen(lerp_interpolation.shape) == 0 and out is None:
lerp_interpolation2 = lerp_interpolation[()] # unpack 0d arrays
else:
lerp_interpolation2 = lerp_interpolation
return lerp_interpolation2
def _quantile(
arr,
quantiles,
axis: int = -1,
method: str = "linear",
out=None,
):
supports_nan = _supports_nan(arr.dtype)
arr = asarray(arr, float)
values_count = arr.shape[axis]
if axis != 0:
arr = moveaxis(arr, axis, destination=0)
def compute_quantile(arr, quantiles, axis: int, method: str, out,
virtual_indexes, supports_nan: bool):
virtual_indexes = asarray(virtual_indexes)
if (virtual_indexes.dtype is int
or isinstance(virtual_indexes.dtype, Int)):
# No interpolation needed, take the points along axis
if supports_nan:
# may contain nan, which would sort to the end
arr.partition(concatenate((virtual_indexes.ravel(), [-1])),
axis=0)
slices_having_nans = _isnan(arr[-1, ...])
else:
# cannot contain nan
arr.partition(virtual_indexes.ravel(), axis=0)
result = take(arr, virtual_indexes, axis=0, out=out)
else:
previous_indexes, next_indexes = _get_indexes(
arr, virtual_indexes, values_count, supports_nan)
# --- Sorting
arr.partition(unique(
concatenate((
[0, -1],
previous_indexes.ravel(),
next_indexes.ravel(),
))),
axis=0)
if supports_nan:
slices_having_nans = _isnan(arr[-1, ...])
# --- Get values from indexes
previous = arr[previous_indexes]
next = arr[next_indexes]
# --- Linear interpolation
def _get_gamma(virtual_indexes, previous_indexes, method: str):
gamma = asarray(virtual_indexes - previous_indexes)
if (method == 'inverted_cdf' or method == 'closest_observation'
or method == 'interpolated_inverted_cdf'
or method == 'hazen' or method == 'weibull'
or method == 'linear' or method == 'median_unbiased'
or method == 'normal_unbiased' or method == 'lower'
or method == 'higher' or method == 'nearest'):
return gamma
elif method == 'averaged_inverted_cdf':
return _get_gamma_mask(shape=gamma.shape,
default_value=1.,
conditioned_value=0.5,
where=gamma == 0)
elif method == 'midpoint':
return _get_gamma_mask(shape=gamma.shape,
default_value=0.5,
conditioned_value=0.,
where=virtual_indexes % 1 == 0)
gamma = _get_gamma(virtual_indexes, previous_indexes, method)
gamma = asarray(gamma)
result_shape = virtual_indexes.shape + (1, ) * (arr.ndim - 1)
gamma = gamma.reshape(result_shape)
result = _lerp(previous, next, gamma, out=out)
if supports_nan:
if any(slices_having_nans):
if isinstance(result, ndarray):
if result.ndim == 0 and out is None:
# can't write to a scalar, but indexing will be correct
result = arr[-1]
else:
copyto(result, arr[-1, ...], where=slices_having_nans)
else:
if out is None:
result = util.nan64()
else:
out[()] = util.nan64()
return result
# --- Computation of indexes
# Index where to find the value in the sorted array.
# Virtual because it is a floating point value, not an valid index.
# The nearest neighbours are used for interpolation
if method == 'inverted_cdf':
virtual_indexes = _inverted_cdf(values_count, quantiles)
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes,
supports_nan=supports_nan)
elif method == 'averaged_inverted_cdf':
virtual_indexes = (values_count * quantiles) - 1
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes,
supports_nan=supports_nan)
elif method == 'closest_observation':
virtual_indexes = _closest_observation(values_count, quantiles)
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes,
supports_nan=supports_nan)
elif method == 'interpolated_inverted_cdf':
virtual_indexes = _compute_virtual_index(values_count, quantiles, 0, 1)
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes,
supports_nan=supports_nan)
elif method == 'hazen':
virtual_indexes = _compute_virtual_index(values_count, quantiles, 0.5,
0.5)
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes,
supports_nan=supports_nan)
elif method == 'weibull':
virtual_indexes = _compute_virtual_index(values_count, quantiles, 0, 0)
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes,
supports_nan=supports_nan)
elif method == 'linear':
virtual_indexes = (values_count - 1) * quantiles
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes,
supports_nan=supports_nan)
elif method == 'median_unbiased':
virtual_indexes = _compute_virtual_index(values_count, quantiles,
1 / 3.0, 1 / 3.0)
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes,
supports_nan=supports_nan)
elif method == 'normal_unbiased':
virtual_indexes = _compute_virtual_index(values_count, quantiles,
3 / 8.0, 3 / 8.0)
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes,
supports_nan=supports_nan)
elif method == 'lower':
def get_virtual_indexes(quantiles, values_count):
if isinstance(quantiles, ndarray):
return floor((values_count - 1) * quantiles).astype(int)
else:
return int(floor((values_count - 1) * quantiles))
virtual_indexes2 = get_virtual_indexes(quantiles, values_count)
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes2,
supports_nan=supports_nan)
elif method == 'higher':
def get_virtual_indexes(quantiles, values_count):
if isinstance(quantiles, ndarray):
return ceil((values_count - 1) * quantiles).astype(int)
else:
return int(ceil((values_count - 1) * quantiles))
virtual_indexes2 = get_virtual_indexes(quantiles, values_count)
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes2,
supports_nan=supports_nan)
elif method == 'midpoint':
virtual_indexes = 0.5 * (floor((values_count - 1) * quantiles) + ceil(
(values_count - 1) * quantiles))
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes,
supports_nan=supports_nan)
elif method == 'nearest':
def get_virtual_indexes(quantiles, values_count):
if isinstance(quantiles, ndarray):
return round((values_count - 1) * quantiles).astype(int)
else:
return int(round((values_count - 1) * quantiles))
virtual_indexes2 = get_virtual_indexes(quantiles, values_count)
return compute_quantile(arr,
quantiles=quantiles,
axis=axis,
method=method,
out=out,
virtual_indexes=virtual_indexes2,
supports_nan=supports_nan)
else:
raise ValueError(f"{method} is not a valid method.")
def _quantile_reducer(v: Ptr[T], s: int, n: int, dtype: type, T: type,
**kwargs):
return _quantile(ndarray((n, ), (s, ), v),
quantiles=kwargs['q'],
axis=0,
method=kwargs['method'],
out=None)
def _quantile_reducer_multi(v: Ptr[T], s: int, n: int, out: Ptr[float],
dtype: type, T: type, **kwargs):
q = kwargs['q']
_quantile(ndarray((n, ), (s, ), v),
quantiles=q,
axis=0,
method=kwargs['method'],
out=ndarray((q.size, ), (util.sizeof(dtype), ), out))
def _quantile_unchecked(a,
q,
axis=None,
out=None,
overwrite_input: bool = False,
method: str = "linear",
keepdims: Static[int] = False):
# Assumes that q is in [0, 1], and is an ndarray
if q.ndim == 0:
return _reduce_buffered(a,
_quantile_reducer,
dtype=a.dtype,
axis=axis,
out=out,
overwrite_input=overwrite_input,
keepdims=keepdims,
q=q.item(),
method=method)
elif q.ndim == 1:
return _reduce_buffered_multi(a,
_quantile_reducer_multi,
multi_num=q.size,
dtype=float,
axis=axis,
out=out,
overwrite_input=overwrite_input,
keepdims=keepdims,
q=q,
method=method)
else:
compile_error("q must be a scalar or 1d")
def _asarray_no_complex(a):
a = asarray(a)
if a.dtype is complex or a.dtype is complex64:
compile_error("a must be an array of real numbers")
return a
def quantile(a,
q,
axis=None,
out=None,
overwrite_input: bool = False,
method: str = "linear",
keepdims: Static[int] = False,
interpolation=None):
if interpolation is not None:
method = _check_interpolation_as_method(method, interpolation)
a = _asarray_no_complex(a)
q = asarray(q)
if not _quantile_is_valid(q):
raise ValueError("Quantiles must be in the range [0, 1]")
return _quantile_unchecked(a, q, axis, out, overwrite_input, method,
keepdims)
def _nanquantile_reducer(v: Ptr[T], s: int, n: int, dtype: type, T: type,
**kwargs):
n = _nan_to_back(v, n)
return _quantile(ndarray((n, ), (s, ), v),
quantiles=kwargs['q'],
axis=0,
method=kwargs['method'],
out=None)
def _nanquantile_reducer_multi(v: Ptr[T], s: int, n: int, out: Ptr[dtype],
dtype: type, T: type, **kwargs):
n = _nan_to_back(v, n)
q = kwargs['q']
_quantile(ndarray((n, ), (s, ), v),
quantiles=q,
axis=0,
method=kwargs['method'],
out=ndarray((q.size, ), (util.sizeof(dtype), ), out))
def _nanquantile_unchecked(a,
q,
axis=None,
out=None,
overwrite_input: bool = False,
method: str = "linear",
keepdims: Static[int] = False):
# Assumes that q is in [0, 1], and is an ndarray
if q.ndim == 0:
return _reduce_buffered(a,
_nanquantile_reducer,
dtype=a.dtype,
axis=axis,
out=out,
overwrite_input=overwrite_input,
keepdims=keepdims,
q=q.item(),
method=method)
elif q.ndim == 1:
return _reduce_buffered_multi(a,
_nanquantile_reducer_multi,
multi_num=q.size,
dtype=float,
axis=axis,
out=out,
overwrite_input=overwrite_input,
keepdims=keepdims,
q=q,
method=method)
else:
compile_error("q must be a scalar or 1d")
def nanquantile(a,
q,
axis=None,
out=None,
overwrite_input: bool = False,
method: str = "linear",
keepdims: Static[int] = False,
interpolation=None):
if interpolation is not None:
method = _check_interpolation_as_method(method, interpolation)
a = _asarray_no_complex(a)
if not _supports_nan(a.dtype):
return quantile(a,
q,
axis=axis,
out=out,
overwrite_input=overwrite_input,
method=method,
keepdims=keepdims,
interpolation=interpolation)
q = asarray(q)
if not _quantile_is_valid(q):
raise ValueError("Quantiles must be in the range [0, 1]")
return _nanquantile_unchecked(a, q, axis, out, overwrite_input, method,
keepdims)
def percentile(a,
q,
axis=None,
out=None,
overwrite_input: bool = False,
method: str = "linear",
keepdims: Static[int] = False,
interpolation=None):
if interpolation is not None:
method = _check_interpolation_as_method(method, interpolation)
a = _asarray_no_complex(a)
q = true_divide(q, 100)
q = asarray(q)
if not _quantile_is_valid(q):
raise ValueError("Percentiles must be in the range [0, 100]")
return _quantile_unchecked(a, q, axis, out, overwrite_input, method,
keepdims)
def nanpercentile(a,
q,
axis=None,
out=None,
overwrite_input: bool = False,
method: str = "linear",
keepdims: Static[int] = False,
interpolation=None):
if interpolation is not None:
method = _check_interpolation_as_method(method, interpolation)
a = _asarray_no_complex(a)
if not _supports_nan(a.dtype):
return percentile(a,
q,
axis=axis,
out=out,
overwrite_input=overwrite_input,
method=method,
keepdims=keepdims,
interpolation=interpolation)
q = true_divide(q, 100)
q = asarray(q)
if not _quantile_is_valid(q):
raise ValueError("Percentiles must be in the range [0, 100]")
return _nanquantile_unchecked(a, q, axis, out, overwrite_input, method,
keepdims)
@extend
class ndarray:
def sum(
self,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
initial=0,
where=util._NoValue(),
):
return sum(
self,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
initial=initial,
where=where,
)
def prod(
self,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
initial=1,
where=util._NoValue(),
):
return prod(
self,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
initial=initial,
where=where,
)
def mean(
self,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
where=util._NoValue(),
):
return mean(self,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where)
def nanmean(
self,
axis=None,
dtype: type = NoneType,
out=None,
keepdims: Static[int] = False,
where=util._NoValue(),
):
return nanmean(self,
axis=axis,
dtype=dtype,
out=out,
keepdims=keepdims,
where=where)
def var(
self,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
where=util._NoValue(),
):
return var(
self,
axis=axis,
dtype=dtype,
out=out,
ddof=ddof,
keepdims=keepdims,
where=where,
)
def nanvar(
self,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
where=util._NoValue(),
):
return nanvar(
self,
axis=axis,
dtype=dtype,
out=out,
ddof=ddof,
keepdims=keepdims,
where=where,
)
def std(
self,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
where=util._NoValue(),
):
return std(
self,
axis=axis,
dtype=dtype,
out=out,
ddof=ddof,
keepdims=keepdims,
where=where,
)
def nanstd(
self,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
where=util._NoValue(),
):
return nanstd(
self,
axis=axis,
dtype=dtype,
out=out,
ddof=ddof,
keepdims=keepdims,
where=where,
)
def min(
self,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
initial=util._NoValue(),
where=util._NoValue(),
):
return min(
self,
axis=axis,
dtype=dtype,
out=out,
ddof=ddof,
keepdims=keepdims,
initial=initial,
where=where,
)
def ptp(self, axis=None, out=None, keepdims: Static[int] = False):
return ptp(self, axis=axis, out=out, keepdims=keepdims)
def max(
self,
axis=None,
dtype: type = NoneType,
out=None,
ddof: int = 0,
keepdims: Static[int] = False,
initial=util._NoValue(),
where=util._NoValue(),
):
return max(
self,
axis=axis,
dtype=dtype,
out=out,
ddof=ddof,
keepdims=keepdims,
initial=initial,
where=where,
)
def argmin(self, axis=None, out=None, keepdims: Static[int] = False):
return argmin(self, axis=axis, out=out, keepdims=keepdims)
def argmax(self, axis=None, out=None, keepdims: Static[int] = False):
return argmax(self, axis=axis, out=out, keepdims=keepdims)
def any(self,
axis=None,
out=None,
keepdims: Static[int] = False,
where=util._NoValue()):
return any(self, axis=axis, out=out, keepdims=keepdims, where=where)
def all(self,
axis=None,
out=None,
keepdims: Static[int] = False,
where=util._NoValue()):
return all(self, axis=axis, out=out, keepdims=keepdims, where=where)