Skip to content

Conversation

@ev-br
Copy link
Member

@ev-br ev-br commented Sep 8, 2025

Closes gh-350

Otherwise, the version which emulates "clip" fails with torch.vmap.


This patch is less innocuous than it looks, because it changes the promotion rules. Previously, min and max were not upcasting the result:

In [9]: xpn = array_namespace(np.arange(3))

In [10]: xpn.clip(xpn.arange(5, dtype=xpn.int8), 2, xpn.asarray(3.0))
Out[10]: array([2, 2, 2, 3, 3], dtype=int8)

and now they are:

In [11]: xpt = array_namespace(torch.ones(3))

In [12]: xpt.clip(xpt.arange(5, dtype=xpt.int8), 2, xpt.asarray(3.0))
Out[12]: tensor([2., 2., 2., 3., 3.])

OTOH, the wording in the spec, https://data-apis.org/array-api/draft/API_specification/generated/array_api.clip.html is

min ... should have the same data type as x.

and

If either min or max is an array having a different data type than x, behavior is unspecified and thus implementation-dependent.

Otherwise, the version which emulates "clip" fails with torch.vmap
(see data-apisgh-350)
@ev-br ev-br added this to the 1.13 milestone Oct 28, 2025
@ev-br ev-br closed this Nov 22, 2025
@ev-br ev-br reopened this Nov 22, 2025
@ev-br ev-br mentioned this pull request Nov 23, 2025
@ev-br
Copy link
Member Author

ev-br commented Nov 25, 2025

cc/fyi @mdhaber : IIRC scipy.stats is a big user of the [()] empty tuple indexing. Apparently, it is problematic for torch.vmap, especially if used on the left of the = assignment. This PR and the issue it closes is triggered by this line:
https://github.com/data-apis/array-api-compat/blob/main/array_api_compat/common/_aliases.py#L424

@mdhaber
Copy link

mdhaber commented Dec 1, 2025

Yes, but I don't recall putting [()] on the left of an equals sign. Typically, when code in scipy.stats mutates a 0-d array, it's a special case of mutating a multidimensional array. And usually, that's done with a logical mask generated by some sort of comparison operator, so the 0-d case ends up indexing with a 0-d boolean array, not an empty tuple.

Almost every scipy.stats function uses [()] to the right of an equals sign / return statement to follow the precedent set by NumPy - return scalars instead of 0-d arrays at almost every opportunity. Now that we have to consider array-api-strict, empty tuple __getitem__ is only ever used on 0-d arrays; e.g. like x[() if x.ndim == 0 else x. Fine with me to get rid of all these uses when NumPy makes it less difficult to follow the standard (mdhaber/numpy#2)! But hopefully getting with [()] is not problematic in the meantime? Having to special case that for 0-d arrays is already verbose enough!

@ev-br ev-br closed this Dec 1, 2025
@ev-br ev-br reopened this Dec 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incompatibility between clip and torch.vmap

2 participants