Skip to content

Conversation

@ChrisRackauckas-Claude
Copy link
Contributor

Summary

  • Fixes Calling solve! on cache built with tridiagonal matrix, mutates the matrix and ruins the cache. #825: solve! on LinearCache with Tridiagonal matrix now correctly preserves cache.A without mutation
  • Added Val{cache} type parameter to DirectLdiv! to control whether a matrix copy is cached:
    • DirectLdiv!()DirectLdiv!{true} (default, caches for Tridiagonal/SymTridiagonal)
    • DirectLdiv!(Val(true)) → explicit caching
    • DirectLdiv!(Val(false)) → no caching (may mutate A)
  • For Tridiagonal and SymTridiagonal, ldiv! performs in-place LU factorization which mutates the matrix. The caching variant allocates a workspace during init and uses non-allocating copyto! during solve!

Implementation

  • Modified DirectLdiv! struct to have a {cache} type parameter
  • Added specialized init_cacheval methods for DirectLdiv!{true} with Tridiagonal/SymTridiagonal that allocate a copy
  • Added specialized solve! methods that copy values into the workspace then call ldiv! on the copy
  • Added regression test to verify cache.A is not mutated and multiple solves work correctly

Test plan

  • Verified DirectLdiv!() defaults to DirectLdiv!{true}
  • Verified Tridiagonal matrix is not mutated after solve!
  • Verified multiple calls to solve! on same cache work correctly
  • Verified SymTridiagonal also works correctly

🤖 Generated with Claude Code

ChrisRackauckas and others added 2 commits December 15, 2025 06:59
…ciML#825)

The issue: DirectLdiv! for Tridiagonal matrices calls ldiv!(u, A, b) which
performs in-place LU factorization, mutating cache.A and breaking subsequent
solves with the same cache.

The fix preserves DirectLdiv! for performance while preventing cache.A mutation:
- Add init_cacheval for DirectLdiv! with Tridiagonal/SymTridiagonal that
  allocates a copy of the matrix during init (one-time allocation)
- Add specialized solve! methods that copy cache.A values to the cached
  workspace before calling ldiv! (non-allocating copyto!)
- The original cache.A is never touched, preserving it for subsequent solves

This gives the best of both worlds:
- Fast DirectLdiv! performance (direct ldiv! without lu factorization overhead)
- Non-destructive behavior (cache.A is preserved)
- Minimal allocations during solve! (same 48 bytes as LUFactorization)

Added regression test that verifies:
- Default algorithm for Tridiagonal is DirectLdiv! on Julia 1.11+
- cache.A is not mutated after solve!
- Multiple solves with same cache give correct answers
- Minimal allocations during solve!

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This allows explicit control over whether DirectLdiv! caches a copy
of the matrix during init. DirectLdiv!{true} caches, DirectLdiv!{false}
does not. Default is Val(true) for backwards compatibility.

- DirectLdiv!() → DirectLdiv!{true} (default, caches)
- DirectLdiv!(Val(true)) → DirectLdiv!{true} (explicit caching)
- DirectLdiv!(Val(false)) → DirectLdiv!{false} (no caching, may mutate A)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ChrisRackauckas ChrisRackauckas merged commit 634d35e into SciML:main Dec 15, 2025
139 of 142 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.

Calling solve! on cache built with tridiagonal matrix, mutates the matrix and ruins the cache.

2 participants