Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ PrecompileTools = "1"
Printf = "1.10"
Random = "1"
SafeTestsets = "0.1, 1"
SciMLTesting = "1"
SciMLTesting = "1.6"
SparseArrays = "1.10"
StaticArrays = "1.9.8"
Test = "1"
Expand Down
2 changes: 1 addition & 1 deletion src/ExponentialUtilities.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module ExponentialUtilities
using LinearAlgebra, SparseArrays, Printf
using ArrayInterface: ismutable, allowed_getindex, allowed_setindex!
using ArrayInterface: ismutable, allowed_setindex!
using PrecompileTools
import GenericSchur
import GPUArraysCore
Expand Down
31 changes: 25 additions & 6 deletions src/exp_noalloc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,19 @@ function alloc_mem(A, ::ExpMethodHigham2005)
end

# Import the generated code
for i in 1:13
include("exp_generated/exp_$i.jl")
end
include("exp_generated/exp_1.jl")
include("exp_generated/exp_2.jl")
include("exp_generated/exp_3.jl")
include("exp_generated/exp_4.jl")
include("exp_generated/exp_5.jl")
include("exp_generated/exp_6.jl")
include("exp_generated/exp_7.jl")
include("exp_generated/exp_8.jl")
include("exp_generated/exp_9.jl")
include("exp_generated/exp_10.jl")
include("exp_generated/exp_11.jl")
include("exp_generated/exp_12.jl")
include("exp_generated/exp_13.jl")

