Skip to content

Commit d8d3d74

Browse files
committed
Use @SciMLMessage macro and add condition_number verbosity setting
Based on review feedback: 1. Replaced direct logging with @SciMLMessage macro - Updated log_blas_info to use @SciMLMessage with proper syntax - Structured log messages with appropriate categories and groups - Removed direct @info/@warn calls 2. Added condition_number as a separate verbosity setting - Added condition_number to LinearNumericalVerbosity struct - Condition number computation now controlled by verbosity setting - Default is Verbosity.None() to avoid expensive computation 3. Fixed verbosity checks - Use verbosity_to_int() for proper verbosity level checking - Ensures correct comparison with Verbosity.None() 4. Updated BLISLUFactorization extension - Uses @SciMLMessage for success messages - Proper verbosity checks before computing operation info - Only calls get_blas_operation_info when logging is enabled 5. Updated documentation - Added condition_number verbosity setting documentation - Clarified that condition number is controlled by verbosity 6. Updated tests - Tests now use verbosity parameter for condition number control - Verifies condition number is not computed when disabled These changes ensure efficient logging with proper use of the SciMLLogging infrastructure and make condition number computation a controllable option. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent a2de5b0 commit d8d3d74

File tree

5 files changed

+60
-65
lines changed

5 files changed

+60
-65
lines changed

docs/src/basics/common_solver_opts.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ sol = solve(prob; verbose=verbose)
119119
- blas_errors: Controls messages for BLAS/LAPACK errors like singular matrices (default: Warn)
120120
- blas_info: Controls informational messages from BLAS/LAPACK operations (default: None)
121121
- blas_success: Controls success messages from BLAS/LAPACK operations (default: None)
122+
- condition_number: Controls computation and logging of matrix condition numbers (default: None)
122123

123124
### BLAS/LAPACK Return Code Interpretation
124125

@@ -141,10 +142,11 @@ LinearSolve.jl now provides detailed interpretation of BLAS/LAPACK return codes
141142
```julia
142143
using LinearSolve
143144

144-
# Enable detailed BLAS error logging
145+
# Enable detailed BLAS error logging with condition numbers
145146
verbose = LinearVerbosity(
146-
blas_errors = Verbosity.Info(), # Show detailed error interpretations
147-
blas_info = Verbosity.Info() # Show all BLAS operation details
147+
blas_errors = Verbosity.Info(), # Show detailed error interpretations
148+
blas_info = Verbosity.Info(), # Show all BLAS operation details
149+
condition_number = Verbosity.Info() # Compute and log condition numbers
148150
)
149151

150152
# Solve a potentially singular system
@@ -164,4 +166,4 @@ The enhanced logging also provides:
164166
- Matrix properties (size, type, element type)
165167
- Memory usage estimates
166168
- Detailed context for debugging numerical issues
167-
- Optional condition number computation (can be enabled via compute_condition parameter)
169+
- Condition number computation controlled by the condition_number verbosity setting

ext/LinearSolveBLISExt.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ using LinearSolve: ArrayInterface, BLISLUFactorization, @get_cacheval, LinearCac
1313
interpret_blas_code, log_blas_info, get_blas_operation_info,
1414
check_and_log_lapack_result, LinearVerbosity
1515
using SciMLBase: ReturnCode
16-
using SciMLLogging: Verbosity
16+
using SciMLLogging: Verbosity, @SciMLMessage, verbosity_to_int
1717

1818
const global libblis = blis_jll.blis
1919
const global liblapack = LAPACK_jll.liblapack
@@ -238,14 +238,15 @@ function SciMLBase.solve!(cache::LinearCache, alg::BLISLUFactorization;
238238
info_value = res[3]
239239
if info_value != 0
240240
# Only get operation info if we need to log
241-
if !(verbose.numerical.blas_errors isa Verbosity.None)
242-
op_info = get_blas_operation_info(:dgetrf, A, cache.b)
241+
if verbosity_to_int(verbose.numerical.blas_errors) > 0
242+
op_info = get_blas_operation_info(:dgetrf, A, cache.b, verbose)
243243
log_blas_info(:dgetrf, info_value, verbose; extra_context=op_info)
244244
end
245-
elseif !(verbose.numerical.blas_success isa Verbosity.None)
245+
elseif verbosity_to_int(verbose.numerical.blas_success) > 0
246246
# Only get operation info if we need to log success
247-
op_info = get_blas_operation_info(:dgetrf, A, cache.b)
248-
@info "BLAS LU factorization (dgetrf) completed successfully" op_info
247+
op_info = get_blas_operation_info(:dgetrf, A, cache.b, verbose)
248+
success_msg = "BLAS LU factorization (dgetrf) completed successfully for $(op_info[:matrix_size]) matrix"
249+
@SciMLMessage(success_msg, verbose.numerical.blas_success, :blas_success, :numerical)
249250
end
250251

251252
if !LinearAlgebra.issuccess(fact[1])
@@ -270,7 +271,7 @@ function SciMLBase.solve!(cache::LinearCache, alg::BLISLUFactorization;
270271
end
271272

272273
# Log solve operation result if there was an error
273-
if info[] != 0 && !(verbose.numerical.blas_errors isa Verbosity.None)
274+
if info[] != 0 && verbosity_to_int(verbose.numerical.blas_errors) > 0
274275
log_blas_info(:dgetrs, info[], verbose)
275276
end
276277

src/blas_logging.jl

Lines changed: 33 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# BLAS and LAPACK Return Code Interpretation
22

3-
using SciMLLogging: Verbosity, @match
3+
using SciMLLogging: Verbosity, @match, @SciMLMessage, verbosity_to_int
4+
using LinearAlgebra: cond
45

56
"""
67
interpret_blas_code(func::Symbol, info::Integer)
@@ -112,52 +113,30 @@ function log_blas_info(func::Symbol, info::Integer, verbose::LinearVerbosity;
112113
verbose.numerical.blas_info
113114
end
114115

115-
# Format the log message
116-
log_msg = format_blas_log_message(func, info, category, message, details, extra_context)
116+
# Build structured message components
117+
msg_main = "BLAS/LAPACK $func: $message"
118+
msg_details = !isempty(details) ? details : nothing
119+
msg_info = info
117120

118-
# Log based on verbosity level
119-
log_with_verbosity(verbosity_field, log_msg, category)
120-
end
121-
122-
function format_blas_log_message(func::Symbol, info::Integer, category::Symbol,
123-
message::String, details::String,
124-
extra_context::Dict{Symbol,Any})
125-
msg_parts = String[]
126-
127-
# Main message
128-
push!(msg_parts, "BLAS/LAPACK $func: $message")
129-
130-
# Add details if present
131-
if !isempty(details)
132-
push!(msg_parts, " Details: $details")
133-
end
134-
135-
# Add return code
136-
push!(msg_parts, " Return code (info): $info")
137-
138-
# Add extra context if provided
139-
if !isempty(extra_context)
140-
for (key, value) in extra_context
141-
push!(msg_parts, " $(key): $value")
121+
# Build complete message with all details
122+
full_msg = if !isempty(extra_context) || msg_details !== nothing
123+
parts = String[msg_main]
124+
if msg_details !== nothing
125+
push!(parts, "Details: $msg_details")
142126
end
143-
end
144-
145-
return join(msg_parts, "\n")
146-
end
147-
148-
function log_with_verbosity(verbosity::Verbosity.Type, message::String, category::Symbol)
149-
@match verbosity begin
150-
Verbosity.None() => nothing
151-
Verbosity.Info() => @info message
152-
Verbosity.Warn() => @warn message
153-
Verbosity.Error() => error(message)
154-
Verbosity.Level(n) => begin
155-
if n >= 1
156-
@info message
127+
push!(parts, "Return code (info): $msg_info")
128+
if !isempty(extra_context)
129+
for (key, value) in extra_context
130+
push!(parts, "$key: $value")
157131
end
158132
end
159-
_ => @warn message
133+
join(parts, "\n ")
134+
else
135+
"$msg_main (info=$msg_info)"
160136
end
137+
138+
# Use proper @SciMLMessage syntax
139+
@SciMLMessage(full_msg, verbosity_field, :blas_return_code, :numerical)
161140
end
162141

163142
"""
@@ -190,23 +169,29 @@ end
190169

191170
# Extended information for specific BLAS operations
192171
"""
193-
get_blas_operation_info(func::Symbol, A, b=nothing; compute_condition=false)
172+
get_blas_operation_info(func::Symbol, A, b, verbose::LinearVerbosity)
194173
195174
Get additional information about a BLAS operation for enhanced logging.
196-
Set compute_condition=true to include condition number computation (may be expensive).
175+
Condition number is computed based on the condition_number verbosity setting.
197176
"""
198-
function get_blas_operation_info(func::Symbol, A, b=nothing; compute_condition=false)
177+
function get_blas_operation_info(func::Symbol, A, b, verbose::LinearVerbosity)
199178
info = Dict{Symbol,Any}()
200179

201180
# Matrix properties
202181
info[:matrix_size] = size(A)
203182
info[:matrix_type] = typeof(A)
204183
info[:element_type] = eltype(A)
205184

206-
# Condition number (only if explicitly requested)
207-
if compute_condition && size(A, 1) == size(A, 2)
185+
# Condition number (based on verbosity setting)
186+
should_compute_cond = verbosity_to_int(verbose.numerical.condition_number) > 0
187+
if should_compute_cond && size(A, 1) == size(A, 2)
208188
try
209-
info[:condition_number] = cond(A)
189+
cond_num = cond(A)
190+
info[:condition_number] = cond_num
191+
192+
# Log the condition number if enabled
193+
cond_msg = "Matrix condition number: $(round(cond_num, sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in $func"
194+
@SciMLMessage(cond_msg, verbose.numerical.condition_number, :condition_number, :numerical)
210195
catch
211196
# Skip if condition number computation fails
212197
end

src/verbosity.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ const linear_defaults = Dict{Symbol, Verbosity.Type}(
1313
:blas_errors => Verbosity.Warn(),
1414
:blas_info => Verbosity.None(),
1515
:blas_success => Verbosity.None(),
16-
:blas_invalid_args => Verbosity.Error()
16+
:blas_invalid_args => Verbosity.Error(),
17+
:condition_number => Verbosity.None()
1718
)
1819
mutable struct LinearErrorControlVerbosity
1920
default_lu_fallback::Verbosity.Type
@@ -89,6 +90,7 @@ mutable struct LinearNumericalVerbosity
8990
blas_errors::Verbosity.Type
9091
blas_info::Verbosity.Type
9192
blas_success::Verbosity.Type
93+
condition_number::Verbosity.Type
9294

9395
function LinearNumericalVerbosity(;
9496
using_IterativeSolvers = linear_defaults[:using_IterativeSolvers],
@@ -99,10 +101,11 @@ mutable struct LinearNumericalVerbosity
99101
pardiso_verbosity = linear_defaults[:pardiso_verbosity],
100102
blas_errors = linear_defaults[:blas_errors],
101103
blas_info = linear_defaults[:blas_info],
102-
blas_success = linear_defaults[:blas_success])
104+
blas_success = linear_defaults[:blas_success],
105+
condition_number = linear_defaults[:condition_number])
103106
new(using_IterativeSolvers, IterativeSolvers_iterations,
104107
KrylovKit_verbosity, KrylovJL_verbosity, HYPRE_verbosity, pardiso_verbosity,
105-
blas_errors, blas_info, blas_success)
108+
blas_errors, blas_info, blas_success, condition_number)
106109
end
107110

108111
function LinearNumericalVerbosity(verbose::Verbosity.Type)

test/test_blas_logging.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,19 @@ using SciMLLogging: Verbosity
3636
# Test getting operation info without condition number
3737
A = rand(10, 10)
3838
b = rand(10)
39-
info = LinearSolve.get_blas_operation_info(:dgetrf, A, b)
39+
40+
# Test with condition_number disabled (default)
41+
verbose_no_cond = LinearVerbosity(condition_number = Verbosity.None())
42+
info = LinearSolve.get_blas_operation_info(:dgetrf, A, b, verbose_no_cond)
4043

4144
@test info[:matrix_size] == (10, 10)
4245
@test info[:element_type] == Float64
4346
@test !haskey(info, :condition_number) # Should not compute by default
4447
@test info[:memory_usage_MB] >= 0 # Memory can be 0 for very small matrices
4548

46-
# Test with condition number computation enabled
47-
info_with_cond = LinearSolve.get_blas_operation_info(:dgetrf, A, b; compute_condition=true)
49+
# Test with condition number computation enabled via verbosity
50+
verbose_with_cond = LinearVerbosity(condition_number = Verbosity.Info())
51+
info_with_cond = LinearSolve.get_blas_operation_info(:dgetrf, A, b, verbose_with_cond)
4852
@test haskey(info_with_cond, :condition_number)
4953
end
5054

0 commit comments

Comments
 (0)