Skip to content

Commit 9526eba

Browse files
Merge pull request #818 from ChrisRackauckas-Claude/fix-jet-tests-v110-v112
Fix JET test expectations for Julia v1.10 and v1.12
2 parents 1ef6c74 + 51b20be commit 9526eba

File tree

6 files changed

+165
-113
lines changed

6 files changed

+165
-113
lines changed

src/appleaccelerate.jl

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -263,17 +263,20 @@ function SciMLBase.solve!(cache::LinearCache, alg::AppleAccelerateLUFactorizatio
263263
info_value = res[3]
264264

265265
if info_value != 0
266-
if !isa(verbose.blas_info, SciMLLogging.Silent) || !isa(verbose.blas_errors, SciMLLogging.Silent) ||
267-
!isa(verbose.blas_invalid_args, SciMLLogging.Silent)
268-
op_info = get_blas_operation_info(:dgetrf, A, cache.b, condition = !isa(verbose.condition_number, SciMLLogging.Silent))
266+
if !isa(verbose.blas_info, SciMLLogging.Silent) ||
267+
!isa(verbose.blas_errors, SciMLLogging.Silent) ||
268+
!isa(verbose.blas_invalid_args, SciMLLogging.Silent)
269+
op_info = get_blas_operation_info(:dgetrf, A, cache.b,
270+
condition = !isa(verbose.condition_number, SciMLLogging.Silent))
269271
@SciMLMessage(cache.verbose, :condition_number) do
270-
if op_info[:condition_number] === nothing
272+
if isinf(op_info.condition_number)
271273
return "Matrix condition number calculation failed."
272274
else
273-
return "Matrix condition number: $(round(op_info[:condition_number], sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf"
275+
return "Matrix condition number: $(round(op_info.condition_number, sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf"
274276
end
275277
end
276-
verb_option, message = blas_info_msg(
278+
verb_option,
279+
message = blas_info_msg(
277280
:dgetrf, info_value; extra_context = op_info)
278281
@SciMLMessage(message, verbose, verb_option)
279282
end
@@ -282,13 +285,13 @@ function SciMLBase.solve!(cache::LinearCache, alg::AppleAccelerateLUFactorizatio
282285
op_info = get_blas_operation_info(:dgetrf, A, cache.b,
283286
condition = !isa(verbose.condition_number, SciMLLogging.Silent))
284287
@SciMLMessage(cache.verbose, :condition_number) do
285-
if op_info[:condition_number] === nothing
288+
if isinf(op_info.condition_number)
286289
return "Matrix condition number calculation failed."
287290
else
288-
return "Matrix condition number: $(round(op_info[:condition_number], sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf"
291+
return "Matrix condition number: $(round(op_info.condition_number, sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf"
289292
end
290293
end
291-
return "BLAS LU factorization (dgetrf) completed successfully for $(op_info[:matrix_size]) matrix"
294+
return "BLAS LU factorization (dgetrf) completed successfully for $(op_info.matrix_size) matrix"
292295
end
293296
end
294297

@@ -326,7 +329,8 @@ const PREALLOCATED_APPLE32_LU = begin
326329
LU(luinst.factors, similar(A, Cint, 0), luinst.info), Ref{Cint}()
327330
end
328331

329-
function LinearSolve.init_cacheval(alg::AppleAccelerate32MixedLUFactorization, A, b, u, Pl, Pr,
332+
function LinearSolve.init_cacheval(
333+
alg::AppleAccelerate32MixedLUFactorization, A, b, u, Pl, Pr,
330334
maxiters::Int, abstol, reltol, verbose::Union{LinearVerbosity, Bool},
331335
assumptions::OperatorAssumptions)
332336
# Pre-allocate appropriate 32-bit arrays based on input type
@@ -349,7 +353,8 @@ function SciMLBase.solve!(cache::LinearCache, alg::AppleAccelerate32MixedLUFacto
349353

350354
if cache.isfresh
351355
# Get pre-allocated arrays from cacheval
352-
luinst, info, A_32, b_32, u_32 = @get_cacheval(cache, :AppleAccelerate32MixedLUFactorization)
356+
luinst, info, A_32,
357+
b_32, u_32 = @get_cacheval(cache, :AppleAccelerate32MixedLUFactorization)
353358
# Compute 32-bit type on demand and copy A
354359
T32 = eltype(A) <: Complex ? ComplexF32 : Float32
355360
A_32 .= T32.(A)
@@ -365,14 +370,15 @@ function SciMLBase.solve!(cache::LinearCache, alg::AppleAccelerate32MixedLUFacto
365370
cache.isfresh = false
366371
end
367372

368-
A_lu, info, A_32, b_32, u_32 = @get_cacheval(cache, :AppleAccelerate32MixedLUFactorization)
373+
A_lu, info, A_32, b_32,
374+
u_32 = @get_cacheval(cache, :AppleAccelerate32MixedLUFactorization)
369375
require_one_based_indexing(cache.u, cache.b)
370376
m, n = size(A_lu, 1), size(A_lu, 2)
371377

372378
# Compute types on demand for conversions
373379
T32 = eltype(A) <: Complex ? ComplexF32 : Float32
374380
Torig = eltype(cache.u)
375-
381+
376382
# Copy b to pre-allocated 32-bit array
377383
b_32 .= T32.(cache.b)
378384

src/blas_logging.jl

Lines changed: 86 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
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
85103
end
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
97140
Log BLAS/LAPACK return code information with appropriate verbosity level.
98141
"""
99142
function 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
135181
end
136182

137-
138183
function 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

src/mkl.jl

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ struct MKLLUFactorization <: AbstractFactorization end
1212
# MKL_jll < 2022.2 doesn't support the mixed LP64 and ILP64 interfaces that we make use of in LinearSolve
1313
# In particular, the `_64` APIs do not exist
1414
# https://www.intel.com/content/www/us/en/developer/articles/release-notes/onemkl-release-notes-2022.html
15-
@static if !@isdefined(MKL_jll) || !MKL_jll.is_available() || pkgversion(MKL_jll) < v"2022.2"
15+
@static if !@isdefined(MKL_jll) || !MKL_jll.is_available() ||
16+
pkgversion(MKL_jll) < v"2022.2"
1617
__mkl_isavailable() = false
1718
else
1819
__mkl_isavailable() = true
@@ -252,32 +253,40 @@ function SciMLBase.solve!(cache::LinearCache, alg::MKLLUFactorization;
252253
info_value = res[3]
253254

254255
if info_value != 0
255-
if !isa(verbose.blas_info, SciMLLogging.Silent) || !isa(verbose.blas_errors, SciMLLogging.Silent) ||
256-
!isa(verbose.blas_invalid_args, SciMLLogging.Silent)
257-
op_info = get_blas_operation_info(:dgetrf, A, cache.b, condition = !isa(verbose.condition_number, SciMLLogging.Silent))
256+
if !isa(verbose.blas_info, SciMLLogging.Silent) ||
257+
!isa(verbose.blas_errors, SciMLLogging.Silent) ||
258+
!isa(verbose.blas_invalid_args, SciMLLogging.Silent)
259+
op_info = get_blas_operation_info(:dgetrf, A, cache.b,
260+
condition = !isa(verbose.condition_number, SciMLLogging.Silent))
258261
if cache.verbose.condition_number != Silent()
259-
if op_info[:condition_number] === nothing
260-
@SciMLMessage("Matrix condition number calculation failed.", cache.verbose, :condition_number)
262+
if isinf(op_info.condition_number)
263+
@SciMLMessage("Matrix condition number calculation failed.",
264+
cache.verbose, :condition_number)
261265
else
262-
@SciMLMessage("Matrix condition number: $(round(op_info[:condition_number], sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf", cache.verbose, :condition_number)
266+
@SciMLMessage("Matrix condition number: $(round(op_info.condition_number, sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf",
267+
cache.verbose, :condition_number)
263268
end
264269
end
265-
verb_option, message = blas_info_msg(
270+
verb_option,
271+
message = blas_info_msg(
266272
:dgetrf, info_value; extra_context = op_info)
267273
@SciMLMessage(message, verbose, verb_option)
268274
end
269275
else
270276
if cache.verbose.blas_success != Silent()
271-
op_info = get_blas_operation_info(:dgetrf, A, cache.b, condition = !isa(verbose.condition_number, SciMLLogging.Silent))
277+
op_info = get_blas_operation_info(:dgetrf, A, cache.b,
278+
condition = !isa(verbose.condition_number, SciMLLogging.Silent))
272279
if cache.verbose.condition_number != Silent()
273-
if op_info[:condition_number] === nothing
274-
@SciMLMessage("Matrix condition number calculation failed.", cache.verbose, :condition_number)
280+
if isinf(op_info.condition_number)
281+
@SciMLMessage("Matrix condition number calculation failed.",
282+
cache.verbose, :condition_number)
275283
else
276-
@SciMLMessage("Matrix condition number: $(round(op_info[:condition_number], sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf",
284+
@SciMLMessage("Matrix condition number: $(round(op_info.condition_number, sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf",
277285
cache.verbose, :condition_number)
278286
end
279287
end
280-
@SciMLMessage("BLAS LU factorization (dgetrf) completed successfully for $(op_info[:matrix_size]) matrix", cache.verbose, :blas_success)
288+
@SciMLMessage("BLAS LU factorization (dgetrf) completed successfully for $(op_info.matrix_size) matrix",
289+
cache.verbose, :blas_success)
281290
end
282291
end
283292

@@ -360,7 +369,7 @@ function SciMLBase.solve!(cache::LinearCache, alg::MKL32MixedLUFactorization;
360369
# Compute types on demand for conversions
361370
T32 = eltype(A) <: Complex ? ComplexF32 : Float32
362371
Torig = eltype(cache.u)
363-
372+
364373
# Copy b to pre-allocated 32-bit array
365374
b_32 .= T32.(cache.b)
366375

src/openblas.jl

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -274,17 +274,20 @@ function SciMLBase.solve!(cache::LinearCache, alg::OpenBLASLUFactorization;
274274
info_value = res[3]
275275

276276
if info_value != 0
277-
if !isa(verbose.blas_info, SciMLLogging.Silent) || !isa(verbose.blas_errors, SciMLLogging.Silent) ||
278-
!isa(verbose.blas_invalid_args, SciMLLogging.Silent)
279-
op_info = get_blas_operation_info(:dgetrf, A, cache.b, condition = !isa(verbose.condition_number, SciMLLogging.Silent))
277+
if !isa(verbose.blas_info, SciMLLogging.Silent) ||
278+
!isa(verbose.blas_errors, SciMLLogging.Silent) ||
279+
!isa(verbose.blas_invalid_args, SciMLLogging.Silent)
280+
op_info = get_blas_operation_info(:dgetrf, A, cache.b,
281+
condition = !isa(verbose.condition_number, SciMLLogging.Silent))
280282
@SciMLMessage(cache.verbose, :condition_number) do
281-
if op_info[:condition_number] === nothing
283+
if isinf(op_info.condition_number)
282284
return "Matrix condition number calculation failed."
283285
else
284-
return "Matrix condition number: $(round(op_info[:condition_number], sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf"
286+
return "Matrix condition number: $(round(op_info.condition_number, sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf"
285287
end
286288
end
287-
verb_option, message = blas_info_msg(
289+
verb_option,
290+
message = blas_info_msg(
288291
:dgetrf, info_value; extra_context = op_info)
289292
@SciMLMessage(message, verbose, verb_option)
290293
end
@@ -293,13 +296,13 @@ function SciMLBase.solve!(cache::LinearCache, alg::OpenBLASLUFactorization;
293296
op_info = get_blas_operation_info(:dgetrf, A, cache.b,
294297
condition = !isa(verbose.condition_number, SciMLLogging.Silent))
295298
@SciMLMessage(cache.verbose, :condition_number) do
296-
if op_info[:condition_number] === nothing
299+
if isinf(op_info.condition_number)
297300
return "Matrix condition number calculation failed."
298301
else
299-
return "Matrix condition number: $(round(op_info[:condition_number], sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf"
302+
return "Matrix condition number: $(round(op_info.condition_number, sigdigits=4)) for $(size(A, 1))×$(size(A, 2)) matrix in dgetrf"
300303
end
301304
end
302-
return "BLAS LU factorization (dgetrf) completed successfully for $(op_info[:matrix_size]) matrix"
305+
return "BLAS LU factorization (dgetrf) completed successfully for $(op_info.matrix_size) matrix"
303306
end
304307
end
305308

@@ -359,7 +362,8 @@ function SciMLBase.solve!(cache::LinearCache, alg::OpenBLAS32MixedLUFactorizatio
359362

360363
if cache.isfresh
361364
# Get pre-allocated arrays from cacheval
362-
luinst, info, A_32, b_32, u_32 = @get_cacheval(cache, :OpenBLAS32MixedLUFactorization)
365+
luinst, info, A_32, b_32,
366+
u_32 = @get_cacheval(cache, :OpenBLAS32MixedLUFactorization)
363367
# Compute 32-bit type on demand and copy A
364368
T32 = eltype(A) <: Complex ? ComplexF32 : Float32
365369
A_32 .= T32.(A)
@@ -382,7 +386,7 @@ function SciMLBase.solve!(cache::LinearCache, alg::OpenBLAS32MixedLUFactorizatio
382386
# Compute types on demand for conversions
383387
T32 = eltype(A) <: Complex ? ComplexF32 : Float32
384388
Torig = eltype(cache.u)
385-
389+
386390
# Copy b to pre-allocated 32-bit array
387391
b_32 .= T32.(cache.b)
388392

0 commit comments

Comments
 (0)