1+ """
2+ Type-stable container for BLAS operation information.
3+
4+ Uses sentinel values for optional fields to maintain type stability:
5+
6+ - condition_number: -Inf means not computed
7+ - rhs_length: 0 means not applicable
8+ - rhs_type: "" means not applicable
9+ """
10+ struct BlasOperationInfo
11+ matrix_size:: Tuple{Int, Int}
12+ matrix_type:: String
13+ element_type:: String
14+ condition_number:: Float64 # -Inf means not computed
15+ rhs_length:: Int # 0 means not applicable
16+ rhs_type:: String # "" means not applicable
17+ memory_usage_MB:: Float64
18+ end
119
220"""
321 interpret_blas_code(func::Symbol, info::Integer)
@@ -66,15 +84,9 @@ function interpret_positive_info(func::Symbol, info::Integer)
6684
6785 # General eigenvalue problem
6886 elseif occursin (" ggev" , func_str) || occursin (" gges" , func_str)
69- if info <= size
70- return (:convergence_failure ,
71- " QZ iteration failed" ,
72- " The QZ iteration failed to compute all eigenvalues. Elements 1:$(info- 1 ) converged." )
73- else
74- return (:unexpected_error ,
75- " Unexpected error in generalized eigenvalue problem" ,
76- " Info value $info is unexpected for $func ." )
77- end
87+ return (:convergence_failure ,
88+ " Generalized eigenvalue computation failed" ,
89+ " The algorithm failed to compute eigenvalues (info=$info ). This may indicate QZ iteration failure or other numerical issues." )
7890
7991 # LDLT factorization
8092 elseif occursin (" ldlt" , func_str)
@@ -90,19 +102,50 @@ function interpret_positive_info(func::Symbol, info::Integer)
90102 end
91103end
92104
105+ """
106+ Format BlasOperationInfo fields into human-readable strings.
107+
108+ Type-stable implementation using concrete struct fields instead of Dict iteration.
109+ """
110+ function _format_blas_context (op_info:: BlasOperationInfo )
111+ parts = String[]
112+
113+ # Always-present fields
114+ push! (parts, " Matrix size: $(op_info. matrix_size) " )
115+ push! (parts, " Matrix type: $(op_info. matrix_type) " )
116+ push! (parts, " Element type: $(op_info. element_type) " )
117+ push! (parts, " Memory usage: $(op_info. memory_usage_MB) MB" )
118+
119+ # Optional fields - check for sentinel values
120+ if ! isinf (op_info. condition_number)
121+ push! (parts, " Condition number: $(round (op_info. condition_number, sigdigits= 4 )) " )
122+ end
93123
124+ if op_info. rhs_length > 0
125+ push! (parts, " RHS length: $(op_info. rhs_length) " )
126+ end
127+
128+ if ! isempty (op_info. rhs_type)
129+ push! (parts, " RHS type: $(op_info. rhs_type) " )
130+ end
131+
132+ return parts
133+ end
94134
95135"""
96- blas_info_msg(func::Symbol, info::Integer, verbose::LinearVerbosity;
97- extra_context::Dict{Symbol,Any} = Dict())
136+ blas_info_msg(func::Symbol, info::Integer;
137+ extra_context::BlasOperationInfo = BlasOperationInfo(
138+ (0, 0), "", "", -Inf, 0, "", 0.0))
98139
99140Log BLAS/LAPACK return code information with appropriate verbosity level.
100141"""
101142function blas_info_msg (func:: Symbol , info:: Integer ;
102- extra_context:: Dict{Symbol, Any} = Dict ())
143+ extra_context:: BlasOperationInfo = BlasOperationInfo (
144+ (0 , 0 ), " " , " " , - Inf , 0 , " " , 0.0 ))
103145 category, message, details = interpret_blas_code (func, info)
104146
105- verbosity_field = if category in [:singular_matrix , :not_positive_definite , :convergence_failure ]
147+ verbosity_field = if category in [
148+ :singular_matrix , :not_positive_definite , :convergence_failure ]
106149 :blas_errors
107150 elseif category == :invalid_argument
108151 :blas_invalid_args
@@ -116,16 +159,18 @@ function blas_info_msg(func::Symbol, info::Integer;
116159 msg_info = info
117160
118161 # Build complete message with all details
119- full_msg = if ! isempty (extra_context) || msg_details != = nothing
162+ # Check if extra_context has any non-sentinel values
163+ has_extra_context = extra_context. matrix_size != (0 , 0 )
164+
165+ full_msg = if has_extra_context || msg_details != = nothing
120166 parts = String[msg_main]
121167 if msg_details != = nothing
122168 push! (parts, " Details: $msg_details " )
123169 end
124170 push! (parts, " Return code (info): $msg_info " )
125- if ! isempty (extra_context)
126- for (key, value) in extra_context
127- push! (parts, " $key : $value " )
128- end
171+ if has_extra_context
172+ # Type-stable formatting using struct fields
173+ append! (parts, _format_blas_context (extra_context))
129174 end
130175 join (parts, " \n " )
131176 else
@@ -135,39 +180,38 @@ function blas_info_msg(func::Symbol, info::Integer;
135180 verbosity_field, full_msg
136181end
137182
138-
139183function get_blas_operation_info (func:: Symbol , A, b; condition = false )
140- info = Dict {Symbol, Any} ()
184+ # Matrix properties (always present)
185+ matrix_size = size (A)
186+ matrix_type = string (typeof (A))
187+ element_type = string (eltype (A))
141188
142- # Matrix properties
143- info[:matrix_size ] = size (A)
144- info[:matrix_type ] = typeof (A)
145- info[:element_type ] = eltype (A)
189+ # Memory usage estimate (always present)
190+ mem_bytes = prod (matrix_size) * sizeof (eltype (A))
191+ memory_usage_MB = round (mem_bytes / 1024 ^ 2 , digits = 2 )
146192
147- # Condition number (based on verbosity setting )
148- if condition && size (A, 1 ) == size (A, 2 )
193+ # Condition number (optional - use -Inf as sentinel )
194+ condition_number = if condition && matrix_size[ 1 ] == matrix_size[ 2 ]
149195 try
150- cond_num = cond (A)
151- info[:condition_number ] = cond_num
152-
153- # Log the condition number if enabled
154- cond_msg = " Matrix condition number: $(round (cond_num, sigdigits= 4 )) for $(size (A, 1 )) ×$(size (A, 2 )) matrix in $func "
155-
196+ cond (A)
156197 catch
157- # Skip if condition number computation fails
158- info[:condition_number ] = nothing
198+ - Inf
159199 end
200+ else
201+ - Inf
160202 end
161203
162- # RHS properties if provided
163- if b != = nothing
164- info[:rhs_size ] = size (b)
165- info[:rhs_type ] = typeof (b)
166- end
167-
168- # Memory usage estimate
169- mem_bytes = prod (size (A)) * sizeof (eltype (A))
170- info[:memory_usage_MB ] = round (mem_bytes / 1024 ^ 2 , digits = 2 )
171-
172- return info
173- end
204+ # RHS properties (optional - use 0 and "" as sentinels)
205+ rhs_length = b != = nothing ? length (b) : 0
206+ rhs_type = b != = nothing ? string (typeof (b)) : " "
207+
208+ return BlasOperationInfo (
209+ matrix_size,
210+ matrix_type,
211+ element_type,
212+ condition_number,
213+ rhs_length,
214+ rhs_type,
215+ memory_usage_MB
216+ )
217+ end
0 commit comments