Skip to content

MLX compatibility: Creation functions #452

Description

@aaishwarymishra
Array API MLX Analog Status Blame / Notes Upstream Test Node Result
arange(start, /, stop=None, step=1, *, dtype=None, device=None) arange(start, stop, step, dtype=None, *, stream=None) partial stop=None now accepted. Remaining failure: integer args larger than signed 32-bit (e.g. step=2**31) — the nanobind binding uses C++ int, so xp.arange(n-1, n+3) with n = iinfo(int32).max raises TypeError. Still no device. ml-explore/mlx#3982 (merged); int32 limit fixed ml-explore/mlx#4255 test_arange Passed
asarray(obj, /, *, dtype=None, device=None, copy=None) asarray(a, dtype=None, *, copy=None) partial — won't fix copy=False raises even for an MLX array already of the requested dtype. Fix was proposed and closed unmerged. No device; dtype not keyword-only. ml-explore/mlx#4036 (closed, not merged) test_asarray_arrays Failed
empty(shape, *, dtype=None, device=None) empty(shape, dtype=float32, *, stream=None) undocumented Implemented (pure alias) but still absent from MLX docs. No device. ml-explore/mlx#3729 (merged) test_empty Passed
empty_like(x, /, *, dtype=None, device=None) empty_like(a, /, *, dtype=None, stream=None) undocumented dtype now accepted — empty_like aliases zeros_like, so it inherited the fix. Still undocumented; no device. ml-explore/mlx#4028 (merged); #4037 (closed, superseded) test_empty_like Passed
eye(n_rows, n_cols=None, /, *, k=0, dtype=None, device=None) eye(n, m=None, k=0, dtype=float32, *, stream=None) partial eye(0) fixed upstream; the too-large-k failure was a test-suite issue, fixed at the tip of array-api-tests. Remaining failure: GPU scatter does not support uint64 MLX limitation, so identity creation fails for that dtype. ml-explore/mlx#3952 (merged); uint64 case cant be supported due to mlx limitation ml-explore/mlx#4300 test_eye Failed
from_dlpack(x, /, *, device=None, copy=None) from_dlpack(x, /, *, copy=None) Incompatible Test fails before reaching from_dlpack: MLX has no x.device and does not have device parameter in the signature - test_dlpack.py::test_from_dlpack Failed
full(shape, fill_value, *, dtype=None, device=None) full(shape, vals, dtype=None, *, stream=None) signature mismatch fill_value is named vals; dtype not keyword-only; no device. — test_full Passed
full_like(x, /, fill_value, *, dtype=None, device=None) full_like(a, vals, dtype=None, *, stream=None) signature mismatch fill_value is named vals; dtype not keyword-only; no device. — test_full_like Passed
linspace(start, stop, /, num, *, dtype=None, device=None, endpoint=True) linspace(start, stop, num=50, dtype=float32, stream=None) partial — in progress endpoint still unsupported, so endpoint=False fails. Draft PR open. No device. ml-explore/mlx#4152 (issue, open), #4184 (draft PR, open) test_linspace Passed
meshgrid(*arrays, indexing="xy") meshgrid(*arrays, sparse=False, indexing="xy", stream=None) return mismatch — in progress MLX returns a list; Array API 2025.12 requires a tuple. ml-explore/mlx#4034 (issue, open) test_meshgrid Passed
ones(shape, *, dtype=None, device=None) ones(shape, dtype=float32, *, stream=None) signature mismatch dtype not keyword-only; no device. Behavior passes. — test_ones Passed
ones_like(x, /, *, dtype=None, device=None) ones_like(a, /, *, dtype=None, stream=None) signature mismatch dtype added upstream as a keyword-only arg. No device. ml-explore/mlx#4001 (issue, closed) → #4028 (merged) test_ones_like Passed
tril(x, /, *, k=0) tril(x, k, *, stream=None) signature mismatch k accepted positionally; spec makes it keyword-only. Behavior passes. — test_tril Passed
triu(x, /, *, k=0) triu(x, k, *, stream=None) signature mismatch k accepted positionally; spec makes it keyword-only. Behavior passes. — test_triu Passed
zeros(shape, *, dtype=None, device=None) zeros(shape, dtype=float32, *, stream=None) signature mismatch dtype not keyword-only; no device. Behavior passes. — test_zeros Passed
zeros_like(x, /, *, dtype=None, device=None) zeros_like(a, /, *, dtype=None, stream=None) signature mismatch dtype added upstream as a keyword-only arg. No device. ml-explore/mlx#4001 (issue, closed) → #4028 (merged) test_zeros_like Passed

