Skip to content

Raise on implicit device transfer in __setitem__ #207

Description

@ogrisel

Consider the following two arrays:

>>> import array_api_strict as xp
>>> a = xp.ones(10, device=xp.Device("device2"))
>>> b = 2 * xp.ones(10)

As expected, it's not possible to run operations that combine two such arrays because they live on different devices:

>>> a + b
Traceback (most recent call last):
  Cell In[23], line 1
    a + b
  File ~/miniforge3/envs/dev/lib/python3.13/site-packages/array_api_strict/_array_object.py:545 in __add__
    self._check_type_device(other)
  File ~/miniforge3/envs/dev/lib/python3.13/site-packages/array_api_strict/_array_object.py:241 in _check_type_device
    raise ValueError(f"Arrays from two different devices ({self.device} and {other.device}) can not be combined.")
ValueError: Arrays from two different devices (array_api_strict.Device('device2') and array_api_strict.Device('CPU_DEVICE')) can not be combined.

However, doing assignment works without raising an exception despite the fact that this causes an implicit data transfer between devices:

>>> b[:5] = a[:5]
>>> b
Array([1., 1., 1., 1., 1., 2., 2., 2., 2.,
       2.], dtype=array_api_strict.float64)

Shouldn't the __setitem__ call raise in this case?

Activity

  1. ogrisel commented on Apr 30, 2026

    @ogrisel
    Author

    Note that the current behavior (no exception on cross-device __setitem__) of array-api-strict is aligned with PyTorch:

    >>> import torch
    >>> a = torch.ones(10, device="mps")
    >>> b = 2 * torch.ones(10)  # CPU
    >>> a + b
    Traceback (most recent call last):
      Cell In[9], line 1
        a + b
    RuntimeError: Expected all tensors to be on the same device, but found at least two devices, mps:0 and cpu!
    >>> b[:5] = a[:5]  # implicit MPS to CPU transfer does not raise!
    >>> b
    tensor([1., 1., 1., 1., 1., 2., 2., 2., 2., 2.])

    Not sure if this lack of exception could be considered a "bug" of PyTorch with MPS.

    However, DPNP on some hardware architectures do raise: ValueError: Execution queue is not compatible with allocation queues as seen in scikit-learn/scikit-learn#32460 (comment).

  2. ogrisel commented on Apr 30, 2026

    @ogrisel
    Author

    I asked Claude that did a source code / doc review, and __setitem__ is considered "data movement" operation (like .to(), .copy_(), .cpu(), .cuda(), ...) and therefore is not expected to raise in PyTorch (contrary to "compute" operations like +).

    I also checked the array API spec and there is no mention of constraints related to device transfers: https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__setitem__.html#setitem.

    So I am not sure if it's ok or not for an array library to raise in this case.

  3. ogrisel commented on Apr 30, 2026

    @ogrisel
    Author

    Also from:

    Handling devices is complex, and some frameworks have elaborate policies for handling device placement. Therefore this section only gives recommendations, rather than hard requirements:
    ...

    • Raise an exception if an operation involves arrays on different devices (i.e. avoid implicit data transfer between devices).

    So I think it would make sense for array-api-strict to raise on cross-device __setitem__ if we consider assignment an "operation".

  4. ogrisel commented on Apr 30, 2026

    @ogrisel
    Author
  5. lucascolley commented on May 2, 2026

    @lucascolley
    Member

    would this fall under gh-168 Olivier?

  6. ev-br commented on May 2, 2026

    @ev-br
    Member

    We discussed this in the Array API community meeting last week, https://hackmd.io/zn5bvdZTQIeJmb3RW1B-8g?view#Meeting-minutes-30-April-2026, with a resolution to designate it as implementation-defined.

    Currently the Array API spec has a general recommendation to avoid implicit transfers, however different libraries make specific choices (e.g. torch special-cases a CPU device), hence the spec itself cannot really force a specific choice on all compliant libraries.

    For array-api-strict this means it should indeed raise an exception, because it only implements behaviors which are explicitly allowed by the spec, and rejects anything unspecified, hence implementation-defined.

    data-apis/array-api#1005 updates the specifications of __setitem__ and __getitem__; for array-api-strict, we could either lump an update to #206, or have a separate PR just for __{get,set}item__ (the latter's preferred, I'd think).

  7. ogrisel commented on May 4, 2026

    @ogrisel
    Author

    would this fall under #168 Olivier?

    This is indeed related but raising on cross-device __setitem__ by default would be an even more direct way to achieve this.

  8. ogrisel commented on May 4, 2026

    @ogrisel
    Author

    we could either lump an update to #206, or have a separate PR just for __{get,set}item__ (the latter's preferred, I'd think).

    Raising on cross-device __{get,set}item__ is actually not directly related to the dtype restrictions of a particular device so better implement that independently to ease the review and keep a neat changelog.

  9. ev-br commented on May 9, 2026

    @ev-br
    Member

    Raising on cross-device {get,set}item is actually not directly related to the dtype restrictions of a particular device so better implement that independently

    Agreed. Fix in #209

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions