Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decomposed linear map of CartesianProductArray #1419

Merged
merged 15 commits into from
Jun 6, 2019
Merged
87 changes: 84 additions & 3 deletions src/Approximations/overapproximate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ function overapproximate(X::LazySet{N},
end

"""
overapproximate(S::LazySet{N}, ::Type{Interval}) where {N<:Real}
overapproximate(S::LazySet{N}, ::Union{Type{Interval}, Type{Interval{N}}}) where {N<:Real}

Return the overapproximation of a real unidimensional set with an interval.

Expand All @@ -352,11 +352,10 @@ An interval.
The method relies on the exact conversion to `Interval`. Two support
function evaluations are needed in general.
"""
function overapproximate(S::LazySet{N}, ::Type{Interval}) where {N<:Real}
function overapproximate(S::LazySet{N}, ::Union{Type{Interval}, Type{Interval{N}}}) where {N<:Real}
schillic marked this conversation as resolved.
Show resolved Hide resolved
@assert dim(S) == 1 "cannot overapproximate a $(dim(S))-dimensional set with an `Interval`"
return convert(Interval, S)
end

function overapproximate_cap_helper(X::LazySet{N}, # compact set
P::AbstractPolyhedron{N}, # polyhedron
dir::AbstractDirections{N};
Expand Down Expand Up @@ -516,3 +515,85 @@ function overapproximate(cap::Intersection{N,
return overapproximate(swap(cap), dir; kwargs...)
end

"""
overapproximate(lm::LinearMap{N, CartesianProductArray{N, T}},
::Type{CartesianProductArray{N, O}}) where {N, T<:LazySet{N}, O<:LazySet{N}}

Decompose a lazy linear map of a cartesian product array keeping original block structure.

### Input

- `lm` -- lazy linear map of cartesian product array
- `CartesianProductArray` -- type for dispatch

### Output

A `CartesianProductArray` representing the decomposed linear map.
"""
function overapproximate(lm::LinearMap{N, CartesianProductArray{N, T}},
::Type{CartesianProductArray{N, O}}) where {N, T<:LazySet{N}, O<:LazySet{N}}

M, cpa = lm.M, lm.X
array = Vector{O}(undef, length(cpa.array))
return _overapproximate_lm_cpa!(M, cpa, array, O)
end

"""
overapproximate(lm::LinearMap{N, CartesianProductArray{N, T}},
::Type{CartesianProductArray{N, HPolytope{N}}},
dir::AbstractDirections{N}) where {N, T<:LazySet{N}}

Decompose a lazy linear map of a cartesian product array.

### Input

- `lm` -- lazy linear map of cartesian product array
- `CartesianProductArray` -- type for dispatch
- `dir` -- approximation option for decomposition

### Output

A `CartesianProductArray` representing the decomposed linear map.
"""
function overapproximate(lm::LinearMap{N, CartesianProductArray{N, T}},
::Type{<:CartesianProductArray},
dir::Type{<:AbstractDirections}) where {N, T<:LazySet{N}}
M, cpa = lm.M, lm.X
array = Vector{HPolytope{N}}(undef, length(cpa.array))
return _overapproximate_lm_cpa!(M, cpa, array, dir)
end

#same for <:AbstractHyperrectangle
function overapproximate(lm::LinearMap{N, CartesianProductArray{N, T}},
::Type{<:CartesianProductArray},
oa::Type{<:AbstractHyperrectangle}) where {N, T<:LazySet{N}}
M, cpa = lm.M, lm.X
array = Vector{oa{N}}(undef, length(cpa.array))
return _overapproximate_lm_cpa!(M, cpa, array, oa)
end

function _overapproximate_lm_cpa!(M, cpa, array, O)
row_start_ind, row_end_ind = 1, 0
@inbounds for (i, bi) in enumerate(cpa.array)
row_end_ind += dim(bi)
ms = blocks_linear_map(cpa, M, row_start_ind : row_end_ind)
array[i] = overapproximate(ms, O)
row_start_ind = row_end_ind + 1
end
return CartesianProductArray(array)
end

function blocks_linear_map(cpa::CartesianProductArray{N, T},
M::AbstractMatrix{N},
row_range::UnitRange{Int}) where {N, T<:LazySet{N}}
array = Vector{LinearMap{N, <:T}}(undef, length(cpa.array))

col_start_ind, col_end_ind = 1, 0
@inbounds for (i, bi) in enumerate(cpa.array)
col_end_ind += dim(bi)
array[i] = LinearMap(M[row_range, col_start_ind : col_end_ind], bi)
col_start_ind = col_end_ind + 1
end
schillic marked this conversation as resolved.
Show resolved Hide resolved

return MinkowskiSumArray(array)
end
schillic marked this conversation as resolved.
Show resolved Hide resolved
47 changes: 46 additions & 1 deletion test/unit_overapproximate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,56 @@ for N in [Float64, Rational{Int}, Float32]
h2 = Hyperrectangle(N[2.5, 4.5], N[1/2, 1/2])
H = overapproximate(h1 × h2, Hyperrectangle) # defaults to convert method
@test low(H) == N[0, 2, 4] && high(H) == N[1, 3, 5]

# overapproximation of the lazy linear map of a hyperrectangular set
H = Hyperrectangle(N[0, 0], N[1/2, 1])
M = Diagonal(N[2, 2])
OA = overapproximate(M*H, Hyperrectangle)
@test OA isa Hyperrectangle && OA.center == N[0, 0] && OA.radius == N[1, 2]

#overapproximation of Minkowski sum of linear maps for each block in the row block
i1 = Interval(N[0, 1])
schillic marked this conversation as resolved.
Show resolved Hide resolved
h = Hyperrectangle(low=N[3, 4], high=N[5, 7])
M = N[1 2 3; 4 5 6; 7 8 9]
cpa = CartesianProductArray([i1, h])
lm = M * cpa

oa = overapproximate(lm, Hyperrectangle)
oa_box = overapproximate(lm, Approximations.BoxDirections)
d_oa_d_hp = overapproximate(lm, CartesianProductArray{N, Hyperrectangle{N}})
d_oa_d_box = overapproximate(lm, CartesianProductArray, Approximations.BoxDirections)
oa_d_hp = overapproximate(d_oa_d_hp)
oa_d_box = overapproximate(d_oa_d_box, Approximations.BoxDirections)

@test oa == oa_d_hp
@test oa_box == oa_d_box

for (oax, set_type) in [(d_oa_d_hp, Hyperrectangle), (d_oa_d_box, HPolytope)]
@test oax isa CartesianProductArray
arr = oax.array
@test length(arr) == 2 && dim(arr[1]) == 1 && dim(arr[2]) == 2
@test all(X -> X isa set_type, arr)
end

i1 = Interval(N[0, 1])
i2 = Interval(N[2, 3])
i3 = Interval(N[1, 4])
M = N[1 2; 0 1]
cpa = CartesianProductArray([i1, i2])
lm = M * cpa
d_oa = overapproximate(lm, CartesianProductArray{N, Interval{N}})
oa = overapproximate(lm, 1e-8)
schillic marked this conversation as resolved.
Show resolved Hide resolved
@test oa ⊆ d_oa

cpa = CartesianProductArray([i1, i2, i3])
M = N[1 2 0; 0 1 0; 0 1 1]
lm = M * cpa
d_oa = overapproximate(lm, CartesianProductArray{N, Interval{N}})
oa = overapproximate(lm)
@test overapproximate(d_oa) == oa
@test typeof(d_oa) == CartesianProductArray{N, Interval{N}}


end

# tests that do not work with Rational{Int}
Expand Down Expand Up @@ -129,4 +173,5 @@ for N in [Float64, Float32]
Y_zonotope = overapproximate(Y, Zonotope) # overapproximate with a zonotope
@test Y_polygon ⊆ Y_zonotope
@test !(Y_zonotope ⊆ Y_polygon)

end