LU factorizations and complex matrix types#136
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #136 +/- ##
==========================================
+ Coverage 90.12% 90.41% +0.28%
==========================================
Files 6 6
Lines 1874 1899 +25
==========================================
+ Hits 1689 1717 +28
+ Misses 185 182 -3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR extends the sparse solver bindings by adding libSparse LU factorization variants, updating the default factorization choice to use LU for square non-symmetric matrices on macOS ≥ 15.5, and improving error reporting by translating libSparse status codes into more specific Julia exceptions.
Changes:
- Add LU factorization kinds (LU / LUUnpivoted / LUSPP / LUTPP) and related new enum values.
- Change
factor!default selection to prefer LU (macOS ≥ 15.5) for square non-symmetric matrices, otherwise QR. - Centralize libSparse status handling via
_libsparse_throwand add LU-focused tests gated on macOS version.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/sparse.jl |
Adds LU factorization enum values, updates default factorization selection, and introduces centralized status→exception translation. |
test/sparse_tests.jl |
Updates singular-matrix error expectation and adds LU factorization tests gated on macOS ≥ 15.5. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @eval begin | ||
| N = 50 | ||
| # Square, non-symmetric, well-conditioned. | ||
| jlA = sprand($T, N, N, 0.1) + $T(N) * I |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (2)
src/sparse.jl:850
attributes |= ATT_UNIT_TRIANGULARis incorrect for a multi-bit enum field:ATT_TRI_LOWER/UPPERalready set the kind bits toATT_TRIANGULAR, and OR-ing inATT_UNIT_TRIANGULARsets both kind bits, which encodesATT_SYMMETRICand can make a unit-triangular matrix appear symmetric. Instead, clear the kind field with the appropriate mask and then set it toATT_UNIT_TRIANGULARwhile preserving the independent triangle/transpose bits.
if attributes in (ATT_TRI_LOWER, ATT_TRI_UPPER) &&
all(diag(sparseM) .== one(eltype(sparseM)))
attributes |= ATT_UNIT_TRIANGULAR
end
src/sparse.jl:873
istri(and thereforeistriu/istril) only recognizesATT_TRIANGULARbut notATT_UNIT_TRIANGULAR. After fixing the kind-field assignment, unit-triangular matrices will not be detected as triangular. Consider treating bothATT_TRIANGULARandATT_UNIT_TRIANGULARas triangular kinds when implementingistri/istriu/istril.
istri(M::AASparseMatrix) = (M.matrix.structure.attributes
& ATT_KIND_MASK_COMPLEX) == ATT_TRIANGULAR
LinearAlgebra.istriu(M::AASparseMatrix) = istri(M) && (M.matrix.structure.attributes &
ATT_LOWER_TRIANGLE == ATT_UPPER_TRIANGLE)
LinearAlgebra.istril(M::AASparseMatrix) = istri(M) && (M.matrix.structure.attributes &
ATT_LOWER_TRIANGLE == ATT_LOWER_TRIANGLE)
| function AASparseMatrix(sparseM::SparseMatrixCSC{T, Int64}, | ||
| attributes::att_type = ATT_ORDINARY) where T<:vTypes | ||
| if issymmetric(sparseM) && attributes == ATT_ORDINARY | ||
| return AASparseMatrix(tril(sparseM), ATT_SYMMETRIC | ATT_LOWER_TRIANGLE) | ||
| elseif (istril(sparseM) || istriu(sparseM)) && attributes == ATT_ORDINARY | ||
| attributes = istril(sparseM) ? ATT_TRI_LOWER : ATT_TRI_UPPER | ||
| if attributes == ATT_ORDINARY | ||
| # `ishermitian` falls back to `issymmetric` for real T, so this branch | ||
| # is taken for real-symmetric and complex-Hermitian alike — both map | ||
| # to the Cholesky-amenable kind for their respective attribute layout. | ||
| if ishermitian(sparseM) | ||
| kind = T <: Complex ? ATT_HERMITIAN : ATT_SYMMETRIC | ||
| return AASparseMatrix(tril(sparseM), kind | ATT_LOWER_TRIANGLE) | ||
| elseif T <: Complex && issymmetric(sparseM) | ||
| # Complex symmetric (not Hermitian) — rare but valid; not Cholesky-amenable. | ||
| return AASparseMatrix(tril(sparseM), ATT_SYMMETRIC | ATT_LOWER_TRIANGLE) | ||
| elseif istril(sparseM) || istriu(sparseM) | ||
| attributes = istril(sparseM) ? ATT_TRI_LOWER : ATT_TRI_UPPER | ||
| end |
| # Cholesky for symmetric; on macOS 15.5+ LU for square non-symmetric | ||
| # (faster than QR for square solves); QR otherwise. | ||
| nrow, ncol = size(aa_fact.matrixObj) | ||
| lu_ok = something(_macos_version[], v"0.0.0") >= v"15.5" |
Add the new LU factorization types and make errors a bit more informative.