From c8be74930aa352aea8713084a9a13a21c6742152 Mon Sep 17 00:00:00 2001 From: SatoshiTerasaki Date: Thu, 12 Dec 2024 15:45:34 +0900 Subject: [PATCH 1/4] Add type annotation for 1grid` --- src/_roots.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/_roots.jl b/src/_roots.jl index eeaf49b..76df061 100644 --- a/src/_roots.jl +++ b/src/_roots.jl @@ -39,10 +39,10 @@ end closeenough(a::T, b::T, ϵ) where {T<:AbstractFloat} = isapprox(a, b; rtol=0, atol=ϵ) closeenough(a::T, b::T, _) where {T<:Integer} = a == b -function refine_grid(grid, ::Val{α}) where {α} +function refine_grid(grid::Vector{T}, ::Val{α}) where {T, α} n = length(grid) newn = α * (n - 1) + 1 - newgrid = Vector{eltype(grid)}(undef, newn) + newgrid = Vector{float(T)}(undef, newn) @inbounds for i in 1:(n - 1) xb = grid[i] From 5ad2767e14ce6d2b474b0d211c7ccdea7b211fc4 Mon Sep 17 00:00:00 2001 From: SatoshiTerasaki Date: Thu, 12 Dec 2024 15:46:00 +0900 Subject: [PATCH 2/4] Empty input array should return itself --- src/_roots.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_roots.jl b/src/_roots.jl index 76df061..54d7f8b 100644 --- a/src/_roots.jl +++ b/src/_roots.jl @@ -40,6 +40,7 @@ closeenough(a::T, b::T, ϵ) where {T<:AbstractFloat} = isapprox(a, b; rtol=0, at closeenough(a::T, b::T, _) where {T<:Integer} = a == b function refine_grid(grid::Vector{T}, ::Val{α}) where {T, α} + isempty(grid) && return grid n = length(grid) newn = α * (n - 1) + 1 newgrid = Vector{float(T)}(undef, newn) From 96bbdec8ec764cacb57f874da7c50953f322f896 Mon Sep 17 00:00:00 2001 From: SatoshiTerasaki Date: Thu, 12 Dec 2024 15:47:40 +0900 Subject: [PATCH 3/4] Add tests for refine_grid --- test/_roots.jl | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/test/_roots.jl b/test/_roots.jl index 45ac513..c0ca36c 100644 --- a/test/_roots.jl +++ b/test/_roots.jl @@ -2,6 +2,79 @@ using Test using SparseIR @testset "_roots.jl" begin + @testset "refine_grid" begin + @testset "Basic refinement" begin + # Test with α = 2 + grid = [0.0, 1.0, 2.0] + refined = SparseIR.refine_grid(grid, Val(2)) + @test length(refined) == 5 # α * (n-1) + 1 = 2 * (3-1) + 1 = 5 + @test refined ≈ [0.0, 0.5, 1.0, 1.5, 2.0] + + # Test with α = 3 + refined3 = SparseIR.refine_grid(grid, Val(3)) + @test length(refined3) == 7 # α * (n-1) + 1 = 3 * (3-1) + 1 = 7 + @test refined3 ≈ [0.0, 1/3, 2/3, 1.0, 4/3, 5/3, 2.0] + + # Test with α = 4 + refined4 = SparseIR.refine_grid(grid, Val(4)) + @test length(refined4) == 9 # α * (n-1) + 1 = 4 * (3-1) + 1 = 9 + @test refined4 ≈ [0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0] + end + + #= + Currently the SparseIR.refine_grid function is used only for the + SparseIR.find_all function, which should accept only Float64 grids, but + just in case it is a good idea to test that it works for other types. + =# + @testset "Type stability" begin + # Integer grid + int_grid = [0, 1, 2] + refined_int = SparseIR.refine_grid(int_grid, Val(2)) + @test eltype(refined_int) === Float64 + @test refined_int == [0.0, 0.5, 1.0, 1.5, 2.0] + + # Float32 grid + f32_grid = Float32[0, 1, 2] + refined_f32 = SparseIR.refine_grid(f32_grid, Val(2)) + @test eltype(refined_f32) === Float32 + @test refined_f32 ≈ Float32[0, 0.5, 1, 1.5, 2] + end + + @testset "Edge cases" begin + # Single interval + single_interval = [0.0, 1.0] + refined_single = SparseIR.refine_grid(single_interval, Val(4)) + @test length(refined_single) == 5 # α * (2-1) + 1 = 4 * 1 + 1 = 5 + @test refined_single ≈ [0.0, 0.25, 0.5, 0.75, 1.0] + + # Empty grid + empty_grid = Float64[] + @test isempty(SparseIR.refine_grid(empty_grid, Val(2))) + + # Single point + single_point = [1.0] + @test SparseIR.refine_grid(single_point, Val(2)) == [1.0] + end + + @testset "Uneven spacing" begin + # Test with unevenly spaced grid + uneven = [0.0, 1.0, 10.0] + refined_uneven = SparseIR.refine_grid(uneven, Val(2)) + @test length(refined_uneven) == 5 + @test refined_uneven[1:3] ≈ [0.0, 0.5, 1.0] # First interval + @test refined_uneven[3:5] ≈ [1.0, 5.5, 10.0] # Second interval + end + + @testset "Preservation of endpoints" begin + grid = [-1.0, 0.0, 1.0] + for α in [2, 3, 4] + refined = SparseIR.refine_grid(grid, Val(α)) + @test first(refined) == first(grid) + @test last(refined) == last(grid) + end + end + end + @testset "discrete_extrema" begin nonnegative = collect(0:8) symmetric = collect(-8:8) From eee06e853b6a6d1a9400510824ebeae91990cb0c Mon Sep 17 00:00:00 2001 From: SatoshiTerasaki Date: Thu, 12 Dec 2024 16:34:55 +0900 Subject: [PATCH 4/4] Return `float(T)[]` so that refine_grid should be type stable --- src/_roots.jl | 2 +- test/_roots.jl | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/_roots.jl b/src/_roots.jl index 54d7f8b..aa784e2 100644 --- a/src/_roots.jl +++ b/src/_roots.jl @@ -40,7 +40,7 @@ closeenough(a::T, b::T, ϵ) where {T<:AbstractFloat} = isapprox(a, b; rtol=0, at closeenough(a::T, b::T, _) where {T<:Integer} = a == b function refine_grid(grid::Vector{T}, ::Val{α}) where {T, α} - isempty(grid) && return grid + isempty(grid) && return float(T)[] n = length(grid) newn = α * (n - 1) + 1 newgrid = Vector{float(T)}(undef, newn) diff --git a/test/_roots.jl b/test/_roots.jl index c0ca36c..453cc24 100644 --- a/test/_roots.jl +++ b/test/_roots.jl @@ -6,7 +6,7 @@ using SparseIR @testset "Basic refinement" begin # Test with α = 2 grid = [0.0, 1.0, 2.0] - refined = SparseIR.refine_grid(grid, Val(2)) + refined = @inferred SparseIR.refine_grid(grid, Val(2)) @test length(refined) == 5 # α * (n-1) + 1 = 2 * (3-1) + 1 = 5 @test refined ≈ [0.0, 0.5, 1.0, 1.5, 2.0] @@ -29,13 +29,13 @@ using SparseIR @testset "Type stability" begin # Integer grid int_grid = [0, 1, 2] - refined_int = SparseIR.refine_grid(int_grid, Val(2)) - @test eltype(refined_int) === Float64 - @test refined_int == [0.0, 0.5, 1.0, 1.5, 2.0] + refined = @inferred SparseIR.refine_grid(int_grid, Val(2)) + @test eltype(refined) === Float64 + @test refined == [0.0, 0.5, 1.0, 1.5, 2.0] # Float32 grid f32_grid = Float32[0, 1, 2] - refined_f32 = SparseIR.refine_grid(f32_grid, Val(2)) + refined_f32 = @inferred SparseIR.refine_grid(f32_grid, Val(2)) @test eltype(refined_f32) === Float32 @test refined_f32 ≈ Float32[0, 0.5, 1, 1.5, 2] end @@ -50,7 +50,11 @@ using SparseIR # Empty grid empty_grid = Float64[] @test isempty(SparseIR.refine_grid(empty_grid, Val(2))) - + # Empty grid + empty_grid = Int[] + out_grid = SparseIR.refine_grid(empty_grid, Val(2)) + @test isempty(out_grid) + @test eltype(out_grid) === Float64 # Single point single_point = [1.0] @test SparseIR.refine_grid(single_point, Val(2)) == [1.0]