Skip to content

Commit f998aa1

Browse files
committed
Add enhanced BLAS/LAPACK return code interpretation and logging
This commit builds upon PR #622's verbosity system by adding: 1. Detailed BLAS/LAPACK return code interpretation - Human-readable explanations for all BLAS/LAPACK info codes - Categorized errors (singular_matrix, not_positive_definite, etc.) - Operation-specific interpretations for getrf, potrf, geqrf, etc. 2. Extended logging information for BLAS operations - Matrix properties (size, type, condition number) - Memory usage estimates - Performance timing metrics - Contextual information for debugging 3. New verbosity controls - blas_errors: Controls BLAS/LAPACK error messages (default: Warn) - blas_info: Controls informational messages (default: None) - blas_success: Controls success messages (default: None) - blas_invalid_args: Controls invalid argument errors (default: Error) - blas_timing: Controls performance timing (default: None) 4. Integration with BLISLUFactorization - Added detailed logging to the BLIS extension - Includes timing and error interpretation 5. Comprehensive documentation - Updated verbosity documentation with new BLAS options - Added section on BLAS/LAPACK return codes - Examples demonstrating enhanced logging capabilities 6. Tests - Added test suite for BLAS return code interpretation - Tests for different error categories - Verbosity integration tests This enhancement makes debugging numerical issues much easier by providing clear, actionable information when BLAS/LAPACK operations encounter problems. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 0ca5459 commit f998aa1

File tree

6 files changed

+497
-17
lines changed

6 files changed

+497
-17
lines changed

docs/src/basics/common_solver_opts.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,62 @@ sol = solve(prob; verbose=verbose)
108108
#### Verbosity Levels
109109
##### Error Control Settings
110110
- default_lu_fallback: Controls messages when falling back to LU factorization (default: Warn)
111+
- blas_invalid_args: Controls messages when BLAS/LAPACK receives invalid arguments (default: Error)
111112
##### Performance Settings
112113
- no_right_preconditioning: Controls messages when right preconditioning is not used (default: Warn)
114+
- blas_timing: Controls performance timing messages for BLAS/LAPACK operations (default: None)
113115
##### Numerical Settings
114116
- using_IterativeSolvers: Controls messages when using the IterativeSolvers.jl package (default: Warn)
115117
- IterativeSolvers_iterations: Controls messages about iteration counts from IterativeSolvers.jl (default: Warn)
116118
- KrylovKit_verbosity: Controls messages from the KrylovKit.jl package (default: Warn)
117-
- KrylovJL_verbosity: Controls verbosity of the KrylovJL.jl package (default: None)
119+
- KrylovJL_verbosity: Controls verbosity of the KrylovJL.jl package (default: None)
120+
- blas_errors: Controls messages for BLAS/LAPACK errors like singular matrices (default: Warn)
121+
- blas_info: Controls informational messages from BLAS/LAPACK operations (default: None)
122+
- blas_success: Controls success messages from BLAS/LAPACK operations (default: None)
123+
124+
### BLAS/LAPACK Return Code Interpretation
125+
126+
LinearSolve.jl now provides detailed interpretation of BLAS/LAPACK return codes (info parameter) to help diagnose numerical issues. When BLAS/LAPACK operations encounter problems, the logging system will provide human-readable explanations based on the specific return code and operation.
127+
128+
#### Common BLAS/LAPACK Return Codes
129+
130+
- **info = 0**: Operation completed successfully
131+
- **info < 0**: Argument -info had an illegal value (e.g., wrong dimensions, invalid parameters)
132+
- **info > 0**: Operation-specific issues:
133+
- **LU factorization (getrf)**: U(info,info) is exactly zero, matrix is singular
134+
- **Cholesky factorization (potrf)**: Leading minor of order info is not positive definite
135+
- **QR factorization (geqrf)**: Numerical issues with Householder reflector info
136+
- **SVD (gesdd/gesvd)**: Algorithm failed to converge, info off-diagonal elements did not converge
137+
- **Eigenvalue computation (syev/heev)**: info off-diagonal elements did not converge to zero
138+
- **Bunch-Kaufman (sytrf/hetrf)**: D(info,info) is exactly zero, matrix is singular
139+
140+
#### Example Usage with Enhanced BLAS Logging
141+
142+
```julia
143+
using LinearSolve
144+
145+
# Enable detailed BLAS error logging
146+
verbose = LinearVerbosity(
147+
blas_errors = Verbosity.Info(), # Show detailed error interpretations
148+
blas_timing = Verbosity.Info(), # Show performance metrics
149+
blas_info = Verbosity.Info() # Show all BLAS operation details
150+
)
151+
152+
# Solve a potentially singular system
153+
A = [1.0 2.0; 2.0 4.0] # Singular matrix
154+
b = [1.0, 2.0]
155+
prob = LinearProblem(A, b)
156+
sol = solve(prob, LUFactorization(); verbose=verbose)
157+
158+
# The logging will show:
159+
# - BLAS/LAPACK dgetrf: Matrix is singular
160+
# - Details: U(2,2) is exactly zero. The factorization has been completed, but U is singular
161+
# - Return code (info): 2
162+
# - Additional context: matrix size, condition number, memory usage
163+
```
164+
165+
The enhanced logging also provides:
166+
- Matrix properties (size, type, condition number when feasible)
167+
- Memory usage estimates
168+
- Performance timing for BLAS operations (when blas_timing is enabled)
169+
- Detailed context for debugging numerical issues

