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
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,30 @@ Nothing on the board edits config.
[PyAutoBrain/ORGANISM.md](https://github.com/PyAutoLabs/PyAutoBrain/blob/main/ORGANISM.md),
documented in full at <https://pyautoscientist.readthedocs.io>
- Ecosystem: [PyAutoLabs on GitHub](https://github.com/PyAutoLabs)

## JAX compatibility

The package retains JAX/JAXlib `>=0.7,<0.12`, excluding `0.10.*` and `0.11.0`.
Those excluded releases contain CPU batched LAPACK scheduling that can deadlock
while materializing a vectorized likelihood (PyAutoHeart#274). The failure was
captured on 0.10.2; tagged source identifies the same path in the other excluded
releases. Open-source builds disable it from 0.11.1. This restriction does not
replace the separate historical FFT/Eigen workaround.

The compatibility diagnostics exercise **0.9.2** as an older endpoint and
**0.11.2** as the recommended validation baseline. They do not certify every
version permitted by the retained range or promise identical performance across
versions. A new minimum of 0.11.2 is deliberately avoided: it would unnecessarily
force newer NumPy/SciPy requirements on users with working older environments.

Updated family packages require `autonerves>2026.10.4.1` so their resolver cannot
fall back to a Nerves release without the exclusions. This is a release ordering
requirement: publish a Nerves wheel containing this policy before the corresponding
family wheels. No release version is chosen by this bound, and existing published
wheels are not retroactively repaired. An unpinned family package can still be
backtracked to an entirely older family release; select the repaired family
release explicitly when applying the fix to a constrained environment.

Keep JAX, JAXlib and any CUDA plugin on a mutually compatible version. Use pip's
resolver rather than `--no-deps`, and verify the resulting environment with
`python -m pip check`. Existing lockfiles need regeneration to adopt the policy.
6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ dependencies = [
# wheels for >=0.7), so the markers let Intel Macs resolve to the
# NumPy-only path instead of failing at install. jax_wrapper warns loudly
# at import when JAX is absent.
# CPU batched LAPACK can deadlock in 0.10.x / 0.11.0 (Heart#274).
# Preserve older versions; 0.9.2 and 0.11.2 are compatibility witnesses.
# jax 0.11 note: 0.11 requires numpy>=2.1 and scipy>=1.15, so this cap
# widen also raises those effective floors for every install that
# resolves jax (PyAutoFit#1510).
'jax>=0.7.0,<0.12.0; sys_platform != "darwin" or platform_machine == "arm64"',
'jaxlib>=0.7.0,<0.12.0; sys_platform != "darwin" or platform_machine == "arm64"',
'jax>=0.7.0,<0.12.0,!=0.10.*,!=0.11.0; sys_platform != "darwin" or platform_machine == "arm64"',
'jaxlib>=0.7.0,<0.12.0,!=0.10.*,!=0.11.0; sys_platform != "darwin" or platform_machine == "arm64"',
'jaxnnls==1.0.1; sys_platform != "darwin" or platform_machine == "arm64"'
]

Expand Down
30 changes: 30 additions & 0 deletions test_autonerves/test_dependency_policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Installer contract: exclude the CPU deadlock without discarding older JAX."""
from pathlib import Path
import tomllib

from packaging.requirements import Requirement
import pytest


@pytest.fixture(params=['jax', 'jaxlib'])
def requirement(request):
project = tomllib.loads((Path(__file__).parents[1] / 'pyproject.toml').read_text())
return next(Requirement(value) for value in project['project']['dependencies']
if Requirement(value).name == request.param)


@pytest.mark.parametrize('version,allowed', [
('0.7.0', True), ('0.9.2', True), ('0.10.0', False), ('0.10.1', False),
('0.10.2', False), ('0.10.99', False), ('0.11.0', False), ('0.11.1', True),
('0.11.2', True), ('0.12.0', False),
])
def test_cpu_deadlock_exclusion_keeps_older_versions(requirement, version, allowed):
assert (version in requirement.specifier) is allowed


@pytest.mark.parametrize('system,machine,required', [
('darwin', 'x86_64', False), ('darwin', 'arm64', True),
('linux', 'x86_64', True), ('win32', 'AMD64', True),
])
def test_existing_platform_exemption_is_preserved(requirement, system, machine, required):
assert requirement.marker.evaluate({'sys_platform': system, 'platform_machine': machine}) is required
Loading