function getmem(cache, k) # Called from generated code
return cache[k - 1]
Expand Down Expand Up @@ -89,13 +99,22 @@ function exponential!(A, method::ExpMethodHigham2005, _cache = alloc_mem(A, meth
n = LinearAlgebra.checksquare(A)
nA = opnorm(A, 1)

# Maybe to balancing
# Maybe to balancing. `ilo`/`ihi`/`scale` are seeded with no-op defaults so they are
# always defined before the symmetric undo block below; the two `do_balancing`
# branches are not provably correlated to the compiler, so without these seeds the
# undo block reads possibly-undefined locals (flagged by JET typo-mode).
ilo = 1
ihi = n
scale = _scale
prow = nothing # row/col permutations from the GenericSchur (non-BLAS) balancing path
pcol = nothing
if method.do_balancing
if A isa StridedMatrix{<:LinearAlgebra.BLAS.BlasFloat}
ilo, ihi, scale = gebal_noalloc!('B', A, _scale) # modifies A and _scale
else
A, bal = GenericSchur.balance!(A)
ilo, ihi, scale = bal.ilo, bal.ihi, bal.D
prow, pcol = bal.prow, bal.pcol
end
end

Expand Down Expand Up @@ -134,12 +153,12 @@ function exponential!(A, method::ExpMethodHigham2005, _cache = alloc_mem(A, meth
else
if ilo > 1 # apply lower permutations in reverse order
for j in (ilo - 1):-1:1
LinearAlgebra.rcswap!(j, bal.prow[j], X)
LinearAlgebra.rcswap!(j, prow[j], X)
end
end
if ihi < n # apply upper permutations in forward order
for j in (ihi + 1):n
LinearAlgebra.rcswap!(j, bal.pcol[j - ihi], X)
LinearAlgebra.rcswap!(j, pcol[j - ihi], X)
end
end
end
Expand Down
8 changes: 4 additions & 4 deletions test/qa/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
SciMLTesting = "09d9d899-5365-40a9-917a-5f67fddea283"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[sources]
ExponentialUtilities = {path = "../.."}

[compat]
Aqua = "0.8"
JET = "0.9, 0.10, 0.11"
SafeTestsets = "0.1, 1"
SciMLTesting = "1"
SciMLTesting = "1.6"
Test = "1"
julia = "1.10"

[sources]
ExponentialUtilities = {path = "../.."}
107 changes: 34 additions & 73 deletions test/qa/qa.jl
Original file line number Diff line number Diff line change
@@ -1,73 +1,34 @@
using ExponentialUtilities, Aqua, JET, Test

@testset "Aqua" begin
Aqua.find_persistent_tasks_deps(ExponentialUtilities)
Aqua.test_ambiguities(ExponentialUtilities, recursive = false)
Aqua.test_deps_compat(
ExponentialUtilities,
ignore = [:libblastrampoline_jll]
)
Aqua.test_piracies(ExponentialUtilities)
Aqua.test_project_extras(ExponentialUtilities)
Aqua.test_stale_deps(ExponentialUtilities)
Aqua.test_unbound_args(ExponentialUtilities)
Aqua.test_undefined_exports(ExponentialUtilities)
end

# Analyze only ExponentialUtilities' own code. Without this, JET on Julia 1.12 traces
# into LinearAlgebra/Base internals (e.g. `norm(::Vector)` -> `norm_recursive_check`,
# and the broadcast `unalias`/`copyto_unaliased!` path over `Adjoint{T, Union{}}`) and
# reports abstract-interpretation artifacts there that are not under this package's
# control. Scoping to `ExponentialUtilities` keeps full coverage of this package's code
# (it still flags real `may be undefined` findings here) without asserting that all of
# the stdlib is JET-clean.
const JET_TARGET = (ExponentialUtilities,)

@testset "JET static analysis" begin
@testset "expv" begin
rep = JET.report_call(
expv, (Float64, Matrix{Float64}, Vector{Float64}); target_modules = JET_TARGET
)
@test length(JET.get_reports(rep)) == 0
end

@testset "arnoldi" begin
rep = JET.report_call(
arnoldi, (Matrix{Float64}, Vector{Float64}); target_modules = JET_TARGET
)
@test length(JET.get_reports(rep)) == 0
end

@testset "phi" begin
rep = JET.report_call(phi, (Matrix{Float64}, Int); target_modules = JET_TARGET)
@test length(JET.get_reports(rep)) == 0
end

@testset "exponential!" begin
rep = JET.report_call(
ExponentialUtilities.exponential!, (Matrix{Float64},); target_modules = JET_TARGET
)
@test length(JET.get_reports(rep)) == 0
end

@testset "phiv" begin
rep = JET.report_call(
phiv, (Float64, Matrix{Float64}, Vector{Float64}, Int); target_modules = JET_TARGET
)
@test length(JET.get_reports(rep)) == 0
end

@testset "kiops" begin
rep = JET.report_call(
kiops, (Float64, Matrix{Float64}, Vector{Float64}); target_modules = JET_TARGET
)
@test length(JET.get_reports(rep)) == 0
end

@testset "expv_timestep" begin
rep = JET.report_call(
expv_timestep, (Float64, Matrix{Float64}, Vector{Float64}); target_modules = JET_TARGET
)
@test length(JET.get_reports(rep)) == 0
end
end
using SciMLTesting, ExponentialUtilities, JET, Test

run_qa(
ExponentialUtilities;
explicit_imports = true,
aqua_kwargs = (; deps_compat = (; ignore = [:libblastrampoline_jll])),
ei_kwargs = (;
# Names owned elsewhere but reached through LinearAlgebra.BLAS.
all_qualified_accesses_via_owners = (;
ignore = (:BlasFloat, :chkstride1, :libblastrampoline),
),
# Non-public names of Base / LinearAlgebra(.BLAS/.LAPACK) accessed qualified.
all_qualified_accesses_are_public = (;
ignore = (
Symbol("@aliasscope"), Symbol("@assume_effects"),
Symbol("@blasfunc"), Symbol("@propagate_inbounds"),
:BlasFloat, :Cartesian, :Const, :Experimental,
:checksquare, :chkfinite, :chklapackerror, :chkstride1,
:gebal!, :gesv!, :libblastrampoline, :rcswap!, :stegr!,
),
),
# Non-public names explicitly imported from LinearAlgebra(.BLAS/.LAPACK,
# incl. the Stegr submodule) / ArrayInterface / Base.
all_explicit_imports_are_public = (;
ignore = (
:BlasInt, :checksquare, :allowed_setindex!, :ismutable, :typename,
Symbol("@blasfunc"), :stegr!,
),
),
),
# Heavy `using LinearAlgebra, SparseArrays, Printf, PrecompileTools` brings ~31
# names implicitly; making them explicit is a large refactor tracked separately.
ei_broken = (:no_implicit_imports,)
) # SciML/ExponentialUtilities.jl#231
Loading