diff --git a/docs/src/lib/interfaces/AbstractHPolygon.md b/docs/src/lib/interfaces/AbstractHPolygon.md index ae6f957af1..23868d4478 100644 --- a/docs/src/lib/interfaces/AbstractHPolygon.md +++ b/docs/src/lib/interfaces/AbstractHPolygon.md @@ -28,7 +28,7 @@ tohrep(::HPOLYGON) where {HPOLYGON<:AbstractHPolygon} tovrep(::AbstractHPolygon) vertices_list(::AbstractHPolygon) addconstraint!(::AbstractHPolygon, ::HalfSpace) -addconstraint!(::Vector{LC}, ::HalfSpace) where {LC<:HalfSpace} +addconstraint!(::Vector{<:HalfSpace}, ::HalfSpace) ∈(::AbstractVector, ::AbstractHPolygon) isredundant(::HalfSpace, ::HalfSpace, ::HalfSpace) ``` diff --git a/docs/src/lib/interfaces/AbstractPolygon.md b/docs/src/lib/interfaces/AbstractPolygon.md index e9506924c3..398fa554b5 100644 --- a/docs/src/lib/interfaces/AbstractPolygon.md +++ b/docs/src/lib/interfaces/AbstractPolygon.md @@ -35,7 +35,7 @@ The following helper functions are used for sorting directions: LazySets.jump2pi ⪯(::AbstractVector, ::AbstractVector) LazySets._leq_trig(::AbstractVector{N}, ::AbstractVector{N}) where {N<:AbstractFloat} -LazySets.quadrant(::AbstractVector{N}) where {N} +LazySets.quadrant(::AbstractVector) ``` ## Implementations diff --git a/docs/src/lib/interfaces/AbstractPolyhedron.md b/docs/src/lib/interfaces/AbstractPolyhedron.md index 8cd08c75c4..afb65e54a9 100644 --- a/docs/src/lib/interfaces/AbstractPolyhedron.md +++ b/docs/src/lib/interfaces/AbstractPolyhedron.md @@ -31,13 +31,13 @@ CurrentModule = LazySets This interface defines the following functions: ```@docs -an_element(::AbstractPolyhedron{N}) where {N} +an_element(::AbstractPolyhedron) constrained_dimensions(::AbstractPolyhedron) -isbounded(::AbstractPolyhedron{N}) where {N} +isbounded(::AbstractPolyhedron) isuniversal(::AbstractPolyhedron, ::Bool=false) vertices_list(::AbstractPolyhedron) ∈(::AbstractVector, ::AbstractPolyhedron) -project(::AbstractPolyhedron{N}, ::AbstractVector{Int}) where {N} +project(::AbstractPolyhedron, ::AbstractVector{Int}) LazySets._isbounded_stiemke LazySets._linear_map_polyhedron ``` @@ -53,9 +53,9 @@ Some common functions to work with linear constraints: ```@docs constraints_list(::AbstractMatrix, ::AbstractVector) -tosimplehrep(::AbstractVector{LC}) where {N, LC<:HalfSpace{N}} -remove_redundant_constraints(::AbstractVector{S}) where {S<:HalfSpace} -remove_redundant_constraints!(::AbstractVector{S}) where {S<:HalfSpace} +tosimplehrep(::AbstractVector{<:HalfSpace}) +remove_redundant_constraints(::AbstractVector{<:HalfSpace}) +remove_redundant_constraints!(::AbstractVector{<:HalfSpace}) ``` Plotting (bounded) polyhedra is available, too: diff --git a/docs/src/lib/interfaces/AbstractZonotope.md b/docs/src/lib/interfaces/AbstractZonotope.md index 788cad4953..7fec45f441 100644 --- a/docs/src/lib/interfaces/AbstractZonotope.md +++ b/docs/src/lib/interfaces/AbstractZonotope.md @@ -27,9 +27,9 @@ This interface defines the following functions: ```@docs constraints_list(::AbstractZonotope) -constraints_list(::AbstractZonotope{N}; ::Bool=true) where {N<:AbstractFloat} +constraints_list(::AbstractZonotope{<:AbstractFloat}; ::Bool=true) generators_fallback(::AbstractZonotope) -genmat_fallback(::AbstractZonotope{N}) where {N} +genmat_fallback(::AbstractZonotope) ngens(::AbstractZonotope) order(::AbstractZonotope) reflect(::AbstractZonotope) diff --git a/docs/src/lib/interfaces/LazySet.md b/docs/src/lib/interfaces/LazySet.md index 3177b183d9..ee6a30dd65 100644 --- a/docs/src/lib/interfaces/LazySet.md +++ b/docs/src/lib/interfaces/LazySet.md @@ -69,7 +69,7 @@ isfeasible norm(::LazySet, ::Real=Inf) radius(::LazySet, ::Real=Inf) diameter(::LazySet, ::Real=Inf) -isempty(::LazySet{N}, ::Bool=false) where {N} +isempty(::LazySet, ::Bool=false) linear_map(::AbstractMatrix, ::LazySet; kwargs...) linear_map(::Number, ::LazySet; kwargs...) affine_map(::Any, ::LazySet, ::AbstractVector) @@ -85,10 +85,10 @@ area(::LazySet) concretize(::LazySet) complement(::LazySet) polyhedron(::LazySet) -project(::LazySet, ::AbstractVector{Int}, ::Nothing=nothing, ::Int=dim(S)) -project(::LazySet, ::AbstractVector{Int}, ::Type{TS}, ::Int=dim(S)) where {TS<:LazySet} -project(::LazySet, ::AbstractVector{Int}, ::Pair{T, N}, ::Int=dim(S)) where {T<:UnionAll, N<:Real} -project(::LazySet, ::AbstractVector{Int}, ::Real, ::Int=dim(S)) +project(::LazySet, ::AbstractVector{Int}, ::Nothing=nothing, ::Int=dim(X)) +project(::LazySet, ::AbstractVector{Int}, ::Type{<:LazySet}, ::Int=dim(X)) +project(::LazySet, ::AbstractVector{Int}, ::Pair{<:UnionAll,<:Real}, ::Int=dim(X)) +project(::LazySet, ::AbstractVector{Int}, ::Real, ::Int=dim(X)) rectify(::LazySet, ::Bool=false) permute rationalize(::Type{T}, ::LazySet{<:AbstractFloat}, ::Real) where {T<:Integer} @@ -96,21 +96,12 @@ singleton_list(::LazySet) constraints(::LazySet) vertices(::LazySet) delaunay -chebyshev_center_radius(::LazySet{N}) where {N} +chebyshev_center_radius(::LazySet) scale(::Real, ::LazySet) translate(::LazySet, ::AbstractVector) plot_recipe(::LazySet, ::Any) ``` -The following methods are also defined for `LazySet` but cannot be documented -due to a bug in the documentation package. - -```@docs -low(::ConvexSet{N}, ::Int) where {N} -high(::ConvexSet{N}, ::Int) where {N} -an_element(::ConvexSet{N}) where {N} -``` - ## Support function and support vector Every `LazySet` type must define a function `σ` to compute the support vector. diff --git a/docs/src/lib/sets/Ellipsoid.md b/docs/src/lib/sets/Ellipsoid.md index 672ef271e1..f586cde7df 100644 --- a/docs/src/lib/sets/Ellipsoid.md +++ b/docs/src/lib/sets/Ellipsoid.md @@ -94,9 +94,11 @@ Inherited from [`LazySet`](@ref): * [`eltype`](@ref eltype(::Type{<:LazySet})) * [`eltype`](@ref eltype(::LazySet)) * [`high`](@ref high(::LazySet)) +* [`high`](@ref high(::LazySet, ::Int)) * [`ispolyhedral`](@ref ispolyhedral(::LazySet)) * [`isoperation`](@ref isoperation(::LazySet)) * [`low`](@ref low(::LazySet)) +* [`low`](@ref low(::LazySet, ::Int)) * [`norm`](@ref norm(::LazySet, ::Real)) * [`radius`](@ref radius(::LazySet, ::Real)) * [`exponential_map`](@ref exponential_map(::AbstractMatrix, ::LazySet)) @@ -108,10 +110,6 @@ Inherited from [`LazySet`](@ref): * [`==`](@ref ==(::LazySet, ::LazySet)) * [`isequivalent`](@ref isequivalent(::LazySet, ::LazySet)) -Inherited from [`ConvexSet`](@ref): -* [`high`](@ref high(::ConvexSet, ::Int)) -* [`low`](@ref low(::ConvexSet, ::Int)) - Inherited from [`AbstractCentrallySymmetric`](@ref): * [`an_element`](@ref an_element(::AbstractCentrallySymmetric)) * [`center`](@ref center(::AbstractCentrallySymmetric, ::Int)) diff --git a/docs/src/lib/sets/HPolyhedron.md b/docs/src/lib/sets/HPolyhedron.md index 920511bfd8..74b2352a97 100644 --- a/docs/src/lib/sets/HPolyhedron.md +++ b/docs/src/lib/sets/HPolyhedron.md @@ -146,7 +146,7 @@ Inherited from [`AbstractPolyhedron`](@ref): * [`extrema`](@ref extrema(::AbstractPolyhedron, ::Int)) * [`high`](@ref high(::AbstractPolyhedron)) * [`high`](@ref high(::AbstractPolyhedron, ::Int)) -* [`isbounded`](@ref isbounded(::AbstractPolyhedron{N}) where {N}) +* [`isbounded`](@ref isbounded(::AbstractPolyhedron)) * [`isconvextype`](@ref isconvextype(::Type{AbstractPolyhedron})) * [`ispolyhedral`](@ref ispolyhedral(::AbstractPolyhedron)) * [`isuniversal`](@ref isuniversal(::AbstractPolyhedron, ::Bool=false)) diff --git a/docs/src/lib/sets/LineSegment.md b/docs/src/lib/sets/LineSegment.md index 444be6f050..b1cfd31a3f 100644 --- a/docs/src/lib/sets/LineSegment.md +++ b/docs/src/lib/sets/LineSegment.md @@ -123,9 +123,7 @@ Inherited from [`LazySet`](@ref): * [`diameter`](@ref diameter(::LazySet, ::Real)) * [`eltype`](@ref eltype(::Type{<:LazySet})) * [`eltype`](@ref eltype(::LazySet)) -* [`high`](@ref high(::LazySet)) * [`isoperation`](@ref isoperation(::LazySet)) -* [`low`](@ref low(::LazySet)) * [`norm`](@ref norm(::LazySet, ::Real)) * [`radius`](@ref radius(::LazySet, ::Real)) * [`singleton_list`](@ref singleton_list(::LazySet)) @@ -142,12 +140,14 @@ Inherited from [`LazySet`](@ref): * [`⊂`](@ref ⊂(::LazySet, ::LazySet)) Inherited from [`ConvexSet`](@ref): -* [`high`](@ref high(::ConvexSet, ::Int)) -* [`low`](@ref low(::ConvexSet, ::Int)) * [`linear_combination`](@ref linear_combination(::ConvexSet, ::ConvexSet)) Inherited from [`AbstractPolyhedron`](@ref): +* [`high`](@ref high(::AbstractPolyhedron)) +* [`high`](@ref high(::AbstractPolyhedron, ::Int)) * [`ispolyhedral`](@ref ispolyhedral(::AbstractPolyhedron)) +* [`low`](@ref low(::AbstractPolyhedron)) +* [`low`](@ref low(::AbstractPolyhedron, ::Int)) Inherited from [`AbstractPolytope`](@ref): * [`isbounded`](@ref isbounded(::AbstractPolytope)) diff --git a/docs/src/lib/sets/Zonotope.md b/docs/src/lib/sets/Zonotope.md index 17e9f04c88..eb9a4aa09b 100644 --- a/docs/src/lib/sets/Zonotope.md +++ b/docs/src/lib/sets/Zonotope.md @@ -155,7 +155,7 @@ Inherited from [`AbstractCentrallySymmetricPolytope`](@ref): Inherited from [`AbstractZonotope`](@ref): * [`constraints_list`](@ref constraints_list(::AbstractZonotope)) -* [`constraints_list`](@ref constraints_list(::AbstractZonotope{N}; ::Bool=true) where {N<:AbstractFloat}) +* [`constraints_list`](@ref constraints_list(::AbstractZonotope{<:AbstractFloat}; ::Bool=true)) * [`order`](@ref order(::AbstractZonotope)) * [`reflect`](@ref reflect(::AbstractZonotope)) * [`vertices_list`](@ref vertices_list(::AbstractZonotope)) diff --git a/src/Interfaces/AbstractHPolygon.jl b/src/Interfaces/AbstractHPolygon.jl index fa6e06d2c9..b5c0bb2224 100644 --- a/src/Interfaces/AbstractHPolygon.jl +++ b/src/Interfaces/AbstractHPolygon.jl @@ -429,9 +429,9 @@ function addconstraint!(P::AbstractHPolygon, constraint::HalfSpace; end """ - addconstraint!(constraints::Vector{LC}, new_constraint::HalfSpace; + addconstraint!(constraints::Vector{<:HalfSpace}, new_constraint::HalfSpace; [linear_search]::Bool=length(P.constraints) < $BINARY_SEARCH_THRESHOLD, - [prune]::Bool=true) where {LC<:HalfSpace} + [prune]::Bool=true) Add a linear constraint to a sorted vector of constrains, keeping the constraints sorted by their normal directions. @@ -452,9 +452,9 @@ If `prune` is active, we check if the new constraint is redundant. If the constraint is not redundant, we perform the same check to the left and to the right until we find the first constraint that is not redundant. """ -function addconstraint!(constraints::Vector{LC}, new_constraint::HalfSpace; +function addconstraint!(constraints::Vector{<:HalfSpace}, new_constraint::HalfSpace; linear_search::Bool=length(constraints) < BINARY_SEARCH_THRESHOLD, - prune::Bool=true) where {LC<:HalfSpace} + prune::Bool=true) m = length(constraints) k = m if k > 0 diff --git a/src/Interfaces/AbstractPolygon.jl b/src/Interfaces/AbstractPolygon.jl index 829d4f4b0a..975b614107 100644 --- a/src/Interfaces/AbstractPolygon.jl +++ b/src/Interfaces/AbstractPolygon.jl @@ -107,7 +107,7 @@ julia> jump2pi(0.5) end """ - quadrant(w::AbstractVector{N}) where {N} + quadrant(w::AbstractVector) Compute the quadrant where the direction `w` belongs. @@ -134,7 +134,8 @@ The idea is to encode the following logic function: This function is inspired from AGPX's answer in: [Sort points in clockwise order?](https://stackoverflow.com/a/46635372) """ -@inline function quadrant(w::AbstractVector{N}) where {N} +@inline function quadrant(w::AbstractVector) + N = eltype(w) dwx = w[1] >= zero(N) ? 1 : 0 dwy = w[2] >= zero(N) ? 1 : 0 return (1 - dwx) + (1 - dwy) + ((dwx & (1 - dwy)) << 1) diff --git a/src/Interfaces/AbstractPolyhedron_functions.jl b/src/Interfaces/AbstractPolyhedron_functions.jl index ae42ddfd21..47bf6587dd 100644 --- a/src/Interfaces/AbstractPolyhedron_functions.jl +++ b/src/Interfaces/AbstractPolyhedron_functions.jl @@ -96,8 +96,7 @@ function isuniversal(P::AbstractPolyhedron, witness::Bool=false) end """ - tosimplehrep(constraints::AbstractVector{LC}; - [n]::Int=0) where {N, LC<:HalfSpace{N}} + tosimplehrep(constraints::AbstractVector{<:HalfSpace}; [n]::Int=0) Return the simple H-representation ``Ax ≤ b`` from a list of linear constraints. @@ -116,8 +115,8 @@ vector of offsets. The parameter `n` can be used to create a matrix with no constraints but a non-zero dimension. """ -function tosimplehrep(constraints::AbstractVector{LC}; - n::Int=0) where {N,LC<:HalfSpace{N}} +function tosimplehrep(constraints::AbstractVector{<:HalfSpace}; n::Int=0) + N = eltype(eltype(constraints)) m = length(constraints) if m == 0 A = Matrix{N}(undef, 0, n) @@ -139,8 +138,8 @@ function tosimplehrep(constraints::AbstractVector{LC}; end """ - remove_redundant_constraints!(constraints::AbstractVector{S}; - [backend]=nothing) where {S<:HalfSpace} + remove_redundant_constraints!(constraints::AbstractVector{<:HalfSpace}; + [backend]=nothing) Remove the redundant constraints of a given list of linear constraints; the list is updated in-place. @@ -180,8 +179,8 @@ If the calculation finished successfully, this function returns `true`. For details, see [Fukuda's Polyhedra FAQ](https://www.cs.mcgill.ca/~fukuda/soft/polyfaq/node24.html). """ -function remove_redundant_constraints!(constraints::AbstractVector{S}; - backend=nothing) where {S<:HalfSpace} +function remove_redundant_constraints!(constraints::AbstractVector{<:HalfSpace}; + backend=nothing) if isempty(constraints) return true end @@ -224,8 +223,8 @@ function remove_redundant_constraints!(constraints::AbstractVector{S}; end """ - remove_redundant_constraints(constraints::AbstractVector{S}; - backend=nothing) where {S<:HalfSpace} + remove_redundant_constraints(constraints::AbstractVector{<:HalfSpace}; + backend=nothing) Remove the redundant constraints of a given list of linear constraints. @@ -248,8 +247,8 @@ If `backend` is `nothing`, it defaults to `default_lp_solver(N)`. See `remove_redundant_constraints!(::AbstractVector{<:HalfSpace})` for details. """ -function remove_redundant_constraints(constraints::AbstractVector{S}; - backend=nothing) where {S<:HalfSpace} +function remove_redundant_constraints(constraints::AbstractVector{<:HalfSpace}; + backend=nothing) constraints_copy = copy(constraints) if remove_redundant_constraints!(constraints_copy; backend=backend) return constraints_copy @@ -355,29 +354,30 @@ function _get_elimination_instance(N, backend, elimination_method) return LinearMapElimination(backend, elimination_method) end -function _default_linear_map_algorithm(M::AbstractMatrix{N}, P::LazySet; +function _default_linear_map_algorithm(M::AbstractMatrix, P::LazySet; cond_tol=DEFAULT_COND_TOL, backend=nothing, - elimination_method=nothing) where {N} + elimination_method=nothing) if _check_algorithm_applies(M, P, LinearMapInverse; cond_tol=cond_tol) algo = LinearMapInverse(inv(M)) elseif _check_algorithm_applies(M, P, LinearMapLift) algo = LinearMapLift() else + N = promote_type(eltype(M), eltype(P)) algo = _get_elimination_instance(N, backend, elimination_method) end return algo end """ - _linear_map_polyhedron(M::AbstractMatrix{NM}, - P::LazySet{NP}; + _linear_map_polyhedron(M::AbstractMatrix, + P::LazySet; [algorithm]::Union{String, Nothing}=nothing, [check_invertibility]::Bool=true, [cond_tol]::Number=DEFAULT_COND_TOL, [inverse]::Union{AbstractMatrix{N}, Nothing}=nothing, [backend]=nothing, - [elimination_method]=nothing) where {NM, NP} + [elimination_method]=nothing) Concrete linear map of a polyhedral set. @@ -557,18 +557,18 @@ the result back to half-space representation is not computed by default, since this may be costly. If you use this algorithm and still want to convert back to half-space representation, apply `tohrep` to the result of this method. """ -function _linear_map_polyhedron(M::AbstractMatrix{NM}, - P::LazySet{NP}; +function _linear_map_polyhedron(M::AbstractMatrix, + P::LazySet; algorithm::Union{String,Nothing}=nothing, check_invertibility::Bool=true, cond_tol::Number=DEFAULT_COND_TOL, inverse::Union{AbstractMatrix,Nothing}=nothing, backend=nothing, - elimination_method=nothing) where {NM,NP} - N = promote_type(NM, NP) - N != NP && error("conversion between numeric types of polyhedra not " * + elimination_method=nothing) + N = promote_type(eltype(M), eltype(P)) + N != eltype(P) && error("conversion between numeric types of polyhedra not " * "implemented yet (see #1181)") - if NM != NP + if eltype(M) != eltype(P) M = N.(M) end @@ -703,8 +703,8 @@ function _affine_map_inverse_hrep(A::AbstractMatrix, P::LazySet, end # preconditions should have been checked in the caller function -function _linear_map_hrep(M::AbstractMatrix{N}, P::AbstractPolyhedron{N}, - algo::LinearMapInverseRight) where {N} +function _linear_map_hrep(M::AbstractMatrix, P::AbstractPolyhedron, + algo::LinearMapInverseRight) constraints_P = constraints_list(P) constraints_MP = _preallocate_constraints(constraints_P) @inbounds for (i, c) in enumerate(constraints_P) @@ -716,10 +716,9 @@ function _linear_map_hrep(M::AbstractMatrix{N}, P::AbstractPolyhedron{N}, end # preconditions should have been checked in the caller function -function _linear_map_hrep(M::AbstractMatrix{NM}, P::AbstractPolyhedron{NP}, - algo::LinearMapLift) where {NM,NP} +function _linear_map_hrep(M::AbstractMatrix, P::AbstractPolyhedron, algo::LinearMapLift) m, n = size(M) - N = promote_type(NM, NP) + N = promote_type(eltype(M), eltype(P)) # we extend M to an invertible m x m matrix by appending m-n columns # orthogonal to the column space of M @@ -745,10 +744,9 @@ end # (there are length(x) in total) using Polyhedra.eliminate calls # to a backend library that can do variable elimination, typically CDDLib, # with the BlockElimination() algorithm. -function _linear_map_hrep(M::AbstractMatrix{NM}, P::AbstractPolyhedron{NP}, - algo::LinearMapElimination) where {NM,NP} +function _linear_map_hrep(M::AbstractMatrix, P::AbstractPolyhedron, algo::LinearMapElimination) m, n = size(M) - N = promote_type(NM, NP) + N = promote_type(eltype(M), eltype(P)) ₋Id_m = Matrix(-one(N) * I, m, m) backend = algo.backend method = algo.method @@ -840,8 +838,7 @@ function _plot_recipe_2d_vlist(vlist, N) end """ - an_element(P::AbstractPolyhedron{N}; - [solver]=default_lp_solver(N)) where {N} + an_element(P::AbstractPolyhedron; [solver]=default_lp_solver(eltype(P))) Return some element of a polyhedron. @@ -858,9 +855,9 @@ An element of the polyhedron, or an error if the polyhedron is empty. An element is obtained by solving a feasibility linear program. """ -function an_element(P::AbstractPolyhedron{N}; - solver=default_lp_solver(N)) where {N} +function an_element(P::AbstractPolyhedron; solver=default_lp_solver(eltype(P))) A, b = tosimplehrep(P) + N = eltype(P) lbounds, ubounds = -Inf, Inf sense = '<' @@ -877,7 +874,7 @@ function an_element(P::AbstractPolyhedron{N}; end """ - isbounded(P::AbstractPolyhedron{N}; [solver]=default_lp_solver(N)) where {N} + isbounded(P::AbstractPolyhedron; [solver]=default_lp_solver(eltype(P))) Check whether a polyhedron is bounded. @@ -898,7 +895,7 @@ necessary condition for boundedness. If so, we check boundedness via `_isbounded_stiemke`. """ -function isbounded(P::AbstractPolyhedron{N}; solver=default_lp_solver(N)) where {N} +function isbounded(P::AbstractPolyhedron; solver=default_lp_solver(eltype(P))) return isbounded(constraints_list(P); solver=solver) end @@ -1016,8 +1013,7 @@ function vertices_list(P::AbstractPolyhedron; check_boundedness::Bool=true) end """ - project(P::AbstractPolyhedron{N}, block::AbstractVector{Int}; - [kwargs...]) where {N} + project(P::AbstractPolyhedron, block::AbstractVector{Int}; [kwargs...]) Concrete projection of a polyhedral set. @@ -1097,8 +1093,7 @@ julia> project(P, [1, 2]) |> constraints_list HalfSpace{Float64, Vector{Float64}}([0.0, 1.0], 1.0) ``` """ -function project(P::AbstractPolyhedron{N}, block::AbstractVector{Int}; - kwargs...) where {N} +function project(P::AbstractPolyhedron, block::AbstractVector{Int}; kwargs...) # cheap case clist = nothing # allocate later @inbounds for c in constraints(P) @@ -1121,6 +1116,7 @@ function project(P::AbstractPolyhedron{N}, block::AbstractVector{Int}; end if isnothing(clist) # set is unconstrained in the given dimensions + N = eltype(P) return Universe{N}(length(block)) end @@ -1156,7 +1152,8 @@ function _check_constrained_dimensions(c::HalfSpace, block) return status end -function _project_polyhedron(P::LazySet{N}, block; kwargs...) where {N} +function _project_polyhedron(P::LazySet, block; kwargs...) + N = eltype(P) M = projection_matrix(block, dim(P), N) πP = linear_map(M, P; kwargs...) return constraints_list(πP) @@ -1169,8 +1166,9 @@ function _isempty_polyhedron_lp(constraints::AbstractVector{<:HalfSpace}, return _isempty_polyhedron_lp(A, b, witness; solver=solver) end -function _isempty_polyhedron_lp(A::AbstractMatrix{N}, b::AbstractVector{N}, - witness::Bool=false; solver=nothing) where {N} +function _isempty_polyhedron_lp(A::AbstractMatrix, b::AbstractVector, + witness::Bool=false; solver=nothing) + N = promote_type(eltype(A), eltype(b)) # feasibility LP lbounds, ubounds = -Inf, Inf sense = '<' @@ -1266,7 +1264,8 @@ function extrema(P::AbstractPolyhedron, i::Int) return _extrema_lowhigh(P, i) end -function _extrema_1d(P::AbstractPolyhedron{N}) where {N} +function _extrema_1d(P::AbstractPolyhedron) + N = eltype(P) l = N(-Inf) h = N(Inf) @inbounds for c in constraints(P) @@ -1301,7 +1300,8 @@ function low(P::AbstractPolyhedron, i::Int) return _low(P, i) end -function _low_1d(P::AbstractPolyhedron{N}) where {N} +function _low_1d(P::AbstractPolyhedron) + N = eltype(P) l = N(-Inf) @inbounds for c in constraints(P) a = c.a[1] @@ -1329,7 +1329,8 @@ function high(P::AbstractPolyhedron, i::Int) return _high(P, i) end -function _high_1d(P::AbstractPolyhedron{N}) where {N} +function _high_1d(P::AbstractPolyhedron) + N = eltype(P) h = N(Inf) @inbounds for c in constraints(P) a = c.a[1] diff --git a/src/Interfaces/AbstractZonotope.jl b/src/Interfaces/AbstractZonotope.jl index a1f2abd6f3..2b8ecbbb49 100644 --- a/src/Interfaces/AbstractZonotope.jl +++ b/src/Interfaces/AbstractZonotope.jl @@ -83,8 +83,7 @@ A generator matrix of `Z`. function genmat(::AbstractZonotope) end """ - genmat_fallback(Z::AbstractZonotope{N}; - [gens]=generators(Z), [ngens]=nothing) where {N} + genmat_fallback(Z::AbstractZonotope; [gens]=generators(Z), [ngens]=nothing) Fallback definition of `genmat` for zonotopic sets. @@ -105,9 +104,9 @@ Passing the number of generators (`ngens`) is more efficient, since otherwise the generators have to be obtained from the iterator (`gens`) and stored in an intermediate vector until the final result matrix can be allocated. """ -function genmat_fallback(Z::AbstractZonotope{N}; - gens=generators(Z), ngens=nothing) where {N} +function genmat_fallback(Z::AbstractZonotope; gens=generators(Z), ngens=nothing) if isempty(gens) + N = eltype(Z) return Matrix{N}(undef, dim(Z), 0) elseif isnothing(ngens) return _genmat_fallback_generic(Z, gens) @@ -116,7 +115,7 @@ function genmat_fallback(Z::AbstractZonotope{N}; end end -function _genmat_fallback_generic(Z::AbstractZonotope{N}, gens) where {N} +function _genmat_fallback_generic(Z::AbstractZonotope, gens) gens = collect(gens) return _genmat_fallback_ngens(Z, gens, length(gens)) end @@ -459,9 +458,8 @@ function _vertices_list_zonotope_2D_positive(c::AbstractVector{N}, G::AbstractMa return vlist end -function _vertices_list_zonotope_iterative(c::VN, G::MN; - apply_convex_hull::Bool) where {N,VN<:AbstractVector{N}, - MN<:AbstractMatrix{N}} +function _vertices_list_zonotope_iterative(c::VN, G::AbstractMatrix{N}; + apply_convex_hull::Bool) where {N,VN<:AbstractVector{N}} p = size(G, 2) vlist = Vector{VN}() sizehint!(vlist, 2^p) @@ -474,10 +472,9 @@ function _vertices_list_zonotope_iterative(c::VN, G::MN; end # special case 2D zonotope of order 1/2 -function _vertices_list_zonotope_2D_order_one_half(c::VN, G::MN; +function _vertices_list_zonotope_2D_order_one_half(c::VN, G::AbstractMatrix{N}; apply_convex_hull::Bool) where {N, - VN<:AbstractVector{N}, - MN} + VN<:AbstractVector{N}} vlist = Vector{VN}(undef, 2) g = view(G, :, 1) @inbounds begin @@ -488,10 +485,9 @@ function _vertices_list_zonotope_2D_order_one_half(c::VN, G::MN; end # special case 2D zonotope of order 1 -function _vertices_list_zonotope_2D_order_one(c::VN, G::MN; +function _vertices_list_zonotope_2D_order_one(c::VN, G::AbstractMatrix{N}; apply_convex_hull::Bool) where {N, - VN<:AbstractVector{N}, - MN} + VN<:AbstractVector{N}} vlist = Vector{VN}(undef, 4) a = [one(N), one(N)] b = [one(N), -one(N)] @@ -528,11 +524,11 @@ function _vertices_list_2D(c::AbstractVector{N}, G::AbstractMatrix{N}; return vertices_list(translate(reduce(minkowski_sum, polygons), c)) end -@inline function _angles(point::AbstractVector{N}) where {N} +@inline function _angles(point::AbstractVector) return (atand(point[2], point[1]) + 360) % 360 end -function _single_quadrant_vertices_enum(G::AbstractMatrix{N}, sorted::Bool=false) where {N} +function _single_quadrant_vertices_enum(G::AbstractMatrix, sorted::Bool=false) if !sorted G = sortslices(G; dims=2, by=_angles) end @@ -567,7 +563,7 @@ end end """ - constraints_list(Z::AbstractZonotope{N}) where {N<:AbstractFloat} + constraints_list(Z::AbstractZonotope{<:AbstractFloat}) Return a list of constraints defining a zonotopic set. @@ -600,7 +596,7 @@ zonotope to the non-flat dimensions and extend the result later. [1] Althoff, Stursberg, Buss. *Computing Reachable Sets of Hybrid Systems Using a Combination of Zonotopes and Polytopes*. 2009. """ -function constraints_list(Z::AbstractZonotope{N}) where {N<:AbstractFloat} +function constraints_list(Z::AbstractZonotope{<:AbstractFloat}) return _constraints_list_zonotope(Z) end diff --git a/src/Interfaces/ConvexSet.jl b/src/Interfaces/ConvexSet.jl index 1c3bab0b8e..6ccf803812 100644 --- a/src/Interfaces/ConvexSet.jl +++ b/src/Interfaces/ConvexSet.jl @@ -10,49 +10,3 @@ elements ``x, y ∈ S`` and ``0 ≤ λ ≤ 1`` it holds that ``λ·x + (1-λ)·y abstract type ConvexSet{N} <: LazySet{N} end isconvextype(X::Type{<:ConvexSet}) = true - -""" - low(X::ConvexSet{N}, i::Int) where {N} - -Return the lower coordinate of a convex set in a given dimension. - -### Input - -- `X` -- convex set -- `i` -- dimension of interest - -### Output - -The lower coordinate of the set in the given dimension. -""" -function low(X::ConvexSet{N}, i::Int) where {N} - # Note: this method is needed for documentation reasons - # (see the method for LazySet) - return _low(X, i) -end - -""" - high(X::ConvexSet{N}, i::Int) where {N} - -Return the higher coordinate of a convex set in a given dimension. - -### Input - -- `X` -- convex set -- `i` -- dimension of interest - -### Output - -The higher coordinate of the set in the given dimension. -""" -function high(X::ConvexSet{N}, i::Int) where {N} - # Note: this method is needed for documentation reasons - # (see the method for LazySet) - return _high(X, i) -end - -# Note: this method is needed for documentation reasons -# (see the method for LazySet) -function an_element(S::ConvexSet{N}) where {N} - return _an_element_lazySet(S) -end diff --git a/src/Interfaces/LazySet.jl b/src/Interfaces/LazySet.jl index 5c492390da..cc0756d4e5 100644 --- a/src/Interfaces/LazySet.jl +++ b/src/Interfaces/LazySet.jl @@ -1091,8 +1091,8 @@ end end """ - project(X::LazySet, block::AbstractVector{Int}, set_type::Type{T}, - [n]::Int=dim(X); [kwargs...]) where {T<:LazySet} + project(X::LazySet, block::AbstractVector{Int}, set_type::Type{<:LazySet}, + [n]::Int=dim(X); [kwargs...]) Project a set to a given block and set type, possibly involving an overapproximation. @@ -1116,16 +1116,16 @@ coordinates and zero otherwise. 2. Overapproximate the projected set using `overapproximate` and `set_type`. """ @inline function project(X::LazySet, block::AbstractVector{Int}, - set_type::Type{T}, n::Int=dim(X); - kwargs...) where {T<:LazySet} + set_type::Type{<:LazySet}, n::Int=dim(X); + kwargs...) lm = project(X, block, LinearMap, n) return overapproximate(lm, set_type) end """ project(X::LazySet, block::AbstractVector{Int}, - set_type_and_precision::Pair{T, N}, [n]::Int=dim(X); - [kwargs...]) where {T<:UnionAll, N<:Real} + set_type_and_precision::Pair{<:UnionAll,<:Real}, [n]::Int=dim(X); + [kwargs...]) Project a set to a given block and set type with a certified error bound. @@ -1153,8 +1153,8 @@ coordinates and zero otherwise. 2. Overapproximate the projected set with the given error bound `ε`. """ @inline function project(X::LazySet, block::AbstractVector{Int}, - set_type_and_precision::Pair{T,N}, n::Int=dim(X); - kwargs...) where {T<:UnionAll,N<:Real} + set_type_and_precision::Pair{<:UnionAll,<:Real}, n::Int=dim(X); + kwargs...) set_type, ε = set_type_and_precision @assert length(block) == 2 && set_type == HPolygon "currently only 2D HPolygon " * "projection is supported" @@ -1252,10 +1252,9 @@ function rationalize(::Type{T}, X::AbstractVector{<:LazySet{<:AbstractFloat}}, end """ - chebyshev_center_radius(P::LazySet{N}; + chebyshev_center_radius(P::LazySet; [backend]=default_polyhedra_backend(P), - [solver]=default_lp_solver_polyhedra(N; presolve=true) - ) where {N} + [solver]=default_lp_solver_polyhedra(eltype(P); presolve=true)) Compute a [Chebyshev center](https://en.wikipedia.org/wiki/Chebyshev_center) and the corresponding radius of a polytopic set. @@ -1283,9 +1282,9 @@ In general, the center of such a ball is not unique, but the radius is. We call `Polyhedra.chebyshevcenter`. """ -function chebyshev_center_radius(P::LazySet{N}; +function chebyshev_center_radius(P::LazySet; backend=default_polyhedra_backend(P), - solver=default_lp_solver_polyhedra(N; presolve=true)) where {N} + solver=default_lp_solver_polyhedra(eltype(P); presolve=true)) require(@__MODULE__, :Polyhedra; fun_name="chebyshev_center") if !ispolyhedral(P) && !isboundedtype(typeof(P)) error("can only compute a Chebyshev center for polytopes") @@ -1372,9 +1371,9 @@ function load_polyhedra_lazyset() # function to be loaded by Requires end # quote / load_polyhedra_lazyset() """ - isempty(P::LazySet{N}, witness::Bool=false; + isempty(P::LazySet, witness::Bool=false; [use_polyhedra_interface]::Bool=false, [solver]=nothing, - [backend]=nothing) where {N} + [backend]=nothing) Check whether a polyhedral set is empty. @@ -1385,7 +1384,7 @@ Check whether a polyhedral set is empty. - `use_polyhedra_interface` -- (optional, default: `false`) if `true`, we use the `Polyhedra` interface for the emptiness test - `solver` -- (optional, default: `nothing`) LP-solver backend; uses - `default_lp_solver(N)` if not provided + `default_lp_solver` if not provided - `backend` -- (optional, default: `nothing`) backend for polyhedral computations in `Polyhedra`; uses `default_polyhedra_backend(P)` if not provided @@ -1411,11 +1410,11 @@ The algorithm sets up a feasibility LP for the constraints of `P`. If `use_polyhedra_interface` is `true`, we call `Polyhedra.isempty`. Otherwise, we set up the LP internally. """ -function isempty(P::LazySet{N}, # type parameter must be present for Documenter +function isempty(P::LazySet, witness::Bool=false; use_polyhedra_interface::Bool=false, solver=nothing, - backend=nothing) where {N} + backend=nothing) @assert ispolyhedral(P) "this algorithm requires a polyhedral set" clist = constraints_list(P) if length(clist) < 2