diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 7c813a3..9697814 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -13,28 +13,5 @@ concurrency: jobs: tests: - name: "Tests" - strategy: - fail-fast: false - matrix: - version: - - "1" - - "lts" - - "pre" - os: - - ubuntu-latest - arch: - - x64 - include: - - version: "1.10" - os: windows-latest - arch: x64 - - version: "1.10" - os: macOS-latest - arch: x64 - uses: "SciML/.github/.github/workflows/tests.yml@v1" - with: - julia-version: "${{ matrix.version }}" - julia-arch: "${{ matrix.arch }}" - os: "${{ matrix.os }}" + uses: "SciML/.github/.github/workflows/grouped-tests.yml@v1" secrets: "inherit" diff --git a/Project.toml b/Project.toml index 380dc7d..307e797 100644 --- a/Project.toml +++ b/Project.toml @@ -16,8 +16,11 @@ DataCollocationsDataInterpolationsExt = "DataInterpolations" [compat] ArrayInterface = "7" DataInterpolations = "6.4, 7, 8" +Documenter = "1" JLArrays = "0.3" OrdinaryDiffEq = "6, 7" +Plots = "1" +Test = "1" julia = "1.10" [extras] @@ -26,9 +29,10 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] docs = ["Documenter", "DataInterpolations", "OrdinaryDiffEq", "Plots"] -test = ["DataInterpolations", "JET", "JLArrays", "OrdinaryDiffEq", "Test"] +test = ["DataInterpolations", "JET", "JLArrays", "OrdinaryDiffEq", "Pkg", "Test"] diff --git a/test/qa/Project.toml b/test/qa/Project.toml new file mode 100644 index 0000000..1275e98 --- /dev/null +++ b/test/qa/Project.toml @@ -0,0 +1,12 @@ +[deps] +DataCollocations = "9454e98c-75cb-4dbc-9573-481819719962" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[sources] +DataCollocations = {path = "../.."} + +[compat] +JET = "0.9, 0.10" +Test = "1" +julia = "1.10" diff --git a/test/qa/qa.jl b/test/qa/qa.jl new file mode 100644 index 0000000..47db831 --- /dev/null +++ b/test/qa/qa.jl @@ -0,0 +1,25 @@ +using DataCollocations +using Test +using JET + +@testset "JET Static Analysis" begin + # Test kernel functions for type stability + @testset "calckernel optimization" begin + kernels = [ + EpanechnikovKernel(), UniformKernel(), TriangularKernel(), + QuarticKernel(), TriweightKernel(), TricubeKernel(), + GaussianKernel(), CosineKernel(), LogisticKernel(), + SigmoidKernel(), SilvermanKernel(), + ] + @testset "$kernel" for kernel in kernels + JET.@test_opt target_modules = (DataCollocations,) DataCollocations.calckernel(kernel, 0.5) + end + end + + # Test main collocate_data function + @testset "collocate_data optimization" begin + data = rand(2, 20) + tpoints = collect(range(0.0, 1.0, length = 20)) + JET.@test_opt target_modules = (DataCollocations,) collocate_data(data, tpoints, TriangularKernel(), 0.1) + end +end diff --git a/test/runtests.jl b/test/runtests.jl index 043a5e0..f24d4fc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,142 +1,129 @@ +using Pkg using DataCollocations using Test using OrdinaryDiffEq using DataInterpolations using JLArrays -using JET -@testset "DataCollocations.jl" begin - bounded_support_kernels = [ - EpanechnikovKernel(), UniformKernel(), TriangularKernel(), - QuarticKernel(), TriweightKernel(), TricubeKernel(), CosineKernel(), - ] +const GROUP = get(ENV, "GROUP", "All") - unbounded_support_kernels = [ - GaussianKernel(), LogisticKernel(), SigmoidKernel(), SilvermanKernel(), - ] +if GROUP == "QA" + Pkg.activate(joinpath(@__DIR__, "qa")) + Pkg.develop(PackageSpec(path = dirname(@__DIR__))) + Pkg.instantiate() + include(joinpath(@__DIR__, "qa", "qa.jl")) +else + @testset "DataCollocations.jl" begin + bounded_support_kernels = [ + EpanechnikovKernel(), UniformKernel(), TriangularKernel(), + QuarticKernel(), TriweightKernel(), TricubeKernel(), CosineKernel(), + ] - @testset "Kernel Functions" begin - ts = collect(-5.0:0.1:5.0) - @testset "Kernels with support from -1 to 1" begin - minus_one_index = findfirst(x -> ==(x, -1.0), ts) - plus_one_index = findfirst(x -> ==(x, 1.0), ts) - @testset "$kernel" for (kernel, x0) in zip( - bounded_support_kernels, - [0.75, 0.5, 1.0, 15.0 / 16.0, 35.0 / 32.0, 70.0 / 81.0, pi / 4.0] - ) - ws = DataCollocations.calckernel.((kernel,), ts) - # t < -1 - @test all(ws[1:(minus_one_index - 1)] .== 0.0) - # t > 1 - @test all(ws[(plus_one_index + 1):end] .== 0.0) - # -1 < t <1 - @test all(ws[(minus_one_index + 1):(plus_one_index - 1)] .> 0.0) - # t = 0 - @test DataCollocations.calckernel(kernel, 0.0) == x0 + unbounded_support_kernels = [ + GaussianKernel(), LogisticKernel(), SigmoidKernel(), SilvermanKernel(), + ] + + @testset "Kernel Functions" begin + ts = collect(-5.0:0.1:5.0) + @testset "Kernels with support from -1 to 1" begin + minus_one_index = findfirst(x -> ==(x, -1.0), ts) + plus_one_index = findfirst(x -> ==(x, 1.0), ts) + @testset "$kernel" for (kernel, x0) in zip( + bounded_support_kernels, + [0.75, 0.5, 1.0, 15.0 / 16.0, 35.0 / 32.0, 70.0 / 81.0, pi / 4.0] + ) + ws = DataCollocations.calckernel.((kernel,), ts) + # t < -1 + @test all(ws[1:(minus_one_index - 1)] .== 0.0) + # t > 1 + @test all(ws[(plus_one_index + 1):end] .== 0.0) + # -1 < t <1 + @test all(ws[(minus_one_index + 1):(plus_one_index - 1)] .> 0.0) + # t = 0 + @test DataCollocations.calckernel(kernel, 0.0) == x0 + end end - end - @testset "Kernels with unbounded support" begin - @testset "$kernel" for (kernel, x0) in zip( - unbounded_support_kernels, - [1 / (sqrt(2 * pi)), 0.25, 1 / pi, 1 / (2 * sqrt(2))] - ) - # t = 0 - @test DataCollocations.calckernel(kernel, 0.0) == x0 + @testset "Kernels with unbounded support" begin + @testset "$kernel" for (kernel, x0) in zip( + unbounded_support_kernels, + [1 / (sqrt(2 * pi)), 0.25, 1 / pi, 1 / (2 * sqrt(2))] + ) + # t = 0 + @test DataCollocations.calckernel(kernel, 0.0) == x0 + end end end - end - @testset "Collocation of data" begin - f(u, p, t) = p .* u - rc = 2 - ps = repeat([-0.001], rc) - tspan = (0.0, 10.0) # Reduced time span - u0 = 3.4 .+ ones(rc) - t = collect(range(minimum(tspan); stop = maximum(tspan), length = 100)) # Reduced data points - prob = ODEProblem(f, u0, tspan, ps) - data = Array(solve(prob, Tsit5(); saveat = t, abstol = 1.0e-12, reltol = 1.0e-12)) - @testset "$kernel" for kernel in [ - bounded_support_kernels..., unbounded_support_kernels..., - ] - u′, u = collocate_data(data, t, kernel, 0.1) # Higher bandwidth - @test sum(abs2, u - data) < 1.0e-6 # More lenient tolerance - end - @testset "$kernel" for kernel in [bounded_support_kernels...] - # Errors out as the bandwidth is too low - @test_throws ErrorException collocate_data(data, t, kernel, 0.001) + @testset "Collocation of data" begin + f(u, p, t) = p .* u + rc = 2 + ps = repeat([-0.001], rc) + tspan = (0.0, 10.0) # Reduced time span + u0 = 3.4 .+ ones(rc) + t = collect(range(minimum(tspan); stop = maximum(tspan), length = 100)) # Reduced data points + prob = ODEProblem(f, u0, tspan, ps) + data = Array(solve(prob, Tsit5(); saveat = t, abstol = 1.0e-12, reltol = 1.0e-12)) + @testset "$kernel" for kernel in [ + bounded_support_kernels..., unbounded_support_kernels..., + ] + u′, u = collocate_data(data, t, kernel, 0.1) # Higher bandwidth + @test sum(abs2, u - data) < 1.0e-6 # More lenient tolerance + end + @testset "$kernel" for kernel in [bounded_support_kernels...] + # Errors out as the bandwidth is too low + @test_throws ErrorException collocate_data(data, t, kernel, 0.001) + end end - end - @testset "DataInterpolations Extension" begin - # Test with simple data - t = 0.0:0.1:1.0 - data = sin.(t) - tpoints_sample = 0.05:0.1:0.95 + @testset "DataInterpolations Extension" begin + # Test with simple data + t = 0.0:0.1:1.0 + data = sin.(t) + tpoints_sample = 0.05:0.1:0.95 - # Test that the extension method works - du, u = collocate_data(data, collect(t), collect(tpoints_sample), LinearInterpolation) - @test length(du) == length(tpoints_sample) - @test length(u) == length(tpoints_sample) - end + # Test that the extension method works + du, u = collocate_data(data, collect(t), collect(tpoints_sample), LinearInterpolation) + @test length(du) == length(tpoints_sample) + @test length(u) == length(tpoints_sample) + end - @testset "Interface Compatibility" begin - @testset "BigFloat support" begin - # Test that BigFloat inputs are supported and eltype is preserved - tpoints = BigFloat.(collect(range(0.0, stop = 10.0, length = 30))) - data = BigFloat.(reshape(sin.(Float64.(tpoints)), 1, :)) - bandwidth = BigFloat(0.5) + @testset "Interface Compatibility" begin + @testset "BigFloat support" begin + # Test that BigFloat inputs are supported and eltype is preserved + tpoints = BigFloat.(collect(range(0.0, stop = 10.0, length = 30))) + data = BigFloat.(reshape(sin.(Float64.(tpoints)), 1, :)) + bandwidth = BigFloat(0.5) - kernels = [ - EpanechnikovKernel(), UniformKernel(), TriangularKernel(), - QuarticKernel(), TriweightKernel(), TricubeKernel(), - GaussianKernel(), CosineKernel(), LogisticKernel(), - SigmoidKernel(), SilvermanKernel(), - ] + kernels = [ + EpanechnikovKernel(), UniformKernel(), TriangularKernel(), + QuarticKernel(), TriweightKernel(), TricubeKernel(), + GaussianKernel(), CosineKernel(), LogisticKernel(), + SigmoidKernel(), SilvermanKernel(), + ] - @testset "$kernel" for kernel in kernels - u_prime, u = collocate_data(data, tpoints, kernel, bandwidth) - @test eltype(u_prime) == BigFloat - @test eltype(u) == BigFloat + @testset "$kernel" for kernel in kernels + u_prime, u = collocate_data(data, tpoints, kernel, bandwidth) + @test eltype(u_prime) == BigFloat + @test eltype(u) == BigFloat + end end - end - @testset "GPU array error message" begin - # Test that GPU-like arrays (JLArrays) give a clear error message - # instead of cryptic scalar indexing errors - tpoints = JLArray([1.0, 2.0, 3.0, 4.0, 5.0]) - data = JLArray([1.0 2.0 3.0 4.0 5.0]) + @testset "GPU array error message" begin + # Test that GPU-like arrays (JLArrays) give a clear error message + # instead of cryptic scalar indexing errors + tpoints = JLArray([1.0, 2.0, 3.0, 4.0, 5.0]) + data = JLArray([1.0 2.0 3.0 4.0 5.0]) - @test_throws ArgumentError collocate_data(data, tpoints) + @test_throws ArgumentError collocate_data(data, tpoints) - # Also test that only GPU tpoints triggers error - tpoints_cpu = collect(1.0:5.0) - @test_throws ArgumentError collocate_data(data, tpoints_cpu) + # Also test that only GPU tpoints triggers error + tpoints_cpu = collect(1.0:5.0) + @test_throws ArgumentError collocate_data(data, tpoints_cpu) - # And only GPU data triggers error - data_cpu = reshape(collect(1.0:5.0), 1, :) - @test_throws ArgumentError collocate_data(data_cpu, tpoints) - end - end - - @testset "JET Static Analysis" begin - # Test kernel functions for type stability - @testset "calckernel optimization" begin - kernels = [ - EpanechnikovKernel(), UniformKernel(), TriangularKernel(), - QuarticKernel(), TriweightKernel(), TricubeKernel(), - GaussianKernel(), CosineKernel(), LogisticKernel(), - SigmoidKernel(), SilvermanKernel(), - ] - @testset "$kernel" for kernel in kernels - JET.@test_opt target_modules = (DataCollocations,) DataCollocations.calckernel(kernel, 0.5) + # And only GPU data triggers error + data_cpu = reshape(collect(1.0:5.0), 1, :) + @test_throws ArgumentError collocate_data(data_cpu, tpoints) end end - - # Test main collocate_data function - @testset "collocate_data optimization" begin - data = rand(2, 20) - tpoints = collect(range(0.0, 1.0, length = 20)) - JET.@test_opt target_modules = (DataCollocations,) collocate_data(data, tpoints, TriangularKernel(), 0.1) - end end end diff --git a/test/test_groups.toml b/test/test_groups.toml new file mode 100644 index 0000000..8d7b74e --- /dev/null +++ b/test/test_groups.toml @@ -0,0 +1,6 @@ +[Core] +versions = ["lts", "1", "pre"] +os = ["ubuntu-latest", "windows-latest", "macos-latest"] + +[QA] +versions = ["lts", "1"]