ext/LinearSolveBLISExt.jl

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ using LinearSolve
99
using LinearAlgebra: BlasInt, LU
1010
using LinearAlgebra.LAPACK: require_one_based_indexing, chkfinite, chkstride1,
1111
@blasfunc, chkargsok
12-
using LinearSolve: ArrayInterface, BLISLUFactorization, @get_cacheval, LinearCache, SciMLBase
12+
using LinearSolve: ArrayInterface, BLISLUFactorization, @get_cacheval, LinearCache, SciMLBase,
13+
interpret_blas_code, log_blas_info, get_blas_operation_info,
14+
time_blas_operation, check_and_log_lapack_result, LinearVerbosity
1315
using SciMLBase: ReturnCode
16+
using SciMLLogging: Verbosity
1417

1518
const global libblis = blis_jll.blis
1619
const global liblapack = LAPACK_jll.liblapack
@@ -220,11 +223,29 @@ function SciMLBase.solve!(cache::LinearCache, alg::BLISLUFactorization;
220223
kwargs...)
221224
A = cache.A
222225
A = convert(AbstractMatrix, A)
226+
verbose = cache.verbose
227+
223228
if cache.isfresh
224229
cacheval = @get_cacheval(cache, :BLISLUFactorization)
225-
res = getrf!(A; ipiv = cacheval[1].ipiv, info = cacheval[2])
230+
231+
# Get additional operation info for logging
232+
op_info = get_blas_operation_info(:dgetrf, A, cache.b)
233+
234+
# Time the BLAS operation if verbosity requires it
235+
res = time_blas_operation(:dgetrf, verbose) do
236+
getrf!(A; ipiv = cacheval[1].ipiv, info = cacheval[2])
237+
end
238+
226239
fact = LU(res[1:3]...), res[4]
227240
cache.cacheval = fact
241+
242+
# Log BLAS return code with detailed interpretation
243+
info_value = res[3]
244+
if info_value != 0
245+
log_blas_info(:dgetrf, info_value, verbose; extra_context=op_info)
246+
elseif isa(verbose.numerical.blas_success, Verbosity.Info)
247+
@info "BLAS LU factorization (dgetrf) completed successfully" op_info
248+
end
228249

229250
if !LinearAlgebra.issuccess(fact[1])
230251
return SciMLBase.build_linear_solution(
@@ -236,13 +257,22 @@ function SciMLBase.solve!(cache::LinearCache, alg::BLISLUFactorization;
236257
A, info = @get_cacheval(cache, :BLISLUFactorization)
237258
require_one_based_indexing(cache.u, cache.b)
238259
m, n = size(A, 1), size(A, 2)
239-
if m > n
240-
Bc = copy(cache.b)
241-
getrs!('N', A.factors, A.ipiv, Bc; info)
242-
copyto!(cache.u, 1, Bc, 1, n)
243-
else
244-
copyto!(cache.u, cache.b)
245-
getrs!('N', A.factors, A.ipiv, cache.u; info)
260+
261+
# Time the solve operation
262+
solve_result = time_blas_operation(:dgetrs, verbose) do
263+
if m > n
264+
Bc = copy(cache.b)
265+
getrs!('N', A.factors, A.ipiv, Bc; info)
266+
copyto!(cache.u, 1, Bc, 1, n)
267+
else
268+
copyto!(cache.u, cache.b)
269+
getrs!('N', A.factors, A.ipiv, cache.u; info)
270+
end
271+
end
272+
273+
# Log solve operation result if there was an error
274+
if info[] != 0
275+
log_blas_info(:dgetrs, info[], verbose)
246276
end
247277

248278
SciMLBase.build_linear_solution(alg, cache.u, nothing, cache; retcode = ReturnCode.Success)

src/LinearSolve.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ const BLASELTYPES = Union{Float32, Float64, ComplexF32, ComplexF64}
339339
function defaultalg_symbol end
340340

341341
include("verbosity.jl")
342+
include("blas_logging.jl")
342343
include("generic_lufact.jl")
343344
include("common.jl")
344345
include("extension_algs.jl")

0 commit comments

Comments
 (0)