Skip to content

Commit fdafcc7

Browse files
committed
WIP: update top_k to match the spec proposal
1 parent a6433ac commit fdafcc7

2 files changed

Lines changed: 40 additions & 12 deletions

File tree

array_api_strict/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,9 @@
297297

298298
__all__ += ["concat", "expand_dims", "flip", "moveaxis", "permute_dims", "repeat", "reshape", "roll", "squeeze", "stack", "tile", "unstack"]
299299

300-
from ._searching_functions import argmax, argmin, nonzero, count_nonzero, searchsorted, where
300+
from ._searching_functions import argmax, argmin, nonzero, count_nonzero, searchsorted, where, top_k
301301

302-
__all__ += ["argmax", "argmin", "nonzero", "count_nonzero", "searchsorted", "where"]
302+
__all__ += ["argmax", "argmin", "nonzero", "count_nonzero", "searchsorted", "where", "top_k"]
303303

304304
from ._set_functions import unique_all, unique_counts, unique_inverse, unique_values, isin
305305

array_api_strict/_searching_functions.py

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Literal
1+
from typing import Literal, NamedTuple
22

33
import numpy as np
44

@@ -9,6 +9,11 @@
99
from ._helpers import _maybe_normalize_py_scalars
1010

1111

12+
class TopKResult(NamedTuple):
13+
values: Array
14+
indices: Array
15+
16+
1217
def argmax(x: Array, /, *, axis: int | None = None, keepdims: bool = False) -> Array:
1318
"""
1419
Array API compatible wrapper for :py:func:`np.argmax <numpy.argmax>`.
@@ -122,23 +127,46 @@ def where(condition: Array, x1: Array | complex, x2: Array | complex, /) -> Arra
122127
return Array._new(np.where(condition._array, x1._array, x2._array), device=x1.device)
123128

124129

125-
def top_k(a, k, /, axis=-1, *, mode="largest"):
130+
131+
def top_k(
132+
a: Array,
133+
k: int,
134+
/,
135+
*,
136+
axis: int =-1,
137+
mode: Literal["largest", "smallest"] = "largest"
138+
) -> TopKResult:
139+
"""
140+
Array API compatible wrapper for :py:func:`np.top_k <numpy.top_k>`.
141+
142+
See its docstring for more information.
143+
"""
126144
if k <= 0:
127145
raise ValueError(f'k(={k}) provided must be positive.')
128146

129-
positive_axis = axis if axis > 0 else axis % arr.ndim
147+
if mode not in ["largest", "smallest"]:
148+
raise ValueError(f'{mode = } not in ["largest", "smallest"]')
149+
150+
if k > a.shape[axis]:
151+
raise ValueError(f"{k = } exceeds {a.shape[axis] = }")
152+
153+
positive_axis = axis if axis > 0 else axis % a.ndim
154+
155+
arr = a._array
130156

131157
slice_start = (np.s_[:],) * positive_axis
132-
if largest:
158+
if mode == "largest":
133159
indices_array = np.argpartition(arr, -k, axis=axis)
134-
slice = slice_start + (np.s_[-k:],)
135-
topk_indices = indices_array[slice]
160+
slice_ = slice_start + (np.s_[-k:],)
161+
topk_indices = indices_array[slice_]
136162
else:
137163
indices_array = np.argpartition(arr, k-1, axis=axis)
138-
slice = slice_start + (np.s_[:k],)
139-
topk_indices = indices_array[slice]
164+
slice_ = slice_start + (np.s_[:k],)
165+
topk_indices = indices_array[slice_]
140166

141167
topk_values = np.take_along_axis(arr, topk_indices, axis=axis)
142168

143-
return topk_values, topk_indices
144-
169+
return TopKResult(
170+
Array._new(topk_values, device=a.device),
171+
Array._new(topk_indices, device=a.device)
172+
)

0 commit comments

Comments
 (0)