Skip to content

Commit

Permalink
Merge pull request #1799 from JuliaReach/schillic/1125
Browse files Browse the repository at this point in the history
#1125 - isuniversal methods for bounded sets
  • Loading branch information
schillic authored Dec 12, 2019
2 parents 3e9a6df + 79c7f0f commit b1f61c3
Show file tree
Hide file tree
Showing 23 changed files with 225 additions and 40 deletions.
3 changes: 3 additions & 0 deletions docs/src/lib/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ This interface defines the following functions:
```@docs
dim(::AbstractCentrallySymmetric)
isbounded(::AbstractCentrallySymmetric)
isuniversal(::AbstractCentrallySymmetric{N}, ::Bool=false) where {N<:Real}
an_element(::AbstractCentrallySymmetric{N}) where {N<:Real}
isempty(::AbstractCentrallySymmetric)
```
Expand All @@ -129,6 +130,7 @@ This interface defines the following functions:

```@docs
∈(::AbstractVector{N}, ::AbstractPolyhedron{N}) where {N<:Real}
isuniversal(::AbstractPolyhedron{N}, ::Bool=false) where {N<:Real}
constrained_dimensions(::AbstractPolyhedron)
linear_map(::AbstractMatrix{N}, ::AbstractPolyhedron{N}) where {N<:Real}
chebyshev_center(::AbstractPolyhedron{N}) where {N<:AbstractFloat}
Expand All @@ -155,6 +157,7 @@ This interface defines the following functions:

```@docs
isbounded(::AbstractPolytope)
isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real}
singleton_list(::AbstractPolytope{N}) where {N<:Real}
isempty(::AbstractPolytope)
```
Expand Down
21 changes: 20 additions & 1 deletion docs/src/lib/representations.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Inherited from [`AbstractCentrallySymmetric`](@ref):
* [`dim`](@ref dim(::AbstractCentrallySymmetric))
* [`isbounded`](@ref isbounded(::AbstractCentrallySymmetric))
* [`isempty`](@ref isempty(::AbstractCentrallySymmetric))
* [`isuniversal`](@ref isuniversal(::AbstractCentrallySymmetric{N}, ::Bool=false) where {N<:Real})
* [`an_element`](@ref an_element(::AbstractCentrallySymmetric{N}) where {N<:Real})

### Infinity norm ball
Expand All @@ -56,6 +57,7 @@ Inherited from [`LazySet`](@ref):

Inherited from [`AbstractPolytope`](@ref):
* [`isbounded`](@ref isbounded(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})

Inherited from [`AbstractCentrallySymmetricPolytope`](@ref):
Expand Down Expand Up @@ -98,6 +100,7 @@ Inherited from [`LazySet`](@ref):

Inherited from [`AbstractPolytope`](@ref):
* [`isbounded`](@ref isbounded(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})

Inherited from [`AbstractCentrallySymmetricPolytope`](@ref):
Expand All @@ -124,6 +127,7 @@ Inherited from [`AbstractCentrallySymmetric`](@ref):
* [`dim`](@ref dim(::AbstractCentrallySymmetric))
* [`isbounded`](@ref isbounded(::AbstractCentrallySymmetric))
* [`isempty`](@ref isempty(::AbstractCentrallySymmetric))
* [`isuniversal`](@ref isuniversal(::AbstractCentrallySymmetric{N}, ::Bool=false) where {N<:Real})
* [`an_element`](@ref an_element(::AbstractCentrallySymmetric{N}) where {N<:Real})

## Ellipsoid
Expand All @@ -146,6 +150,7 @@ Inherited from [`AbstractCentrallySymmetric`](@ref):
* [`dim`](@ref dim(::AbstractCentrallySymmetric))
* [`isbounded`](@ref isbounded(::AbstractCentrallySymmetric))
* [`isempty`](@ref isempty(::AbstractCentrallySymmetric))
* [`isuniversal`](@ref isuniversal(::AbstractCentrallySymmetric{N}, ::Bool=false) where {N<:Real})
* [`an_element`](@ref an_element(::AbstractCentrallySymmetric{N}) where {N<:Real})

## Empty set
Expand All @@ -161,6 +166,7 @@ an_element(::EmptySet)
rand(::Type{EmptySet})
isbounded(::EmptySet)
isempty(::EmptySet)
isuniversal(::EmptySet{N}, ::Bool=false) where {N<:Real}
norm(::EmptySet, ::Real=Inf)
radius(::EmptySet, ::Real=Inf)
diameter(::EmptySet, ::Real=Inf)
Expand Down Expand Up @@ -240,6 +246,7 @@ Inherited from [`LazySet`](@ref):

Inherited from [`AbstractPolytope`](@ref):
* [`isbounded`](@ref isbounded(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})

Inherited from [`AbstractCentrallySymmetricPolytope`](@ref):
Expand Down Expand Up @@ -297,6 +304,7 @@ Inherited from [`LazySet`](@ref):

Inherited from [`AbstractPolytope`](@ref):
* [`isbounded`](@ref isbounded(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})

Inherited from [`AbstractCentrallySymmetricPolytope`](@ref):
Expand Down Expand Up @@ -362,6 +370,7 @@ Inherited from [`LazySet`](@ref):

Inherited from [`AbstractPolytope`](@ref):
* [`isbounded`](@ref isbounded(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})

Inherited from [`AbstractCentrallySymmetricPolytope`](@ref):
* [`isempty`](@ref isempty(::AbstractCentrallySymmetricPolytope))
Expand All @@ -387,6 +396,7 @@ Inherited from [`LazySet`](@ref):

Inherited from [`AbstractPolytope`](@ref):
* [`isempty`](@ref isempty(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})
* [`linear_map`](@ref linear_map(::AbstractMatrix{N}, ::AbstractPolyhedron{N}) where {N<:Real})

Expand Down Expand Up @@ -419,6 +429,7 @@ Inherited from [`LazySet`](@ref):

Inherited from [`AbstractPolytope`](@ref):
* [`isempty`](@ref isempty(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})

Inherited from [`AbstractPolygon`](@ref):
Expand Down Expand Up @@ -460,6 +471,7 @@ Inherited from [`LazySet`](@ref):
Inherited from [`AbstractPolytope`](@ref):
* [`isbounded`](@ref isbounded(::AbstractPolytope))
* [`isempty`](@ref isempty(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})
* [`linear_map`](@ref linear_map(::AbstractMatrix{N}, ::AbstractPolyhedron{N}) where {N<:Real})

Expand Down Expand Up @@ -528,6 +540,7 @@ isbounded(::HPolytope, ::Bool=true)

Inherited from [`AbstractPolytope`](@ref):
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})

#### Polyhedra

Expand All @@ -536,11 +549,13 @@ The following methods are specific for `HPolyhedron`.
```@docs
rand(::Type{HPolyhedron})
isbounded(::HPolyhedron)
isuniversal(::HPolyhedron{N}, ::Bool=false) where {N<:Real}
vertices_list(::HPolyhedron{N}) where {N<:Real}
singleton_list(::HPolyhedron{N}) where {N<:Real}
```

Inherited from [`AbstractPolyhedron`](@ref):
* [`isuniversal`](@ref isuniversal(::AbstractPolyhedron{N}, ::Bool=false) where {N<:Real})

### Vertex representation

```@docs
Expand All @@ -566,6 +581,7 @@ Inherited from [`LazySet`](@ref):
Inherited from [`AbstractPolytope`](@ref):
* [`isbounded`](@ref isbounded(::AbstractPolytope))
* [`isempty`](@ref isempty(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})
* [`linear_map`](@ref linear_map(::AbstractMatrix{N}, ::AbstractPolyhedron{N}) where {N<:Real})

