diff --git a/docs/src/lib/conversion.md b/docs/src/lib/conversion.md index 2fb2bae49e..253b2a5e4b 100644 --- a/docs/src/lib/conversion.md +++ b/docs/src/lib/conversion.md @@ -15,9 +15,6 @@ CurrentModule = LazySets ```@docs convert(::Type{Interval}, ::Rectification{N, IN}) where {N, IN<:Interval} convert(::Type{Interval}, ::MinkowskiSum{N, IT, IT}) where {N, IT<:Interval} -convert(::Type{IA.IntervalBox}, ::AbstractHyperrectangle) -convert(::Type{Hyperrectangle}, ::IA.IntervalBox) -convert(::Type{Hyperrectangle}, ::AbstractHyperrectangle) convert(::Type{Hyperrectangle}, ::CartesianProduct{N, HN1, HN2}) where {N, HN1<:AbstractHyperrectangle, HN2<:AbstractHyperrectangle} convert(::Type{Hyperrectangle}, ::CartesianProductArray{N, HN}) where {N, HN<:AbstractHyperrectangle} convert(::Type{Hyperrectangle}, ::CartesianProductArray{N, IN}) where {N, IN<:Interval} @@ -30,13 +27,7 @@ convert(::Type{HPolygonOpt}, ::LazySet) convert(::Type{HPolygonOpt}, ::VPolygon) convert(::Type{HPolygonOpt}, ::LineSegment{N}) where {N} convert(::Type{HPolygonOpt}, ::AbstractSingleton{N}) where {N} -convert(::Type{HPolyhedron}, ::LazySet) -convert(::Type{HPolyhedron}, ::HRep{N}) where {N} -convert(::Type{HPolytope}, ::LazySet) -convert(::Type{VPolygon}, ::LazySet) convert(::Type{VPolygon}, ::AbstractHPolygon) -convert(::Type{VPolytope}, ::LazySet) -convert(::Type{Zonotope}, ::AbstractZonotope) convert(::Type{Zonotope}, ::LinearMap{N, ZN}) where {N, ZN<:AbstractZonotope} convert(::Type{Zonotope}, ::LinearMap{N, CartesianProduct{N, HN1, HN2}}) where {N, HN1<:AbstractHyperrectangle, HN2<:AbstractHyperrectangle} convert(::Type{Zonotope}, ::LinearMap{N, CartesianProductArray{N, HN}}) where {N, HN<:AbstractHyperrectangle} @@ -47,10 +38,8 @@ convert(::Type{Zonotope}, ::CartesianProductArray{N, HN}) where {N, HN<:Abstract convert(::Type{CartesianProduct{N, Interval{N}, Interval{N}}}, ::AbstractHyperrectangle{N}) where {N} convert(::Type{CartesianProductArray{N, Interval{N}}}, ::AbstractHyperrectangle{N}) where {N} convert(::Type{MinkowskiSumArray}, ::MinkowskiSum{N, ST, MinkowskiSumArray{N, ST}}) where {N, ST} -convert(::Type{HParallelotope}, Z::AbstractZonotope{N}) where {N} convert(::Type{STAR}, ::AbstractPolyhedron{N}) where {N} convert(::Type{STAR}, ::Star) -convert(::Type{Star}, ::AbstractPolyhedron{N}) where {N} convert(::Type{SimpleSparsePolynomialZonotope}, ::AbstractZonotope) convert(::Type{SimpleSparsePolynomialZonotope}, ::SparsePolynomialZonotope) convert(::Type{SparsePolynomialZonotope}, ::AbstractZonotope{N}) where {N} diff --git a/docs/src/lib/sets/HParallelotope.md b/docs/src/lib/sets/HParallelotope.md index db33966f45..d968d89fd3 100644 --- a/docs/src/lib/sets/HParallelotope.md +++ b/docs/src/lib/sets/HParallelotope.md @@ -8,6 +8,12 @@ CurrentModule = LazySets.HParallelotopeModule HParallelotope ``` +## Conversion + +```@docs +convert(::Type{HParallelotope}, Z::AbstractZonotope{N}) where {N} +``` + ## Operations ```@docs diff --git a/docs/src/lib/sets/HPolyhedron.md b/docs/src/lib/sets/HPolyhedron.md index b2b725f494..c4b9740afa 100644 --- a/docs/src/lib/sets/HPolyhedron.md +++ b/docs/src/lib/sets/HPolyhedron.md @@ -8,6 +8,13 @@ CurrentModule = LazySets.HPolyhedronModule HPolyhedron ``` +## Conversion + +```@docs +convert(::Type{HPolyhedron}, ::LazySet) +convert(::Type{HPolyhedron}, ::HRep{N}) where {N} +``` + ## Operations The following methods are shared between `HPolytope` and `HPolyhedron`. diff --git a/docs/src/lib/sets/HPolytope.md b/docs/src/lib/sets/HPolytope.md index 2f103027ac..91bbd12dff 100644 --- a/docs/src/lib/sets/HPolytope.md +++ b/docs/src/lib/sets/HPolytope.md @@ -17,6 +17,14 @@ CurrentModule = LazySets.HPolytopeModule HPolytope ``` +## Conversion + +```@docs +convert(::Type{HPolytope}, ::LazySet) +``` + +## Operations + ```@meta CurrentModule = LazySets ``` diff --git a/docs/src/lib/sets/Hyperrectangle.md b/docs/src/lib/sets/Hyperrectangle.md index 9f0d494445..7b701235ca 100644 --- a/docs/src/lib/sets/Hyperrectangle.md +++ b/docs/src/lib/sets/Hyperrectangle.md @@ -8,6 +8,14 @@ CurrentModule = LazySets.HyperrectangleModule Hyperrectangle ``` +## Conversion + +```@docs +convert(::Type{Hyperrectangle}, ::AbstractHyperrectangle) +convert(::Type{Hyperrectangle}, ::IA.IntervalBox) +convert(::Type{IA.IntervalBox}, ::AbstractHyperrectangle) +``` + ## Operations ```@docs diff --git a/docs/src/lib/sets/Star.md b/docs/src/lib/sets/Star.md index 0034795c0e..f05f54c000 100644 --- a/docs/src/lib/sets/Star.md +++ b/docs/src/lib/sets/Star.md @@ -8,6 +8,12 @@ CurrentModule = LazySets.StarModule Star ``` +## Conversion + +```@docs +convert(::Type{Star}, ::AbstractPolyhedron{N}) where {N} +``` + ## Operations ```@docs diff --git a/docs/src/lib/sets/VPolygon.md b/docs/src/lib/sets/VPolygon.md index 713ca25d62..b2c9291e8c 100644 --- a/docs/src/lib/sets/VPolygon.md +++ b/docs/src/lib/sets/VPolygon.md @@ -8,6 +8,12 @@ CurrentModule = LazySets.VPolygonModule VPolygon ``` +## Conversion + +```@docs +convert(::Type{VPolygon}, ::LazySet) +``` + ## Operations ```@docs diff --git a/docs/src/lib/sets/VPolytope.md b/docs/src/lib/sets/VPolytope.md index d73ecc3959..388de5fa3e 100644 --- a/docs/src/lib/sets/VPolytope.md +++ b/docs/src/lib/sets/VPolytope.md @@ -8,6 +8,12 @@ CurrentModule = LazySets.VPolytopeModule VPolytope ``` +## Conversion + +```@docs +convert(::Type{VPolytope}, ::LazySet) +``` + ## Operations ```@docs diff --git a/docs/src/lib/sets/Zonotope.md b/docs/src/lib/sets/Zonotope.md index ebb39939de..083b59d409 100644 --- a/docs/src/lib/sets/Zonotope.md +++ b/docs/src/lib/sets/Zonotope.md @@ -8,6 +8,12 @@ CurrentModule = LazySets.ZonotopeModule Zonotope ``` +## Conversion + +```@docs +convert(::Type{Zonotope}, ::AbstractZonotope) +``` + ## Operations ```@docs diff --git a/src/Sets/HParallelotope/HParallelotopeModule.jl b/src/Sets/HParallelotope/HParallelotopeModule.jl index 754043d9b5..b7f59276fd 100644 --- a/src/Sets/HParallelotope/HParallelotopeModule.jl +++ b/src/Sets/HParallelotope/HParallelotopeModule.jl @@ -2,7 +2,8 @@ module HParallelotopeModule using Reexport, Requires -using ..LazySets: AbstractZonotope, HalfSpace, generators_fallback +using ..LazySets: AbstractZonotope, HalfSpace, generators_fallback, order, + _constraints_list_zonotope using LinearAlgebra: checksquare, det using Random: AbstractRNG, GLOBAL_RNG using ReachabilityBase.Arrays: to_negative_vector @@ -12,6 +13,7 @@ using ReachabilityBase.Require: require @reexport import ..API: center, constraints_list, dim, isoperationtype, rand, volume @reexport import ..LazySets: generators, genmat +import Base: convert @reexport using ..API export HParallelotope, @@ -35,6 +37,8 @@ include("offset.jl") include("rand.jl") include("volume.jl") +include("convert.jl") + include("init.jl") end # module diff --git a/src/Sets/HParallelotope/convert.jl b/src/Sets/HParallelotope/convert.jl new file mode 100644 index 0000000000..96e663ff3b --- /dev/null +++ b/src/Sets/HParallelotope/convert.jl @@ -0,0 +1,39 @@ +""" + convert(::Type{HParallelotope}, Z::AbstractZonotope{N}) where {N} + +Convert a zonotopic set of order one to a parallelotope in constraint +representation. + +### Input + +- `HParallelotope` -- target type +- `Z` -- zonotopic set of order one + +### Output + +A parallelotope in constraint representation. + +### Notes + +This function requires that the list of constraints of `Z` are obtained in +the particular order returned from the `constraints_list` function of a +`Zonotope`. Hence it first converts `Z` to a `Zonotope`. +""" +function convert(::Type{HParallelotope}, Z::AbstractZonotope{N}) where {N} + @assert order(Z) == 1 "cannot convert a zonotope that is not of order 1 " * + "to a parallelotope" + n = dim(Z) + + constraints = _constraints_list_zonotope(Z) + + D = Matrix{N}(undef, n, n) + c = Vector{N}(undef, 2n) + j = 1 + @inbounds for i in 1:n + D[i, :] = constraints[j].a + c[i] = constraints[j].b + c[i + n] = constraints[j + 1].b + j += 2 + end + return HParallelotope(D, c; check_consistency=false) +end diff --git a/src/Sets/HPolyhedron/HPolyhedronModule.jl b/src/Sets/HPolyhedron/HPolyhedronModule.jl index aa59435766..103be883ba 100644 --- a/src/Sets/HPolyhedron/HPolyhedronModule.jl +++ b/src/Sets/HPolyhedron/HPolyhedronModule.jl @@ -2,7 +2,7 @@ module HPolyhedronModule using Reexport, Requires -using ..LazySets: AbstractPolyhedron, default_lp_solver, +using ..LazySets: AbstractPolyhedron, LazySet, default_lp_solver, default_polyhedra_backend, iscomplement, is_lp_infeasible, is_lp_optimal, is_lp_unbounded, has_lp_infeasibility_ray, linprog, tosimplehrep, _isempty_polyhedron, _normal_Vector @@ -49,6 +49,8 @@ include("tohrep.jl") include("tovrep.jl") include("addconstraint.jl") +include("convert.jl") + function load_polyhedra_hpolyhedron() # function to be loaded by Requires return quote using .Polyhedra: HRep, diff --git a/src/Sets/HPolyhedron/convert.jl b/src/Sets/HPolyhedron/convert.jl new file mode 100644 index 0000000000..01ba76a8d2 --- /dev/null +++ b/src/Sets/HPolyhedron/convert.jl @@ -0,0 +1,33 @@ +""" + convert(::Type{HPolyhedron}, X::LazySet) + +Convert a polyhedral set to a polyhedron in constraint representation. + +### Input + +- `HPolyhedron` -- target type +- `X` -- polyhedral set + +### Output + +The given set represented as a polyhedron in constraint representation. + +### Algorithm + +This method uses `constraints_list`. +""" +function convert(::Type{HPolyhedron}, X::LazySet) + if !is_polyhedral(X) + error("conversion to `HPolyhedron` requires a polyhedral set") + end + return HPolyhedron(constraints_list(X)) +end + +convert(::Type{HPolyhedron{N,VT}}, P::HPolyhedron{N,VT}) where {N,VT} = P + +function convert(::Type{HPolyhedron{N,VT}}, X::LazySet) where {N,VT} + if !is_polyhedral(X) + error("conversion to `HPolyhedron` requires a polyhedral set") + end + return HPolyhedron([HalfSpace(VT(c.a), N(c.b)) for c in constraints(X)]) +end diff --git a/src/Sets/HPolytope/HPolytopeModule.jl b/src/Sets/HPolytope/HPolytopeModule.jl index 16507a884c..650f67e0e7 100644 --- a/src/Sets/HPolytope/HPolytopeModule.jl +++ b/src/Sets/HPolytope/HPolytopeModule.jl @@ -2,7 +2,7 @@ module HPolytopeModule using Reexport, Requires -using ..LazySets: AbstractPolytope, AbstractLinearMapAlgorithm, +using ..LazySets: AbstractPolytope, LazySet, AbstractLinearMapAlgorithm, default_polyhedra_backend, vertices_list_1d, _linear_map_hrep, _normal_Vector using ..HalfSpaceModule: HalfSpace @@ -13,7 +13,7 @@ using ReachabilityBase.Require: require @reexport import ..API: isbounded, isoperationtype, rand, vertices_list @reexport import ..LazySets: _linear_map_hrep_helper, _vertices_list -@reexport import Base: convert +import Base: convert @reexport using ..API export HPolytope @@ -26,6 +26,8 @@ include("rand.jl") include("vertices_list.jl") include("linear_map.jl") +include("convert.jl") + function load_polyhedra_hpolytope() # function to be loaded by Requires return quote using .Polyhedra: HRep diff --git a/src/Sets/HPolytope/convert.jl b/src/Sets/HPolytope/convert.jl new file mode 100644 index 0000000000..5ae30ee103 --- /dev/null +++ b/src/Sets/HPolytope/convert.jl @@ -0,0 +1,33 @@ +""" + convert(::Type{HPolytope}, X::LazySet) + +Convert a polytopic set to a polytope in constraint representation. + +### Input + +- `HPolytope` -- target type +- `X` -- polytopic set + +### Output + +The given polytope represented as a polytope in constraint representation. + +### Algorithm + +This method uses `constraints_list`. +""" +function convert(::Type{HPolytope}, X::LazySet) + if !isboundedtype(typeof(X)) || !is_polyhedral(X) + error("conversion to `HPolytope` requires a polytopic set") + end + return HPolytope(constraints_list(X)) +end + +convert(::Type{HPolytope{N,VT}}, P::HPolytope{N,VT}) where {N,VT} = P + +function convert(::Type{HPolytope{N,VT}}, X::LazySet) where {N,VT} + if !isboundedtype(typeof(X)) || !is_polyhedral(X) + error("conversion to `HPolytope` requires a polytopic set") + end + return HPolytope([HalfSpace(VT(c.a), N(c.b)) for c in constraints_list(X)]) +end diff --git a/src/Sets/HalfSpace/HalfSpaceModule.jl b/src/Sets/HalfSpace/HalfSpaceModule.jl index 8be1b1d47e..89f40d5a1c 100644 --- a/src/Sets/HalfSpace/HalfSpaceModule.jl +++ b/src/Sets/HalfSpace/HalfSpaceModule.jl @@ -50,6 +50,8 @@ include("halfspace_right.jl") include("iscomplement.jl") include("normalize.jl") +include("convert.jl") + """ LinearConstraint diff --git a/src/Sets/HalfSpace/convert.jl b/src/Sets/HalfSpace/convert.jl new file mode 100644 index 0000000000..4c56be3c63 --- /dev/null +++ b/src/Sets/HalfSpace/convert.jl @@ -0,0 +1,5 @@ +# convert to concrete Vector representation +function convert(::Type{HalfSpace{N,Vector{N}}}, + hs::HalfSpace{N,<:AbstractVector{N}}) where {N} + return HalfSpace(Vector(hs.a), hs.b) +end diff --git a/src/Sets/Hyperrectangle/HyperrectangleModule.jl b/src/Sets/Hyperrectangle/HyperrectangleModule.jl index 8a045f6ca7..7a4ad9eeaa 100644 --- a/src/Sets/Hyperrectangle/HyperrectangleModule.jl +++ b/src/Sets/Hyperrectangle/HyperrectangleModule.jl @@ -13,6 +13,7 @@ using SparseArrays: SparseVector, findnz, sparse @reexport import ..API: center, isoperationtype, rand, permute, scale!, ρ, σ, translate, translate! @reexport import ..LazySets: genmat, radius_hyperrectangle, □, _genmat_static +import Base: convert @reexport using ..API export Hyperrectangle @@ -31,6 +32,8 @@ include("translate.jl") include("genmat.jl") include("radius_hyperrectangle.jl") +include("convert.jl") + function □(c::VNC, r::VNR) where {N,VNC<:AbstractVector{N},VNR<:AbstractVector{N}} return Hyperrectangle(c, r) end diff --git a/src/Sets/Hyperrectangle/convert.jl b/src/Sets/Hyperrectangle/convert.jl new file mode 100644 index 0000000000..cb7a9f09e1 --- /dev/null +++ b/src/Sets/Hyperrectangle/convert.jl @@ -0,0 +1,81 @@ +""" + convert(::Type{Hyperrectangle}, H::AbstractHyperrectangle) + +Convert a hyperrectangular set to a hyperrectangle. + +### Input + +- `Hyperrectangle` -- hyperrectangle target type +- `H` -- hyperrectangular set + +### Output + +A hyperrectangle. + +### Examples + +```jldoctest +julia> convert(Hyperrectangle, Interval(0.0, 1.0)) +Hyperrectangle{Float64, Vector{Float64}, Vector{Float64}}([0.5], [0.5]) +``` +""" +function convert(::Type{Hyperrectangle}, H::AbstractHyperrectangle) + return Hyperrectangle(center(H), radius_hyperrectangle(H)) +end + +function load_IntervalArithmetic_convert() + return quote + import IntervalArithmetic as IA + + """ + convert(::Type{IntervalArithmetic.IntervalBox}, H::AbstractHyperrectangle) + + Convert a hyperrectangular set to an `IntervalBox` from `IntervalArithmetic`. + + ### Input + + - `IntervalBox` -- target type + - `H` -- hyperrectangular set + + ### Output + + An `IntervalBox`. + """ + function convert(::Type{IA.IntervalBox}, H::AbstractHyperrectangle) + return IA.IntervalBox(IA.interval.(low(H), high(H))) + end + + """ + convert(::Type{Hyperrectangle}, IB::IntervalArithmetic.IntervalBox) + + Convert an `IntervalBox` from `IntervalArithmetic` to a hyperrectangular set. + + ### Input + + - `Hyperrectangle` -- target type + - `IB` -- interval box + + ### Output + + A `Hyperrectangle`. + + ### Notes + + `IntervalArithmetic.IntervalBox` uses *static* vectors to store each component + interval; hence the resulting `Hyperrectangle` has its center and radius + represented as a static vector (`SArray`). + """ + function convert(::Type{Hyperrectangle}, IB::IA.IntervalBox) + low_IB = IA.inf.(IB) + high_IB = IA.sup.(IB) + return Hyperrectangle(; low=low_IB, high=high_IB) + end + + # method for Interval + function convert(::Type{Hyperrectangle}, I::IA.Interval) + low_I = [IA.inf(I)] + high_I = [IA.sup(I)] + return Hyperrectangle(; low=low_I, high=high_I) + end + end +end # quote / load_IntervalArithmetic_convert diff --git a/src/Sets/Hyperrectangle/init.jl b/src/Sets/Hyperrectangle/init.jl index 25b891c76c..685b1f5ae9 100644 --- a/src/Sets/Hyperrectangle/init.jl +++ b/src/Sets/Hyperrectangle/init.jl @@ -1,3 +1,4 @@ function __init__() + @require IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" eval(load_IntervalArithmetic_convert()) @require StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" eval(load_genmat_hyperrectangle_static()) end diff --git a/src/Sets/Star/StarModule.jl b/src/Sets/Star/StarModule.jl index 7788c14903..83a9b93c73 100644 --- a/src/Sets/Star/StarModule.jl +++ b/src/Sets/Star/StarModule.jl @@ -4,7 +4,7 @@ using Reexport, Requires using ..LazySets: AbstractPolyhedron using ..HPolytopeModule: HPolytope -using LinearAlgebra: dot +using LinearAlgebra: I, dot using Random: AbstractRNG, GLOBAL_RNG using ReachabilityBase.Arrays: At_mul_B, to_matrix, DEFAULT_COND_TOL using ReachabilityBase.Distribution: reseed! @@ -13,6 +13,7 @@ using ReachabilityBase.Require: require @reexport import ..API: an_element, center, constraints_list, dim, isbounded, isempty, isoperationtype, rand, vertices_list, affine_map, ∈, linear_map, ρ, σ +import Base: convert @reexport using ..API export Star, @@ -39,6 +40,8 @@ include("support_vector.jl") include("basis.jl") include("predicate.jl") +include("convert.jl") + include("init.jl") end # module diff --git a/src/Sets/Star/convert.jl b/src/Sets/Star/convert.jl new file mode 100644 index 0000000000..d1b48c38b4 --- /dev/null +++ b/src/Sets/Star/convert.jl @@ -0,0 +1,20 @@ +""" + convert(::Type{Star}, P::AbstractPolyhedron{N}) where {N} + +Convert a polyhedral set to a star set. + +### Input + +- `Star` -- target type +- `P` -- polyhedral set + +### Output + +A star set. +""" +function convert(::Type{Star}, P::AbstractPolyhedron{N}) where {N} + n = dim(P) + c = zeros(N, n) + V = Matrix(one(N) * I, n, n) + return Star(c, V, P) +end diff --git a/src/Sets/VPolygon/VPolygonModule.jl b/src/Sets/VPolygon/VPolygonModule.jl index db47faeeba..7750eb0d13 100644 --- a/src/Sets/VPolygon/VPolygonModule.jl +++ b/src/Sets/VPolygon/VPolygonModule.jl @@ -2,7 +2,7 @@ module VPolygonModule using Reexport, Requires -using ..LazySets: AbstractPolygon, AbstractHPolygon, convex_hull, +using ..LazySets: AbstractPolygon, LazySet, AbstractHPolygon, convex_hull, halfspace_left, is_right_turn, _area_vlist, _linear_map_vrep using ..HPolygonModule: HPolygon using LinearAlgebra: dot @@ -16,6 +16,7 @@ using ReachabilityBase.Require: require σ, translate, translate! @reexport import ..LazySets: remove_redundant_vertices, remove_redundant_vertices!, tohrep, tovrep +import Base: convert @reexport using ..API export VPolygon @@ -39,6 +40,8 @@ include("remove_redundant_vertices.jl") include("tohrep.jl") include("tovrep.jl") +include("convert.jl") + include("init.jl") end # module diff --git a/src/Sets/VPolygon/convert.jl b/src/Sets/VPolygon/convert.jl new file mode 100644 index 0000000000..e90fe631e5 --- /dev/null +++ b/src/Sets/VPolygon/convert.jl @@ -0,0 +1,22 @@ +""" + convert(::Type{VPolygon}, X::LazySet) + +Convert a two-dimensional polytopic set to a polygon in vertex representation. + +### Input + +- `VPolygon` -- target type +- `X` -- two-dimensional polytopic set + +### Output + +The 2D set represented as a polygon. + +### Algorithm + +This method uses `vertices_list`. +""" +function convert(::Type{VPolygon}, X::LazySet) + @assert dim(X) == 2 "set must be two-dimensional for conversion" + return VPolygon(vertices_list(X)) +end diff --git a/src/Sets/VPolytope/VPolytopeModule.jl b/src/Sets/VPolytope/VPolytopeModule.jl index ac77ad84c1..af01cc7bc1 100644 --- a/src/Sets/VPolytope/VPolytopeModule.jl +++ b/src/Sets/VPolytope/VPolytopeModule.jl @@ -2,7 +2,7 @@ module VPolytopeModule using Reexport, Requires -using ..LazySets: AbstractPolytope, LinearMapVRep, default_lp_solver, +using ..LazySets: AbstractPolytope, LazySet, LinearMapVRep, default_lp_solver, default_lp_solver_polyhedra, default_polyhedra_backend, is_lp_infeasible, is_lp_optimal, linprog using LinearAlgebra: dot @@ -17,6 +17,7 @@ using ReachabilityBase.Require: require ρ, σ, translate, translate! @reexport import ..LazySets: remove_redundant_vertices, tohrep, tovrep, _linear_map_vrep +import Base: convert @reexport using ..API export VPolytope @@ -42,6 +43,8 @@ include("remove_redundant_vertices.jl") include("tohrep.jl") include("tovrep.jl") +include("convert.jl") + function load_polyhedra_vpolytope() # function to be loaded by Requires return quote import .Polyhedra: polyhedron diff --git a/src/Sets/VPolytope/convert.jl b/src/Sets/VPolytope/convert.jl new file mode 100644 index 0000000000..2cb665cd94 --- /dev/null +++ b/src/Sets/VPolytope/convert.jl @@ -0,0 +1,23 @@ +""" + convert(::Type{VPolytope}, X::LazySet; [prune]::Bool=true) + +Convert a polytopic set to a polytope in vertex representation. + +### Input + +- `VPolytope` -- target type +- `X` -- polytopic set +- `prune` -- (optional, default: `true`) option to remove redundant vertices + +### Output + +The given set represented as a polytope in vertex representation. + +### Algorithm + +This method uses `vertices_list`. Use the option `prune` to select whether to +remove redundant vertices before constructing the polytope. +""" +function convert(::Type{VPolytope}, X::LazySet; prune::Bool=true) + return VPolytope(vertices_list(X; prune=prune)) +end diff --git a/src/Sets/VPolytope/project.jl b/src/Sets/VPolytope/project.jl index ee8b12395d..cd9659a252 100644 --- a/src/Sets/VPolytope/project.jl +++ b/src/Sets/VPolytope/project.jl @@ -15,7 +15,6 @@ function project(P::VPolytope, block::AbstractVector{Int}; kwargs...) πvertices = broadcast(v -> M * v, P.vertices) if m == 2 - return VPolygon(πvertices; apply_convex_hull=true) else return VPolytope(πvertices) diff --git a/src/Sets/Zonotope/ZonotopeModule.jl b/src/Sets/Zonotope/ZonotopeModule.jl index 431be5bb48..ac71a2c155 100644 --- a/src/Sets/Zonotope/ZonotopeModule.jl +++ b/src/Sets/Zonotope/ZonotopeModule.jl @@ -15,6 +15,7 @@ using ReachabilityBase.Require: require permute, scale!, translate! @reexport import ..LazySets: generators, genmat, ngens, reduce_order, remove_redundant_generators, togrep +import Base: convert @reexport using ..API export Zonotope, @@ -44,6 +45,8 @@ include("togrep.jl") include("remove_zero_generators.jl") include("split.jl") +include("convert.jl") + include("init.jl") end # module diff --git a/src/Sets/Zonotope/convert.jl b/src/Sets/Zonotope/convert.jl new file mode 100644 index 0000000000..bcfa1d81ec --- /dev/null +++ b/src/Sets/Zonotope/convert.jl @@ -0,0 +1,17 @@ +""" + convert(::Type{Zonotope}, Z::AbstractZonotope) + +Convert a zonotopic set to a zonotope. + +### Input + +- `Zonotope` -- target type +- `H` -- zonotopic set + +### Output + +A zonotope. +""" +function convert(::Type{Zonotope}, Z::AbstractZonotope) + return Zonotope(center(Z), genmat(Z)) +end diff --git a/src/convert.jl b/src/convert.jl index 9db69cd417..ab756e7fed 100644 --- a/src/convert.jl +++ b/src/convert.jl @@ -26,121 +26,6 @@ function convert(::Type{VPolygon}, P::AbstractHPolygon) return tovrep(P) end -""" - convert(::Type{VPolygon}, X::LazySet) - -Convert a two-dimensional polytopic set to a polygon in vertex representation. - -### Input - -- `VPolygon` -- target type -- `X` -- two-dimensional polytopic set - -### Output - -The 2D set represented as a polygon. - -### Algorithm - -This method uses `vertices_list`. -""" -function convert(::Type{VPolygon}, X::LazySet) - @assert dim(X) == 2 "set must be two-dimensional for conversion" - return VPolygon(vertices_list(X)) -end - -""" - convert(::Type{HPolytope}, X::LazySet) - -Convert a polytopic set to a polytope in constraint representation. - -### Input - -- `HPolytope` -- target type -- `X` -- polytopic set - -### Output - -The given polytope represented as a polytope in constraint representation. - -### Algorithm - -This method uses `constraints_list`. -""" -function convert(::Type{HPolytope}, X::LazySet) - if !isboundedtype(typeof(X)) || !is_polyhedral(X) - error("conversion to `HPolytope` requires a polytopic set") - end - return HPolytope(constraints_list(X)) -end - -convert(::Type{HPolytope{N,VT}}, P::HPolytope{N,VT}) where {N,VT} = P - -function convert(::Type{HPolytope{N,VT}}, X::LazySet) where {N,VT} - if !isboundedtype(typeof(X)) || !is_polyhedral(X) - error("conversion to `HPolytope` requires a polytopic set") - end - return HPolytope([HalfSpace(VT(c.a), N(c.b)) for c in constraints_list(X)]) -end - -""" - convert(::Type{HPolyhedron}, X::LazySet) - -Convert a polyhedral set to a polyhedron in constraint representation. - -### Input - -- `HPolyhedron` -- target type -- `X` -- polyhedral set - -### Output - -The given set represented as a polyhedron in constraint representation. - -### Algorithm - -This method uses `constraints_list`. -""" -function convert(::Type{HPolyhedron}, X::LazySet) - if !is_polyhedral(X) - error("conversion to `HPolyhedron` requires a polyhedral set") - end - return HPolyhedron(constraints_list(X)) -end - -convert(::Type{HPolyhedron{N,VT}}, P::HPolyhedron{N,VT}) where {N,VT} = P - -function convert(::Type{HPolyhedron{N,VT}}, X::LazySet) where {N,VT} - if !is_polyhedral(X) - error("conversion to `HPolyhedron` requires a polyhedral set") - end - return HPolyhedron([HalfSpace(VT(c.a), N(c.b)) for c in constraints(X)]) -end - -""" - convert(::Type{VPolytope}, X::LazySet; [prune]::Bool=true) - -Convert a polytopic set to a polytope in vertex representation. - -### Input - -- `VPolytope` -- target type -- `X` -- polytopic set -- `prune` -- (optional, default: `true`) option to remove redundant vertices - -### Output - -The given set represented as a polytope in vertex representation. - -### Algorithm - -This method uses `vertices_list`. Use the option `prune` to select whether to -remove redundant vertices before constructing the polytope. -""" -function convert(::Type{VPolytope}, X::LazySet; prune::Bool=true) - return VPolytope(vertices_list(X; prune=prune)) -end - # fast conversion from a 2D hyperrectangular set to a zonotope function _convert_2D(::Type{Zonotope}, H::AbstractHyperrectangle{N}) where {N} c = center(H) @@ -209,31 +94,11 @@ function load_genmat_2D_static() end end # quote / load_genmat_2D_static -""" - convert(::Type{Zonotope}, Z::AbstractZonotope) - -Convert a zonotopic set to a zonotope. - -### Input - -- `Zonotope` -- target type -- `H` -- zonotopic set - -### Output - -A zonotope. -""" -function convert(::Type{Zonotope}, Z::AbstractZonotope) - return _convert_zonotope_fallback(Z) -end - function convert(::Type{Zonotope}, H::AbstractHyperrectangle) dim(H) == 2 && return _convert_2D(Zonotope, H) - return _convert_zonotope_fallback(H) + return Zonotope(center(H), genmat(H)) end -_convert_zonotope_fallback(Z) = Zonotope(center(Z), genmat(Z)) - function convert(::Type{Singleton}, cp::CartesianProduct{N,S1,S2}) where {N,S1<:AbstractSingleton, S2<:AbstractSingleton} @@ -365,30 +230,6 @@ function convert(::Type{Zonotope}, return linear_map(S.M, convert(Zonotope, S.X)) end -""" - convert(::Type{Hyperrectangle}, H::AbstractHyperrectangle) - -Convert a hyperrectangular set to a hyperrectangle. - -### Input - -- `Hyperrectangle` -- hyperrectangle target type -- `H` -- hyperrectangular set - -### Output - -A hyperrectangle. - -### Examples - -```jldoctest -julia> convert(Hyperrectangle, Interval(0.0, 1.0)) -Hyperrectangle{Float64, Vector{Float64}, Vector{Float64}}([0.5], [0.5]) -``` -""" -function convert(::Type{Hyperrectangle}, H::AbstractHyperrectangle) - return Hyperrectangle(center(H), radius_hyperrectangle(H)) -end """ convert(::Type{Hyperrectangle}, cpa::CartesianProductArray{N, HN}) @@ -572,57 +413,6 @@ function convert(::Type{Zonotope}, return Zonotope(c, G) end -""" - convert(::Type{IntervalArithmetic.IntervalBox}, H::AbstractHyperrectangle) - -Convert a hyperrectangular set to an `IntervalBox` from `IntervalArithmetic`. - -### Input - -- `IntervalBox` -- target type -- `H` -- hyperrectangular set - -### Output - -An `IntervalBox`. -""" -function convert(::Type{IA.IntervalBox}, H::AbstractHyperrectangle) - return IA.IntervalBox(IA.interval.(low(H), high(H))) -end - -""" - convert(::Type{Hyperrectangle}, IB::IntervalArithmetic.IntervalBox) - -Convert an `IntervalBox` from `IntervalArithmetic` to a hyperrectangular set. - -### Input - -- `Hyperrectangle` -- target type -- `IB` -- interval box - -### Output - -A `Hyperrectangle`. - -### Notes - -`IntervalArithmetic.IntervalBox` uses *static* vectors to store each component -interval; hence the resulting `Hyperrectangle` has its center and radius -represented as a static vector (`SArray`). -""" -function convert(::Type{Hyperrectangle}, IB::IA.IntervalBox) - low_IB = IA.inf.(IB) - high_IB = IA.sup.(IB) - return Hyperrectangle(; low=low_IB, high=high_IB) -end - -# method for Interval -function convert(::Type{Hyperrectangle}, I::IA.Interval) - low_I = [IA.inf(I)] - high_I = [IA.sup(I)] - return Hyperrectangle(; low=low_I, high=high_I) -end - """ convert(::Type{Hyperrectangle}, r::Rectification{N, AH}) where {N, AH<:AbstractHyperrectangle} @@ -700,12 +490,6 @@ function convert(::Type{Interval}, ms::MinkowskiSum{N,IT,IT}) where {N,IT<:Inter return concretize(ms) end -# convert to concrete Vector representation -function convert(::Type{HalfSpace{N,Vector{N}}}, - hs::HalfSpace{N,<:AbstractVector{N}}) where {N} - return HalfSpace(Vector(hs.a), hs.b) -end - function convert(::Type{Zonotope}, am::AbstractAffineMap{N,<:AbstractZonotope{N}}) where {N} Z1 = convert(Zonotope, linear_map(matrix(am), set(am))) @@ -713,46 +497,6 @@ function convert(::Type{Zonotope}, return Z1 end -""" - convert(::Type{HParallelotope}, Z::AbstractZonotope{N}) where {N} - -Convert a zonotopic set of order one to a parallelotope in constraint -representation. - -### Input - -- `HParallelotope` -- target type -- `Z` -- zonotopic set of order one - -### Output - -A parallelotope in constraint representation. - -### Notes - -This function requires that the list of constraints of `Z` are obtained in -the particular order returned from the `constraints_list` function of a -`Zonotope`. Hence it first converts `Z` to a `Zonotope`. -""" -function convert(::Type{HParallelotope}, Z::AbstractZonotope{N}) where {N} - @assert order(Z) == 1 "cannot convert a zonotope that is not of order 1 " * - "to a parallelotope" - n = dim(Z) - - constraints = _constraints_list_zonotope(Z) - - D = Matrix{N}(undef, n, n) - c = Vector{N}(undef, 2n) - j = 1 - @inbounds for i in 1:n - D[i, :] = constraints[j].a - c[i] = constraints[j].b - c[i + n] = constraints[j + 1].b - j += 2 - end - return HParallelotope(D, c; check_consistency=false) -end - """ convert(::Type{Zonotope}, cpa::CartesianProductArray{N, AZ}) where {N, AZ<:AbstractZonotope} @@ -946,26 +690,6 @@ function convert(::Type{STAR}, X::Star) return AffineMap(X.V, X.P, X.c) end -""" - convert(::Type{Star}, P::AbstractPolyhedron{N}) where {N} - -Convert a polyhedral set to a star set. - -### Input - -- `Star` -- target type -- `P` -- polyhedral set - -### Output - -A star set. -""" -function convert(::Type{Star}, P::AbstractPolyhedron{N}) where {N} - n = dim(P) - c = zeros(N, n) - V = Matrix(one(N) * I, n, n) - return Star(c, V, P) -end function convert(::Type{Hyperplane}, P::HPolyhedron; skip_check::Bool=false) # check that the number of constraints is fine diff --git a/test/Sets/Polyhedron.jl b/test/Sets/Polyhedron.jl index c06ec40c0d..12e1146272 100644 --- a/test/Sets/Polyhedron.jl +++ b/test/Sets/Polyhedron.jl @@ -159,6 +159,11 @@ for N in [Float64, Rational{Int}, Float32] P = HPolyhedron([HalfSpace(SingleEntryVector(1, 2, N(1)), N(0))]) Q = convert(typeof(P), P) @test P == Q + Q = convert(HPolyhedron{N,Vector{N}}, P.constraints[1]) + @test P == Q + B = Ball2(N[1], N(1)) + @test_throws ErrorException convert(HPolyhedron, B) + @test_throws ErrorException convert(HPolyhedron{N,Vector{N}}, B) # permute P = HPolyhedron(HalfSpace[HalfSpace(N[1, 2], N(3)), HalfSpace(N[-1, -2], N(-3))]) diff --git a/test/Sets/Polytope.jl b/test/Sets/Polytope.jl index 40092a5757..a1ba35e631 100644 --- a/test/Sets/Polytope.jl +++ b/test/Sets/Polytope.jl @@ -184,6 +184,14 @@ for N in [Float64, Rational{Int}, Float32] HalfSpace(SingleEntryVector(1, 1, N(-1)), N(0))]) Q = convert(typeof(P), P) @test P == Q + Q = convert(HPolytope{N,Vector{N}}, tovrep(P)) + @test P == Q + H = HalfSpace(N[1], N(1)) + @test_throws ErrorException convert(HPolytope, H) + @test_throws ErrorException convert(HPolytope{N,Vector{N}}, H) + B = Ball2(N[1], N(1)) + @test_throws ErrorException convert(HPolytope, B) + @test_throws ErrorException convert(HPolytope{N,Vector{N}}, B) # ----- # V-rep