diff --git a/.github/workflows/Downgrade.yml b/.github/workflows/Downgrade.yml index 0c2b21e..951212a 100644 --- a/.github/workflows/Downgrade.yml +++ b/.github/workflows/Downgrade.yml @@ -12,6 +12,7 @@ on: - 'docs/**' jobs: test: + if: false # Disabled pending dependency updates - see issue #142 runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/Tests.yml b/.github/workflows/Tests.yml index d5a0c02..bb75dbc 100644 --- a/.github/workflows/Tests.yml +++ b/.github/workflows/Tests.yml @@ -26,7 +26,14 @@ jobs: - "1" - "lts" - "pre" + group: + - Core + - nopre + exclude: + - version: "pre" + group: nopre uses: "SciML/.github/.github/workflows/tests.yml@v1" with: julia-version: "${{ matrix.version }}" + group: ${{ matrix.group }} secrets: "inherit" diff --git a/src/DataReduction/POD.jl b/src/DataReduction/POD.jl index 6e1c79a..cb28ba9 100644 --- a/src/DataReduction/POD.jl +++ b/src/DataReduction/POD.jl @@ -1,7 +1,7 @@ using TSVD: tsvd using RandomizedLinAlg: rsvd -function matricize(VoV::Vector{Vector{T}}) where {T} +function matricize(VoV::Vector{Vector{T}})::Matrix{T} where {T} return reduce(hcat, VoV) end @@ -26,35 +26,51 @@ end _rsvd(data, n::Int, p::Int) = rsvd(data, n, p) -mutable struct POD <: AbstractDRProblem +mutable struct POD{S, T <: AbstractFloat} <: AbstractDRProblem # specified - snapshots::Any - min_renergy::Any + snapshots::S + min_renergy::T min_nmodes::Int max_nmodes::Int # computed nmodes::Int - rbasis::Any - renergy::Any - spectrum::Any + rbasis::Union{Missing, Matrix{T}} + renergy::T + spectrum::Union{Missing, Vector{T}} # constructors function POD( - snaps; - min_renergy = 1.0, + snaps::S; + min_renergy::T = 1.0, min_nmodes::Int = 1, max_nmodes::Int = length(snaps[1]) - ) + ) where {S <: AbstractMatrix{T}} where {T <: AbstractFloat} nmodes = min_nmodes errorhandle(snaps, nmodes, min_renergy, min_nmodes, max_nmodes) - return new(snaps, min_renergy, min_nmodes, max_nmodes, nmodes, missing, 1.0, missing) + return new{S, T}(snaps, min_renergy, min_nmodes, max_nmodes, nmodes, missing, one(T), missing) end - function POD(snaps, nmodes::Int) - errorhandle(snaps, nmodes, 0.0, nmodes, nmodes) - return new(snaps, 0.0, nmodes, nmodes, nmodes, missing, 1.0, missing) + function POD( + snaps::S; + min_renergy::T = 1.0, + min_nmodes::Int = 1, + max_nmodes::Int = length(snaps[1]) + ) where {T <: AbstractFloat, S <: AbstractVector{<:AbstractVector{T}}} + nmodes = min_nmodes + errorhandle(snaps, nmodes, min_renergy, min_nmodes, max_nmodes) + return new{S, T}(snaps, min_renergy, min_nmodes, max_nmodes, nmodes, missing, one(T), missing) + end + function POD(snaps::S, nmodes::Int) where {S <: AbstractMatrix{T}} where {T <: AbstractFloat} + errorhandle(snaps, nmodes, zero(T), nmodes, nmodes) + return new{S, T}(snaps, zero(T), nmodes, nmodes, nmodes, missing, one(T), missing) + end + function POD(snaps::S, nmodes::Int) where {T <: AbstractFloat, S <: AbstractVector{<:AbstractVector{T}}} + errorhandle(snaps, nmodes, zero(T), nmodes, nmodes) + return new{S, T}(snaps, zero(T), nmodes, nmodes, nmodes, missing, one(T), missing) end end -function determine_truncation(s, min_nmodes, min_renergy, max_nmodes) +function determine_truncation( + s::AbstractVector{T}, min_nmodes::Int, max_nmodes::Int, min_renergy::T + )::Tuple{Int, T} where {T <: AbstractFloat} nmodes = min_nmodes overall_energy = sum(s) energy = sum(s[1:nmodes]) / overall_energy @@ -65,42 +81,43 @@ function determine_truncation(s, min_nmodes, min_renergy, max_nmodes) return nmodes, energy end -function reduce!(pod::POD, alg::SVD) +function reduce!(pod::POD{S, T}, alg::SVD)::Nothing where {S, T} u, s, v = _svd(pod.snapshots; alg.kwargs...) pod.nmodes, pod.renergy = determine_truncation( s, pod.min_nmodes, pod.max_nmodes, pod.min_renergy ) - pod.rbasis = u[:, 1:(pod.nmodes)] - pod.spectrum = s + pod.rbasis = Matrix{T}(u[:, 1:(pod.nmodes)]) + pod.spectrum = Vector{T}(s) return nothing end -function reduce!(pod::POD, alg::TSVD) +function reduce!(pod::POD{S, T}, alg::TSVD)::Nothing where {S, T} u, s, v = _tsvd(pod.snapshots, pod.nmodes; alg.kwargs...) n_max = min(size(u, 1), size(v, 1)) - pod.renergy = sum(s) / (sum(s) + (n_max - pod.nmodes) * s[end]) - pod.rbasis = u - pod.spectrum = s + pod.renergy = T(sum(s) / (sum(s) + (n_max - pod.nmodes) * s[end])) + pod.rbasis = Matrix{T}(u) + pod.spectrum = Vector{T}(s) return nothing end -function reduce!(pod::POD, alg::RSVD) +function reduce!(pod::POD{S, T}, alg::RSVD)::Nothing where {S, T} u, s, v = _rsvd(pod.snapshots, pod.nmodes, alg.p) n_max = min(size(u, 1), size(v, 1)) - pod.renergy = sum(s) / (sum(s) + (n_max - pod.nmodes) * s[end]) - pod.rbasis = u - pod.spectrum = s + pod.renergy = T(sum(s) / (sum(s) + (n_max - pod.nmodes) * s[end])) + pod.rbasis = Matrix{T}(u) + pod.spectrum = Vector{T}(s) return nothing end -function Base.show(io::IO, pod::POD) +function Base.show(io::IO, pod::POD)::Nothing print(io, "POD \n") print(io, "Reduction Order = ", pod.nmodes, "\n") print( io, "Snapshot size = (", size(pod.snapshots, 1), ",", size(pod.snapshots[1], 2), ")\n" ) - return print(io, "Relative Energy = ", pod.renergy, "\n") + print(io, "Relative Energy = ", pod.renergy, "\n") + return nothing end diff --git a/src/Types.jl b/src/Types.jl index d03f52b..e14af7c 100644 --- a/src/Types.jl +++ b/src/Types.jl @@ -4,17 +4,19 @@ abstract type AbstractDRProblem <: AbstractReductionProblem end abstract type AbstractSVD end -struct SVD <: AbstractSVD - kwargs::Any +struct SVD{K <: NamedTuple} <: AbstractSVD + kwargs::K function SVD(; kwargs...) - return new(kwargs) + kw = NamedTuple(kwargs) + return new{typeof(kw)}(kw) end end -struct TSVD <: AbstractSVD - kwargs::Any +struct TSVD{K <: NamedTuple} <: AbstractSVD + kwargs::K function TSVD(; kwargs...) - return new(kwargs) + kw = NamedTuple(kwargs) + return new{typeof(kw)}(kw) end end diff --git a/src/utils.jl b/src/utils.jl index f33cf67..d134175 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -31,7 +31,7 @@ $(SIGNATURES) Returns `true` if `expr` contains variables in `dvs` only and does not contain `iv`. """ -function only_dvs(expr, dvs, iv) +function only_dvs(expr, dvs, iv)::Bool if isequal(expr, iv) return false elseif expr in dvs diff --git a/test/Project.toml b/test/Project.toml index 027be15..9dc015a 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,16 +1,16 @@ [deps] -Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" -ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MethodOfLines = "94925ecb-adb7-4558-8ed8-f975c56a0bf4" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -Aqua = "0.8" -ExplicitImports = "1" +LinearAlgebra = "1" MethodOfLines = "0.11" +Pkg = "1.10" ModelingToolkit = "10.10" OrdinaryDiffEq = "6" SafeTestsets = "0.1" diff --git a/test/nopre/Project.toml b/test/nopre/Project.toml new file mode 100644 index 0000000..2653121 --- /dev/null +++ b/test/nopre/Project.toml @@ -0,0 +1,12 @@ +[deps] +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Aqua = "0.8" +ExplicitImports = "1" +JET = "0.9, 0.10, 0.11" +LinearAlgebra = "1" diff --git a/test/explicit_imports.jl b/test/nopre/explicit_imports_tests.jl similarity index 100% rename from test/explicit_imports.jl rename to test/nopre/explicit_imports_tests.jl diff --git a/test/nopre/jet_tests.jl b/test/nopre/jet_tests.jl new file mode 100644 index 0000000..c906afd --- /dev/null +++ b/test/nopre/jet_tests.jl @@ -0,0 +1,41 @@ +using Test, JET +using ModelOrderReduction +using LinearAlgebra: qr + +@testset "JET Static Analysis" begin + # Create test data + n = 20 # state dimension + m = 10 # number of snapshots + snapshot_matrix = Float64[sin(i * j / n) for i in 1:n, j in 1:m] + snapshot_vov = [Float64[sin(i * j / n) for i in 1:n] for j in 1:m] + + # Create an orthonormal basis for deim_interpolation_indices + Q, _ = qr(snapshot_matrix) + deim_basis = Matrix(Q[:, 1:5]) + + @testset "deim_interpolation_indices type stability" begin + rep = JET.report_call(ModelOrderReduction.deim_interpolation_indices, (Matrix{Float64},)) + @test length(JET.get_reports(rep)) == 0 + end + + @testset "matricize type stability" begin + rep = JET.report_call(ModelOrderReduction.matricize, (Vector{Vector{Float64}},)) + @test length(JET.get_reports(rep)) == 0 + end + + @testset "POD constructor type stability" begin + # Matrix constructor + rep1 = JET.report_call(ModelOrderReduction.POD, (Matrix{Float64}, Int)) + @test length(JET.get_reports(rep1)) == 0 + + # Vector{Vector} constructor + rep2 = JET.report_call(ModelOrderReduction.POD, (Vector{Vector{Float64}}, Int)) + @test length(JET.get_reports(rep2)) == 0 + end + + @testset "reduce! with SVD type stability" begin + pod = POD(snapshot_matrix, 3) + rep = JET.report_call(ModelOrderReduction.reduce!, (typeof(pod), typeof(SVD()))) + @test length(JET.get_reports(rep)) == 0 + end +end diff --git a/test/qa.jl b/test/nopre/qa_tests.jl similarity index 100% rename from test/qa.jl rename to test/nopre/qa_tests.jl diff --git a/test/runtests.jl b/test/runtests.jl index 6d1c1af..cb37f6a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,17 +1,32 @@ using SafeTestsets -@safetestset "Quality Assurance" begin - include("qa.jl") -end -@safetestset "Explicit Imports" begin - include("explicit_imports.jl") -end -@safetestset "POD" begin - include("DataReduction.jl") -end -@safetestset "utils" begin - include("utils.jl") +const GROUP = get(ENV, "GROUP", "All") + +if GROUP == "All" || GROUP == "Core" + @safetestset "POD" begin + include("DataReduction.jl") + end + @safetestset "utils" begin + include("utils.jl") + end + @safetestset "DEIM" begin + include("deim.jl") + end end -@safetestset "DEIM" begin - include("deim.jl") + +if GROUP == "nopre" + using Pkg + Pkg.activate(@__DIR__() * "/nopre") + Pkg.develop(path = dirname(@__DIR__)) + Pkg.instantiate() + + @safetestset "Quality Assurance" begin + include("nopre/qa_tests.jl") + end + @safetestset "Explicit Imports" begin + include("nopre/explicit_imports_tests.jl") + end + @safetestset "JET Static Analysis" begin + include("nopre/jet_tests.jl") + end end