Repository navigation
MLX compatibility: Creation functions #452
Copy link
Copy link
Open
Description
| 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
-
test_asarray_arrays -
test_eye -
test_from_dlpackdepends on fix: define dask reshape copy behavior #459
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
aaishwarymishra commentedon Jul 18, 2026
I wasn't able to run tests on this file mainly because,
complexbug also affected these tests.[-]MLX compatibility: Creation methods[/-][+]MLX compatibility: Creation functions[/+]ev-br commentedon Jul 19, 2026
This is systemic and is worth noting indeed. Does not block testing at this stage, not more than
cupywhich does not havedevicearguments either.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_deviceto CPU? https://ml-explore.github.io/mlx/build/html/python/_autosummary/mlx.core.set_default_device.htmlThat'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.
ev-br commentedon Jul 19, 2026
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 andarray_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.aaishwarymishra commentedon Jul 19, 2026
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:
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_dlpackits's test is in a separate file and it didn't ran It tried to determine which device to use in two ways: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:
Only test_dlpack.py::test_from_dlpack failed.
Details
ev-br commentedon Jul 23, 2026
Thanks @aaishwarymishra , this is very helpful! Quick triage:
{empty,zeros,ones}_likenot accepting adtypeargument: this looks like a simple enhancement in MLXeye(0): it's a simple edge case yes, an annoying one to run into, and a simple one to fix at the sourcearange(1, None, 1): likewise, this shouldn't be a hard fix in MLXlinspace(...., endpoint={True,False}: likewiseOf these,
linspaceI 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 avoidmlxand_compat.mlxdivergencies.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.
meshgridreturning lists not tuples: this was a deliberate change in 2025.12; NumPy changed in in 2.0, CuPy followed up in ENH: makebroadcast_arrays,meshgridreturn 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.
asarray(copy=False)failure is pointing at some deeper problem. Would be nice to understand in more details, could you provide an standalone MRE?the lack of
.devicearray attribute is something which 1) we cannot work around in the -compat layer at all (we do not touch the array object); 2) is likely to be a tripping hazard going forward, as we improve the device support and work towards device-dependent dtype subsets, cf [RFC]: Updates for float16/bfloat16 and for dtypes that are lacking full support in libraries array-api#998Working around the lack of
.deviceattribute is brittle, cfarray-api-compat/src/array_api_compat/common/_helpers.py
Lines 781 to 792 in bbfe8c2
rgommers commentedon Jul 27, 2026
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.meshgridis simple but don't start with a backwards compat break; it's trivial to work around in this repo..devicedefinitely leave to the end, I don't expect that to be well-received.aaishwarymishra commentedon Aug 2, 2026
@ev-br Hi, I have made some pr's mainly focusing on bugs and non breaking changes :)
ev-br commentedon Aug 4, 2026
For completeness, here are @aaishwarymishra 's upstream PRs:
aaishwarymishra commentedon Aug 5, 2026
Hi @ev-br I have a question I looked at the adding
dtypeargument 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
dtypeafterdeviceorstreamin 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 :)
ev-br commentedon Aug 5, 2026
Not sure I understand the concern. Comparing the signatures (am copy-pasting from your table above):
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, beforestream, 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 -lor something like that.aaishwarymishra commentedon Aug 6, 2026
Additional statuses of other PRS and issues:
aaishwarymishra commentedon Aug 7, 2026
I don't think the copy inconsistency in
asarraycan be fixed upstream ml-explore/mlx#4036ev-br commentedon Aug 7, 2026
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).
aaishwarymishra commentedon Aug 10, 2026
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
ev-br commentedon Aug 10, 2026
Nice! Any chance you'd be interested in generalising what you did to, say, manipulation functions ?
aaishwarymishra commentedon Aug 11, 2026
Sure :)
aaishwarymishra commentedon Aug 13, 2026
Hi i re-ran tests
arange— rejects integers larger than signed 32-bit, such asstep=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.asarray— raises forcopy=Falseknow issue.eye— GPU scatter does not supportuint64, so identity matrix creation fails for that dtype.linspace— does not support the Array APIendpointkeyword, there is an draft pr open but not sure how it will proceed Add endpoint parameter to linspace ml-explore/mlx#4184.meshgrid— returns alist; Array API 2025.12 requires atuplewell 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.aaishwarymishra commentedon Aug 13, 2026
Also in
hypothesis_helpers.pycauses 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.prady0t commentedon Aug 13, 2026
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
ev-br commentedon Aug 13, 2026
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,
arangeandeye, indeed look likeint32limitations: I triedn = xp.iinfo(xp.int32).max ; xp.arange(n-1, n+3)and it raises a TypeError, and so doesxp.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.
aaishwarymishra commentedon Aug 21, 2026
ok as of now only 2 tests are failing
Of which one is dependant on ml-explore/mlx#4328
aaishwarymishra commentedon Aug 21, 2026
I don't think for now the
from_dlpackbe made compliant as the test uses .device which mlx does not exposeSo 3 tests in total are failing
ev-br commentedon Aug 21, 2026
Great progress indeed!
test_asarray_arrayswill just need to be skipped/xfailed in the test suite (via an xfails file similar to https://github.com/data-apis/array-api-compat/blob/main/torch-xfails.txt)test_eye: might be helpful to check whether building MLX with the linked MLX PR fixes the test? And comment on the upstream PR.EDIT:
test_dlpackcf Fix test failure if no device parameter array-api-tests#459. It's either fixable at the test suite level, or will keep being a known failure.So, one known failure, two more being worked on.
aaishwarymishra commentedon Aug 21, 2026
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_eyemight 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)ev-br commentedon Aug 21, 2026
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.
Please please edit this in into the OP table, together with other updates from the last month.