Skip to content

Commit 52a0b7e

Browse files
committed
upgrade to IntervalArithmetic v0.22+
1 parent be4a573 commit 52a0b7e

37 files changed

+208
-201
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c"
2222
Distributed = "<0.0.1, 1.6"
2323
ExprTools = "0.1"
2424
GLPK = "0.11 - 0.15, 1"
25-
IntervalArithmetic = "0.15 - 0.21, =0.21.2" # v0.22 removed IntervalBox
25+
IntervalArithmetic = "0.22 - 1"
2626
JuMP = "0.21 - 0.23, 1"
2727
LinearAlgebra = "<0.0.1, 1.6"
2828
Random = "<0.0.1, 1.6"

docs/Project.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
88
ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18"
99
GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
1010
IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253"
11+
IntervalBoxes = "43d83c95-ebbb-40ec-8188-24586a1458ed"
1112
IntervalMatrices = "5c1f47dc-42dd-5697-8aaa-4d102d140ba9"
1213
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
1314
MiniQhull = "978d7f02-9e05-4691-894f-ae31a51d76ca"
@@ -29,7 +30,8 @@ Documenter = "1"
2930
DocumenterCitations = "1.3"
3031
ExponentialUtilities = "1"
3132
GR = "0"
32-
IntervalArithmetic = "0.20 - 0.21, =0.21.2" # v0.22 removed IntervalBox
33+
IntervalArithmetic = "0.22 - 1"
34+
IntervalBoxes = "0.2"
3335
IntervalMatrices = "0.8 - 0.12"
3436
LaTeXStrings = "1"
3537
MiniQhull = "0.4"
@@ -40,4 +42,4 @@ RecipesBase = "1"
4042
StaticArrays = "1"
4143
SymEngine = "0.7 - 0.13"
4244
Symbolics = "6.1"
43-
TaylorModels = "0.6 - 0.8"
45+
TaylorModels = "0.9"

docs/src/lib/sets/Interval.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,3 @@ Inherited from [`AbstractHyperrectangle`](@ref):
224224
* [`genmat`](@ref genmat(::AbstractHyperrectangle))
225225
* [`is_interior_point`](@ref is_interior_point(::AbstractVector, ::AbstractHyperrectangle))
226226
* [`cartesian_product`](@ref cartesian_product(::AbstractHyperrectangle, ::AbstractHyperrectangle))
227-
228-
Some additional functionality is available for `IntervalArithmetic.Interval`s:
229-
230-
```@docs
231-
fast_interval_pow(::IA.Interval, ::Int)
232-
```

docs/src/man/tour.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,6 @@ vector:
9696
H = convert(Hyperrectangle, C)
9797
```
9898

99-
IntervalArithmetic.jl represents multi-dimensional intervals with the type
100-
`IntervalBox`, to which we can also `convert`:
101-
102-
```@example tour
103-
using IntervalArithmetic
104-
105-
Hbox = convert(IntervalBox, H)
106-
107-
typeof(Hbox)
108-
```
109-
11099
Hyperrectangles are a special subclass of
111100
[zonotopes](https://juliareach.github.io/LazySets.jl/dev/lib/sets/Zonotope/).
112101

src/Approximations/box_approximation.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,8 @@ function load_taylormodels_box_approximation()
421421
box_approximation(vTM::Vector{<:TaylorModelN}) = _box_approximation_vTM(vTM)
422422

423423
function _box_approximation_vTM(vTM)
424-
B = IA.IntervalBox([evaluate(vTM[i], domain(p)) for (i, p) in enumerate(vTM)]...)
425-
return convert(Hyperrectangle, B)
424+
bounds = [evaluate(vTM[i], domain(p)) for (i, p) in enumerate(vTM)]
425+
return Hyperrectangle(low=IA.inf.(bounds), high=IA.sup.(bounds))
426426
end
427427
end
428428
end # quote / load_taylormodels_box_approximation

src/Approximations/init.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
function __init__()
22
@require Expokit = "a1e7a1ef-7a5d-5822-a38c-be74e1bb89f4" (nothing,)
33
@require ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" (nothing,)
4-
@require IntervalMatrices = "5c1f47dc-42dd-5697-8aaa-4d102d140ba9" include("init_IntervalMatrices.jl")
4+
@require IntervalBoxes = "43d83c95-ebbb-40ec-8188-24586a1458ed" include("init_IntervalBoxes.jl")
55
@require IntervalConstraintProgramming = "138f1668-1576-5ad7-91b9-7425abbf3153" include("init_IntervalConstraintProgramming.jl")
6+
@require IntervalMatrices = "5c1f47dc-42dd-5697-8aaa-4d102d140ba9" include("init_IntervalMatrices.jl")
67
@require Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" include("init_Ipopt.jl")
78
@require SetProg = "39881422-4b75-5582-a5c7-0feb14562a65" include("init_SetProg.jl")
89
# @require StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" include("init_StaticArraysCore.jl")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
eval(load_IntervalBoxes_overapproximate_paving())
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
eval(load_paving_overapproximation())
21
eval(load_overapproximate_ICP())

src/Approximations/overapproximate.jl

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using LazySets: block_to_dimension_indices,
22
substitute_blocks,
3-
fast_interval_pow,
43
get_constrained_lowdimset
54

65
"""
@@ -369,7 +368,7 @@ function overapproximate(P::AbstractSparsePolynomialZonotope,
369368
return UnionSetArray([overapproximate(P, Zonotope)])
370369
end
371370

372-
dom = IA.IntervalBox(IA.interval(-1, 1), q)
371+
dom = fill(IA.interval(-1, 1), q)
373372
cells = IA.mince(dom, isnothing(partition) ? nsdiv : partition)
374373
return UnionSetArray([overapproximate(P, Zonotope, c) for c in cells])
375374
end
@@ -677,50 +676,46 @@ function overapproximate(P::AbstractSparsePolynomialZonotope{N}, ::Type{<:VPolyt
677676
return VPolytope(vlist)
678677
end
679678

680-
# function to be loaded by Requires
681-
function load_paving_overapproximation()
679+
function load_IntervalBoxes_overapproximate_paving()
682680
return quote
683-
using .IntervalConstraintProgramming: Paving
681+
import .IntervalBoxes as IB
684682

685683
"""
686-
overapproximate(p::Paving{L, N}, dirs::AbstractDirections{N, VN})
687-
where {L, N, VN}
684+
overapproximate(boundary::Vector{<:IB.IntervalBox}, dirs::AbstractDirections)
688685
689-
Overapproximate a Paving-type set representation with a polyhedron in constraint
686+
Overapproximate a vector of `IntervalBox`es ("paving") with a polyhedron in constraint
690687
representation.
691688
692689
### Input
693690
694-
- `p` -- paving
695-
- `dirs` -- template directions
691+
- `boundary` -- vector of `IntervalBox`es
692+
- `dirs` -- template directions
696693
697694
### Output
698695
699-
An overapproximation of a paving using a polyhedron in constraint representation
700-
(`HPolyhedron`) with constraints in direction `dirs`.
696+
An overapproximation in constraint representation (`HPolyhedron`) with constraints in
697+
direction `dirs`.
701698
702699
### Algorithm
703700
704-
This function takes the union of the elements at the boundary of `p`, first
705-
converted into hyperrectangles, and then calculates the support function of the
706-
set along each direction in dirs, to compute the `HPolyhedron` constraints.
707-
708-
This algorithm requires the IntervalConstraintProgramming package.
701+
This implementation first converts the boxes into `Hyperrectangle`s and then calculates the
702+
support function of the set along each direction in `dirs` to compute the `HPolyhedron`
703+
constraints.
709704
"""
710-
function overapproximate(p::Paving{L,N}, dirs::AbstractDirections{N,VN}) where {L,N,VN}
705+
function overapproximate(boundary::Vector{<:IB.IntervalBox}, dirs::AbstractDirections)
711706
# enclose outer approximation
712-
Uouter = UnionSetArray(convert.(Hyperrectangle, p.boundary))
707+
Uouter = UnionSetArray(convert.(Hyperrectangle, boundary))
713708
constraints = [HalfSpace(d, ρ(d, Uouter)) for d in dirs]
714709
return HPolyhedron(constraints)
715710
end
716711

717712
# alias with HPolyhedron type as second argument
718-
function overapproximate(p::Paving{L,N}, ::Type{<:HPolyhedron},
719-
dirs::AbstractDirections{N,VN}) where {L,N,VN}
720-
return overapproximate(p, dirs)
713+
function overapproximate(boundary::Vector{<:IB.IntervalBox}, ::Type{<:HPolyhedron},
714+
dirs::AbstractDirections)
715+
return overapproximate(boundary, dirs)
721716
end
722717
end
723-
end # quote / load_paving_overapproximation
718+
end # quote / load_IntervalBoxes_overapproximate_paving
724719

725720
"""
726721
# Extended help

src/Approximations/overapproximate_zonotope.jl

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ end
247247

248248
"""
249249
overapproximate(P::AbstractSparsePolynomialZonotope, ::Type{<:Zonotope},
250-
dom::IntervalBox)
250+
dom::AbstractVector{<:IA.Interval})
251251
252252
Overapproximate a sparse polynomial zonotope over the parameter domain `dom`
253253
with a zonotope.
@@ -264,9 +264,10 @@ with a zonotope.
264264
A zonotope.
265265
"""
266266
function overapproximate(P::AbstractSparsePolynomialZonotope, ::Type{<:Zonotope},
267-
dom::IA.IntervalBox)
268-
@assert dom IA.IntervalBox(IA.interval(-1, 1), nparams(P)) "dom should " *
269-
"be a subset of [-1, 1]^q"
267+
dom::AbstractVector{<:IA.Interval})
268+
@assert length(dom) == nparams(P) &&
269+
all(IA.issubset_interval(vi, IA.interval(-1, 1)) for vi in dom) "dom should be a " *
270+
"subset of [-1, 1]^q"
270271

271272
# handle dependent generators
272273
G = genmat_dep(P)
@@ -275,12 +276,11 @@ function overapproximate(P::AbstractSparsePolynomialZonotope, ::Type{<:Zonotope}
275276
Gnew = similar(G)
276277
@inbounds for (j, g) in enumerate(eachcol(G))
277278
# monomial value over the domain
278-
# α = mapreduce(x -> _fast_interval_pow(x[1], x[2]), *, zip(dom, E[:, i]))
279279
α = IA.interval(1, 1)
280280
for (i, vi) in enumerate(dom)
281-
α *= fast_interval_pow(vi, E[i, j])
281+
α *= vi^E[i, j]
282282
end
283-
m, r = IA.midpoint_radius(α)
283+
m, r = IA.midradius(α)
284284
cnew .+= m * g
285285
Gnew[:, j] .= r * g
286286
end
@@ -396,10 +396,10 @@ function load_taylormodels_overapproximation()
396396
[-0.5, 0.5]
397397
398398
julia> x₀ = IA.interval(0.0) # expansion point
399-
[0, 0]
399+
[0.0, 0.0]
400400
401401
julia> D = IA.interval(-3.0, 1.0)
402-
[-3, 1]
402+
[-3.0, 1.0]
403403
404404
julia> p1 = Taylor1([2.0, 1.0], 2) # define a linear polynomial
405405
2.0 + 1.0 t + 𝒪(t³)
@@ -440,11 +440,10 @@ function load_taylormodels_overapproximation()
440440
julia> X = box_approximation(Z)
441441
Hyperrectangle{Float64, Vector{Float64}, Vector{Float64}}([1.0, -2.1], [2.5, 6.5])
442442
443-
julia> Y = evaluate(vTM[1], vTM[1].dom) × evaluate(vTM[2], vTM[2].dom)
444-
[-1.5, 3.5] × [-8.60001, 4.40001]
445-
446-
julia> H = convert(Hyperrectangle, Y) # this IntervalBox is the same as X
447-
Hyperrectangle{Float64, StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SVector{2, Float64}}([1.0, -2.1000000000000005], [2.5, 6.500000000000001])
443+
julia> Y = [evaluate(vTM[1], vTM[1].dom), evaluate(vTM[2], vTM[2].dom)]
444+
2-element Vector{IntervalArithmetic.Interval{Float64}}:
445+
│ [-1.50001, 3.50001]
446+
[-8.60001, 4.40001]
448447
```
449448
However, the zonotope returns better results if we want to approximate the
450449
Taylor model because it is not axis-aligned:
@@ -553,17 +552,21 @@ function load_taylormodels_overapproximation()
553552
1.0 x₁ + 𝒪(‖x‖⁹)
554553
1.0 x₂ + 𝒪(‖x‖⁹)
555554
556-
julia> x₀ = IA.IntervalBox(0..0, 2) # expansion point
557-
[0, 0]²
555+
julia> x₀ = fill(0..0, 2) # expansion point
556+
2-element Vector{IntervalArithmetic.Interval{Float64}}:
557+
│ [0.0, 0.0]
558+
│ [0.0, 0.0]
558559
559560
julia> Dx₁ = IA.interval(0.0, 3.0) # domain for x₁
560-
[0, 3]
561+
[0.0, 3.0]
561562
562563
julia> Dx₂ = IA.interval(-1.0, 1.0) # domain for x₂
563-
[-1, 1]
564+
[-1.0, 1.0]
564565
565-
julia> D = Dx₁ × Dx₂ # take the Cartesian product of the domain on each variable
566-
[0, 3] × [-1, 1]
566+
julia> D = [Dx₁, Dx₂]
567+
2-element Vector{IntervalArithmetic.Interval{Float64}}:
568+
│ [0.0, 3.0]
569+
│ [-1.0, 1.0]
567570
568571
julia> r = IA.interval(-0.5, 0.5) # interval remainder
569572
[-0.5, 0.5]
@@ -629,13 +632,17 @@ function load_taylormodels_overapproximation()
629632

630633
# build the generators
631634
α = mid(rem_nonlin)
632-
c[i] = constant_term(pol_lin_norm) + α # constant terms
633-
G[i, 1:n] = get_linear_coeffs(pol_lin_norm) # linear terms
635+
cterm = constant_term(pol_lin_norm)
636+
@assert IA.isthin(cterm) "unexpected interval value"
637+
c[i] = mid(cterm) + α # constant terms
638+
lin_coeffs = get_linear_coeffs(pol_lin_norm)
639+
@assert all(IA.isthin, lin_coeffs) "unexpected interval value"
640+
G[i, 1:n] = mid.(lin_coeffs) # linear terms
634641
# interval generator
635642
for j in (n + 1):(n + m)
636643
G[i, j] = zero(N)
637644
end
638-
G[i, n + i] = abs(rem_nonlin.hi - α)
645+
G[i, n + i] = abs(IA.sup(rem_nonlin) - α)
639646
end
640647

641648
if remove_redundant_generators
@@ -1194,35 +1201,40 @@ end
11941201
# - the resulting zonotope is G * D + c
11951202
function _overapproximate_zonotope_halfspace_ICP(Z::AbstractZonotope{N},
11961203
H::HalfSpace{N,SingleEntryVector{N}}) where {N}
1204+
require(@__MODULE__, :IntervalConstraintProgramming; fun_name="overapproximate")
1205+
11971206
c = center(Z)
11981207
G = genmat(Z)
11991208
p = size(G, 2)
12001209
d = H.a.i
12011210

