diff --git a/docs/src/lib/conversion.md b/docs/src/lib/conversion.md index dc9ee78a81..5303dd57f4 100644 --- a/docs/src/lib/conversion.md +++ b/docs/src/lib/conversion.md @@ -21,4 +21,6 @@ convert(::Type{HPolytope}, ::HPolygon) convert(::Type{HPolygon}, ::HPolytope) convert(::Type{Zonotope}, ::AbstractHyperrectangle) convert(::Type{Hyperrectangle}, ::Interval) +convert(::Type{HPolytope}, ::AbstractHyperrectangle) +convert(::Type{HPolygon}, ::AbstractHyperrectangle) ``` diff --git a/docs/src/lib/interfaces.md b/docs/src/lib/interfaces.md index aafb05b48b..84a6a15ea5 100644 --- a/docs/src/lib/interfaces.md +++ b/docs/src/lib/interfaces.md @@ -162,6 +162,7 @@ radius(::AbstractHyperrectangle, ::Real) σ(::AbstractVector{Real}, ::AbstractHyperrectangle{Real}) ∈(::AbstractVector{Real}, ::AbstractHyperrectangle{Real}) vertices_list(::AbstractHyperrectangle{Real}) +constraints_list(::AbstractHyperrectangle{Real}) ``` #### Singleton diff --git a/src/AbstractHyperrectangle.jl b/src/AbstractHyperrectangle.jl index c63156e787..70998808b2 100644 --- a/src/AbstractHyperrectangle.jl +++ b/src/AbstractHyperrectangle.jl @@ -1,7 +1,8 @@ import Base.∈ export AbstractHyperrectangle, - radius_hyperrectangle + radius_hyperrectangle, + constraints_list """ AbstractHyperrectangle{N<:Real} <: AbstractCentrallySymmetricPolytope{N} @@ -59,6 +60,31 @@ function vertices_list(H::AbstractHyperrectangle{N} for si in Iterators.product([[1, -1] for i = 1:dim(H)]...)][:] end +""" + constraints_list(H::AbstractHyperrectangle{N})::Vector{Vector{N}} where {N<:Real} + +Return the list of constraints of an axis-aligned hyperrectangular set. + +### Input + +- `H` -- hyperrectangular set + +### Output + +A list of linear constraints. +""" +function constraints_list(H::AbstractHyperrectangle{N})::Vector{LinearConstraint{N}} where {N<:Real} + n = dim(H) + constraints = Vector{LinearConstraint{N}}(undef, 2*n) + b, c = high(H), -low(H) + one_N = one(N) + for i in 1:n + ei = LazySets.Approximations.UnitVector(i, n, one_N) + constraints[i] = HalfSpace(ei, b[i]) + constraints[i+n] = HalfSpace(-ei, c[i]) + end + return constraints +end # --- LazySet interface functions --- diff --git a/src/convert.jl b/src/convert.jl index c67b8d35ce..4eebd37c76 100644 --- a/src/convert.jl +++ b/src/convert.jl @@ -173,3 +173,40 @@ Hyperrectangle{Float64}([0.5], [0.5]) function convert(::Type{Hyperrectangle}, x::Interval{N, IN}) where {N, IN <: AbstractInterval{N}} return Hyperrectangle(low=[low(x)], high=[high(x)]) end + +""" + convert(::Type{HPolytope}, H::AbstractHyperrectangle{N}) where {N} + +Converts a hyperrectangular set to a polytope in constraint representation. + +### Input + +- `HPolytope` -- type used for dispatch +- `H` -- hyperrectangular set + +### Output + +A polytope in constraint representation. +""" +function convert(::Type{HPolytope}, H::AbstractHyperrectangle{N}) where {N} + return HPolytope{N}(constraints_list(H)) +end + +""" + convert(::Type{HPOLYGON}, H::AbstractHyperrectangle{N}) where {N, HPOLYGON<:AbstractHPolygon} + +Converts a hyperrectangular set to a polygon in constraint representation. + +### Input + +- `HPOLYGON` -- type used for dispatch +- `H` -- hyperrectangular set + +### Output + +A polygon in constraint representation. +""" +function convert(X::Type{HPOLYGON}, H::AbstractHyperrectangle{N}) where {N, HPOLYGON<:AbstractHPolygon} + @assert dim(H) == 2 "cannot convert a $(dim(H))-dimensional hyperrectangle into a two-dimensional polygon" + return HPOLYGON{N}(constraints_list(H)) +end diff --git a/test/unit_Hyperrectangle.jl b/test/unit_Hyperrectangle.jl index 82423db9f8..c34c36ee3d 100644 --- a/test/unit_Hyperrectangle.jl +++ b/test/unit_Hyperrectangle.jl @@ -140,4 +140,18 @@ for N in [Float64, Rational{Int}, Float32] H = Hyperrectangle(fill(N(1.), 100), fill(N(0.), 100)) vl = vertices_list(H) @test length(vl) == 1 && vl[1] == H.center + + # transform hyperrectangle into a polygon + H1pol = convert(HPolygon, H1) + vlist = vertices_list(H1pol) + @test length(vlist) == 4 + @test all([vi ∈ vlist for vi in [N[3, 3], N[3, -1], N[-1, -1], N[-1, 3]]]) + + # test that we can produce the list of constraints + clist = constraints_list(H1) + @test length(clist) == 4 + @test any([HalfSpace(N[1, 0], N(3)) == ci for ci in constraints_list(H1)]) && + any([HalfSpace(N[0, 1], N(3)) == ci for ci in constraints_list(H1)]) && + any([HalfSpace(N[-1, 0], N(1)) == ci for ci in constraints_list(H1)]) && + any([HalfSpace(N[0, -1], N(1)) == ci for ci in constraints_list(H1)]) end diff --git a/test/unit_Polytope.jl b/test/unit_Polytope.jl index de6fc5e543..386dbab4e1 100644 --- a/test/unit_Polytope.jl +++ b/test/unit_Polytope.jl @@ -56,6 +56,15 @@ for N in [Float64, Rational{Int}, Float32] @test length(p.constraints) == length(cl) end + if test_suite_polyhedra + # convert hyperrectangle to a HPolytope + H = Hyperrectangle(N[1, 1], N[2, 2]) + P = convert(HPolytope, H) + vlist = vertices_list(P) + @test length(vlist) == 4 + @test all([vi ∈ vlist for vi in [N[3, 3], N[3, -1], N[-1, -1], N[-1, 3]]]) + end + # ----- # V-rep # -----