Expand Down Expand Up @@ -596,6 +612,7 @@ Inherited from [`LazySet`](@ref):

Inherited from [`AbstractPolytope`](@ref):
* [`isbounded`](@ref isbounded(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})

Inherited from [`AbstractCentrallySymmetricPolytope`](@ref):
Expand Down Expand Up @@ -665,6 +682,7 @@ Inherited from [`LazySet`](@ref):

Inherited from [`AbstractPolytope`](@ref):
* [`isbounded`](@ref isbounded(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})

Inherited from [`AbstractCentrallySymmetricPolytope`](@ref):
Expand Down Expand Up @@ -711,6 +729,7 @@ Inherited from [`LazySet`](@ref):

Inherited from [`AbstractPolytope`](@ref):
* [`isbounded`](@ref isbounded(::AbstractPolytope))
* [`isuniversal`](@ref isuniversal(::AbstractPolytope{N}, ::Bool=false) where {N<:Real})
* [`singleton_list`](@ref singleton_list(::AbstractPolytope{N}) where {N<:Real})

Inherited from [`AbstractCentrallySymmetricPolytope`](@ref):
Expand Down
32 changes: 32 additions & 0 deletions src/Interfaces/AbstractCentrallySymmetric.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,35 @@ Return if a centrally symmetric set is empty or not.
function isempty(::AbstractCentrallySymmetric)::Bool
return false
end

"""
isuniversal(S::AbstractCentrallySymmetric{N}, [witness]::Bool=false
)::Union{Bool, Tuple{Bool, Vector{N}}} where {N<:Real}
Check whether a centrally symmetric set is universal.
### Input
- `S` -- centrally symmetric set
- `witness` -- (optional, default: `false`) compute a witness if activated
### Output
* If `witness` option is deactivated: `false`
* If `witness` option is activated: `(false, v)` where ``v ∉ S``
### Algorithm
A witness is obtained by computing the support vector in direction
`d = [1, 0, …, 0]` and adding `d` on top.
"""
function isuniversal(S::AbstractCentrallySymmetric{N}, witness::Bool=false
)::Union{Bool, Tuple{Bool, Vector{N}}} where {N<:Real}
if witness
d = SingleEntryVector{N}(1, dim(S))
w = σ(d, S) + d
return (false, w)
else
return false
end
end
35 changes: 35 additions & 0 deletions src/Interfaces/AbstractPolyhedron_functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,41 @@ function ∈(x::AbstractVector{N}, P::AbstractPolyhedron{N})::Bool where {N<:Rea
return true
end

"""
isuniversal(P::AbstractPolyhedron{N}, [witness]::Bool=false
)::Union{Bool, Tuple{Bool, Vector{N}}} where {N<:Real}
Check whether a polyhedron is universal.
### Input
- `P` -- polyhedron
- `witness` -- (optional, default: `false`) compute a witness if activated
### Output
* If `witness` option is deactivated: `true` iff ``P`` is universal
* If `witness` option is activated:
* `(true, [])` iff ``P`` is universal
* `(false, v)` iff ``P`` is not universal and ``v ∉ P``
### Algorithm
`P` is universal iff it has no constraints.
A witness is produced using `isuniversal(H)` where `H` is the first linear
constraint of `P`.
"""
function isuniversal(P::AbstractPolyhedron{N}, witness::Bool=false
)::Union{Bool, Tuple{Bool, Vector{N}}} where {N<:Real}
constraints = constraints_list(P)
if isempty(constraints)
return witness ? (true, N[]) : true
else
return witness ? isuniversal(constraints[1], true) : false
end
end

"""
constrained_dimensions(P::AbstractPolyhedron)::Vector{Int} where {N<:Real}
Expand Down
34 changes: 34 additions & 0 deletions src/Interfaces/AbstractPolytope.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,40 @@ function isempty(P::AbstractPolytope)::Bool
return isempty(vertices_list(P))
end

"""
isuniversal(P::AbstractPolytope{N}, [witness]::Bool=false
)::Union{Bool, Tuple{Bool, Vector{N}}} where {N<:Real}
Check whether a polyhedron is universal.
### Input
- `P` -- polyhedron
- `witness` -- (optional, default: `false`) compute a witness if activated
### Output
* If `witness` option is deactivated: `false`
* If `witness` option is activated: `(false, v)` where ``v ∉ P``
### Algorithm
A witness is produced using `isuniversal(H)` where `H` is the first linear
constraint of `P`.
"""
function isuniversal(P::AbstractPolytope{N}, witness::Bool=false
)::Union{Bool, Tuple{Bool, Vector{N}}} where {N<:Real}
if witness
constraints = constraints_list(P)
if isempty(constraints)
return (true, N[]) # special case for polytopes without constraints
end
return isuniversal(constraints[1], true)
else
return false
end
end

# given a polytope P, apply the linear map P to each vertex of P
# it is assumed that the interface function `vertices_list(P)` is available
@inline function _linear_map_vrep(M::AbstractMatrix{N}, P::AbstractPolytope{N}) where {N<:Real}
Expand Down
27 changes: 27 additions & 0 deletions src/Sets/EmptySet.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,33 @@ function isbounded(::EmptySet)::Bool
return true
end

"""
isuniversal(∅::EmptySet{N}, [witness]::Bool=false
)::Union{Bool, Tuple{Bool, Vector{N}}} where {N<:Real}
Check whether an empty is universal.
### Input
- `∅` -- empty set
- `witness` -- (optional, default: `false`) compute a witness if activated
### Output
* If `witness` option is deactivated: `false`
* If `witness` option is activated: `(false, v)` where ``v ∉ S``, although
we currently throw an error
"""
function isuniversal(∅::EmptySet{N}, witness::Bool=false
)::Union{Bool, Tuple{Bool, Vector{N}}} where {N<:Real}
if witness
error("witness production is currently not supported")
# return (false, zeros(N, dim(∅))) # deactivated, see #1201
else
return false
end
end

"""
∈(x::AbstractVector{N}, ∅::EmptySet{N})::Bool where {N<:Real}
Expand Down
34 changes: 0 additions & 34 deletions src/Sets/HPolyhedron.jl
Original file line number Diff line number Diff line change
Expand Up @@ -215,40 +215,6 @@ function isbounded(P::HPolyhedron)::Bool
return isbounded_unit_dimensions(P)
end

"""
isuniversal(P::HPolyhedron{N}, [witness]::Bool=false
)::Union{Bool, Tuple{Bool, Vector{N}}} where {N<:Real}
Check whether a polyhedron is universal.
### Input
- `P` -- polyhedron
- `witness` -- (optional, default: `false`) compute a witness if activated
### Output
* If `witness` option is deactivated: `true` iff ``P`` is universal
* If `witness` option is activated:
* `(true, [])` iff ``P`` is universal
* `(false, v)` iff ``P`` is not universal and ``v ∉ P``
### Algorithm
`P` is universal iff it has no constraints.
A witness is produced using `isuniversal(H)` where `H` is the first linear
constraint of `P`.
"""
function isuniversal(P::HPolyhedron{N}, witness::Bool=false
)::Union{Bool, Tuple{Bool, Vector{N}}} where {N<:Real}
if isempty(P.constraints)
return witness ? (true, N[]) : true
else
return witness ? isuniversal(P.constraints[1], true) : false
end
end

"""
rand(::Type{HPolyhedron}; [N]::Type{<:Real}=Float64, [dim]::Int=2,
[rng]::AbstractRNG=GLOBAL_RNG, [seed]::Union{Int, Nothing}=nothing
Expand Down
4 changes: 4 additions & 0 deletions test/unit_Ball1.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ for N in [Float64, Rational{Int}, Float32]
# isempty
@test !isempty(b)

# isuniversal
answer, w = isuniversal(b, true)
@test !isuniversal(b) && !answer && w b

# an_element & membership function
@test an_element(b) b

Expand Down
4 changes: 4 additions & 0 deletions test/unit_Ball2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ for N in [Float64, Float32]
# isempty
@test !isempty(b)

# isuniversal
answer, w = isuniversal(b, true)
@test !isuniversal(b) && !answer && w b

# an_element function
b = Ball2(N[1, 2], N(2))
@test an_element(b) b
Expand Down
Loading

0 comments on commit b1f61c3

Please sign in to comment.