Skip to content

Restore cache.A before QR safety fallback after in-place LU corruption - #888

Merged
ChrisRackauckas merged 2 commits into
SciML:mainfrom
ChrisRackauckas-Claude:fix-mkl-fallback-corruption
Feb 19, 2026
Merged

ChrisRackauckas merged 2 commits into
SciML:mainfrom
ChrisRackauckas-Claude:fix-mkl-fallback-corruption

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member

Summary

  • In-place LU factorizations (MKLLUFactorization, AppleAccelerateLU, GenericLU, RFLU, BLIS, CUDA, Metal) corrupt cache.A via getrf!. When LU fails on a singular matrix and DefaultLinearSolver's safety fallback triggers QR, the QR operates on the corrupted matrix producing incorrect results.
  • Store a reference to the original prob.A in DefaultLinearSolverInit.A_backup (zero-cost: when alias_A=false (default), cache.A is already a copy so prob.A is untouched). Before QR fallback, restore via copyto!(cache.A, backup).
  • When alias_A=true (cache.A === prob.A), skip the fallback with a clear warning since there is no clean backup.

Fixes #887

Root Cause

MKLLUFactorization (and other in-place LU variants) call LAPACK's getrf! which overwrites cache.A in-place with the LU factors. When the matrix is singular, getrf! returns an error code and solve! returns ReturnCode.Failure. The DefaultLinearSolver then falls back to QRFactorization(ColumnNorm()), but cache.A still contains the corrupted LU factors rather than the original matrix. This causes the QR fallback to produce garbage results.

This was discovered via Julia 1.11 vs 1.12 behavioral difference: MKL_jll loads on 1.11 (selecting MKLLUFactorization) but not on 1.12 (selecting LUFactorization which uses lu(A, check=false) — non-destructive).

Test plan

  • Verified singular matrix solve through DefaultLinearSolver matches direct QRFactorization(ColumnNorm()) result
  • Verified prob.A is not modified (serves as backup)
  • Verified A_backup references prob.A (not the copy) with alias_A=false
  • Verified alias_A=true correctly detected (cache.A === A_backup)
  • Package precompiles and loads successfully
  • Full test suite (running)

🤖 Generated with Claude Code

ChrisRackauckas and others added 2 commits February 19, 2026 06:55
In-place LU factorizations (MKLLUFactorization, AppleAccelerateLU, etc.)
corrupt cache.A via getrf!. When LU fails on a singular matrix and the
DefaultLinearSolver safety fallback triggers, the QR fallback was operating
on the corrupted matrix, producing incorrect results.

Fix: Store a reference to the original prob.A in DefaultLinearSolverInit.A_backup
(zero-cost since alias_A=false means cache.A is already a copy). Before the QR
fallback, restore cache.A via copyto!. When alias_A=true (cache.A === prob.A),
skip the fallback with a warning since there is no clean backup available.

Fixes SciML#887

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace @warn with @SciMLMessage(:default_lu_fallback) in the aliased
  fallback warning path for consistency with the rest of the codebase
- Add regression test verifying QR fallback produces correct results
  on singular matrices and that prob.A is preserved as backup

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ChrisRackauckas
ChrisRackauckas merged commit 1094573 into SciML:main Feb 19, 2026
241 of 261 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MKLLUFactorization corrupts cache.A, breaking DefaultLinearSolver QR safety fallback

2 participants