Warn about Accelerate-linked NumPy/SciPy, and correct figures added by #543 - #582
Conversation
…enBLAS wheel On the macOS arm64 NumPy 2.x wheels, which link Apple's Accelerate framework, the decoders' rank-deficient, wide-spectrum matrices made numpy.linalg.qr die with SIGBUS and numpy.linalg.svd trip malloc's heap-corruption check inside dgesdd (five crash reports from the [[72,12,6]] investigation), and a chi_max=400 decode returned wrong verdicts while every unit test passed. The OpenBLAS build of the same NumPy version (the macosx_11_0_arm64 wheel) runs the same reproducers clean. The backend now warns once at import when Accelerate is found behind NumPy (MDOPT_ALLOW_ACCELERATE=1 silences it) and the README gives the two commands that install the OpenBLAS wheel. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
…AS wheels The SVD helpers call SciPy's LAPACK too, and the SciPy macOS arm64 wheels link Accelerate like NumPy's; with only NumPy switched to OpenBLAS the reduced SVD path still returned a wrong factorisation (reconstruction error 0.15) or crashed, and with both switched it passes repeatedly. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
…rate
SciPy 1.10 and later report their LAPACK through show_config(mode="dicts"),
but SciPy 1.9, which the dependency floor allows, has show() without a mode
argument, so the SciPy check silently reported an unknown vendor there. The
helper now falls back to __config__.get_info("lapack_opt") in that case, and
two SciPy-shaped test doubles cover both APIs.
The README said the macOS arm64 wheels link Accelerate; only the
macosx_14_0_arm64 wheels do (checked NumPy 2.4.6, SciPy 1.15.3 and 1.18.1),
which pip picks on macOS 14 and later, while the macosx_11_0_arm64 NumPy
and macosx_12_0_arm64 SciPy wheels bundle OpenBLAS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
test_defaults_to_numpy asserted that importing the backend warns about nothing, which fails on exactly the builds the new warning targets: the macOS CI runners install the Accelerate-linked NumPy and SciPy wheels, and all three macOS test jobs failed on it. The test now allows RuntimeWarnings that mention Accelerate and still fails on any other warning. Checked with NumPy and SciPy made to report Accelerate: the backend tests and the full suite pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
The import-time checks were skipped when CuPy was selected, yet the GPU path still runs NumPy's linalg and BLAS on the host (orthogonality-centre moves, host-side contractions) and SciPy's LAPACK in the SVD fallbacks and in qr, so a GPU user on the stock macOS wheels was exposed to the same corruption without a warning. Both checks now run regardless of the backend. The CuPy-selection test allows the Accelerate warnings, and a new test checks that they fire with CuPy selected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
The test faked show_config by delegating to the installed function with mode="dicts", which SciPy 1.9 (still allowed by the dependency floor and handled by _lapack_vendor) does not accept; there the helper fell back to the real OpenBLAS config and the expected SciPy warning never fired. The fake now returns a synthetic modern config and no longer touches the installed API. Checked with real OpenBLAS, with NumPy and SciPy reporting Accelerate, and with SciPy's show_config replaced by the 1.9 signature. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
The README described the failure only as "a bivariate-bicycle decode returned wrong verdicts". It now gives the scale: on the [[72,12,6]] code in the natural qubit order at chi_max=400, where the SVDs act on matrices of about 800x1600, 21 of 22 shots with a non-trivial error decoded wrongly while mdopt still reduced its SVDs by QR first, against 3 of 24 on OpenBLAS; the same test shot decoded correctly at chi_max 64, 128 and 256, which is noted as no guarantee because the fault depends on heap state. The SIGBUS matrix size (636x304) is given as well. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
An audit of the claims #543 added, against the result files and fresh measurements, found five wrong figures: - svd() comment and the convergence test's docstring: the chi_max=400 [[72,12,6]] failure was 21 of 22 shots with a non-trivial error, not "24 of 24" (that count mixed repeated runs of one shot with a second). - svd() comment: the pre-reduction saved at most 7% and nothing measurable on most workloads, rather than "0-7%". - _to_numpy docstring: the per-call cupy import cost about 11,000 failed imports per decode, between roughly a tenth and a third of a decode (surface_bitflip 4-13%, dem_d3 about a third, timed on pre-#543 main), not a flat "~18%". - _contract_cached docstring: a shape-keyed cache misses 1-2% of zip-up calls on the DEM workloads and 23% on the RCM surface workload, not "7-14% on large codes". - test_convergence docstring: the test takes about 20 minutes on an idle laptop, not 30-60 minutes per decode. The benchmark README's classical_ldpc row now says three LDPC codes. Claims checked and left as they are: Apple M5 10 cores, the ~1700-site DEM chain (1677 mechanisms), the DEM workload parameters, the opt_einsum overhead at small chi (42% of a zip step at chi=32), and agreement of pre- and post-#543 decoders at chi=1e5 (1.6e-14 on 22 posteriors). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
The _warn_if_accelerate docstring said the macOS arm64 wheels of NumPy 2.x link Accelerate; only the macOS 14+ wheels (macosx_14_0_arm64) do, while the macosx_11_0_arm64 wheels are OpenBLAS builds. The docstring and the NumPy warning message also attributed the wrong chi_max=400 verdicts to Accelerate alone, but those occurred while mdopt still reduced its SVDs by QR first; with the plain SVD the checked chi_max=400 shots decoded correctly even on Accelerate. The memory corruption itself (SIGBUS in linalg.qr, malloc's heap check in dgesdd) does not depend on that path, so the warning stays; its wording now matches the README. Also reflows an over-long README line. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
There was a problem hiding this comment.
🟡 Changes recommended
One corrected performance range still contradicts the measurements stated in the PR description.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds import-time warnings for Accelerate-linked NumPy/SciPy and corrects benchmark documentation.
Changes:
- Detects Accelerate LAPACK and documents OpenBLAS alternatives.
- Adds backend warning tests across supported configurations.
- Corrects benchmark and regression figures.
File summaries
| File | Description |
|---|---|
mdopt/backend/array.py |
Adds LAPACK detection and warnings. |
tests/backend/test_array.py |
Tests detection, suppression, and GPU behavior. |
README.md |
Documents the Accelerate issue and workaround. |
mdopt/utils/utils.py |
Updates profiling and SVD comments. |
mdopt/contractor/contractor.py |
Corrects cache-miss figures. |
tests/decoding/test_convergence.py |
Corrects regression figures and timing. |
benchmarks/README.md |
Corrects the LDPC workload description. |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #582 +/- ##
==========================================
- Coverage 96.89% 96.84% -0.06%
==========================================
Files 28 28
Lines 5509 5574 +65
==========================================
+ Hits 5338 5398 +60
- Misses 171 176 +5 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- The trailing backslash in _warn_if_accelerate's docstring was a line continuation inside a normal string literal, so the two-line pip command rendered as one run-on line; it is escaped now. - The _to_numpy docstring's "between roughly a tenth and a third" left out the measured low end; it now says about 4% on surface_bitflip to about a third on dem_d3, matching the measurements. - test_accelerate_lapack_warns_unless_allowed re-imported warnings, which the module already imports. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
…llback The dependency table allowed scipy>=1.9.2 next to numpy>=2.3.0, but no SciPy before 1.15 can be installed with NumPy 2.3: SciPy 1.9 to 1.12 require numpy<1.29, and 1.13 and 1.14 require numpy<2.3 (PyPI metadata). SciPy 1.15.0 allows numpy<2.5 and Python >=3.10, matching this package's NumPy and Python floors, so it is the real minimum. poetry.lock already locks SciPy 1.15.3; only its content hash changes. With the floor raised, the vendor check's fallback for SciPy 1.9's configuration API (show() without a mode argument, __config__.get_info) could never run, so it and its test are removed; an unreadable configuration still reports an unknown vendor instead of raising, which a test now checks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud
There was a problem hiding this comment.
🟢 Approval recommended
The warning logic, tests, dependency constraint, documentation, and corrected measurements are consistent and complete.
Review details
- Files reviewed: 8/9 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Stacks #574 and #581, which touch no files in common, into one PR. Both are merged into a fresh branch off
main; the full suite passes on the result, and the backend tests also pass with NumPy and SciPy made to report Accelerate. On the real stock macOS wheels (NumPy 2.4.6 and SciPy 1.18.1, both Accelerate-linked) the warnings fire, the README's commands switch both libraries to OpenBLAS, and the warnings stop.From #574: warn when NumPy or SciPy links Apple's Accelerate
On Apple silicon running macOS 14 or later, pip installs the
macosx_14_0_arm64NumPy and SciPy wheels, which link Accelerate. On mdopt's rank-deficient, wide-spectrum matrices Accelerate's LAPACK corrupted memory:numpy.linalg.qrdied with SIGBUS on a 636x304 matrix andnumpy.linalg.svdtripped malloc's heap check insidedgesdd. While mdopt still reduced its SVDs by QR first, a [[72,12,6]] decode at chi_max=400 (SVDs on about 800x1600 matrices) returned wrong verdicts on 21 of 22 shots with a non-trivial error, against 3 of 24 on OpenBLAS, while every unit test passed.mdopt.backend.arraywarns at import when NumPy or SciPy is Accelerate-linked, on every backend (the CuPy path still runs NumPy and SciPy LAPACK on the host);MDOPT_ALLOW_ACCELERATE=1silences it.poetry.lockalready locks SciPy 1.15.3 and only its hash changes.macosx_11_0_arm64NumPy,macosx_12_0_arm64SciPy).From #581: correct figures in the comments and docs added by #543
An audit of every factual claim #543 added, against the experiment result files and fresh measurements, found five wrong figures; no code behaviour changes.
svd()comment,test_convergence.pydocstringsvd()comment_to_numpydocstring_contract_cacheddocstringtest_convergence.pydocstringThe benchmark README's
classical_ldpcrow now says three LDPC codes. Checked and left as written: the Apple M5 hardware, the ~1700-site DEM chain, the DEM workload parameters, the opt_einsum overhead at small chi, and agreement of pre- and post-#543 decoders at chi=1e5 (1.6e-14 on 22 posteriors).Supersedes #574 and #581.
🤖 Generated with Claude Code
https://claude.ai/code/session_01S6mbxc9eJDQMVx7tjvYwud