Adding `moveaxis` & `swapaxes`
There are a few operations that come up like this periodically (also rollaxis). That said, some of these require a doc refresher on how they behave before using them. Still there can be value in doing something simpler than transpose that makes it clearer what changed. Perhaps an alternative approach to adding them to the spec is making sure the NumPy implementations play well with other array implementations.
swapaxes is problematic IIRC, see gh-228. That's why we called it permute_dims
We would benefit from a description of how the many ways of doing this in numpy et al. translate to the preferred way of doing this with the array API. That will show also if there's a gap like moveaxis. IIRC we looked at this fairly carefully, however I cannot find it back right now.
permute_dims is the fundamental operation here. moveaxis is convenient for users, but do we also want to include convenience functions in the API standard?
but do we also want to include convenience functions in the API standard?
I think we parked the many convenience functions previously, and focused on getting the one fundamental operation right. I'd say there is a case for one convenience function here though. Implementing moveaxis in terms of permute_dims is not completely trivial. Looking at the numpy.moveaxis implementation, if you want to get negative axes and other corner cases right, it'd be something like:
def moveaxis(x, /, source, destination):
source = _normalize_axis_tuple(source, x.ndim, 'source')
destination = _normalize_axis_tuple(destination, x.ndim, 'destination')
if len(source) != len(destination):
raise ValueError('`source` and `destination` arguments must have '
'the same number of elements')
order = [n for n in range(x.ndim) if n not in source]
for dest, src in sorted(zip(destination, source)):
order.insert(dest, src)
def _normalize_axis_tuple(axis, ndim, argname=None, allow_duplicate=False):
if type(axis) not in (tuple, list):
try:
axis = [operator.index(axis)]
except TypeError:
pass
axis = tuple([normalize_axis_index(ax, ndim, argname) for ax in axis])
if not allow_duplicate and len(set(axis)) != len(axis):
if argname:
raise ValueError('repeated axis in `{}` argument'.format(argname))
else:
raise ValueError('repeated axis')
return axis
For the other functions mentioned:
-
rollaxisis already doc-deprecated in numpy, in favor ofmoveaxis. -
swapaxesis simple to implement in terms ofmoveaxis(but notpermute_dims).