Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- `cunumpy.interop.julia` (extra `cunumpy[julia]`, juliacall): `to_julia` / `from_julia`
between NumPy arrays and Julia `Array`s that share memory. Julia is column-major, so a
C-ordered array arrives with its dimensions reversed and an F-ordered one with the same
dimensions; `from_julia(order="C" | "F")` picks the order back. Host arrays only; CuPy to
CUDA.jl is planned.
- `copy=None | True | False` on every interop conversion (as in the array API): `False` raises
when the conversion cannot share memory, `True` always copies.
- `supports_float64(device)` in the JAX, PyTorch and MLX adapters and
`cunumpy.interop.jax.enable_x64()`.

### Changed
- Interop conversions never change a dtype without being asked: float64 into JAX without
`jax_enable_x64`, onto an Apple GPU in PyTorch (MPS) or into MLX for the GPU raises a
`TypeError` with advice instead of becoming float32. MLX keeps float64 for
`device=mlx.core.cpu`.
- The transfer profiler tells interop conversions apart: a conversion that shares memory records
nothing, one between host and device records `to_host` / `to_device`, and one within a
memory `device_copy` (before, every conversion was a `device_copy`).
- `from_framework` copies between host and device explicitly (a recorded transfer, an error
under `copy=False`) instead of falling back to `asarray` silently, and a framework that
cannot take an array's device raises a `ValueError` naming the device.
- `from_jax` raises a clear `TypeError` for traced values (inside `jax.jit`, `grad`, `vmap`).
- `to_mlx(device=...)` names the device the array is meant for (MLX arrays have no device);
before, it passed `device` to `mlx.core.array`, which does not take it.

## [0.7.2] - 2026-10-27

### Fixed
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ never hide a NumPy name:
| `xp.profiling` | `timed_region`, `nvtx_range`, `count_transfers` |
| `xp.memory` | `HostStaging`, `DeviceMirror` |
| `xp.petsc` | `petsc_vec` |
| `xp.interop` | `dlpack`, `jax`, `torch`, `mlx`, `julia`: explicit conversions that share memory where they can (`copy=False` to require it) and never change a dtype silently |
| `cunumpy.kernel_testing` | pytest helpers for host/CUDA kernel pairs |

Everything except `xp.cuda`, `xp.arguments` and `CudaKernel` works on both backends.
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ optional-dependencies.dev = [
optional-dependencies.docs = [ "griffe", "ipykernel" ]
optional-dependencies.metal = [ "mlx; sys_platform == 'darwin' and platform_machine == 'arm64'" ]
optional-dependencies.jax = [ "jax" ]
optional-dependencies.julia = [ "juliacall" ]
optional-dependencies.mlx = [ "mlx; sys_platform == 'darwin' and platform_machine == 'arm64'" ]
optional-dependencies.torch = [ "torch" ]
optional-dependencies.test = [ "coverage", "pytest", "scipy" ]
Expand Down
8 changes: 6 additions & 2 deletions src/cunumpy/_transfers.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,12 +341,16 @@ def count_transfers(
* ``to_host`` / ``to_device``: a physical copy between host and device
(conversions such as :func:`~cunumpy.to_numpy` and
:func:`~cunumpy.to_cupy`, mirrors, staging, serial MPI, kernel output
copy-back), with its size in bytes;
copy-back, an :mod:`~cunumpy.interop` conversion between host and
device), with its size in bytes;
* ``kernel_conversion``: a :class:`~cunumpy.kernels.PyccelKernel` call that
copied device arrays to the host and back, one marker per call;
* ``fallback``: a :class:`~cunumpy.kernels.Kernel` without CUDA version
that ran its host kernel on the CuPy backend, one marker per call;
* ``device_copy``: a device-only dtype/layout conversion;
* ``device_copy``: a copy that stays in one memory: a device-only
dtype/layout conversion, or an :mod:`~cunumpy.interop` conversion
that could not share memory (an interop conversion that shares memory
records nothing);
* ``sync``: the host waited for the device (:func:`~cunumpy.synchronize`,
the MPI helpers, the CUDA debug mode and, on the fake CuPy, scalar
reads such as ``float(a)``). Not included in
Expand Down
6 changes: 3 additions & 3 deletions src/cunumpy/interop/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Explicit interoperability with scientific machine-learning libraries.
"""Explicit interoperability with scientific machine-learning libraries and Julia.

The adapters are optional and import their framework lazily. They do not
participate in CuNumpy backend selection.
"""

from cunumpy.interop import dlpack, jax, mlx, torch
from cunumpy.interop import dlpack, jax, julia, mlx, torch

__all__ = ["dlpack", "jax", "mlx", "torch"]
__all__ = ["dlpack", "jax", "julia", "mlx", "torch"]
Loading
Loading