Half-space (HalfSpace)
LazySets.HalfSpaceModule.HalfSpace
— TypeHalfSpace{N, VN<:AbstractVector{N}} <: AbstractPolyhedron{N}
Type that represents a (closed) half-space of the form $a⋅x ≤ b$.
Fields
a
– normal direction (non-zero)b
– constraint
Examples
The half-space $x + 2y - z ≤ 3$:
julia> HalfSpace([1, 2, -1.], 3.)
HalfSpace{Float64, Vector{Float64}}([1.0, 2.0, -1.0], 3.0)
To represent the set $y ≥ 0$ in the plane, we can rearrange the expression as $0x - y ≤ 0$:
julia> HalfSpace([0, -1.], 0.)
HalfSpace{Float64, Vector{Float64}}([0.0, -1.0], 0.0)
LazySets.HalfSpaceModule.LinearConstraint
— TypeLinearConstraint
Alias for HalfSpace
Conversion
convert(::Type{HalfSpace{N,Vector{N}}}, hs::HalfSpace{N,<:AbstractVector{N}}) where {N}
The following method requires the SymEngine
package.
Base.convert
— Methodconvert(::Type{HalfSpace{N}}, expr::Expr; vars::Vector{Basic}=Basic[]) where {N}
Return a LazySet.HalfSpace
given a symbolic expression that represents a half-space.
Input
expr
– a symbolic expressionvars
– (optional, default:nothing
): set of variables with respect to which the gradient is taken; if empty, we take the free symbols in the given expression
Output
A HalfSpace
, in the form ax <= b
.
Examples
julia> convert(HalfSpace, :(x1 <= -0.03))
HalfSpace{Float64, Vector{Float64}}([1.0], -0.03)
julia> convert(HalfSpace, :(x1 < -0.03))
HalfSpace{Float64, Vector{Float64}}([1.0], -0.03)
julia> convert(HalfSpace, :(x1 > -0.03))
HalfSpace{Float64, Vector{Float64}}([-1.0], 0.03)
julia> convert(HalfSpace, :(x1 >= -0.03))
HalfSpace{Float64, Vector{Float64}}([-1.0], 0.03)
julia> convert(HalfSpace, :(x1 + x2 <= 2*x4 + 6))
HalfSpace{Float64, Vector{Float64}}([1.0, 1.0, -2.0], 6.0)
You can also specify the set of "ambient" variables, even if not all of them appear:
julia> using SymEngine: Basic
julia> convert(HalfSpace, :(x1 + x2 <= 2*x4 + 6), vars=Basic[:x1, :x2, :x3, :x4])
HalfSpace{Float64, Vector{Float64}}([1.0, 1.0, 0.0, -2.0], 6.0)
Operations
LazySets.API.an_element
— Methodan_element(X::LazySet)
Return some element of a nonempty set.
Input
X
– set
Output
An element of X
unless X
is empty.
LazySets.API.an_element
— MethodExtended help
an_element(hs::HalfSpace)
Output
This method returns an element on the defining hyperplane.
LazySets.API.complement
— Methodcomplement(X::LazySet)
Compute the complement of a set.
Input
X
– set
Output
A set representing the complement of X
.
LazySets.API.complement
— MethodExtended help
complement(H::HalfSpace)
Algorithm
The result is the complementary half-space to H
. If $H: ⟨ a, x ⟩ ≤ b$, then this method returns the half-space $H′: ⟨ a, x ⟩ ≥ b$. (Note that complementarity is understood in a relaxed sense, since the intersection of $H$ and $H′$ is non-empty).
LazySets.constrained_dimensions
— Methodconstrained_dimensions(hs::HalfSpace)
Return the indices in which a half-space is constrained.
Input
hs
– half-space
Output
A vector of ascending indices i
such that the half-space is constrained in dimension i
.
Examples
A 2D half-space with constraint $x_1 ≥ 0$ is only constrained in dimension 1.
LazySets.API.constraints_list
— Methodconstraints_list(A::AbstractMatrix{N}, b::AbstractVector)
Convert a matrix-vector representation to a linear-constraint representation.
Input
A
– matrixb
– vector
Output
A list of linear constraints.
LazySets.isfeasible
— Functionisfeasible(constraints::AbstractVector{<:HalfSpace}, [witness]::Bool=false;
[solver]=nothing)
Check for feasibility of a list of linear constraints.
Input
constraints
– list of linear constraintswitness
– (optional; default:false
) flag for witness productionsolver
– (optional; default:nothing
) LP solver
Output
If witness
is false
, the result is a Bool
.
If witness
is true
, the result is a pair (res, w)
where res
is a Bool
and w
is a witness point/vector.
Algorithm
This implementation converts the constraints to matrix-vector form via tosimplehrep
and then calls isfeasible
on the result.
LazySets.API.isuniversal
— Functionisuniversal(X::LazySet, witness::Bool=false)
Check whether a set is universal.
Input
X
– setwitness
– (optional, default:false
) compute a witness if activated
Output
- If the
witness
option is deactivated:true
iff $X = ℝ^n$ - If the
witness
option is activated:(true, [])
iff $X = ℝ^n$(false, v)
iff $X ≠ ℝ^n$ for some $v ∉ X$
LazySets.API.isuniversal
— FunctionExtended help
isuniversal(hs::HalfSpace, [witness]::Bool=false)
Algorithm
Witness production falls back to an_element(::Hyperplane)
.
LinearAlgebra.normalize
— Methodnormalize(hs::HalfSpace{N}, p::Real=N(2)) where {N}
Normalize a half-space.
Input
hs
– half-spacep
– (optional, default:2
) norm
Output
A new half-space whose normal direction $a$ is normalized, i.e., such that $‖a‖_p = 1$ holds.
Base.rand
— Methodrand(T::Type{<:LazySet}; [N]::Type{<:Real}=Float64, [dim]::Int=2,
[rng]::AbstractRNG=GLOBAL_RNG, [seed]::Union{Int, Nothing}=nothing
)
Create a random set of the given set type.
Input
T
– set typeN
– (optional, default:Float64
) numeric typedim
– (optional, default: 2) dimensionrng
– (optional, default:GLOBAL_RNG
) random number generatorseed
– (optional, default:nothing
) seed for reseeding
Output
A random set of the given set type.
Base.rand
— MethodExtended help
rand(::Type{HalfSpace}; [N]::Type{<:Real}=Float64, [dim]::Int=2,
[rng]::AbstractRNG=GLOBAL_RNG, [seed]::Union{Int, Nothing}=nothing)
Algorithm
All numbers are normally distributed with mean 0 and standard deviation 1. Additionally, the constraint a
is nonzero.
LazySets.remove_redundant_constraints
— Methodremove_redundant_constraints(constraints::AbstractVector{<:HalfSpace}; backend=nothing)
Remove the redundant constraints of a given list of linear constraints.
Input
constraints
– list of constraintsbackend
– (optional, default:nothing
) the backend used to solve the linear program
Output
The list of constraints with the redundant ones removed, or an empty list if the constraints are infeasible.
Notes
If backend
is nothing
, it defaults to default_lp_solver(N)
.
Algorithm
See [remove_redundant_constraints!(::AbstractVector{<:HalfSpace})](@ref)
for details.
LazySets.remove_redundant_constraints!
— Methodremove_redundant_constraints!(constraints::AbstractVector{<:HalfSpace}; [backend]=nothing)
Remove the redundant constraints of a given list of linear constraints; the list is updated in-place.
Input
constraints
– list of constraintsbackend
– (optional, default:nothing
) the backend used to solve the linear program
Output
true
if the removal was successful and the list of constraints constraints
is modified by removing the redundant constraints, and false
only if the constraints are infeasible.
Notes
Note that the result may be true
even if the constraints are infeasible. For example, $x ≤ 0 && x ≥ 1$ will return true
without removing any constraint. To check if the constraints are infeasible, use isempty(HPolyhedron(constraints))
.
If backend
is nothing
, it defaults to default_lp_solver(N)
.
Algorithm
If there are m
constraints in n
dimensions, this function checks one by one if each of the m
constraints is implied by the remaining ones.
To check if the k
-th constraint is redundant, an LP is formulated using the constraints that have not yet been removed. If, at an intermediate step, it is detected that a subgroup of the constraints is infeasible, this function returns false
. If the calculation finished successfully, this function returns true
.
For details, see Fukuda's Polyhedra FAQ.
LazySets.tosimplehrep
— Methodtosimplehrep(constraints::AbstractVector{<:HalfSpace}; [n]::Int=0)
Return the simple H-representation $Ax ≤ b$ from a list of linear constraints.
Input
constraints
– a list of linear constraintsn
– (optional; default:0
) dimension of the constraints
Output
The tuple (A, b)
where A
is the matrix of normal directions and b
is the vector of offsets.
Notes
The parameter n
can be used to create a matrix with no constraints but a non-zero dimension. If n
≤ 0, this method takes the dimension of the first constraint.
ReachabilityBase.Arrays.distance
— Methoddistance(x::AbstractVector, H::HalfSpace)
Compute the distance between point x
and half-space H
with respect to the Euclidean norm.
Input
x
– vectorH
– half-space
Output
A scalar representing the distance between point x
and half-space H
.
Base.:∈
— Method∈(x::AbstractVector, X::LazySet)
Check whether a point lies in a set.
Input
x
– point/vectorX
– set
Output
true
iff $x ∈ X$.
Base.:∈
— MethodExtended help
∈(x::AbstractVector, hs::HalfSpace)
Algorithm
This implementation checks whether $x$ satisfies $a⋅x ≤ b$.
LazySets.API.project
— Methodproject(X::LazySet, block::AbstractVector{Int})
Project a set to a given block by using a concrete linear map.
Input
X
– setblock
– block structure - a vector with the dimensions of interest
Output
A set representing the projection of X
to block block
.
LazySets.API.project
— MethodExtended help
project(H::HalfSpace, block::AbstractVector{Int}; [kwargs...])
Algorithm
If the unconstrained dimensions of H
are a subset of the block
variables, the projection is applied to the normal direction of H
. Otherwise, the projection results in the universal set.
The latter can be seen as follows. Without loss of generality consider projecting out a single and constrained dimension $xₖ$ (projecting out multiple dimensions can be modeled by repeatedly projecting out one dimension). We can write the projection as an existentially quantified linear constraint:
\[ ∃xₖ: a₁x₁ + … + aₖxₖ + … + aₙxₙ ≤ b\]
Since $aₖ ≠ 0$, there is always a value for $xₖ$ that satisfies the constraint for any valuation of the other variables.
Examples
Consider the half-space $x + y + 0⋅z ≤ 1$, whose ambient dimension is 3
. The (trivial) projection in the three dimensions using the block of variables [1, 2, 3]
is:
julia> H = HalfSpace([1.0, 1.0, 0.0], 1.0)
HalfSpace{Float64, Vector{Float64}}([1.0, 1.0, 0.0], 1.0)
julia> project(H, [1, 2, 3])
HalfSpace{Float64, Vector{Float64}}([1.0, 1.0, 0.0], 1.0)
Projecting along dimensions 1
and 2
only:
julia> project(H, [1, 2])
HalfSpace{Float64, Vector{Float64}}([1.0, 1.0], 1.0)
For convenience, one can use project(H, constrained_dimensions(H))
to return the half-space projected on the dimensions where it is constrained:
julia> project(H, constrained_dimensions(H))
HalfSpace{Float64, Vector{Float64}}([1.0, 1.0], 1.0)
If a constrained dimension is projected, we get the universal set of the dimension corresponding to the projection.
julia> project(H, [1, 3])
Universe{Float64}(2)
julia> project(H, [1])
Universe{Float64}(1)
LazySets.API.ρ
— Methodρ(d::AbstractVector, X::LazySet)
Evaluate the support function of a set in a given direction.
Input
d
– directionX
– set
Output
The evaluation of the support function of X
in direction d
.
Notes
A convenience alias support_function
is also available.
We have the following identity based on the support vector $σ$:
\[ ρ(d, X) = d ⋅ σ(d, X)\]
LazySets.API.ρ
— MethodExtended help
ρ(d::AbstractVector, hs::HalfSpace)
Output
Unless the direction is (a multiple of) the normal direction of the half-space, the result is Inf
.
LazySets.API.σ
— Methodσ(d::AbstractVector, X::LazySet)
Compute a support vector of a set in a given direction.
Input
d
– directionX
– set
Output
A support vector of X
in direction d
.
Notes
A convenience alias support_vector
is also available.
LazySets.API.σ
— MethodExtended help
σ(d::AbstractVector, hs::HalfSpace)
Output
The support vector in the given direction, which is only defined in the following two cases:
- The direction has norm zero.
- The direction is (a multiple of) the normal direction of the half-space.
In both cases the result is any point on the boundary (the defining hyperplane). Otherwise this function throws an error.
LazySets.API.translate
— Methodtranslate(X::LazySet, v::AbstractVector)
Compute the translation of a set with a vector.
Input
X
– setv
– vector
Output
A set representing $X + \{v\}$.
LazySets.API.translate
— MethodExtended help
translate(hs::HalfSpace, v::AbstractVector; [share]::Bool=false)
Notes
The normal vector of the half-space (vector a
in a⋅x ≤ b
) is shared with the original half-space if share == true
.
Algorithm
A half-space $a⋅x ≤ b$ is transformed to the half-space $a⋅x ≤ b + a⋅v$. In other words, we add the dot product $a⋅v$ to $b$.
LazySets.HalfSpaceModule.iscomplement
— Methodiscomplement(H1::HalfSpace, H2::HalfSpace)
Check if two half-spaces complement each other.
Input
H1
– half-spaceH2
– half-space
Output
true
iff H1
and H2
are complementary, i.e., have opposite normal directions and identical boundaries (defining hyperplanes).
Base.isdisjoint
— Methodisdisjoint(X::LazySet, Y::LazySet, [witness]::Bool=false)
Check whether two sets are disjoint (i.e., do not intersect), and optionally compute a witness.
Input
X
– setY
– setwitness
– (optional, default:false
) compute a witness if activated
Output
- If the
witness
option is deactivated:true
iff $X ∩ Y = ∅$ - If the
witness
option is activated:(true, [])
iff $X ∩ Y = ∅$(false, v)
iff $X ∩ Y ≠ ∅$ for some $v ∈ X ∩ Y$
Notes
The convenience alias is_intersection_empty
is also available.
Base.isdisjoint
— FunctionExtended help
isdisjoint(H1::HalfSpace, H2::HalfSpace, [witness]::Bool=false)
Algorithm
Two half-spaces do not intersect if and only if their normal vectors point in the opposite direction and there is a gap between the two defining hyperplanes.
The latter can be checked as follows: Let $H1 : a_1⋅x = b_1$ and $H2 : a_2⋅x = b_2$. Then we already know that $a_2 = -k⋅a_1$ for some positive scaling factor $k$. Let $x_1$ be a point on the defining hyperplane of $H1$. We construct a line segment from $x_1$ to the point $x_2$ on the defining hyperplane of $hs_2$ by shooting a ray from $x_1$ with direction $a_1$. Thus we look for a factor $s$ such that $(x_1 + s⋅a_1)⋅a_2 = b_2$. This gives us $s = (b_2 - x_1⋅a_2) / (-k a_1⋅a_1)$. The gap exists if and only if $s$ is positive.
If the normal vectors do not point in opposite directions, then the defining hyperplanes intersect and we can produce a witness as follows. All points $x$ in this intersection satisfy $a_1⋅x = b_1$ and $a_2⋅x = b_2$. Thus we have $(a_1 + a_2)⋅x = b_1+b_2$. We now find a dimension where $a_1 + a_2$ is non-zero, say, $i$. Then the result is a vector with one non-zero entry in dimension $i$, defined as $[0, …, 0, (b_1 + b_2)/(a_1[i] + a_2[i]), 0, …, 0]$. Such a dimension $i$ always exists.
LazySets.HalfSpaceModule.halfspace_left
— Methodhalfspace_left(p::AbstractVector, q::AbstractVector)
Return a half-space describing the 'left' of a two-dimensional line segment through two points.
Input
p
– first pointq
– second point
Output
The half-space whose boundary goes through the two points p
and q
and which describes the left-hand side of the directed line segment pq
.
Algorithm
The half-space $a⋅x ≤ b$ is calculated as a = [dy, -dx]
, where $d = (dx, dy)$ denotes the line segment pq
, i.e., $\vec{d} = \vec{p} - \vec{q}$, and b = dot(p, a)
.
Examples
The left half-space of the "east" and "west" directions in two-dimensions are the upper and lower half-spaces:
julia> using LazySets: halfspace_left
julia> halfspace_left([0.0, 0.0], [1.0, 0.0])
HalfSpace{Float64, Vector{Float64}}([0.0, -1.0], 0.0)
julia> halfspace_left([0.0, 0.0], [-1.0, 0.0])
HalfSpace{Float64, Vector{Float64}}([0.0, 1.0], 0.0)
We create a box from the sequence of line segments that describe its edges:
julia> H1 = halfspace_left([-1.0, -1.0], [1.0, -1.0]);
julia> H2 = halfspace_left([1.0, -1.0], [1.0, 1.0]);
julia> H3 = halfspace_left([1.0, 1.0], [-1.0, 1.0]);
julia> H4 = halfspace_left([-1.0, 1.0], [-1.0, -1.0]);
julia> H = HPolygon([H1, H2, H3, H4]);
julia> B = BallInf([0.0, 0.0], 1.0);
julia> B ⊆ H && H ⊆ B
true
LazySets.HalfSpaceModule.halfspace_right
— Methodhalfspace_right(p::AbstractVector, q::AbstractVector)
Return a half-space describing the 'right' of a two-dimensional line segment through two points.
Input
p
– first pointq
– second point
Output
The half-space whose boundary goes through the two points p
and q
and which describes the right-hand side of the directed line segment pq
.
Algorithm
See the documentation of halfspace_left
.
LazySets._ishalfspace
— Function_ishalfspace(expr::Expr)
Determine whether the given expression corresponds to a half-space.
Input
expr
– a symbolic expression
Output
true
if expr
corresponds to a half-space or false
otherwise.
Examples
julia> using LazySets: _ishalfspace
julia> all(_ishalfspace.([:(x1 <= 0), :(x1 < 0), :(x1 > 0), :(x1 >= 0)]))
true
julia> _ishalfspace(:(x1 = 0))
false
julia> _ishalfspace(:(2*x1 <= 4))
true
julia> _ishalfspace(:(6.1 <= 5.3*f - 0.1*g))
true
julia> _ishalfspace(:(2*x1^2 <= 4))
false
julia> _ishalfspace(:(x1^2 > 4*x2 - x3))
false
julia> _ishalfspace(:(x1 > 4*x2 - x3))
true
Undocumented implementations:
Inherited from LazySet
:
area
chebyshev_center_radius
concretize
constraints
convex_hull
copy(::Type{LazySet})
delaunay
diameter
eltype
eltype
isboundedtype
isoperation
norm
polyhedron
radius
rationalize
rectify
reflect
singleton_list
surface
tosimplehrep
triangulate
vertices
affine_map
exponential_map
is_interior_point
linear_map
sample
scale
cartesian_product
convex_hull
difference
distance
exact_sum
≈
==
isequivalent
⊂
minkowski_difference
Inherited from ConvexSet
:
Inherited from AbstractPolyhedron
: