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)
@@ -84,23 +102,50 @@ function interpret_positive_info(func::Symbol, info::Integer)
84102 end
85103end
86104
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
123+
124+ if op_info. rhs_length > 0
125+ push! (parts, " RHS length: $(op_info. rhs_length) " )
126+ end
87127
128+ if ! isempty (op_info. rhs_type)
129+ push! (parts, " RHS type: $(op_info. rhs_type) " )
130+ end
88131
89- # Type barrier for string interpolation with Any-typed values
90- # The ::String return type annotation prevents JET from seeing runtime dispatch propagate
91- @noinline _format_context_pair (key:: Symbol , value):: String = string (key, " : " , value)
132+ return parts
133+ end
92134
93135"""
94- blas_info_msg(func::Symbol, info::Integer, verbose::LinearVerbosity;
95- 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))
96139
97140Log BLAS/LAPACK return code information with appropriate verbosity level.
98141"""
99142function blas_info_msg (func:: Symbol , info:: Integer ;
100- extra_context:: Dict{Symbol, Any} = Dict ())
143+ extra_context:: BlasOperationInfo = BlasOperationInfo (
144+ (0 , 0 ), " " , " " , - Inf , 0 , " " , 0.0 ))
101145 category, message, details = interpret_blas_code (func, info)
102146
103- 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 ]
104149 :blas_errors
105150 elseif category == :invalid_argument
106151 :blas_invalid_args
@@ -114,17 +159,18 @@ function blas_info_msg(func::Symbol, info::Integer;
114159 msg_info = info
115160
116161 # Build complete message with all details
117- 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
118166 parts = String[msg_main]
119167 if msg_details != = nothing
120168 push! (parts, " Details: $msg_details " )
121169 end
122170 push! (parts, " Return code (info): $msg_info " )
123- if ! isempty (extra_context)
124- for (key, value) in extra_context
125- # Use type barrier to prevent runtime dispatch from propagating
126- push! (parts, _format_context_pair (key, value))
127- end
171+ if has_extra_context
172+ # Type-stable formatting using struct fields
173+ append! (parts, _format_blas_context (extra_context))
128174 end
129175 join (parts, " \n " )
130176 else
@@ -134,39 +180,38 @@ function blas_info_msg(func::Symbol, info::Integer;
134180 verbosity_field, full_msg
135181end
136182
137-
138183function get_blas_operation_info (func:: Symbol , A, b; condition = false )
139- 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))
140188
141- # Matrix properties
142- info[:matrix_size ] = size (A)
143- info[:matrix_type ] = typeof (A)
144- 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 )
145192
146- # Condition number (based on verbosity setting )
147- 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 ]
148195 try
149- cond_num = cond (A)
150- info[:condition_number ] = cond_num
151-
152- # Log the condition number if enabled
153- cond_msg = " Matrix condition number: $(round (cond_num, sigdigits= 4 )) for $(size (A, 1 )) ×$(size (A, 2 )) matrix in $func "
154-
196+ cond (A)
155197 catch
156- # Skip if condition number computation fails
157- info[:condition_number ] = nothing
198+ - Inf
158199 end
200+ else
201+ - Inf
159202 end
160203
161- # RHS properties if provided
162- if b != = nothing
163- info[:rhs_size ] = size (b)
164- info[:rhs_type ] = typeof (b)
165- end
166-
167- # Memory usage estimate
168- mem_bytes = prod (size (A)) * sizeof (eltype (A))
169- info[:memory_usage_MB ] = round (mem_bytes / 1024 ^ 2 , digits = 2 )
170-
171- return info
172- 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