Planned x-fails

Activity

  1. aaishwarymishra commented on Jul 18, 2026

    @aaishwarymishra
    Author

    I wasn't able to run tests on this file mainly because,

    • By default mlx arrays are on gpu stream and they dont support float64, many tests failed because of that.
    • some tests were checking different datatypes the complex bug also affected these tests.
    • No device parameter or method signature mismatch
  2. changed the title [-]MLX compatibility: Creation methods[/-] [+]MLX compatibility: Creation functions[/+] on Jul 19, 2026
  3. ev-br commented on Jul 19, 2026

    @ev-br
    Member

    No device parameter

    This is systemic and is worth noting indeed. Does not block testing at this stage, not more than cupy which does not have device arguments either.

    By default mlx arrays are on gpu stream and they dont support float64, many tests failed because of that.

    This is a nice observation and runs into a systemic problem in the test suite (cf data-apis/array-api-tests#440).
    Meanwhile, can you run tests with set_default_device to CPU? https://ml-explore.github.io/mlx/build/html/python/_autosummary/mlx.core.set_default_device.html
    That'd be similar to JAX, data-apis/array-api-tests#368 (comment)


    Your table is very useful, but is a tad hard to read because the "notes" column runs into the page width, could swap with "Test node" and "result" columns.

    And it'd be useful to continue compiling a compatibility table for the rest of the spec in this same issue.

  4. ev-br commented on Jul 19, 2026

    @ev-br
    Member

    By default mlx arrays are on gpu stream and they dont support float64, many tests failed because of that.

    In addition / as an alternative to setting the MLX default device to CPU, you may run the test suite with the environment variable ARRAY_API_TESTS_SKIP_DTYPES=float64,complex128. Skipping float64 mostly works: if a test fails with this skip and MLX, it'd be helpful to double-check the test failure with the skip and array_api_compat.numpy. If it still fails, the problem is with the test suite (please report it in data-apis/array-api-tests#431). If it passes with numpy and fails with MLX, then report the failure here.

  5. aaishwarymishra commented on Jul 19, 2026

    @aaishwarymishra
    Author
    • arange: MLX rejects the valid three-argument form when stop=None, e.g. arange(0, None, 1).

    • asarray: copy=False fails even when the input is already an MLX array with the requested dtype; MLX claims it cannot
      avoid copying.

    • empty_like: MLX does not accept the standard dtype keyword—even dtype=None. The error mentioning zeros_like also
      suggests empty_like is internally aliased or misrouted.

    • eye: two issues:

      • Zero-sized dimensions such as eye(0) are rejected.
      • Large valid diagonal offsets such as k=2147483648 overflow or fail MLX’s argument binding.
    • linspace: MLX does not implement the endpoint keyword.

    • meshgrid: MLX returns a list, but Array API 2025.12 requires a tuple.

    • ones_like: MLX does not accept the standard dtype keyword.

    • zeros_like: Same missing dtype keyword support.

    what I found was the empty and empty_like was implemented on new release, but the docs wasn't updated so I marked them as missing, I will update that, out of 16, 8 passed and 8 failed.

    For the from_dlpack its's test is in a separate file and it didn't ran It tried to determine which device to use in two ways:

    1. With copy=False, it reads x.device, but MLX arrays do not have that attribute.
    2. Otherwise, it call xp.array_namespace_info().devices(),but MLX does not implement array_namespace_info.
      Even if I manually hardcode the MLX device test will fail as mlx does not have device parameter which it is passing.

    The two passing tests were:

    • test_dlpack.py::test_dlpack_device
    • test_dlpack.py::test_dunder_dlpack

    Only test_dlpack.py::test_from_dlpack failed.

    Details
    FAILED array_api_tests/test_creation_functions.py::test_arange - TypeError: arange(): incompatible function arguments. The following argument types are supported:
    FAILED array_api_tests/test_creation_functions.py::test_asarray_arrays - ValueError: Unable to avoid copy while creating an array as requested.
    FAILED array_api_tests/test_creation_functions.py::test_empty_like - TypeError: zeros_like(): incompatible function arguments. The following argument types are supp...
    FAILED array_api_tests/test_creation_functions.py::test_eye - ExceptionGroup: Hypothesis found 2 distinct failures. (2 sub-exceptions)
    FAILED array_api_tests/test_creation_functions.py::test_linspace - TypeError: linspace(): incompatible function arguments. The following argument types are suppor...
    FAILED array_api_tests/test_creation_functions.py::test_meshgrid - AssertionError: assert <class 'list'> == <class 'tuple'>
    FAILED array_api_tests/test_creation_functions.py::test_ones_like - TypeError: ones_like(): incompatible function arguments. The following argument types are suppo...
    FAILED array_api_tests/test_creation_functions.py::test_zeros_like - TypeError: zeros_like(): incompatible function arguments. The following argument types are supp...
  6. ev-br commented on Jul 23, 2026

    @ev-br
    Member

    Thanks @aaishwarymishra , this is very helpful! Quick triage:

    • {empty,zeros,ones}_like not accepting a dtype argument: this looks like a simple enhancement in MLX
    • eye(0) : it's a simple edge case yes, an annoying one to run into, and a simple one to fix at the source
    • arange(1, None, 1) : likewise, this shouldn't be a hard fix in MLX
    • linspace(...., endpoint={True,False}: likewise

    Of these, linspace I would very much prefer to not meddle with in the compat layer, as it's not intrinsically hard but is prone to small inconsistencies, and will need rather extensive testing to avoid mlx and _compat.mlx divergencies.

    The other ones, one strategy could be to write small wrappers in a -compat fork/PR, make sure they pass the test suite, and then submit to MLX. When you do, feel free to link back here or ping me :-).
    The wrappers ideally are temporary and are needed to see if there are other issues masked by a first problem.

    • meshgrid returning lists not tuples: this was a deliberate change in 2025.12; NumPy changed in in 2.0, CuPy followed up in ENH: make broadcast_arrays, meshgrid return a tuple not list cupy/cupy#9582. I think there were no loud compaints about either change, which probably means the backwards compatibility effect is not serious in practice, so I'd advocate to just change it despite that it's a backcompat break.

    These all are small-ish issues, would be nice to fix for user experience. In principle can fix in the compat layer, but even if we do, I'd very much prefer to have some strategy for adding them to MLX and dropping them from the compat layer.

    Working around the lack of .device attribute is brittle, cf

    # FIXME Jitted JAX arrays do not have a device attribute
    # https://github.com/jax-ml/jax/issues/26000
    # Return None in this case. Note that this workaround breaks
    # the standard and will result in new arrays being created on the
    # default device instead of the same device as the input array(s).
    x_device = getattr(x, "device", None)
    # Older JAX releases had .device() as a method, which has been replaced
    # with a property in accordance with the standard.
    if inspect.ismethod(x_device):
    return x_device()
    else:
    return x_device
    so it would be really great if MLX could add the attribute, even if it's not used internally.

  7. rgommers commented on Jul 27, 2026

    @rgommers
    Member

    I'll link to ml-explore/mlx#3484 (comment) as the recent comment with the MLX devs's stance. I'd suggest starting with the upstream changes that are most concrete, uncontroversial, and won't require separate kernel's. The first four bullets in the comment above could be a good start? eye(0) for example I'd expect to work well. meshgrid is simple but don't start with a backwards compat break; it's trivial to work around in this repo. .device definitely leave to the end, I don't expect that to be well-received.

  8. aaishwarymishra commented on Aug 2, 2026

    @aaishwarymishra
    Author

    @ev-br Hi, I have made some pr's mainly focusing on bugs and non breaking changes :)

  9. aaishwarymishra commented on Aug 5, 2026

    @aaishwarymishra
    Author

    Hi @ev-br I have a question I looked at the adding dtype argument in {empty,zeros,ones}_like one blocker that I noticed if I put it in standard position (a,dtype.device) is that many of sub methods that rely on these methods in mlx uses positional arguments and it could possibly be backward breaking too.
    One solution could be to add dtype after device or stream in the case of the mlx like (a,device,dtype).

    I made an issue regarding it I am not sure if my wording was not that good cause I wasn't able to get a concrete answer on how to proceed

    ml-explore/mlx#4001

    I would appreciate your opinion :)

  10. ev-br commented on Aug 5, 2026

    @ev-br
    Member

    Not sure I understand the concern. Comparing the signatures (am copy-pasting from your table above):

    empty_like(a, /, *, stream=None)   # the current MLX signature
    empty_like(x, /, *, dtype=None, device=None)   # the Array API spec signature
    

    I think making it empty_like(x, /, *, dtype=None, stream=None) is backwards compatible because you're adding a keyword-only argument.

    In the upstream issue above you mention C++ signatures, but those are of course different since the whole positional/kwarg argument parsing works differently in C++. And as long as the python frontend correctly sends the dtype argument to C++, there should be no fundamental issue---what am I missing?

    If the concern is how to structure updating the C++, what I'd do is I'd start with one function, say, empty_like, add the new argument in its natural location, before stream, update the call sites, send the PR and flag it to the reviewers whether they are OK with this new argument in the middle of the C++ signature, or whether they prefer it in the end.
    Maybe also include the count of the places which will need to be updated for other functions, via grep | wc -l or something like that.

  11. aaishwarymishra commented on Aug 6, 2026

    @aaishwarymishra
    Author

    Additional statuses of other PRS and issues:

  12. aaishwarymishra commented on Aug 7, 2026

    @aaishwarymishra
    Author

    I don't think the copy inconsistency in asarray can be fixed upstream ml-explore/mlx#4036

  13. ev-br commented on Aug 7, 2026

    @ev-br
    Member

    Thanks for the upstream updates @aaishwarymishra , that's really impressive!

    I presume you build mlx from source when working on upstream PRs?

    It would be great to rerun the comparison after your fixes (+the tip of array-api-tests which fixed the too-large-k issue in test_eye, but that's minor).

    My impression is that the remaining failures should be mostly hard mlx limitations (device attribute, copy= of asarray etc) and divergences with backwards compatibility considerations (meshgrid).

  14. aaishwarymishra commented on Aug 10, 2026

    @aaishwarymishra
    Author

    Hi @ev-br I am waiting for the response on the ml-explore/mlx#4152 and ml-explore/mlx#4034 as after these 2 issues are resolved I think we would have covered most of the easy and solvable cases, before I re-run the tests again

  15. ev-br commented on Aug 10, 2026

    @ev-br
    Member

    Nice! Any chance you'd be interested in generalising what you did to, say, manipulation functions ?

  16. aaishwarymishra commented on Aug 11, 2026

    @aaishwarymishra
    Author

    Sure :)

  17. aaishwarymishra commented on Aug 13, 2026

    @aaishwarymishra
    Author

    Hi i re-ran tests

    1. arange — rejects integers larger than signed 32-bit, such as step=2**31, well I found the reason they use standard c++ int for int values for arange binding so nanobind tries to convert it to int32 and fails not sure if supporting int64 for parameters in the spec.
    2. asarray — raises for copy=False know issue.
    3. eye — GPU scatter does not support uint64, so identity matrix creation fails for that dtype.
    4. linspace — does not support the Array API endpoint keyword, there is an draft pr open but not sure how it will proceed Add endpoint parameter to linspace ml-explore/mlx#4184.
    5. meshgrid — returns a list; Array API 2025.12 requires a tuple well someone wanted to work on it so i have left it for now Returning a tuple instead of list for meshgrid to make it compliant with Array API ml-explore/mlx#4034.
  18. aaishwarymishra commented on Aug 13, 2026

    @aaishwarymishra
    Author

    Also in hypothesis_helpers.py

    _sorted_dtypes = [d for category in _dtype_categories for d in category]
    _device_dtype_pairs = [
        (dtype, device)
        for dtype in _sorted_dtypes
        for device in xp.__array_namespace_info__().devices()
        if dh.is_device_dlpack_compatible(device)
        if dh.is_dtype_device_compatible(dtype, device)
    ]

    causes tests to fail as for now MLX does not support xp.__array_namespace_info__ so I have to remove it to run the tests probably missed the last time, I re-ran tests on fresh pull so i ran into again.

  19. prady0t commented on Aug 13, 2026

    @prady0t

    causes tests to fail as for now MLX does not support xp.array_namespace_info

    Also no device parameter. Another workaround would be to put it in a try block so it doesn't effect other parts of the test suit. See below some changes I made regarding this in my local branch:

    https://github.com/prady0t/array-api-tests/pull/1/changes

  20. ev-br commented on Aug 13, 2026

    @ev-br
    Member

    Great progress!
    So we're down to 5 failures out of 15 tests; two are being worked on, and one is not going to be fixed.

    The remaining ones, arange and eye, indeed look like int32 limitations: I tried n = xp.iinfo(xp.int32).max ; xp.arange(n-1, n+3) and it raises a TypeError, and so does xp.eye(n + 1).shape. Would be best to report upstream.

    Could you please edit the top post @aaishwarymishra , with the current status and links to upstream issues/PRs? Including rejected ones, so that the top post links to ml-explore/mlx#4036 and so on.

  21. aaishwarymishra commented on Aug 21, 2026

    @aaishwarymishra
    Author

    ok as of now only 2 tests are failing

    FAILED array-api-tests/array_api_tests/test_creation_functions.py::test_asarray_arrays - ValueError: Unable to avoid copy while creating an array as requested.
    FAILED array-api-tests/array_api_tests/test_creation_functions.py::test_eye - ValueError: [scatter] GPU scatter does not yet support uint64 for the input or updates.
    

    Of which one is dependant on ml-explore/mlx#4328

  22. aaishwarymishra commented on Aug 21, 2026

    @aaishwarymishra
    Author

    I don't think for now the from_dlpack be made compliant as the test uses .device which mlx does not expose

    ======================================== FAILURES =========================================
    ____________________________________ test_from_dlpack _____________________________________
      + Exception Group Traceback (most recent call last):
      |   File "/Users/blanky/code/array-api/array-api-tests/array_api_tests/test_dlpack.py", line 68, in test_from_dlpack
      |     dtype_device_pair=hh.device_dtype_pairs,
      |                ^^^
      |   File "/Users/blanky/code/array-api/.venv/lib/python3.13/site-packages/hypothesis/core.py", line 2288, in wrapped_test
      |     raise the_error_hypothesis_found
      | ExceptionGroup: Hypothesis found 3 distinct failures. (3 sub-exceptions)
      +-+---------------- 1 ----------------
        | Traceback (most recent call last):
        |   File "/Users/blanky/code/array-api/array-api-tests/array_api_tests/test_dlpack.py", line 80, in test_from_dlpack
        |     tgt_device = x.device if copy is False else device
        |                  ^^^^^^^^
        | AttributeError: 'mlx.core.array' object has no attribute 'device'
        | Failing test case: test_from_dlpack(
        |     dtype_device_pair=(mlx.core.bool, None),
        |     copy_kw={'copy': False},
        |     data=data(...),
        | )
        | Draw 1: array([], dtype=bool)
        +---------------- 2 ----------------
        | Traceback (most recent call last):
        |   File "/Users/blanky/code/array-api/array-api-tests/array_api_tests/test_dlpack.py", line 91, in test_from_dlpack
        |     y = xp.from_dlpack(x, **tgt_device_kw, **copy_kw)
        | TypeError: from_dlpack(): incompatible function arguments. The following argument types are supported:
        |     1. from_dlpack(x: DLPackCompatible, /, *, copy: bool | None = None) -> array
        |
        | Invoked with types: mlx.core.array, kwargs = { device: NoneType }
        |
        | ========== FAILING CODE SNIPPET:
        | y = from_dlpack(array([], dtype=bool), **tgt_device_kw, **copy_kw) with tgt_device_kw={'device': None} and copy_kw={}
        | ====================
        |
        | Failing test case: test_from_dlpack(
        |     dtype_device_pair=(mlx.core.bool, None),
        |     copy_kw={},
        |     data=data(...),
        | )
        | Draw 1: array([], dtype=bool)
        | Draw 2: True
        +---------------- 3 ----------------
        | Traceback (most recent call last):
        |   File "/Users/blanky/code/array-api/array-api-tests/array_api_tests/test_dlpack.py", line 94, in test_from_dlpack
        |     assert y.device == x.device
        |            ^^^^^^^^
        | AttributeError: 'mlx.core.array' object has no attribute 'device'
        |
        | ========== FAILING CODE SNIPPET:
        | y = from_dlpack(array([], dtype=bool), **tgt_device_kw, **copy_kw) with tgt_device_kw={} and copy_kw={}
        | ====================
        |
        | Failing test case: test_from_dlpack(
        |     dtype_device_pair=(mlx.core.bool, None),
        |     copy_kw={},
        |     data=data(...),
        | )
        | Draw 1: array([], dtype=bool)
        | Draw 2: False
        +------------------------------------
    ================================= short test summary info =================================
    FAILED array-api-tests/array_api_tests/test_dlpack.py::test_from_dlpack - ExceptionGroup: Hypothesis found 3 distinct failures. (3 sub-exceptions)
    =============================== 1 failed, 2 passed in 0.43

    So 3 tests in total are failing

  23. ev-br commented on Aug 21, 2026

    @ev-br
    Member

    Great progress indeed!

    EDIT:

    So, one known failure, two more being worked on.

  24. aaishwarymishra commented on Aug 21, 2026

    @aaishwarymishra
    Author

    I mean we can also add an wrapper for simply returning the original array when copy=False similar to how jax does even though they don't allow mutations similar to mlx.

    • test_eye : might be helpful to check whether building MLX with the linked MLX PR fixes the test? And comment on the upstream PR.

    test_eye might need to be skipped/xfailed too as its MLX limitation and I don't think they are open for workarounds ml-explore/mlx#4300 (comment)

  25. ev-br commented on Aug 21, 2026

    @ev-br
    Member

    we can also add an wrapper for simply returning the original array when copy=False

    We could yes. The question is whether we should. The less workarounds are there, the better, for many reasons. At this stage at least, I don't see a reason to rush a workaround.

    test_eye might need to be skipped/xfailed too as its MLX limitation and I don't think they are open for workarounds ml-explore/mlx#4300 (comment)

    Please please edit this in into the OP table, together with other updates from the last month.

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