12021211
a = G[d, :]
12031212
io = IOBuffer()
1204-
first = true
12051213
v = H.a.v
12061214
negate = v < zero(N)
12071215
if negate
12081216
v = -v
12091217
end
1218+
vars = ""
1219+
first = true
12101220
for (i, ai) in enumerate(a)
12111221
if first
12121222
first = false
12131223
elseif ai >= 0
12141224
write(io, "+")
1225+
vars *= ", "
12151226
end
12161227
write(io, "$(v * ai)*x$(i)")
1228+
vars *= "x$(i)"
12171229
end
12181230
if negate
12191231
write(io, ">=$(-H.b + c[d])")
12201232
else
12211233
write(io, "<=$(H.b - c[d])")
12221234
end
12231235
e = Meta.parse(String(take!(io)))
1224-
X = IA.IntervalBox(IA.interval(-1, 1), p)
1225-
newD = _contract_zonotope_halfspace_ICP(e, X)
1236+
X = fill(IA.interval(-1, 1), p)
1237+
newD = _contract_zonotope_halfspace_ICP(e, X, vars)
12261238
if isempty(newD)
12271239
return EmptySet{N}(length(c))
12281240
end
@@ -1232,15 +1244,22 @@ end
12321244
function load_overapproximate_ICP()
12331245
return quote
12341246
import .IntervalConstraintProgramming as ICP
1235-
1236-
function _contract_zonotope_halfspace_ICP(e, X)
1247+
import .IntervalConstraintProgramming.IntervalBoxes as IB
1248+
1249+
function _contract_zonotope_halfspace_ICP(e, X, vars_string)
1250+
n = length(X)
1251+
prefix = "IntervalConstraintProgramming.Symbolics.@variables "
1252+
sym = Meta.parse(prefix * vars_string)
1253+
vars = eval(quote
1254+
$sym
1255+
end)
12371256
separator = eval(quote
1238-
ICP.@constraint $e
1257+
ICP.Separator($e, $vars)
12391258
end)
12401259
# smallest box containing all points in domain X satisfying constraint
12411260
# (`invokelatest` to avoid world-age issue; `Base.` for VERSION < v"1.9")
1242-
out, _ = Base.invokelatest(separator, X)
1243-
return out
1261+
boundary, _, _ = Base.invokelatest(separator, IB.IntervalBox(X...))
1262+
return boundary
12441263
end
12451264
end
12461265
end # load_overapproximate_ICP()

0 commit comments

Comments
 (0)