diff --git a/docs/src/lib/representations.md b/docs/src/lib/representations.md index 2b7b19c865..bce3c975d9 100644 --- a/docs/src/lib/representations.md +++ b/docs/src/lib/representations.md @@ -25,6 +25,7 @@ Ball2 ∈(::AbstractVector{N}, ::Ball2{N}) where {N<:AbstractFloat} center(::Ball2{N}) where {N<:AbstractFloat} rand(::Type{Ball2}) +translate(::Ball2{N}, ::AbstractVector{N}) where {N<:AbstractFloat} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -46,6 +47,7 @@ radius(::BallInf, ::Real=Inf) radius_hyperrectangle(::BallInf{N}) where {N<:Real} radius_hyperrectangle(::BallInf{N}, ::Int) where {N<:Real} rand(::Type{BallInf}) +translate(::BallInf{N}, ::AbstractVector{N}) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`diameter`](@ref diameter(::LazySet, ::Real)) @@ -77,6 +79,7 @@ vertices_list(::Ball1{N}) where {N<:Real} center(::Ball1{N}) where {N<:Real} rand(::Type{Ball1}) constraints_list(::Ball1{N}) where {N<:Real} +translate(::Ball1{N}, ::AbstractVector{N}) where {N<:Real} ``` Inherited from [`LazySet`](@ref): @@ -101,6 +104,7 @@ Ballp ∈(::AbstractVector{N}, ::Ballp{N}) where {N<:AbstractFloat} center(::Ballp{N}) where {N<:AbstractFloat} rand(::Type{Ballp}) +translate(::Ballp{N}, ::AbstractVector{N}) where {N<:AbstractFloat} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -121,6 +125,7 @@ Ellipsoid ∈(::AbstractVector{N}, ::Ellipsoid{N}) where {N<:AbstractFloat} rand(::Type{Ellipsoid}) center(::Ellipsoid{N}) where {N<:AbstractFloat} +translate(::Ellipsoid{N}, ::AbstractVector{N}) where {N<:AbstractFloat} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -149,6 +154,7 @@ norm(::EmptySet, ::Real=Inf) radius(::EmptySet, ::Real=Inf) diameter(::EmptySet, ::Real=Inf) linear_map(::AbstractMatrix{N}, ::EmptySet{N}) where {N} +translate(::EmptySet{N}, ::AbstractVector{N}) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -171,6 +177,7 @@ isempty(::HalfSpace) constraints_list(::HalfSpace{N}) where {N<:Real} constraints_list(::AbstractMatrix{N}, ::AbstractVector{N}) where {N<:Real} constrained_dimensions(::HalfSpace{N}) where {N<:Real} +translate(::HalfSpace{N}, ::AbstractVector{N}) where {N<:Real} halfspace_left(::AbstractVector{N}, ::AbstractVector{N}) where {N<:Real} halfspace_right(::AbstractVector{N}, ::AbstractVector{N}) where {N<:Real} tosimplehrep(::AbstractVector{HalfSpace{N}}) where {N<:Real} @@ -196,6 +203,7 @@ isbounded(::Hyperplane) isempty(::Hyperplane) constrained_dimensions(::Hyperplane{N}) where {N<:Real} constraints_list(::Hyperplane{N}) where {N<:Real} +translate(::Hyperplane{N}, ::AbstractVector{N}) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -210,6 +218,7 @@ rand(::Type{Hyperrectangle}) center(::Hyperrectangle{N}) where {N<:Real} radius_hyperrectangle(::Hyperrectangle{N}) where {N<:Real} radius_hyperrectangle(::Hyperrectangle{N}, ::Int) where {N<:Real} +translate(::Hyperrectangle{N}, ::AbstractVector{N}) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`diameter`](@ref diameter(::LazySet, ::Real)) @@ -242,6 +251,7 @@ dim(::Interval) ∈(::N, ::Interval{N}) where {N<:Real} an_element(::Interval{N}) where {N<:Real} vertices_list(::Interval{N}) where {N<:Real} +translate(::Interval{N}, ::AbstractVector{N}) where {N<:Real} center(::Interval{N}) where {N<:Real} min(::Interval{N}) where {N<:Real} max(::Interval{N}) where {N<:Real} @@ -283,6 +293,7 @@ isbounded(::Line) isempty(::Line) constrained_dimensions(::Line{N}) where {N<:Real} constraints_list(::Line{N}) where {N<:Real} +translate(::Line{N}, ::AbstractVector{N}) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -303,6 +314,7 @@ halfspace_left(::LineSegment) halfspace_right(::LineSegment) vertices_list(::LineSegment{N}) where {N<:Real} constraints_list(::LineSegment{N}) where {N<:Real} +translate(::LineSegment{N}, ::AbstractVector{N}) where {N<:Real} RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::LineSegment) RecipesBase.apply_recipe(::Dict{Symbol,Any}, ::Vector{S}) where {S<:LineSegment} ``` @@ -324,6 +336,7 @@ Inherited from [`AbstractCentrallySymmetricPolytope`](@ref): ```@docs HPolygon σ(::AbstractVector{N}, ::HPolygon{N}) where {N<:Real} +translate(::HPolygon{N}, ::AbstractVector{N}) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -355,6 +368,7 @@ Inherited from [`AbstractHPolygon`](@ref): ```@docs HPolygonOpt σ(::AbstractVector{N}, ::HPolygonOpt{N}) where {N<:Real} +translate(::HPolygonOpt{N}, ::AbstractVector{N}) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`norm`](@ref norm(::LazySet, ::Real)) @@ -392,6 +406,7 @@ vertices_list(::VPolygon{N}) where {N<:Real} tohrep(::VPolygon{N}, ::Type{HPOLYGON}=HPolygon) where {N<:Real, HPOLYGON<:AbstractHPolygon} tovrep(::VPolygon{N}) where {N<:Real} constraints_list(::VPolygon{N}) where {N<:Real} +translate(::VPolygon{N}, ::AbstractVector{N}) where {N<:Real} remove_redundant_vertices(::VPolygon{N}; ::String="monotone_chain") where {N<:Real} remove_redundant_vertices!(::VPolygon{N}; ::String="monotone_chain") where {N<:Real} ``` @@ -443,6 +458,7 @@ constraints_list(::HPoly{N}) where {N<:Real} tohrep(::HPoly{N}) where {N<:Real} tovrep(::HPoly{N}) where {N<:Real} isempty(::HPoly{N}, ::Bool=false) where {N<:Real} +translate(::PT, ::AbstractVector{N}) where {N<:Real, PT<:HPoly{N}} cartesian_product(::HPoly{N}, ::HPoly{N}) where {N<:Real} polyhedron(::HPoly{N}) where {N<:Real} remove_redundant_constraints(::PT) where {N<:Real, PT<:HPoly{N}} @@ -459,7 +475,7 @@ Inherited from [`AbstractPolyhedron`](@ref): * [`constrained_dimensions`](@ref constrained_dimensions(::AbstractPolyhedron) * [`linear_map`](@ref linear_map(::AbstractMatrix{N}, ::AbstractPolyhedron{N}) where {N<:Real}) -#### Polytopes in constraint representation +#### Polytopes The following methods are specific for `HPolytope`. @@ -491,6 +507,7 @@ dim(::VPolytope) σ(::AbstractVector{N}, ::VPolytope{N}) where {N<:Real} ∈(::AbstractVector{N}, ::VPolytope{N}) where {N<:Real} rand(::Type{VPolytope}) +translate(::VPolytope{N}, ::AbstractVector{N}) where {N<:Real} vertices_list(::VPolytope{N}) where {N<:Real} remove_redundant_vertices(::VPolytope{N}) where {N<:Real} constraints_list(::VPolytope{N}) where {N<:Real} @@ -518,6 +535,7 @@ Singleton rand(::Type{Singleton}) element(::Singleton{N}) where {N<:Real} element(::Singleton{N}, ::Int) where {N<:Real} +translate(::Singleton{N}, ::AbstractVector{N}) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`diameter`](@ref diameter(::LazySet, ::Real)) @@ -563,6 +581,7 @@ radius(::Universe, ::Real=Inf) diameter(::Universe, ::Real=Inf) constraints_list(::Universe{N}) where {N<:Real} constrained_dimensions(::Universe) +translate(::Universe{N}, ::AbstractVector{N}) where {N<:Real} ``` ## Zero set @@ -576,6 +595,7 @@ rand(::Type{ZeroSet}) element(::ZeroSet{N}) where {N<:Real} element(::ZeroSet{N}, ::Int) where {N<:Real} linear_map(::AbstractMatrix{N}, ::ZeroSet{N}) where {N<:Real} +translate(::ZeroSet{N}, ::AbstractVector{N}) where {N<:Real} ``` Inherited from [`LazySet`](@ref): * [`diameter`](@ref diameter(::LazySet, ::Real)) @@ -614,6 +634,7 @@ center(::Zonotope{N}) where {N<:Real} order(::Zonotope) minkowski_sum(::Zonotope{N}, ::Zonotope{N}) where {N<:Real} linear_map(::AbstractMatrix{N}, ::Zonotope{N}) where {N<:Real} +translate(::Zonotope{N}, ::AbstractVector{N}) where {N<:Real} scale(::Real, ::Zonotope) ngens(::Zonotope) reduce_order(::Zonotope, r) diff --git a/docs/src/man/set_operations.md b/docs/src/man/set_operations.md index ce54c5b773..b6a66eb4d3 100644 --- a/docs/src/man/set_operations.md +++ b/docs/src/man/set_operations.md @@ -61,58 +61,58 @@ The table entries have the following meaning. - "i" indicates that the operation is inherited from a supertype. -| type ↓ \ operation → | dim | ρ | σ | an_element | ∈ | isempty | isbounded | linear_map | norm | radius | diameter | -|------------------------------|-----|---|---|------------|---|---------|-----------|------------|------|--------|----------| -| **Interfaces** | | | | | | | | | | | | -| `LazySet` | | x | | x | | | x | | | | x | -| `APolytope` | | i | | i | | x | x | x | | | i | -| `ACentrallySymmetric` | x | i | | x | | x | x | | | | i | -| `ACentrallySymmetricPolytope`| i | i | | i | | x | i | i | | | i | -| `APolygon` | x | i | | i | | i | i | i | | | i | -| `AHyperrectangle` | i | i | x | i | x | i | i | i | x | x | i | -| `AHPolygon` | i | i | | x | x | i | i | i | | | i | -| `ASingleton` | i | i | x | i | x | i | i | x | i | i | i | -| | | | | | | | | | | | | -| **Basic set types** | | | | | | | | | | | | -| `Ball1` | i | i | x | i | x | i | i | i | | | i | -| `Ball2` | i | i | x | i | x | i | i | | | | i | -| `BallInf` | i | i | i | i | i | i | i | i | i | x | i | -| `Ballp` | i | i | x | i | x | i | i | | | | i | -| `Ellipsoid` | i | i | x | i | x | i | i | | | | i | -| `EmptySet` | x | i | x | x | x | x | x | | x | x | x | -| `HalfSpace` | x | x | x | x | x | x | x | | | | i | -| `HPolygon`/`HPolygonOpt` | i | i | x | i | i | i | i | i | | | i | -| `HPolyhedron` | x | x | x | i | x | x | x | x | | | i | -| `HPolytope` | x | x | x | i | x | x | i | x | | | i | -| `Hyperplane` | x | x | x | x | x | x | x | | | | i | -| `Hyperrectangle` | i | i | i | i | i | i | i | i | i | i | i | -| `Interval` | x | i | x | x | x | i | i | i | i | i | i | -| `Line` | x | i | x | x | x | x | x | | | | i | -| `LineSegment` | x | i | x | x | x | i | i | i | | | i | -| `Singleton` | i | i | i | i | i | i | i | i | i | i | i | -| `Universe` | x | x | x | x | x | x | x | | x | x | x | -| `VPolygon` | i | i | x | x | x | i | i | x | | | i | -| `VPolytope` | x | i | x | i | x | i | i | x | | | i | -| `ZeroSet` | x | i | x | i | x | i | i | x | i | i | i | -| `Zonotope` | i | i | x | i | x | i | i | x | | | i | -| | | | | | | | | | | | | -| **Lazy set operation types** | | | | | | | | | | | | -| `CartesianProduct` | x | x | x | i | x | x | x | | | | i | -| `CartesianProductArray` | x | x | x | i | x | x | x | | | | i | -| `ConvexHull` | x | x | x | i | | x | x | | | | i | -| `ConvexHullArray` | x | x | x | i | | x | x | | | | i | -| `ExponentialMap` | x | x | x | i | x | x | x | | | | i | -| `ExponentialProjectionMap` | x | i | x | i | | x | x | | | | i | -| `Intersection` | x | x | | i | x | x | x | | | | i | -| `IntersectionArray` | x | i | | i | x | | x | | | | i | -| `LinearMap` | x | x | x | x | x | x | x | | | | i | -| `MinkowskiSum` | x | x | x | i | | x | x | | | | i | -| `MinkowskiSumArray` | x | x | x | i | | x | x | | | | i | -| `CacheMinkowskiSum` | x | i | x | i | | x | x | | | | i | -| `ResetMap` | x | x | x | x | | x | | | | | i | -| `SymmetricIntervalHull` | x | i | x | i | i | i | i | i | i | i | i | -| `UnionSet` | x | x | x | x | x | x | x | | | | | -| `UnionSetArray` | x | x | x | x | x | x | x | | | | | +| type ↓ \ operation → | dim | ρ | σ | an_element | ∈ | isempty | isbounded | linear_map | translate | norm | radius | diameter | +|------------------------------|-----|---|---|------------|---|---------|-----------|------------|-----------|------|--------|----------| +| **Interfaces** | | | | | | | | | | | | | +| `LazySet` | | x | | x | | | x | | | | | x | +| `APolytope` | | i | | i | | x | x | x | | | | i | +| `ACentrallySymmetric` | x | i | | x | | x | x | | | | | i | +| `ACentrallySymmetricPolytope`| i | i | | i | | x | i | i | | | | i | +| `APolygon` | x | i | | i | | i | i | i | | | | i | +| `AHyperrectangle` | i | i | x | i | x | i | i | i | | x | x | i | +| `AHPolygon` | i | i | | x | x | i | i | i | | | | i | +| `ASingleton` | i | i | x | i | x | i | i | x | | i | i | i | +| | | | | | | | | | | | | | +| **Basic set types** | | | | | | | | | | | | | +| `Ball1` | i | i | x | i | x | i | i | i | x | | | i | +| `Ball2` | i | i | x | i | x | i | i | | x | | | i | +| `BallInf` | i | i | i | i | i | i | i | i | x | i | x | i | +| `Ballp` | i | i | x | i | x | i | i | | x | | | i | +| `Ellipsoid` | i | i | x | i | x | i | i | | x | | | i | +| `EmptySet` | x | i | x | x | x | x | x | | x | x | x | x | +| `HalfSpace` | x | x | x | x | x | x | x | | x | | | i | +| `HPolygon`/`HPolygonOpt` | i | i | x | i | i | i | i | i | x | | | i | +| `HPolyhedron` | x | x | x | i | x | x | x | x | x | | | i | +| `HPolytope` | x | x | x | i | x | x | i | x | x | | | i | +| `Hyperplane` | x | x | x | x | x | x | x | | x | | | i | +| `Hyperrectangle` | i | i | i | i | i | i | i | i | x | i | i | i | +| `Interval` | x | i | x | x | x | i | i | i | x | i | i | i | +| `Line` | x | i | x | x | x | x | x | | x | | | i | +| `LineSegment` | x | i | x | x | x | i | i | i | x | | | i | +| `Singleton` | i | i | i | i | i | i | i | i | x | i | i | i | +| `Universe` | x | x | x | x | x | x | x | | x | x | x | x | +| `VPolygon` | i | i | x | x | x | i | i | x | x | | | i | +| `VPolytope` | x | i | x | i | x | i | i | x | x | | | i | +| `ZeroSet` | x | i | x | i | x | i | i | x | x | i | i | i | +| `Zonotope` | i | i | x | i | x | i | i | x | x | | | i | +| | | | | | | | | | | | | | +| **Lazy set operation types** | | | | | | | | | | | | | +| `CartesianProduct` | x | x | x | i | x | x | x | | | | | i | +| `CartesianProductArray` | x | x | x | i | x | x | x | | | | | i | +| `ConvexHull` | x | x | x | i | | x | x | | | | | i | +| `ConvexHullArray` | x | x | x | i | | x | x | | | | | i | +| `ExponentialMap` | x | x | x | i | x | x | x | | | | | i | +| `ExponentialProjectionMap` | x | i | x | i | | x | x | | | | | i | +| `Intersection` | x | x | | i | x | x | x | | | | | i | +| `IntersectionArray` | x | i | | i | x | | x | | | | | i | +| `LinearMap` | x | x | x | x | x | x | x | | | | | i | +| `MinkowskiSum` | x | x | x | i | | x | x | | | | | i | +| `MinkowskiSumArray` | x | x | x | i | | x | x | | | | | i | +| `CacheMinkowskiSum` | x | i | x | i | | x | x | | | | | i | +| `ResetMap` | x | x | x | x | | x | | | | | | i | +| `SymmetricIntervalHull` | x | i | x | i | i | i | i | i | | i | i | i | +| `UnionSet` | x | x | x | x | x | x | x | | | | | | +| `UnionSetArray` | x | x | x | x | x | x | x | | | | | | ### `dim` diff --git a/src/Ball1.jl b/src/Ball1.jl index 203c2f06b3..8456466022 100644 --- a/src/Ball1.jl +++ b/src/Ball1.jl @@ -250,3 +250,27 @@ function constraints_list(B::Ball1{N})::Vector{LinearConstraint{N}} where {N<:Re end return clist end + +""" + translate(B::Ball1{N}, v::AbstractVector{N}) where {N<:Real} + +Translate (i.e., shift) a ball in the 1-norm by a given vector. + +### Input + +- `B` -- ball in the 1-norm +- `v` -- translation vector + +### Output + +A translated ball in the 1-norm. + +### Algorithm + +We add the vector to the center of the ball. +""" +function translate(B::Ball1{N}, v::AbstractVector{N}) where {N<:Real} + @assert length(v) == dim(B) "cannot translate a $(dim(B))-dimensional " * + "set by a $(length(v))-dimensional vector" + return Ball1(center(B) + v, B.radius) +end \ No newline at end of file diff --git a/src/Ball2.jl b/src/Ball2.jl index 1bd35a6096..0c4fbb809a 100644 --- a/src/Ball2.jl +++ b/src/Ball2.jl @@ -210,3 +210,27 @@ function rand(::Type{Ball2}; radius = abs(randn(rng, N)) return Ball2(center, radius) end + +""" + translate(B::Ball2{N}, v::AbstractVector{N}) where {N<:AbstractFloat} + +Translate (i.e., shift) a ball in the 2-norm by a given vector. + +### Input + +- `B` -- ball in the 2-norm +- `v` -- translation vector + +### Output + +A translated ball in the 2-norm. + +### Algorithm + +We add the vector to the center of the ball. +""" +function translate(B::Ball2{N}, v::AbstractVector{N}) where {N<:AbstractFloat} + @assert length(v) == dim(B) "cannot translate a $(dim(B))-dimensional " * + "set by a $(length(v))-dimensional vector" + return Ball2(center(B) + v, B.radius) +end \ No newline at end of file diff --git a/src/BallInf.jl b/src/BallInf.jl index bb4fdbee27..4d5ef18b0f 100644 --- a/src/BallInf.jl +++ b/src/BallInf.jl @@ -175,3 +175,27 @@ function rand(::Type{BallInf}; radius = abs(randn(rng, N)) return BallInf(center, radius) end + +""" + translate(B::BallInf{N}, v::AbstractVector{N}) where {N<:Real} + +Translate (i.e., shift) a ball in the infinity norm by a given vector. + +### Input + +- `B` -- ball in the infinity norm +- `v` -- translation vector + +### Output + +A translated ball in the infinity norm. + +### Algorithm + +We add the vector to the center of the ball. +""" +function translate(B::BallInf{N}, v::AbstractVector{N}) where {N<:Real} + @assert length(v) == dim(B) "cannot translate a $(dim(B))-dimensional " * + "set by a $(length(v))-dimensional vector" + return BallInf(center(B) + v, B.radius) +end diff --git a/src/Ballp.jl b/src/Ballp.jl index b36255ff2f..fd05fd4c2c 100644 --- a/src/Ballp.jl +++ b/src/Ballp.jl @@ -236,3 +236,27 @@ function rand(::Type{Ballp}; radius = abs(randn(rng, N)) return Ballp(p, center, radius) end + +""" + translate(B::Ballp{N}, v::AbstractVector{N}) where {N<:AbstractFloat} + +Translate (i.e., shift) a ball in the p-norm by a given vector. + +### Input + +- `B` -- ball in the p-norm +- `v` -- translation vector + +### Output + +A translated ball in the p- norm. + +### Algorithm + +We add the vector to the center of the ball. +""" +function translate(B::Ballp{N}, v::AbstractVector{N}) where {N<:AbstractFloat} + @assert length(v) == dim(B) "cannot translate a $(dim(B))-dimensional " * + "set by a $(length(v))-dimensional vector" + return Ballp(B.p, center(B) + v, B.radius) +end diff --git a/src/Ellipsoid.jl b/src/Ellipsoid.jl index 620d901a0f..85babb7a70 100644 --- a/src/Ellipsoid.jl +++ b/src/Ellipsoid.jl @@ -231,3 +231,37 @@ function rand(::Type{Ellipsoid}; Matrix{N}(dim*I, dim, dim) return Ellipsoid(center, shape_matrix) end + +""" + translate(E::Ellipsoid{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:AbstractFloat} + +Translate (i.e., shift) an ellipsoid by a given vector. + +### Input + +- `E` -- ellipsoid +- `v` -- translation vector +- `share` -- (optional, default: `false`) flag for sharing unmodified parts of + the original set representation + +### Output + +A translated ellipsoid. + +### Notes + +The shape matrix is shared with the original ellipsoid if `share == true`. + +### Algorithm + +We add the vector to the center of the ellipsoid. +""" +function translate(E::Ellipsoid{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:AbstractFloat} + @assert length(v) == dim(E) "cannot translate a $(dim(E))-dimensional " * + "set by a $(length(v))-dimensional vector" + c = center(E) + v + shape_matrix = share ? E.shape_matrix : copy(E.shape_matrix) + return Ellipsoid(c, shape_matrix) +end diff --git a/src/EmptySet.jl b/src/EmptySet.jl index 2a35965a13..1e2267b50b 100644 --- a/src/EmptySet.jl +++ b/src/EmptySet.jl @@ -243,3 +243,21 @@ Return the linear map of an empty set. The empty set. """ linear_map(M::AbstractMatrix{N}, ∅::EmptySet{N}) where {N} = ∅ + +""" + translate(∅::EmptySet{N}, v::AbstractVector{N}) where {N<:Real} + +Translate (i.e., shift) an empty set by a given vector. + +### Input + +- `∅` -- empty set +- `v` -- translation vector + +### Output + +The empty set. +""" +function translate(∅::EmptySet{N}, v::AbstractVector{N}) where {N<:Real} + return ∅ +end diff --git a/src/HPolygon.jl b/src/HPolygon.jl index 3fbbd6e49e..d8a14c2a60 100644 --- a/src/HPolygon.jl +++ b/src/HPolygon.jl @@ -146,3 +146,40 @@ function σ(d::AbstractVector{N}, P::HPolygon{N}; Line(P.constraints[k-1]))) end end + +""" + translate(v::AbstractVector{N}, P::HPolygon{N}; share::Bool=false + ) where {N<:Real} + +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{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + @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 diff --git a/src/HPolygonOpt.jl b/src/HPolygonOpt.jl index b7c6486faf..12eb74bcd2 100644 --- a/src/HPolygonOpt.jl +++ b/src/HPolygonOpt.jl @@ -182,3 +182,40 @@ function σ(d::AbstractVector{N}, P::HPolygonOpt{N}; end end end + +""" + translate(P::HPolygonOpt{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + +Translate (i.e., shift) an optimized polygon in constraint representation by a +given vector. + +### Input + +- `P` -- optimized polygon in constraint representation +- `v` -- translation vector +- `share` -- (optional, default: `false`) flag for sharing unmodified parts of + the original set representation + +### Output + +A translated optimized 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::HPolygonOpt{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + @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 HPolygonOpt(constraints, P.ind; + sort_constraints=false, check_boundedness=false, + prune=false) +end diff --git a/src/HPolyhedron.jl b/src/HPolyhedron.jl index b3b02d265f..069d2e37dc 100644 --- a/src/HPolyhedron.jl +++ b/src/HPolyhedron.jl @@ -392,6 +392,41 @@ function remove_redundant_constraints!(P::HPoly{N}; remove_redundant_constraints!(P.constraints, backend=backend) end +""" + translate(P::PT, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real, PT<:HPoly{N}} + +Translate (i.e., shift) a polyhedron in constraint representation by a given +vector. + +### Input + +- `P` -- polyhedron in constraint representation +- `v` -- translation vector +- `share` -- (optional, default: `false`) flag for sharing unmodified parts of + the original set representation + +### Output + +A translated polyhedron 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::PT, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real, PT<:HPoly{N}} + @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 PT(constraints) +end + # ======================================================== # External methods that require Polyhedra.jl to be loaded # ======================================================== diff --git a/src/HalfSpace.jl b/src/HalfSpace.jl index 17b9cd4db1..9ceb4771b0 100644 --- a/src/HalfSpace.jl +++ b/src/HalfSpace.jl @@ -421,3 +421,39 @@ function _linear_map_hrep(M::AbstractMatrix{N}, P::HalfSpace{N}, use_inv::Bool) constraint = _linear_map_hrep_helper(M, P, use_inv)[1] return HalfSpace(constraint.a, constraint.b) end + +""" + translate(hs::HalfSpace{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + +Translate (i.e., shift) a half-space by a given vector. + +### Input + +- `hs` -- half-space +- `v` -- translation vector +- `share` -- (optional, default: `false`) flag for sharing unmodified parts of + the original set representation + +### Output + +A translated half-space. + +### Notes + +The normal vectors of the halfspace (vector `a` in `a⋅x ≤ b`) is shared with the +original halfspace 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``. +""" +function translate(hs::HalfSpace{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + @assert length(v) == dim(hs) "cannot translate a $(dim(hs))-dimensional " * + "set by a $(length(v))-dimensional vector" + a = share ? hs.a : copy(hs.a) + b = hs.b + dot(hs.a, v) + return HalfSpace(a, b) +end diff --git a/src/Hyperplane.jl b/src/Hyperplane.jl index 117d7b3110..19cfe575b0 100644 --- a/src/Hyperplane.jl +++ b/src/Hyperplane.jl @@ -400,3 +400,39 @@ function _linear_map_hrep(M::AbstractMatrix{N}, P::Hyperplane{N}, use_inv::Bool) constraint = _linear_map_hrep_helper(M, P, use_inv)[1] return Hyperplane(constraint.a, constraint.b) end + +""" + translate(hp::Hyperplane{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + +Translate (i.e., shift) a hyperplane by a given vector. + +### Input + +- `hp` -- hyperplane +- `v` -- translation vector +- `share` -- (optional, default: `false`) flag for sharing unmodified parts of + the original set representation + +### Output + +A translated hyperplane. + +### Notes + +The normal vectors of the hyperplane (vector `a` in `a⋅x = b`) is shared with +the original hyperplane if `share == true`. + +### Algorithm + +A hyperplane ``a⋅x = b`` is transformed to the hyperplane ``a⋅x = b + a⋅v``. +In other words, we add the dot product ``a⋅v`` to ``b``. +""" +function translate(hp::Hyperplane{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + @assert length(v) == dim(hp) "cannot translate a $(dim(hp))-dimensional " * + "set by a $(length(v))-dimensional vector" + a = share ? hp.a : copy(hp.a) + b = hp.b + dot(hp.a, v) + return Hyperplane(a, b) +end diff --git a/src/Hyperrectangle.jl b/src/Hyperrectangle.jl index 767c08ef95..cdc7d5cc36 100644 --- a/src/Hyperrectangle.jl +++ b/src/Hyperrectangle.jl @@ -186,3 +186,37 @@ function rand(::Type{Hyperrectangle}; radius = abs.(randn(rng, N, dim)) return Hyperrectangle(center, radius) end + +""" + translate(H::Hyperrectangle{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + +Translate (i.e., shift) a hyperrectangle by a given vector. + +### Input + +- `H` -- hyperrectangle +- `v` -- translation vector +- `share` -- (optional, default: `false`) flag for sharing unmodified parts of + the original set representation + +### Output + +A translated hyperrectangle. + +### Notes + +The radius vector is shared with the original hyperrectangle if `share == true`. + +### Algorithm + +We add the vector to the center of the hyperrectangle. +""" +function translate(H::Hyperrectangle{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + @assert length(v) == dim(H) "cannot translate a $(dim(H))-dimensional " * + "set by a $(length(v))-dimensional vector" + c = center(H) + v + radius = share ? H.radius : copy(H.radius) + return Hyperrectangle(c, radius) +end diff --git a/src/Interval.jl b/src/Interval.jl index 1ff7522bf8..ffb0f60716 100644 --- a/src/Interval.jl +++ b/src/Interval.jl @@ -75,7 +75,7 @@ Interval{Rational{Int64},AbstractInterval{Rational{Int64}}}([0//1, 2//1]) ``` """ struct Interval{N<:Real, IN<:AbstractInterval{N}} <: AbstractHyperrectangle{N} - dat::IN + dat::IN end @static if VERSION < v"0.7-" @@ -391,6 +391,30 @@ function vertices_list(x::Interval{N})::Vector{Vector{N}} where {N<:Real} return [[min(x)], [max(x)]] end +""" + translate(x::Interval{N}, v::AbstractVector{N}) where {N<:Real} + +Translate (i.e., shift) an interval by a given vector. + +### Input + +- `x` -- interval +- `v` -- translation vector + +### Output + +A translated interval. + +### Algorithm + +We add the vector to the left and right of the interval. +""" +function translate(x::Interval{N}, v::AbstractVector{N}) where {N<:Real} + @assert length(v) == dim(x) "cannot translate a $(dim(x))-dimensional " * + "set by a $(length(v))-dimensional vector" + return Interval(x.dat + v[1]) +end + # --- AbstractHyperrectangle interface functions --- diff --git a/src/LazySet.jl b/src/LazySet.jl index 489475c61c..88c6af6588 100644 --- a/src/LazySet.jl +++ b/src/LazySet.jl @@ -12,7 +12,8 @@ export LazySet, neutral, absorbing, tosimplehrep, - isuniversal + isuniversal, + translate """ LazySet{N} diff --git a/src/Line.jl b/src/Line.jl index 8e7832dea7..77f95ca1a4 100644 --- a/src/Line.jl +++ b/src/Line.jl @@ -301,3 +301,39 @@ function _linear_map_hrep(M::AbstractMatrix{N}, P::Line{N}, use_inv::Bool) where constraint = _linear_map_hrep_helper(M, P, use_inv)[1] return Line(constraint.a, constraint.b) end + +""" + translate(L::Line{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + +Translate (i.e., shift) a line by a given vector. + +### Input + +- `L` -- line +- `v` -- translation vector +- `share` -- (optional, default: `false`) flag for sharing unmodified parts of + the original set representation + +### Output + +A translated line. + +### Notes + +The normal vector of the line (vector `a` in `a⋅x = b`) is shared with the +original line if `share == true`. + +### Algorithm + +A line ``a⋅x = b`` is transformed to the line ``a⋅x = b + a⋅v``. +In other words, we add the dot product ``a⋅v`` to ``b``. +""" +function translate(L::Line{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + @assert length(v) == dim(L) "cannot translate a $(dim(L))-dimensional " * + "set by a $(length(v))-dimensional vector" + a = share ? L.a : copy(L.a) + b = L.b + dot(L.a, v) + return Line(a, b) +end diff --git a/src/LineSegment.jl b/src/LineSegment.jl index d9616058f2..84857e367f 100644 --- a/src/LineSegment.jl +++ b/src/LineSegment.jl @@ -325,3 +325,27 @@ function constraints_list(L::LineSegment{N})::Vector{LinearConstraint{N}} where clist[4] = halfspace_left(q, q + d) return clist end + +""" + translate(L::LineSegment{N}, v::AbstractVector{N}) where {N<:Real} + +Translate (i.e., shift) a line segment by a given vector. + +### Input + +- `L` -- line segment +- `v` -- translation vector + +### Output + +A translated line segment. + +### Algorithm + +We add the vector to both defining points of the line segment. +""" +function translate(L::LineSegment{N}, v::AbstractVector{N}) where {N<:Real} + @assert length(v) == dim(L) "cannot translate a $(dim(L))-dimensional " * + "set by a $(length(v))-dimensional vector" + return LineSegment(L.p + v, L.q + v) +end diff --git a/src/Singleton.jl b/src/Singleton.jl index cbcb80deb5..f57863b155 100644 --- a/src/Singleton.jl +++ b/src/Singleton.jl @@ -95,3 +95,27 @@ function rand(::Type{Singleton}; element = randn(rng, N, dim) return Singleton(element) end + +""" + translate(S::Singleton{N}, v::AbstractVector{N}) where {N<:Real} + +Translate (i.e., shift) a singleton by a given vector. + +### Input + +- `S` -- singleton +- `v` -- translation vector + +### Output + +A translated singleton. + +### Algorithm + +We add the vector to the point in the singleton. +""" +function translate(S::Singleton{N}, v::AbstractVector{N}) where {N<:Real} + @assert length(v) == dim(S) "cannot translate a $(dim(S))-dimensional " * + "set by a $(length(v))-dimensional vector" + return Singleton(element(S) + v) +end diff --git a/src/Universe.jl b/src/Universe.jl index 433a997e75..b65f8b8665 100644 --- a/src/Universe.jl +++ b/src/Universe.jl @@ -284,3 +284,23 @@ An error. function diameter(U::Universe, p::Real=Inf) error("a universe does not have a diameter") end + +""" + translate(U::Universe{N}, v::AbstractVector{N}) where {N<:Real} + +Translate (i.e., shift) a universe by a given vector. + +### Input + +- `U` -- universe +- `v` -- translation vector + +### Output + +The universe. +""" +function translate(U::Universe{N}, v::AbstractVector{N}) where {N<:Real} + @assert length(v) == dim(U) "cannot translate a $(dim(U))-dimensional " * + "set by a $(length(v))-dimensional vector" + return U +end diff --git a/src/VPolygon.jl b/src/VPolygon.jl index 749e53b950..a13cae6f97 100644 --- a/src/VPolygon.jl +++ b/src/VPolygon.jl @@ -529,3 +529,27 @@ function convex_hull(P::VPolygon{N}, Q::VPolygon{N}; convex_hull!(vunion; algorithm=algorithm) return VPolygon(vunion, apply_convex_hull=false) end + +""" + translate(P::VPolygon{N}, v::AbstractVector{N}) where {N<:Real} + +Translate (i.e., shift) a polygon in vertex representation by a given vector. + +### Input + +- `P` -- polygon in vertex representation +- `v` -- translation vector + +### Output + +A translated polygon in vertex representation. + +### Algorithm + +We add the vector to each vertex of the polygon. +""" +function translate(P::VPolygon{N}, v::AbstractVector{N}) where {N<:Real} + @assert length(v) == dim(P) "cannot translate a $(dim(P))-dimensional " * + "set by a $(length(v))-dimensional vector" + return VPolygon([x + v for x in vertices_list(P)]) +end diff --git a/src/VPolytope.jl b/src/VPolytope.jl index 729b53806b..eb7c835719 100644 --- a/src/VPolytope.jl +++ b/src/VPolytope.jl @@ -247,6 +247,30 @@ end return broadcast(v -> M * v, vertices_list(P)) |> VPolytope{N} end +""" + translate(P::VPolytope{N}, v::AbstractVector{N}) where {N<:Real} + +Translate (i.e., shift) a polytope in vertex representation by a given vector. + +### Input + +- `P` -- polytope in vertex representation +- `v` -- translation vector + +### Output + +A translated polytope in vertex representation. + +### Algorithm + +We add the vector to each vertex of the polytope. +""" +function translate(P::VPolytope{N}, v::AbstractVector{N}) where {N<:Real} + @assert length(v) == dim(P) "cannot translate a $(dim(P))-dimensional " * + "set by a $(length(v))-dimensional vector" + return VPolytope([x + v for x in vertices_list(P)]) +end + # --- AbstractPolytope interface functions --- """ diff --git a/src/ZeroSet.jl b/src/ZeroSet.jl index c5d3478b92..89c4ab4635 100644 --- a/src/ZeroSet.jl +++ b/src/ZeroSet.jl @@ -180,3 +180,23 @@ function linear_map(M::AbstractMatrix{N}, Z::ZeroSet{N}) where {N<:Real} return ZeroSet(size(M, 1)) end + +""" + translate(Z::ZeroSet{N}, v::AbstractVector{N}) where {N<:Real} + +Translate (i.e., shift) a zero set by a given vector. + +### Input + +- `Z` -- zero set +- `v` -- translation vector + +### Output + +A singleton containing the vector `v`. +""" +function translate(Z::ZeroSet{N}, v::AbstractVector{N}) where {N<:Real} + @assert length(v) == dim(Z) "cannot translate a $(dim(Z))-dimensional " * + "set by a $(length(v))-dimensional vector" + return Singleton(v) +end diff --git a/src/Zonotope.jl b/src/Zonotope.jl index a9269c2eb4..b816f03d2c 100644 --- a/src/Zonotope.jl +++ b/src/Zonotope.jl @@ -590,3 +590,37 @@ function constraints_list(Z::Zonotope{N} @assert i == m "expected 2*$m constraints, but only created 2*$i" return constraints end + +""" + translate(Z::Zonotope{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + +Translate (i.e., shift) a zonotope by a given vector. + +### Input + +- `Z` -- zonotope +- `v` -- translation vector +- `share` -- (optional, default: `false`) flag for sharing unmodified parts of + the original set representation + +### Output + +A translated zonotope. + +### Notes + +The generator matrix is shared with the original zonotope if `share == true`. + +### Algorithm + +We add the vector to the center of the zonotope. +""" +function translate(Z::Zonotope{N}, v::AbstractVector{N}; share::Bool=false + ) where {N<:Real} + @assert length(v) == dim(Z) "cannot translate a $(dim(Z))-dimensional " * + "set by a $(length(v))-dimensional vector" + c = center(Z) + v + generators = share ? Z.generators : copy(Z.generators) + return Zonotope(c, generators) +end diff --git a/test/runtests.jl b/test/runtests.jl index b4fbf970f2..3c8b2f74f4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -60,6 +60,7 @@ if test_suite_polyhedra || test_suite_plotting import LazySets.HalfSpace import LazySets.Interval import LazySets.Line + import LazySets.translate end if test_suite_basic diff --git a/test/unit_Ball1.jl b/test/unit_Ball1.jl index 19a22173be..a1dec22fde 100644 --- a/test/unit_Ball1.jl +++ b/test/unit_Ball1.jl @@ -68,6 +68,9 @@ for N in [Float64, Rational{Int}, Float32] # an_element & membership function @test an_element(b) ∈ b + # translation + @test translate(b, N[1, 2]) == Ball1(N[1, 2], N(2)) + # vertices_list vl = vertices_list(b) @test ispermutation(vl, [N[2, 0], N[0, 2], N[-2, 0], N[0, -2]]) diff --git a/test/unit_Ball2.jl b/test/unit_Ball2.jl index d802625878..e451ccea4e 100644 --- a/test/unit_Ball2.jl +++ b/test/unit_Ball2.jl @@ -66,6 +66,9 @@ for N in [Float64, Float32] b = Ball2(N[1, 2], N(2)) @test an_element(b) ∈ b + # translation + @test translate(b, N[1, 2]) == Ball2(N[2, 4], N(2)) + # subset b1 = Ball2(N[1, 2], N(2)) b2 = Ball2(N[1, 2], N(0)) diff --git a/test/unit_BallInf.jl b/test/unit_BallInf.jl index 9b90d2d2f3..a8608cb539 100644 --- a/test/unit_BallInf.jl +++ b/test/unit_BallInf.jl @@ -78,4 +78,7 @@ for N in [Float64, Rational{Int}, Float32] b = BallInf(N[1, 2], N(1)) @test high(b) == N[2, 3] @test low(b) == N[0, 1] + + # translation + @test translate(b, N[1, 2]) == BallInf(N[2, 4], N(1)) end diff --git a/test/unit_Ballp.jl b/test/unit_Ballp.jl index b3a1f317d6..a59e0ca779 100644 --- a/test/unit_Ballp.jl +++ b/test/unit_Ballp.jl @@ -45,4 +45,7 @@ for N in [Float64, Float32] # membership & an_element @test an_element(b) ∈ b + + # translation + @test translate(b, N[1, 2]) == Ballp(N(3), N[1, 2], N(2)) end diff --git a/test/unit_Ellipsoid.jl b/test/unit_Ellipsoid.jl index 3a8abfb840..58a40d020c 100644 --- a/test/unit_Ellipsoid.jl +++ b/test/unit_Ellipsoid.jl @@ -64,6 +64,10 @@ for N in [Float64, Float32] @test !isempty(E) # an_element and set membership functions - E = Ellipsoid(N[1, 2], Matrix{N}(2I, 2, 2)) + M = Matrix{N}(2I, 2, 2) + E = Ellipsoid(N[1, 2], M) @test an_element(E) ∈ E + + # translation + @test translate(E, N[1, 2]) == Ellipsoid(N[2, 4], M) end diff --git a/test/unit_EmptySet.jl b/test/unit_EmptySet.jl index 3671acfdb0..9c2515bbe1 100644 --- a/test/unit_EmptySet.jl +++ b/test/unit_EmptySet.jl @@ -66,6 +66,9 @@ for N in [Float64, Rational{Int}, Float32] # linear map of an empty set linear_map(ones(N, 2, 2), E) == E + + # translation + @test translate(E, N[1, 2]) == E end # default Float64 constructors diff --git a/test/unit_HalfSpace.jl b/test/unit_HalfSpace.jl index 7ec9f66c8c..b53f0ce64a 100644 --- a/test/unit_HalfSpace.jl +++ b/test/unit_HalfSpace.jl @@ -3,8 +3,7 @@ for N in [Float64, Rational{Int}, Float32] rand(HalfSpace) # normal constructor - normal = ones(N, 3) - hs = HalfSpace(normal, N(5)) + hs = HalfSpace(ones(N, 3), N(5)) # numeric-type conversion preserves vector base type hs1 = HalfSpace(spzeros(4), 1.) @@ -70,6 +69,9 @@ for N in [Float64, Rational{Int}, Float32] @test N[1, 2] ∈ halfspace_left(N[1, 1], N[2, 2]) @test N[2, 1] ∈ halfspace_right(N[1, 1], N[2, 2]) + # translation + @test translate(hs, N[1, 2, 3]) == HalfSpace(ones(N, 3), N(11)) + # intersection emptiness b = BallInf(N[3, 3, 3], N(1)) empty_intersection, v = is_intersection_empty(b, hs, true) diff --git a/test/unit_Hyperplane.jl b/test/unit_Hyperplane.jl index c987c01024..e0be4f225d 100644 --- a/test/unit_Hyperplane.jl +++ b/test/unit_Hyperplane.jl @@ -62,6 +62,9 @@ for N in [Float64, Rational{Int}, Float32] @test_throws ArgumentError linear_map(M, H) M = N[2 2; 0 1] # invertible matrix @test linear_map(M, H) == Hyperplane(N[0.5, -2.0], N(0.0)) + + # translation + @test translate(hp, N[1, 2, 3]) == Hyperplane(ones(N, 3), N(11)) end # Polyhedra tests that only work with Float64 diff --git a/test/unit_Interval.jl b/test/unit_Interval.jl index 01c40071b4..a4a2d4e485 100644 --- a/test/unit_Interval.jl +++ b/test/unit_Interval.jl @@ -63,6 +63,9 @@ for N in [Float64, Float32, Rational{Int}] # isempty @test !isempty(x) + # translation + @test translate(x, N[2]) == Interval(N(2), N(3)) + # Minkowski sum (test that we get the same results as the concrete operation) m = x ⊕ y @test m isa MinkowskiSum diff --git a/test/unit_Line.jl b/test/unit_Line.jl index 411a471c16..18245918f4 100644 --- a/test/unit_Line.jl +++ b/test/unit_Line.jl @@ -67,4 +67,7 @@ for N in [Float64, Rational{Int}, Float32] @test_throws ArgumentError linear_map(M, L) M = N[2 2; 0 1] # invertible matrix @test linear_map(M, L) == Line(N[0.5, -2.0], N(0.0)) + + # translation + @test translate(l1, N[1, 2]) == Line(a1, N(3)) end diff --git a/test/unit_LineSegment.jl b/test/unit_LineSegment.jl index b2251ab850..911fa2756c 100644 --- a/test/unit_LineSegment.jl +++ b/test/unit_LineSegment.jl @@ -43,6 +43,9 @@ for N in [Float64, Rational{Int}, Float32] vl = vertices_list(l) @test ispermutation(vl, [l.p, l.q]) + # translation + @test translate(l, N[1, 2]) == LineSegment(N[2, 3], N[3, 4]) + # intersection emptiness l1 = LineSegment(N[1, 1], N[2, 2]) l2 = LineSegment(N[2, 1], N[1, 2]) diff --git a/test/unit_Polygon.jl b/test/unit_Polygon.jl index 575a99dc6c..ba71a27d64 100644 --- a/test/unit_Polygon.jl +++ b/test/unit_Polygon.jl @@ -163,6 +163,11 @@ for N in [Float64, Float32, Rational{Int}] # test constraints list of a VPolygon vp = tovrep(hp) @test ispermutation(constraints_list(vp), hp.constraints) + + # translation + @test translate(hp, N[1, 2]) == typeof(hp)( + [HalfSpace(N[2, 2], N(18)), HalfSpace(N[-3, 3], N(9)), + HalfSpace(N[-1, -1], N(-3)), HalfSpace(N[2, -4], N(-6))]) end # concrete intersection of H-rep @@ -267,6 +272,10 @@ for N in [Float64, Float32, Rational{Int}] @test point ∈ VPolygon([N[0, 0], N[0, 2]]) @test point ∉ VPolygon([N[1, 0], N[1, 2]]) + # translation + vp2 = VPolygon([N[0, 0], N[1, 0], N[0, 1]]) + @test translate(vp2, N[1, 2]) == VPolygon([N[1, 2], N[2, 2], N[1, 3]]) + # subset p1 = VPolygon([N[0, 0], N[2, 0]]) p2 = VPolygon([N[1, 0]]) diff --git a/test/unit_Polyhedron.jl b/test/unit_Polyhedron.jl index ee647576b0..093ec19900 100644 --- a/test/unit_Polyhedron.jl +++ b/test/unit_Polyhedron.jl @@ -70,6 +70,12 @@ for N in [Float64, Rational{Int}, Float32] # concrete linear map with invertible matrix linear_map(N[2 3; 1 2], p) + # translation + p2 = translate(p, N[1, 2]) + @test p2 isa HPolyhedron && ispermutation(constraints_list(p2), + [HalfSpace(N[2, 2], N(18)), HalfSpace(N[-3, 3], N(9)), + HalfSpace(N[-1, -1], N(-3)), HalfSpace(N[2, -4], N(-6))]) + if test_suite_polyhedra # conversion to and from Polyhedra's VRep data structure cl = constraints_list(HPolyhedron(polyhedron(p))) diff --git a/test/unit_Polytope.jl b/test/unit_Polytope.jl index 63298dce25..3ca5342d3a 100644 --- a/test/unit_Polytope.jl +++ b/test/unit_Polytope.jl @@ -96,7 +96,7 @@ for N in [Float64, Rational{Int}, Float32] HalfSpace(N[0, 1], N(1)), HalfSpace(N[-1, -0], N(1)), HalfSpace(N[-0, -1], N(1)), - HalfSpace(N[2, 0], N(2))]) # redundant + HalfSpace(N[1, 0], N(2))]) # redundant Pred = remove_redundant_constraints(P) @test length(Pred.constraints) == 4 @@ -106,6 +106,12 @@ for N in [Float64, Rational{Int}, Float32] remove_redundant_constraints!(P) @test length(P.constraints) == 4 + # translation + P2 = translate(P, N[1, 2]) + @test P2 isa HPolytope && ispermutation(constraints_list(P2), + [HalfSpace(N[1, 0], N(2)), HalfSpace(N[0, 1], N(3)), + HalfSpace(N[-1, -0], N(0)), HalfSpace(N[-0, -1], N(-1))]) + # subset H = BallInf(N[0, 0], N(1)) P = convert(HPolytope, H) @@ -177,6 +183,9 @@ for N in [Float64, Rational{Int}, Float32] @test N[.49, .49] ∈ p @test N[.51, .51] ∉ p + # translation + @test translate(p, N[1, 2]) == VPolytope([N[1, 2], N[2, 2], N[1, 3]]) + # copy (see #1002) p, q = [N(1)], [N(2)] P = VPolytope([p, q]) diff --git a/test/unit_Singleton.jl b/test/unit_Singleton.jl index d80c833bd6..1adc955cae 100644 --- a/test/unit_Singleton.jl +++ b/test/unit_Singleton.jl @@ -60,6 +60,9 @@ for N in [Float64, Rational{Int}, Float32] M = N[0 1; -1 0] @test element(linear_map(M, S)) == an_element(M * S) + # translation + @test translate(s, N[1, 2]) == Singleton(N[2, 4]) + # subset s1 = Singleton(N[0, 1]) s2 = Singleton(N[0, 3]) diff --git a/test/unit_Universe.jl b/test/unit_Universe.jl index d9067f41f8..fe846c8c53 100644 --- a/test/unit_Universe.jl +++ b/test/unit_Universe.jl @@ -54,6 +54,9 @@ for N in [Float64, Rational{Int}, Float32] @test_throws ErrorException radius(U) @test_throws ErrorException diameter(U) + # translation + @test translate(U, N[1, 2]) == U + # concrete intersection @test intersection(B, U) == intersection(U, B) == B @test intersection(U, U) == U diff --git a/test/unit_ZeroSet.jl b/test/unit_ZeroSet.jl index 5d6564f9d2..039e23c15e 100644 --- a/test/unit_ZeroSet.jl +++ b/test/unit_ZeroSet.jl @@ -43,13 +43,14 @@ for N in [Float64, Rational{Int}, Float32] @test ⊆(z, z) && !⊆(z, ZeroSet{N}(2)) # linear map (concrete) -# M = randn(1, 1) M = reshape(to_N(N, [0.217692]), 1, 1) Mz = linear_map(M, z) @test Mz isa ZeroSet && dim(Mz) == 1 -# M = randn(1, 2) M = to_N(N, [-1.82273 -1.17261;]) MZ = linear_map(M, Z) @test MZ isa ZeroSet && dim(MZ) == 1 + + # translation + @test translate(Z, N[1, 2]) == Singleton(N[1, 2]) end diff --git a/test/unit_Zonotope.jl b/test/unit_Zonotope.jl index 4e952da3e7..652176c192 100644 --- a/test/unit_Zonotope.jl +++ b/test/unit_Zonotope.jl @@ -50,10 +50,14 @@ for N in [Float64, Rational{Int}, Float32] @test an_element(z) ∈ z # concrete operations - Z1 = Zonotope(N[1, 1], N[1 1; -1 1]) + gens = N[1 1; -1 1] + Z1 = Zonotope(N[1, 1], gens) Z2 = Zonotope(N[-1, 1], Matrix{N}(I, 2, 2)) A = N[0.5 1; 1 0.5] + # translation + @test translate(Z1, N[1, 2]) == Zonotope(N[2, 3], gens) + # concrete Minkowski sum Z3 = minkowski_sum(Z1, Z2) @test Z3.center == N[0, 2]