Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Outsource HPolygon to its own module #3593

Merged
merged 5 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions docs/src/lib/sets/HPolygon.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
```@meta
CurrentModule = LazySets
CurrentModule = LazySets.HPolygonModule
```

# [Polygon in constraint representation (HPolygon)](@id def_HPolygon)

```@docs
HPolygon
```

## Operations

```@docs
σ(::AbstractVector, ::HPolygon)
translate(::HPolygon, ::AbstractVector)
```

```@meta
CurrentModule = LazySets
```

Inherited from [`LazySet`](@ref):
* [`diameter`](@ref diameter(::LazySet, ::Real))
* [`norm`](@ref norm(::LazySet, ::Real))
* [`radius`](@ref radius(::LazySet, ::Real))
* [`diameter`](@ref diameter(::LazySet, ::Real))
* [`reflect`](@ref reflect(::LazySet))
* [`singleton_list`](@ref singleton_list(::LazySet))
* [`linear_map`](@ref linear_map(::AbstractMatrix, ::LazySet)
* [`reflect`](@ref reflect(::LazySet))

Inherited from [`AbstractPolytope`](@ref):
* [`isempty`](@ref isempty(::AbstractPolytope))
Expand All @@ -27,13 +37,13 @@ Inherited from [`AbstractPolygon`](@ref):

Inherited from [`AbstractHPolygon`](@ref):
* [`an_element`](@ref an_element(::AbstractHPolygon))
* [`∈`](@ref ∈(::AbstractVector, ::AbstractHPolygon))
* [`vertices_list`](@ref vertices_list(::AbstractHPolygon{N}) where {N})
* [`constraints_list`](@ref constraints_list(::AbstractHPolygon))
* [`isbounded`](@ref isbounded(::AbstractHPolygon, ::Bool=true))
* [`normalize`](@ref normalize(::AbstractHPolygon{N}, p::Real=N(2)) where {N})
* [`remove_redundant_constraints!`](@ref remove_redundant_constraints!(::AbstractHPolygon))
* [`tohrep`](@ref tohrep(::HPOLYGON) where {HPOLYGON<:AbstractHPolygon})
* [`tovrep`](@ref tovrep(::AbstractHPolygon))
* [`normalize`](@ref normalize(::AbstractHPolygon{N}, p::Real=N(2)) where {N})
* [`isbounded`](@ref isbounded(::AbstractHPolygon, ::Bool=true))
* [`vertices_list`](@ref vertices_list(::AbstractHPolygon{N}) where {N})
* [`addconstraint!`](@ref addconstraint!(::AbstractHPolygon, ::HalfSpace))
* [`∈`](@ref ∈(::AbstractVector, ::AbstractHPolygon))
* [`isredundant`](@ref isredundant(::HalfSpace, ::HalfSpace, ::HalfSpace))
* [`remove_redundant_constraints!`](@ref remove_redundant_constraints!(::AbstractHPolygon))
* [`constraints_list`](@ref constraints_list(::AbstractHPolygon))
3 changes: 2 additions & 1 deletion src/LazySets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ include("Sets/Ellipsoid/EllipsoidModule.jl")
include("Sets/DensePolynomialZonotope/DensePolynomialZonotopeModule.jl")
@reexport using ..DensePolynomialZonotopeModule: DensePolynomialZonotope

include("Sets/HPolygon.jl")
include("Sets/HPolygon/HPolygonModule.jl")
@reexport using ..HPolygonModule: HPolygon

include("Sets/HPolygonOpt.jl")

Expand Down
89 changes: 0 additions & 89 deletions src/Sets/HPolygon.jl → src/Sets/HPolygon/HPolygon.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export HPolygon

"""
HPolygon{N, VN<:AbstractVector{N}} <: AbstractHPolygon{N}

Expand Down Expand Up @@ -65,8 +63,6 @@ struct HPolygon{N,VN<:AbstractVector{N}} <: AbstractHPolygon{N}
end
end

isoperationtype(::Type{<:HPolygon}) = false

# constructor with no constraints
function HPolygon{N,VN}() where {N,VN<:AbstractVector{N}}
return HPolygon(Vector{HalfSpace{N,VN}}())
Expand All @@ -93,88 +89,3 @@ function HPolygon(A::AbstractMatrix, b::AbstractVector; sort_constraints::Bool=t
return HPolygon(constraints_list(A, b); sort_constraints=sort_constraints,
check_boundedness=check_boundedness, prune=prune)
end

"""
σ(d::AbstractVector, P::HPolygon;
[linear_search]::Bool=(length(P.constraints) < $BINARY_SEARCH_THRESHOLD))

Return a support vector of a polygon in a given direction.

### Input

- `d` -- direction
- `P` -- polygon in constraint representation
- `linear_search` -- (optional, default: see below) flag for controlling whether
to perform a linear search or a binary search

### Output

The support vector in the given direction.
The result is always one of the vertices; in particular, if the direction has
norm zero, any vertex is returned.

### Algorithm

Comparison of directions is performed using polar angles; see the definition of
`⪯` for two-dimensional vectors.

For polygons with $BINARY_SEARCH_THRESHOLD or more constraints we use a binary
search by default.
"""
function σ(d::AbstractVector, P::HPolygon;
linear_search::Bool=(length(P.constraints) < BINARY_SEARCH_THRESHOLD))
n = length(P.constraints)
@assert n > 0 "the polygon has no constraints"

if linear_search
# linear search
k = 1
while k <= n && P.constraints[k].a ⪯ d
k += 1
end
else
# binary search
k = binary_search_constraints(d, P.constraints)
end

if k == 1 || k == n + 1
# corner cases: wrap-around in constraints list
return element(_intersection_line2d(P.constraints[1], P.constraints[n]))
else
return element(_intersection_line2d(P.constraints[k], P.constraints[k - 1]))
end
end

"""
translate(v::AbstractVector, P::HPolygon; [share]::Bool=false)

Translate (i.e., shift) a polygon in constraint representation by a given
vector.

### Input

- `P` -- polygon in constraint representation
- `v` -- translation vector
- `share` -- (optional, default: `false`) flag for sharing unmodified parts of
the original set representation

### Output

A translated polygon in constraint representation.

### Notes

The normal vectors of the constraints (vector `a` in `a⋅x ≤ b`) are shared with
the original constraints if `share == true`.

### Algorithm

We translate every constraint.
"""
function translate(P::HPolygon, v::AbstractVector; share::Bool=false)
@assert length(v) == dim(P) "cannot translate a $(dim(P))-dimensional " *
"set by a $(length(v))-dimensional vector"
constraints = [translate(c, v; share=share) for c in constraints_list(P)]
return HPolygon(constraints; sort_constraints=false,
check_boundedness=false, prune=false)
end
20 changes: 20 additions & 0 deletions src/Sets/HPolygon/HPolygonModule.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module HPolygonModule

using Reexport

using ..LazySets: AbstractHPolygon, BINARY_SEARCH_THRESHOLD, addconstraint!,
binary_search_constraints, element, ⪯, _intersection_line2d
using ..LazySets.HalfSpaceModule: HalfSpace, _normal_Vector

@reexport import ..API: isoperationtype, σ, translate
@reexport using ..API

export HPolygon

include("HPolygon.jl")

include("isoperationtype.jl")
include("support_vector.jl")
include("translate.jl")

end # module
1 change: 1 addition & 0 deletions src/Sets/HPolygon/isoperationtype.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
isoperationtype(::Type{<:HPolygon}) = false
50 changes: 50 additions & 0 deletions src/Sets/HPolygon/support_vector.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
σ(d::AbstractVector, P::HPolygon;
[linear_search]::Bool=(length(P.constraints) < $BINARY_SEARCH_THRESHOLD))

Return a support vector of a polygon in a given direction.

### Input

- `d` -- direction
- `P` -- polygon in constraint representation
- `linear_search` -- (optional, default: see below) flag for controlling whether
to perform a linear search or a binary search

### Output

The support vector in the given direction.
The result is always one of the vertices; in particular, if the direction has
norm zero, any vertex is returned.

### Algorithm

Comparison of directions is performed using polar angles; see the definition of
`⪯` for two-dimensional vectors.

For polygons with $BINARY_SEARCH_THRESHOLD or more constraints we use a binary
search by default.
"""
function σ(d::AbstractVector, P::HPolygon;
linear_search::Bool=(length(P.constraints) < BINARY_SEARCH_THRESHOLD))
n = length(P.constraints)
@assert n > 0 "the polygon has no constraints"

if linear_search
# linear search
k = 1
while k <= n && P.constraints[k].a ⪯ d
k += 1
end
else
# binary search
k = binary_search_constraints(d, P.constraints)
end

if k == 1 || k == n + 1
# corner cases: wrap-around in constraints list
return element(_intersection_line2d(P.constraints[1], P.constraints[n]))
else
return element(_intersection_line2d(P.constraints[k], P.constraints[k - 1]))
end
end
33 changes: 33 additions & 0 deletions src/Sets/HPolygon/translate.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
translate(v::AbstractVector, P::HPolygon; [share]::Bool=false)

Translate (i.e., shift) a polygon in constraint representation by a given
vector.

### Input

- `P` -- polygon in constraint representation
- `v` -- translation vector
- `share` -- (optional, default: `false`) flag for sharing unmodified parts of
the original set representation

### Output

A translated polygon in constraint representation.

### Notes

The normal vectors of the constraints (vector `a` in `a⋅x ≤ b`) are shared with
the original constraints if `share == true`.

### Algorithm

We translate every constraint.
"""
function translate(P::HPolygon, v::AbstractVector; share::Bool=false)
@assert length(v) == dim(P) "cannot translate a $(dim(P))-dimensional " *
"set by a $(length(v))-dimensional vector"
constraints = [translate(c, v; share=share) for c in constraints_list(P)]
return HPolygon(constraints; sort_constraints=false,
check_boundedness=false, prune=false)
end
3 changes: 3 additions & 0 deletions src/Utils/helper_functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,6 @@ function _vec end

# internal function; defined here due to dependency SymEngine and submodules
function _is_linearcombination end

# internal function; defined here due to dependency in submodules
function _intersection_line2d end
8 changes: 8 additions & 0 deletions test/Sets/Polygon.jl
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ for N in [Float64, Float32, Rational{Int}]

# HPolygon/HPolygonOpt tests
for (hp, t_hp) in [(p, HPolygon), (po, HPolygonOpt)]
# constructors
@test t_hp{N}() isa t_hp{N}
@test t_hp{N,Vector{N}}() isa t_hp{N,Vector{N}}
clist = [HalfSpace(N[1, 0], N(1)), HalfSpace(sparsevec([1], N[-1], 2), N(-1))]
P = t_hp(clist)
@test P isa t_hp{N,Vector{N}} &&
P.constraints == [HalfSpace(N[1, 0], N(1)), HalfSpace(N[-1, 0], N(-1))]

# Test Dimension
@test dim(hp) == 2

Expand Down
Loading