Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding moveaxis & swapaxes #483

Closed
jakirkham opened this issue Sep 23, 2022 · 4 comments · Fixed by #656
Closed

Adding moveaxis & swapaxes #483

jakirkham opened this issue Sep 23, 2022 · 4 comments · Fixed by #656
Labels
API extension Adds new functions or objects to the API.
Milestone

Comments

@jakirkham
Copy link
Member

jakirkham commented Sep 23, 2022

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.

@rgommers rgommers added the API extension Adds new functions or objects to the API. label Sep 23, 2022
@rgommers
Copy link
Member

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

@rgommers
Copy link
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
Copy link
Contributor

shoyer commented Sep 23, 2022

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
Copy link
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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API extension Adds new functions or objects to the API.
Projects
Status: Stage 3
Development

Successfully merging a pull request may close this issue.

4 participants