Skip to content

Commit

Permalink
Merge pull request #3526 from JuliaReach/schillic/is_interior_point
Browse files Browse the repository at this point in the history
Support `is_interior_point` for mixed numeric types
  • Loading branch information
schillic committed Jun 26, 2024
2 parents c424435 + b61f93d commit c563f50
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 11 deletions.
2 changes: 1 addition & 1 deletion docs/src/lib/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ volume(::LazySet)
affine_map(::AbstractMatrix, ::LazySet, ::AbstractVector)
exponential_map(::AbstractMatrix, ::LazySet)
∈(::AbstractVector, ::LazySet)
is_interior_point(::AbstractVector{N}, ::LazySet; p=Inf, ε=_rtol(N)) where {N<:Real}
is_interior_point(::AbstractVector{<:Real}, ::LazySet; kwargs...)
linear_map(::AbstractMatrix, ::LazySet)
permute(::LazySet, ::AbstractVector{Int})
project(::LazySet, ::AbstractVector{Int})
Expand Down
2 changes: 1 addition & 1 deletion docs/src/lib/interfaces/LazySet.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ exponential_map(::AbstractMatrix, ::LazySet)
an_element(::LazySet)
tosimplehrep(::LazySet)
reflect(::LazySet)
is_interior_point(::AbstractVector{N}, ::LazySet{N}; p=Inf, ε=_rtol(N)) where {N<:Real}
is_interior_point(::AbstractVector{<:Real}, ::LazySet; kwargs...)
isoperation(::LazySet)
isequivalent(::LazySet, ::LazySet)
surface(::LazySet)
Expand Down
8 changes: 4 additions & 4 deletions src/API/Mixed/is_interior_point.jl
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
"""
is_interior_point(v::AbstractVector{N}, X::LazySet; [p]=N(Inf), [ε]=_rtol(N)) where {N}
is_interior_point(v::AbstractVector{<:Real}, X::LazySet; kwargs...) end
Check whether a point is contained in the interior of a set.
### Input
- `v` -- point/vector
- `X` -- set
- `p` -- (optional; default: `N(Inf)`) norm of the ball used to apply the error
- `p` -- (optional; default: `Inf`) norm of the ball used to apply the error
tolerance
- `ε` -- (optional; default: `_rtol(N)`) error tolerance of the check
- `ε` -- (optional; default: `_rtol(eltype(X))`) error tolerance of the check
### Output
`true` iff the point `v` is strictly contained in `X` with tolerance `ε`.
"""
function is_interior_point(::AbstractVector{N}, ::LazySet; p=N(Inf), ε=_rtol(N)) where {N} end
function is_interior_point(::AbstractVector{<:Real}, ::LazySet; kwargs...) end
17 changes: 16 additions & 1 deletion src/Interfaces/LazySet.jl
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,22 @@ The default implementation determines `v ∈ interior(X)` with error tolerance
`ε` by checking whether a `Ballp` of norm `p` with center `v` and radius `ε` is
contained in `X`.
"""
function is_interior_point(v::AbstractVector{N}, X::LazySet{N}; p=N(Inf), ε=_rtol(N)) where {N}
function is_interior_point(v::AbstractVector{<:Real}, X::LazySet; kwargs...)
N = promote_type(eltype(v), eltype(X))
if N != eltype(X)
throw(ArgumentError("the set eltype must be more general"))
end
if N != eltype(v)
v = convert(Vector{N}, v)
end
ε = get(kwargs, , _rtol(N))
p = get(kwargs, :p, N(Inf))
return is_interior_point(v, X; p=p, ε=ε)
end

function is_interior_point(v::AbstractVector{N}, X::LazySet{N}; p=N(Inf),
ε=_rtol(N)) where {N<:Real}
@assert ε > zero(N) "the tolerance must be strictly positive"
return Ballp(p, v, ε) X
end

Expand Down
16 changes: 12 additions & 4 deletions test/ConcreteOperations/interior.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
for N in [Float64, Rational{Int}, Float32]
P = BallInf(zeros(N, 2), N(1 // 10))
d = N[1 // 10, 1 // 10]
answer = is_interior_point(d, P)
@test answer == (N <: Rational)
if N <: AbstractFloat
@test !is_interior_point(d, P)
else
@test_throws AssertionError is_interior_point(d, P)
@test !is_interior_point(d, P; ε=1//100)
end
@test !is_interior_point(d, P; ε=N(1))
@test is_interior_point(d, P; ε=N(0))
@test_throws AssertionError is_interior_point(d, P; ε=N(0))

d = N[1 // 10, 1 // 10] .- LazySets._rtol(N)
@test is_interior_point(d, P)
if N <: AbstractFloat
@test is_interior_point(d, P)
else
@test !is_interior_point(d, P; ε=1//100)
end
end

# tests that do not work with Rational{Int}
Expand Down
19 changes: 19 additions & 0 deletions test/Sets/Interval.jl
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,25 @@ for N in [Float64, Float32, Rational{Int}]
gens = collect(generators(x_degenerate))
@test isempty(gens) && gens isa Vector{SingleEntryVector{N}}

# is_interior_point
v1 = N[3/2]
v2 = N[1]
if N <: AbstractFloat
@test is_interior_point(v1, x) && !is_interior_point(v2, x)
else
@test_throws AssertionError is_interior_point(v1, x)
@test is_interior_point(v1, x; ε=1//100) && !is_interior_point(v2, x; ε=1//100)
end
# different numeric type
v1 = Float16[3/2]
if N <: AbstractFloat
v2 = Float16[1]
@test is_interior_point(v1, x) && !is_interior_point(v2, x)
else
@test_throws ArgumentError is_interior_point(v1, x)
@test_throws ArgumentError is_interior_point(v1, x; ε=1//100)
end

# Chebyshev center
c, r = chebyshev_center_radius(x)
@test c == center(x) && r == N(1 // 2)
Expand Down

0 comments on commit c563f50

Please sign in to comment.