Skip to content

Adding moveaxis & swapaxes #483

Closed
@jakirkham

Description

@jakirkham
Member

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.

Activity

rgommers

rgommers commented on Sep 23, 2022

@rgommers
Member

swapaxes is problematic IIRC, see gh-228. That's why we called it permute_dims

rgommers

rgommers commented on Sep 23, 2022

@rgommers
Member

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.

shoyer

shoyer commented on Sep 23, 2022

@shoyer
Contributor

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?

rgommers

rgommers commented on Sep 25, 2022

@rgommers
Member

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:

  • rollaxis is already doc-deprecated in numpy, in favor of moveaxis.
  • swapaxes is simple to implement in terms of moveaxis (but not permute_dims).
added this to the v2023 milestone on Jun 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    API extensionAdds new functions or objects to the API.

    Type

    No type

    Projects

    Status

    Stage 3

    Relationships

    None yet

      Development

      Participants

      @rgommers@shoyer@kgryte@jakirkham

      Issue actions

        Adding `moveaxis` & `swapaxes` · Issue #483 · data-apis/array-api