From 83ba3df08628d38c9d0ce2048229f62eb4819a3f Mon Sep 17 00:00:00 2001 From: schillic Date: Wed, 12 Nov 2025 19:02:36 +0100 Subject: [PATCH 1/4] upgrade to IntervalArithmetic v0.22+ --- Project.toml | 2 +- docs/Project.toml | 6 +- docs/src/lib/sets/Interval.md | 6 -- docs/src/man/tour.md | 11 --- src/Approximations/box_approximation.jl | 4 +- src/Approximations/init.jl | 3 +- src/Approximations/init_IntervalBoxes.jl | 1 + .../init_IntervalConstraintProgramming.jl | 1 - src/Approximations/overapproximate.jl | 41 +++++----- .../overapproximate_zonotope.jl | 81 ++++++++++++------- src/ConcreteOperations/difference.jl | 19 ++++- src/Convert/convert.jl | 10 +++ src/Initialization/init_IntervalArithmetic.jl | 48 ++--------- src/Initialization/init_IntervalBoxes.jl | 2 + src/Initialization/init_TaylorModels.jl | 2 +- .../AbstractSparsePolynomialZonotope.jl | 2 +- src/MatrixSets/convert.jl | 6 +- src/Sets/Hyperrectangle/convert.jl | 22 ++--- src/Sets/Hyperrectangle/init.jl | 1 + src/Sets/Hyperrectangle/init_IntervalBoxes.jl | 1 + src/Sets/Interval/Interval.jl | 10 +-- src/Sets/Interval/IntervalModule.jl | 7 +- src/Sets/Interval/difference.jl | 4 +- src/Sets/Interval/in.jl | 3 +- src/Sets/Interval/isequal.jl | 3 + src/Sets/Interval/rectify.jl | 4 +- src/init.jl | 1 + test/Approximations/box_approximation.jl | 5 +- test/Approximations/overapproximate.jl | 20 +++-- test/ConcreteOperations/isdisjoint.jl | 2 - test/ConcreteOperations/issubset.jl | 18 ++--- test/Project.toml | 12 +-- test/Sets/BallInf.jl | 7 +- test/Sets/Hyperrectangle.jl | 20 +++-- test/Sets/Interval.jl | 6 +- test/Sets/SparsePolynomialZonotope.jl | 10 +-- test/runtests.jl | 6 +- 37 files changed, 207 insertions(+), 200 deletions(-) create mode 100644 src/Approximations/init_IntervalBoxes.jl create mode 100644 src/Initialization/init_IntervalBoxes.jl create mode 100644 src/Sets/Hyperrectangle/init_IntervalBoxes.jl create mode 100644 src/Sets/Interval/isequal.jl diff --git a/Project.toml b/Project.toml index c150d0beef..f26dba94ec 100644 --- a/Project.toml +++ b/Project.toml @@ -22,7 +22,7 @@ StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" Distributed = "<0.0.1, 1.6" ExprTools = "0.1" GLPK = "0.11 - 0.15, 1" -IntervalArithmetic = "0.15 - 0.21, =0.21.2" # v0.22 removed IntervalBox +IntervalArithmetic = "0.22 - 1" JuMP = "0.21 - 0.23, 1" LinearAlgebra = "<0.0.1, 1.6" Random = "<0.0.1, 1.6" diff --git a/docs/Project.toml b/docs/Project.toml index d7f84da774..06067dee2c 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -8,6 +8,7 @@ DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244" ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" +IntervalBoxes = "43d83c95-ebbb-40ec-8188-24586a1458ed" IntervalMatrices = "5c1f47dc-42dd-5697-8aaa-4d102d140ba9" LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" MiniQhull = "978d7f02-9e05-4691-894f-ae31a51d76ca" @@ -29,7 +30,8 @@ Documenter = "1" DocumenterCitations = "1.3" ExponentialUtilities = "1" GR = "0" -IntervalArithmetic = "0.20 - 0.21, =0.21.2" # v0.22 removed IntervalBox +IntervalArithmetic = "0.22 - 1" +IntervalBoxes = "0.2" IntervalMatrices = "0.8 - 0.12" LaTeXStrings = "1" MiniQhull = "0.4" @@ -40,4 +42,4 @@ RecipesBase = "1" StaticArrays = "1" SymEngine = "0.7 - 0.13" Symbolics = "6.1" -TaylorModels = "0.6 - 0.8" +TaylorModels = "0.9" diff --git a/docs/src/lib/sets/Interval.md b/docs/src/lib/sets/Interval.md index b1b00af39f..158a7c6b1e 100644 --- a/docs/src/lib/sets/Interval.md +++ b/docs/src/lib/sets/Interval.md @@ -224,9 +224,3 @@ Inherited from [`AbstractHyperrectangle`](@ref): * [`genmat`](@ref genmat(::AbstractHyperrectangle)) * [`is_interior_point`](@ref is_interior_point(::AbstractVector, ::AbstractHyperrectangle)) * [`cartesian_product`](@ref cartesian_product(::AbstractHyperrectangle, ::AbstractHyperrectangle)) - -Some additional functionality is available for `IntervalArithmetic.Interval`s: - -```@docs -fast_interval_pow(::IA.Interval, ::Int) -``` diff --git a/docs/src/man/tour.md b/docs/src/man/tour.md index 7e5f7a54d6..1212ff04fe 100644 --- a/docs/src/man/tour.md +++ b/docs/src/man/tour.md @@ -96,17 +96,6 @@ vector: H = convert(Hyperrectangle, C) ``` -IntervalArithmetic.jl represents multi-dimensional intervals with the type -`IntervalBox`, to which we can also `convert`: - -```@example tour -using IntervalArithmetic: IntervalBox - -Hbox = convert(IntervalBox, H) - -typeof(Hbox) -``` - Hyperrectangles are a special subclass of [zonotopes](https://juliareach.github.io/LazySets.jl/dev/lib/sets/Zonotope/). diff --git a/src/Approximations/box_approximation.jl b/src/Approximations/box_approximation.jl index 2d367de5bb..3f9c9a6bc3 100644 --- a/src/Approximations/box_approximation.jl +++ b/src/Approximations/box_approximation.jl @@ -421,8 +421,8 @@ function load_taylormodels_box_approximation() box_approximation(vTM::Vector{<:TaylorModelN}) = _box_approximation_vTM(vTM) function _box_approximation_vTM(vTM) - B = IA.IntervalBox([evaluate(vTM[i], domain(p)) for (i, p) in enumerate(vTM)]...) - return convert(Hyperrectangle, B) + bounds = [evaluate(vTM[i], domain(p)) for (i, p) in enumerate(vTM)] + return Hyperrectangle(low=IA.inf.(bounds), high=IA.sup.(bounds)) end end end # quote / load_taylormodels_box_approximation diff --git a/src/Approximations/init.jl b/src/Approximations/init.jl index dfaece1627..b12aaa050b 100644 --- a/src/Approximations/init.jl +++ b/src/Approximations/init.jl @@ -1,8 +1,9 @@ function __init__() @require Expokit = "a1e7a1ef-7a5d-5822-a38c-be74e1bb89f4" (nothing,) @require ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" (nothing,) - @require IntervalMatrices = "5c1f47dc-42dd-5697-8aaa-4d102d140ba9" include("init_IntervalMatrices.jl") + @require IntervalBoxes = "43d83c95-ebbb-40ec-8188-24586a1458ed" include("init_IntervalBoxes.jl") @require IntervalConstraintProgramming = "138f1668-1576-5ad7-91b9-7425abbf3153" include("init_IntervalConstraintProgramming.jl") + @require IntervalMatrices = "5c1f47dc-42dd-5697-8aaa-4d102d140ba9" include("init_IntervalMatrices.jl") @require Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" include("init_Ipopt.jl") @require SetProg = "39881422-4b75-5582-a5c7-0feb14562a65" include("init_SetProg.jl") # @require StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" include("init_StaticArraysCore.jl") diff --git a/src/Approximations/init_IntervalBoxes.jl b/src/Approximations/init_IntervalBoxes.jl new file mode 100644 index 0000000000..364b4b3a5c --- /dev/null +++ b/src/Approximations/init_IntervalBoxes.jl @@ -0,0 +1 @@ +eval(load_IntervalBoxes_overapproximate_paving()) diff --git a/src/Approximations/init_IntervalConstraintProgramming.jl b/src/Approximations/init_IntervalConstraintProgramming.jl index 86c4e83585..8d3b590b9e 100644 --- a/src/Approximations/init_IntervalConstraintProgramming.jl +++ b/src/Approximations/init_IntervalConstraintProgramming.jl @@ -1,2 +1 @@ -eval(load_paving_overapproximation()) eval(load_overapproximate_ICP()) diff --git a/src/Approximations/overapproximate.jl b/src/Approximations/overapproximate.jl index e7cda8ceae..e71934e1d6 100644 --- a/src/Approximations/overapproximate.jl +++ b/src/Approximations/overapproximate.jl @@ -1,6 +1,5 @@ using LazySets: block_to_dimension_indices, substitute_blocks, - fast_interval_pow, get_constrained_lowdimset """ @@ -369,7 +368,7 @@ function overapproximate(P::AbstractSparsePolynomialZonotope, return UnionSetArray([overapproximate(P, Zonotope)]) end - dom = IA.IntervalBox(IA.interval(-1, 1), q) + dom = fill(IA.interval(-1, 1), q) cells = IA.mince(dom, isnothing(partition) ? nsdiv : partition) return UnionSetArray([overapproximate(P, Zonotope, c) for c in cells]) end @@ -677,50 +676,46 @@ function overapproximate(P::AbstractSparsePolynomialZonotope{N}, ::Type{<:VPolyt return VPolytope(vlist) end -# function to be loaded by Requires -function load_paving_overapproximation() +function load_IntervalBoxes_overapproximate_paving() return quote - using .IntervalConstraintProgramming: Paving + import .IntervalBoxes as IB """ - overapproximate(p::Paving{L, N}, dirs::AbstractDirections{N, VN}) - where {L, N, VN} + overapproximate(boundary::Vector{<:IB.IntervalBox}, dirs::AbstractDirections) - Overapproximate a Paving-type set representation with a polyhedron in constraint + Overapproximate a vector of `IntervalBox`es ("paving") with a polyhedron in constraint representation. ### Input - - `p` -- paving - - `dirs` -- template directions + - `boundary` -- vector of `IntervalBox`es + - `dirs` -- template directions ### Output - An overapproximation of a paving using a polyhedron in constraint representation - (`HPolyhedron`) with constraints in direction `dirs`. + An overapproximation in constraint representation (`HPolyhedron`) with constraints in + direction `dirs`. ### Algorithm - This function takes the union of the elements at the boundary of `p`, first - converted into hyperrectangles, and then calculates the support function of the - set along each direction in dirs, to compute the `HPolyhedron` constraints. - - This algorithm requires the IntervalConstraintProgramming package. + This implementation first converts the boxes into `Hyperrectangle`s and then calculates the + support function of the set along each direction in `dirs` to compute the `HPolyhedron` + constraints. """ - function overapproximate(p::Paving{L,N}, dirs::AbstractDirections{N,VN}) where {L,N,VN} + function overapproximate(boundary::Vector{<:IB.IntervalBox}, dirs::AbstractDirections) # enclose outer approximation - Uouter = UnionSetArray(convert.(Hyperrectangle, p.boundary)) + Uouter = UnionSetArray(convert.(Hyperrectangle, boundary)) constraints = [HalfSpace(d, ρ(d, Uouter)) for d in dirs] return HPolyhedron(constraints) end # alias with HPolyhedron type as second argument - function overapproximate(p::Paving{L,N}, ::Type{<:HPolyhedron}, - dirs::AbstractDirections{N,VN}) where {L,N,VN} - return overapproximate(p, dirs) + function overapproximate(boundary::Vector{<:IB.IntervalBox}, ::Type{<:HPolyhedron}, + dirs::AbstractDirections) + return overapproximate(boundary, dirs) end end -end # quote / load_paving_overapproximation +end # quote / load_IntervalBoxes_overapproximate_paving """ # Extended help diff --git a/src/Approximations/overapproximate_zonotope.jl b/src/Approximations/overapproximate_zonotope.jl index 9033687cd3..8d48430b58 100644 --- a/src/Approximations/overapproximate_zonotope.jl +++ b/src/Approximations/overapproximate_zonotope.jl @@ -247,7 +247,7 @@ end """ overapproximate(P::AbstractSparsePolynomialZonotope, ::Type{<:Zonotope}, - dom::IntervalBox) + dom::AbstractVector{<:IA.Interval}) Overapproximate a sparse polynomial zonotope over the parameter domain `dom` with a zonotope. @@ -264,9 +264,10 @@ with a zonotope. A zonotope. """ function overapproximate(P::AbstractSparsePolynomialZonotope, ::Type{<:Zonotope}, - dom::IA.IntervalBox) - @assert dom ⊆ IA.IntervalBox(IA.interval(-1, 1), nparams(P)) "dom should " * - "be a subset of [-1, 1]^q" + dom::AbstractVector{<:IA.Interval}) + @assert length(dom) == nparams(P) && + all(IA.issubset_interval(vi, IA.interval(-1, 1)) for vi in dom) "dom should be a " * + "subset of [-1, 1]^q" # handle dependent generators G = genmat_dep(P) @@ -275,12 +276,11 @@ function overapproximate(P::AbstractSparsePolynomialZonotope, ::Type{<:Zonotope} Gnew = similar(G) @inbounds for (j, g) in enumerate(eachcol(G)) # monomial value over the domain - # α = mapreduce(x -> _fast_interval_pow(x[1], x[2]), *, zip(dom, E[:, i])) α = IA.interval(1, 1) for (i, vi) in enumerate(dom) - α *= fast_interval_pow(vi, E[i, j]) + α *= vi^E[i, j] end - m, r = IA.midpoint_radius(α) + m, r = IA.midradius(α) cnew .+= m * g Gnew[:, j] .= r * g end @@ -396,10 +396,10 @@ function load_taylormodels_overapproximation() [-0.5, 0.5] julia> x₀ = IA.interval(0.0) # expansion point - [0, 0] + [0.0, 0.0] julia> D = IA.interval(-3.0, 1.0) - [-3, 1] + [-3.0, 1.0] julia> p1 = Taylor1([2.0, 1.0], 2) # define a linear polynomial 2.0 + 1.0 t + 𝒪(t³) @@ -440,11 +440,10 @@ function load_taylormodels_overapproximation() julia> X = box_approximation(Z) Hyperrectangle{Float64, Vector{Float64}, Vector{Float64}}([1.0, -2.1], [2.5, 6.5]) - julia> Y = evaluate(vTM[1], vTM[1].dom) × evaluate(vTM[2], vTM[2].dom) - [-1.5, 3.5] × [-8.60001, 4.40001] - - julia> H = convert(Hyperrectangle, Y) # this IntervalBox is the same as X - Hyperrectangle{Float64, StaticArraysCore.SVector{2, Float64}, StaticArraysCore.SVector{2, Float64}}([1.0, -2.1000000000000005], [2.5, 6.500000000000001]) + julia> Y = [evaluate(vTM[1], vTM[1].dom), evaluate(vTM[2], vTM[2].dom)] + 2-element Vector{IntervalArithmetic.Interval{Float64}}: + │ [-1.50001, 3.50001] + [-8.60001, 4.40001] ``` However, the zonotope returns better results if we want to approximate the Taylor model because it is not axis-aligned: @@ -553,17 +552,21 @@ function load_taylormodels_overapproximation() 1.0 x₁ + 𝒪(‖x‖⁹) 1.0 x₂ + 𝒪(‖x‖⁹) - julia> x₀ = IA.IntervalBox(0..0, 2) # expansion point - [0, 0]² + julia> x₀ = fill(0..0, 2) # expansion point + 2-element Vector{IntervalArithmetic.Interval{Float64}}: +│ [0.0, 0.0] +│ [0.0, 0.0] julia> Dx₁ = IA.interval(0.0, 3.0) # domain for x₁ - [0, 3] + [0.0, 3.0] julia> Dx₂ = IA.interval(-1.0, 1.0) # domain for x₂ - [-1, 1] + [-1.0, 1.0] - julia> D = Dx₁ × Dx₂ # take the Cartesian product of the domain on each variable - [0, 3] × [-1, 1] + julia> D = [Dx₁, Dx₂] + 2-element Vector{IntervalArithmetic.Interval{Float64}}: +│ [0.0, 3.0] +│ [-1.0, 1.0] julia> r = IA.interval(-0.5, 0.5) # interval remainder [-0.5, 0.5] @@ -629,13 +632,17 @@ function load_taylormodels_overapproximation() # build the generators α = mid(rem_nonlin) - c[i] = constant_term(pol_lin_norm) + α # constant terms - G[i, 1:n] = get_linear_coeffs(pol_lin_norm) # linear terms + cterm = constant_term(pol_lin_norm) + @assert IA.isthin(cterm) "unexpected interval value" + c[i] = mid(cterm) + α # constant terms + lin_coeffs = get_linear_coeffs(pol_lin_norm) + @assert all(IA.isthin, lin_coeffs) "unexpected interval value" + G[i, 1:n] = mid.(lin_coeffs) # linear terms # interval generator for j in (n + 1):(n + m) G[i, j] = zero(N) end - G[i, n + i] = abs(rem_nonlin.hi - α) + G[i, n + i] = abs(IA.sup(rem_nonlin) - α) end if remove_redundant_generators @@ -1194,6 +1201,8 @@ end # - the resulting zonotope is G * D + c function _overapproximate_zonotope_halfspace_ICP(Z::AbstractZonotope{N}, H::HalfSpace{N,SingleEntryVector{N}}) where {N} + require(@__MODULE__, :IntervalConstraintProgramming; fun_name="overapproximate") + c = center(Z) G = genmat(Z) p = size(G, 2) @@ -1201,19 +1210,22 @@ function _overapproximate_zonotope_halfspace_ICP(Z::AbstractZonotope{N}, a = G[d, :] io = IOBuffer() - first = true v = H.a.v negate = v < zero(N) if negate v = -v end + vars = "" + first = true for (i, ai) in enumerate(a) if first first = false elseif ai >= 0 write(io, "+") + vars *= ", " end write(io, "$(v * ai)*x$(i)") + vars *= "x$(i)" end if negate write(io, ">=$(-H.b + c[d])") @@ -1221,8 +1233,8 @@ function _overapproximate_zonotope_halfspace_ICP(Z::AbstractZonotope{N}, write(io, "<=$(H.b - c[d])") end e = Meta.parse(String(take!(io))) - X = IA.IntervalBox(IA.interval(-1, 1), p) - newD = _contract_zonotope_halfspace_ICP(e, X) + X = fill(IA.interval(-1, 1), p) + newD = _contract_zonotope_halfspace_ICP(e, X, vars) if isempty(newD) return EmptySet{N}(length(c)) end @@ -1232,15 +1244,22 @@ end function load_overapproximate_ICP() return quote import .IntervalConstraintProgramming as ICP - - function _contract_zonotope_halfspace_ICP(e, X) + import .IntervalConstraintProgramming.IntervalBoxes as IB + + function _contract_zonotope_halfspace_ICP(e, X, vars_string) + n = length(X) + prefix = "IntervalConstraintProgramming.Symbolics.@variables " + sym = Meta.parse(prefix * vars_string) + vars = eval(quote + $sym + end) separator = eval(quote - ICP.@constraint $e + ICP.Separator($e, $vars) end) # smallest box containing all points in domain X satisfying constraint # (`invokelatest` to avoid world-age issue; `Base.` for VERSION < v"1.9") - out, _ = Base.invokelatest(separator, X) - return out + boundary, _, _ = Base.invokelatest(separator, IB.IntervalBox(X...)) + return boundary end end end # load_overapproximate_ICP() diff --git a/src/ConcreteOperations/difference.jl b/src/ConcreteOperations/difference.jl index 25856f8c14..d25294fb11 100644 --- a/src/ConcreteOperations/difference.jl +++ b/src/ConcreteOperations/difference.jl @@ -13,11 +13,24 @@ union is in general not convex. This implementation uses `IntervalArithmetic.setdiff`. """ @validate function difference(X::AbstractHyperrectangle, Y::AbstractHyperrectangle) - Xib = convert(IA.IntervalBox, X) - Yib = convert(IA.IntervalBox, Y) - return UnionSetArray(convert.(Hyperrectangle, IA.setdiff(Xib, Yib))) + require(@__MODULE__, :IntervalBoxes; fun_name="difference") + + return _difference(X, Y) end +function load_IntervalBoxes_difference() + return quote + import .IntervalBoxes as IB + + function _difference(X::AbstractHyperrectangle, Y::AbstractHyperrectangle) + Xib = convert(IB.IntervalBox, X) + Yib = convert(IB.IntervalBox, Y) + Zibs = IB.setdiff(Xib, Yib) + return UnionSetArray(convert.(Hyperrectangle, Zibs)) + end + end +end # quote / load_IntervalBoxes_difference + @validate function difference(X::Interval{N}, H::HalfSpace) where {N} if H.a[1] < zero(N) # half-space is a lower bound diff --git a/src/Convert/convert.jl b/src/Convert/convert.jl index 3f60d156c6..4d9299bc7a 100644 --- a/src/Convert/convert.jl +++ b/src/Convert/convert.jl @@ -134,3 +134,13 @@ for T in subtypes(AbstractHPolygon, true) end end end + +function load_IntervalBoxes_convert_AbstractHyperrectangle() + return quote + import .IntervalBoxes as IB + + function convert(::Type{IB.IntervalBox}, H::AbstractHyperrectangle) + return IB.IntervalBox(IA.interval.(low(H), high(H))...) + end + end +end # quote / load_IntervalBoxes_convert_AbstractHyperrectangle diff --git a/src/Initialization/init_IntervalArithmetic.jl b/src/Initialization/init_IntervalArithmetic.jl index 25393665e6..5321cc7179 100644 --- a/src/Initialization/init_IntervalArithmetic.jl +++ b/src/Initialization/init_IntervalArithmetic.jl @@ -8,16 +8,16 @@ function zero_itv(N) return res end -const zero_box_store = Dict{Type,Dict{Integer,IA.IntervalBox}}() +const zero_box_store = Dict{Type,Dict{Integer,Vector{<:IA.Interval}}}() function zero_box(n::Int, N=Float64) d = get(zero_box_store, N, nothing) if isnothing(d) - d = Dict{Integer,IA.IntervalBox}() + d = Dict{Integer,Vector{<:IA.Interval}}() zero_box_store[N] = d end res = get(d, n, nothing) if isnothing(res) - res = IA.IntervalBox(zero_itv(N), n) + res = fill(zero_itv(N), n) d[n] = res end return res @@ -33,53 +33,17 @@ function sym_itv(N) return res end -const sym_box_store = Dict{Type,Dict{Integer,IA.IntervalBox}}() +const sym_box_store = Dict{Type,Dict{Integer,Vector{<:IA.Interval}}}() function sym_box(n::Int, N=Float64) d = get(sym_box_store, N, nothing) if isnothing(d) - d = Dict{Integer,IA.IntervalBox}() + d = Dict{Integer,Vector{<:IA.Interval}}() sym_box_store[N] = d end res = get(d, n, nothing) if isnothing(res) - res = IA.IntervalBox(sym_itv(N), n) + res = fill(sym_itv(N), n) d[n] = res end return res end - -""" - fast_interval_pow(a::IntervalArithmetic.Interval, n::Int) - -Compute the `n`th power of an interval without using correct rounding. - -### Input - -- `a` -- interval (from `IntervalArithmetic.jl`) -- `n` -- integer - -### Output - -A non-rigorous approximation of `a^n`. - -### Notes - -For a rigorous approximation with correct rounding, use `a^n` from -`IntervalArithmetic.jl`. -""" -function fast_interval_pow(a::IA.Interval, n::Int) - # TODO review after IntervalArithmetic.jl#388 - if iszero(n) - return one(a) - elseif isodd(n) - return IA.interval(a.lo^n, a.hi^n) - else - if 0 ∈ a - return IA.interval(zero(a.lo), max(abs(a.lo), abs(a.hi))^n) - else - lon = a.lo^n - hin = a.hi^n - return IA.interval(min(lon, hin), max(lon, hin)) - end - end -end diff --git a/src/Initialization/init_IntervalBoxes.jl b/src/Initialization/init_IntervalBoxes.jl new file mode 100644 index 0000000000..3db080c10a --- /dev/null +++ b/src/Initialization/init_IntervalBoxes.jl @@ -0,0 +1,2 @@ +eval(load_IntervalBoxes_convert_AbstractHyperrectangle()) +eval(load_IntervalBoxes_difference()) diff --git a/src/Initialization/init_TaylorModels.jl b/src/Initialization/init_TaylorModels.jl index 53d96820ae..ebe3c08458 100644 --- a/src/Initialization/init_TaylorModels.jl +++ b/src/Initialization/init_TaylorModels.jl @@ -5,7 +5,7 @@ _eltype_TM(TMi) = numtype(polynomial(TMi)) # check that a vector of Taylor models has the [-1, 1] domain function _has_normalized_domain(vTM::Vector) - return all(TMi -> all(==(sym_itv(_eltype_TM(TMi))), domain(TMi)), vTM) + return all(TMi -> all(IA.isequal_interval(sym_itv(_eltype_TM(TMi))), domain(TMi)), vTM) end eval(load_TaylorModels_convert_SparsePolynomialZonotope()) diff --git a/src/Interfaces/AbstractSparsePolynomialZonotope.jl b/src/Interfaces/AbstractSparsePolynomialZonotope.jl index 0d8292f4d5..94c5aab31c 100644 --- a/src/Interfaces/AbstractSparsePolynomialZonotope.jl +++ b/src/Interfaces/AbstractSparsePolynomialZonotope.jl @@ -222,7 +222,7 @@ function load_RangeEnclosures_support_function() f(x) = sum(d' * gi * prod(x .^ ei) for (gi, ei) in zip(eachcol(G), eachcol(E))) - dom = IA.IntervalBox(IA.interval(-1, 1), n) + dom = fill(IA.interval(-1, 1), n) res += IA.sup(RangeEnclosures.enclose(f, dom, method)) return res end diff --git a/src/MatrixSets/convert.jl b/src/MatrixSets/convert.jl index dc2b1c9b31..413a737723 100644 --- a/src/MatrixSets/convert.jl +++ b/src/MatrixSets/convert.jl @@ -16,7 +16,7 @@ function load_intervalmatrices_conversion() A matrix zonotope with one generator - ### Example + ### Example ```jldoctest julia> using LazySets, IntervalMatrices @@ -24,8 +24,8 @@ function load_intervalmatrices_conversion() julia> IM = IntervalMatrix([interval(-1.1, -0.9) interval(-4.1, -3.9); interval(3.9, 4.1) interval(-1.1, -0.9)]) 2×2 IntervalMatrix{Float64, IntervalArithmetic.Interval{Float64}, Matrix{IntervalArithmetic.Interval{Float64}}}: - [-1.10001, -0.9] [-4.1, -3.89999] - [3.89999, 4.1] [-1.10001, -0.9] + [-1.10001, -0.8999999] [-4.10001, -3.89999] + [3.89999, 4.10001] [-1.10001, -0.8999999] julia> MZ = convert(MatrixZonotope, IM) MatrixZonotope{Float64, Matrix{Float64}}([-1.0 -4.0; 4.0 -1.0], [[0.10000000000000009 0.0; 0.0 0.0], [0.0 0.0; 0.10000000000000009 0.0], [0.0 0.10000000000000009; 0.0 0.0], [0.0 0.0; 0.0 0.10000000000000009]], [1, 2, 3, 4]) diff --git a/src/Sets/Hyperrectangle/convert.jl b/src/Sets/Hyperrectangle/convert.jl index 471b609b64..b6075f5d95 100644 --- a/src/Sets/Hyperrectangle/convert.jl +++ b/src/Sets/Hyperrectangle/convert.jl @@ -6,16 +6,6 @@ function load_IntervalArithmetic_convert() return quote import IntervalArithmetic as IA - function convert(::Type{IA.IntervalBox}, H::AbstractHyperrectangle) - return IA.IntervalBox(IA.interval.(low(H), high(H))) - end - - function convert(::Type{Hyperrectangle}, IB::IA.IntervalBox) - low_IB = IA.inf.(IB) - high_IB = IA.sup.(IB) - return Hyperrectangle(; low=low_IB, high=high_IB) - end - function convert(::Type{Hyperrectangle}, I::IA.Interval) low_I = [IA.inf(I)] high_I = [IA.sup(I)] @@ -23,3 +13,15 @@ function load_IntervalArithmetic_convert() end end end # quote / load_IntervalArithmetic_convert + +function load_IntervalBoxes_convert_Hyperrectangle() + return quote + import .IntervalBoxes as IB + + function convert(::Type{Hyperrectangle}, Ibox::IB.IntervalBox) + low_IB = IB.inf.(Ibox) + high_IB = IB.sup.(Ibox) + return Hyperrectangle(; low=low_IB, high=high_IB) + end + end +end # quote / load_IntervalBoxes_convert_Hyperrectangle diff --git a/src/Sets/Hyperrectangle/init.jl b/src/Sets/Hyperrectangle/init.jl index 73e7121db5..59024888a2 100644 --- a/src/Sets/Hyperrectangle/init.jl +++ b/src/Sets/Hyperrectangle/init.jl @@ -1,4 +1,5 @@ function __init__() @require IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" eval(load_IntervalArithmetic_convert()) + @require IntervalBoxes = "43d83c95-ebbb-40ec-8188-24586a1458ed" include("init_IntervalBoxes.jl") @require StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" eval(load_StaticArraysCore_genmat()) end diff --git a/src/Sets/Hyperrectangle/init_IntervalBoxes.jl b/src/Sets/Hyperrectangle/init_IntervalBoxes.jl new file mode 100644 index 0000000000..a4eb3803d7 --- /dev/null +++ b/src/Sets/Hyperrectangle/init_IntervalBoxes.jl @@ -0,0 +1 @@ +eval(load_IntervalBoxes_convert_Hyperrectangle()) diff --git a/src/Sets/Interval/Interval.jl b/src/Sets/Interval/Interval.jl index 286b430f51..27a3934376 100644 --- a/src/Sets/Interval/Interval.jl +++ b/src/Sets/Interval/Interval.jl @@ -27,13 +27,13 @@ of numbers: ```jldoctest interval_constructor julia> x = Interval(0.0, 1.0) -Interval{Float64}([0, 1]) +Interval{Float64}([0.0, 1.0]) ``` A 2-vector is also possible: ```jldoctest interval_constructor julia> x = Interval([0.0, 1.0]) -Interval{Float64}([0, 1]) +Interval{Float64}([0.0, 1.0]) ``` An interval can also be constructed from an `IntervalArithmetic.Interval`. @@ -44,8 +44,8 @@ conflict otherwise. ```jldoctest interval_constructor julia> using IntervalArithmetic -julia> x = LazySets.Interval(IntervalArithmetic.Interval(0.0, 1.0)) -LazySets.IntervalModule.Interval{Float64}([0, 1]) +julia> x = LazySets.Interval(IntervalArithmetic.interval(0.0, 1.0)) +LazySets.IntervalModule.Interval{Float64}([0.0, 1.0]) julia> dim(x) 1 @@ -71,7 +71,7 @@ struct Interval{N} <: AbstractHyperrectangle{N} dat::IA.Interval{N} function Interval(dat::IA.Interval{N}) where {N} - @assert isfinite(dat.lo) && isfinite(dat.hi) "intervals must be bounded" + @assert isfinite(IA.inf(dat)) && isfinite(IA.sup(dat)) "intervals must be bounded" return new{N}(dat) end diff --git a/src/Sets/Interval/IntervalModule.jl b/src/Sets/Interval/IntervalModule.jl index 09dd5a963f..e9dda2d84f 100644 --- a/src/Sets/Interval/IntervalModule.jl +++ b/src/Sets/Interval/IntervalModule.jl @@ -23,7 +23,7 @@ using ReachabilityBase.Require: require @reexport import ..LazySets: chebyshev_center_radius, isflat, ngens, radius_hyperrectangle, rationalize, split import ..LazySets: plot_recipe -import Base: convert, min, max +import Base: ==, convert, min, max @reexport using ..API export Interval @@ -77,6 +77,7 @@ include("radius_hyperrectangle.jl") include("split.jl") include("convert.jl") +include("isequal.jl") """ min(X::Interval) @@ -92,7 +93,7 @@ Return the lower component of an interval. The lower (`lo`) component of the interval (a number). """ function min(X::Interval) - return X.dat.lo + return IA.inf(X.dat) end """ @@ -109,7 +110,7 @@ Return the higher or upper component of an interval. The higher (`hi`) component of the interval (a number). """ function max(X::Interval) - return X.dat.hi + return IA.sup(X.dat) end """ diff --git a/src/Sets/Interval/difference.jl b/src/Sets/Interval/difference.jl index 23e9c1961f..8b98cfd14c 100644 --- a/src/Sets/Interval/difference.jl +++ b/src/Sets/Interval/difference.jl @@ -43,10 +43,10 @@ julia> difference(X, X) ∅(1) julia> difference(X, Y) -Interval{Float64}([0, 1]) +Interval{Float64}([0.0, 1.0]) julia> difference(Y, Z) -UnionSet{Float64, Interval{Float64}, Interval{Float64}}(Interval{Float64}([1, 2]), Interval{Float64}([3, 4])) +UnionSet{Float64, Interval{Float64}, Interval{Float64}}(Interval{Float64}([1.0, 2.0]), Interval{Float64}([3.0, 4.0])) ``` """ @validate function difference(X::Interval, Y::Interval) diff --git a/src/Sets/Interval/in.jl b/src/Sets/Interval/in.jl index aa5df48d00..fc2045ba41 100644 --- a/src/Sets/Interval/in.jl +++ b/src/Sets/Interval/in.jl @@ -1,3 +1,4 @@ @validate function in(v::AbstractVector, X::Interval) - return @inbounds v[1] ∈ X.dat + e = @inbounds v[1] + return IA.in_interval(e, X.dat) end diff --git a/src/Sets/Interval/isequal.jl b/src/Sets/Interval/isequal.jl new file mode 100644 index 0000000000..336c2c51dc --- /dev/null +++ b/src/Sets/Interval/isequal.jl @@ -0,0 +1,3 @@ +function ==(X::Interval, Y::Interval) + return IA.isequal_interval(X.dat, Y.dat) +end diff --git a/src/Sets/Interval/rectify.jl b/src/Sets/Interval/rectify.jl index 593a2fc53a..6c8dfda6d8 100644 --- a/src/Sets/Interval/rectify.jl +++ b/src/Sets/Interval/rectify.jl @@ -10,11 +10,11 @@ An `Interval`, even if it represents a singleton only containing the origin """ function rectify(X::Interval) N = eltype(X) - if X.dat.lo >= zero(N) + if min(X) >= zero(N) # interval is already nonnegative return X else # lower end is negative - return Interval(zero(N), Base.max(X.dat.hi, zero(N))) + return Interval(zero(N), Base.max(max(X), zero(N))) end end diff --git a/src/init.jl b/src/init.jl index 76d96880a7..883bb51574 100644 --- a/src/init.jl +++ b/src/init.jl @@ -5,6 +5,7 @@ function __init__() @require ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" include("Initialization/init_ExponentialUtilities.jl") # the includes for `GeometryBasics` are loaded when `Polyhedra` is loaded @require GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" (nothing,) + @require IntervalBoxes = "43d83c95-ebbb-40ec-8188-24586a1458ed" include("Initialization/init_IntervalBoxes.jl") @require Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" (nothing,) @require Javis = "78b212ba-a7f9-42d4-b726-60726080707e" include("Initialization/init_Javis.jl") @require Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" include("Initialization/init_Makie.jl") diff --git a/test/Approximations/box_approximation.jl b/test/Approximations/box_approximation.jl index d422897542..791a187838 100644 --- a/test/Approximations/box_approximation.jl +++ b/test/Approximations/box_approximation.jl @@ -1,6 +1,5 @@ using LazySets, Test IA = LazySets.IA -using LazySets.IA: IntervalBox if !isdefined(@__MODULE__, Symbol("@tN")) macro tN(v) return v @@ -126,8 +125,8 @@ for N in [Float64] Dx₁ = IA.interval(N(-1), N(1)) Dx₂ = IA.interval(N(-1), N(1)) Dx₃ = IA.interval(N(-1), N(1)) - D = Dx₁ × Dx₂ × Dx₃ - local x0 = IntervalBox(IA.mid.(D)...) + D = [Dx₁, Dx₂, Dx₃] + local x0 = [IA.interval(IA.mid(di)) for di in D] local vTM = [TaylorModels.TaylorModelN(pi, I, x0, D) for pi in [p₁, p₂]] @test box_approximation(vTM) == Hyperrectangle(N[1, 0], N[2, 2]) end diff --git a/test/Approximations/overapproximate.jl b/test/Approximations/overapproximate.jl index 47f7c38b97..0d37ce8b72 100644 --- a/test/Approximations/overapproximate.jl +++ b/test/Approximations/overapproximate.jl @@ -3,7 +3,6 @@ using LazySets.MatrixZonotopeModule: vectorize using LazySets.ReachabilityBase.Arrays: ispermutation, SingleEntryVector using LazySets.ReachabilityBase.Comparison: _leq, _geq IA = LazySets.IA -using LazySets.IA: IntervalBox if !isdefined(@__MODULE__, Symbol("@tN")) macro tN(v) return v @@ -587,8 +586,8 @@ for N in [Float64] Dx₁ = IA.interval(N(1.0), N(3.0)) Dx₂ = IA.interval(N(-1.0), N(1.0)) Dx₃ = IA.interval(N(-1.0), N(0.0)) - D = Dx₁ × Dx₂ × Dx₃ # domain - local x0 = IntervalBox(IA.mid.(D)...) + D = [Dx₁, Dx₂, Dx₃] # domain + local x0 = [IA.interval(IA.mid(di)) for di in D] I = IA.interval(N(0.0), N(0.0)) # interval remainder local p₁ = 1 + x₁ - x₂ local p₂ = x₃ - x₁ @@ -667,16 +666,21 @@ for N in [Float64] @test (L ∩ Z) ⊆ cap end - @static if isdefined(@__MODULE__, :IntervalConstraintProgramming) + @static if isdefined(@__MODULE__, :IntervalConstraintProgramming) && + isdefined(@__MODULE__, :IntervalBoxes) # overapproximate a nonlinear constraint with an HPolyhedron - local dom = IntervalBox(IA.interval(-2, 2), IA.interval(-2, 2)) - C = IntervalConstraintProgramming.@constraint x^2 + y^2 <= 1 - p = IntervalConstraintProgramming.pave(C, dom, 0.01) + vars = IntervalConstraintProgramming.@variables x, y + dom = IntervalBoxes.IntervalBox([IA.interval(-2, 2), IA.interval(-2, 2)]...) + C = IntervalConstraintProgramming.constraint(x^2 + y^2 <= 1, vars) + # (`invokelatest` to avoid world-age issue) + inner, boundary = invokelatest(IntervalConstraintProgramming.pave, dom, C, 0.01) dirs = OctDirections(2) - H = overapproximate(p, dirs) + H = overapproximate(boundary, dirs) B2 = Ball2(N[0, 0], N(1)) @test B2 ⊆ H + end + @static if isdefined(@__MODULE__, :IntervalConstraintProgramming) # overapproximate the intersection of a zonotope with an axis-aligned # half-space by a zonotope using ICP Z = Zonotope(N[0, 2], N[1//2 1//2; 1 0]) diff --git a/test/ConcreteOperations/isdisjoint.jl b/test/ConcreteOperations/isdisjoint.jl index d674f9c64d..5b23bc3a4a 100644 --- a/test/ConcreteOperations/isdisjoint.jl +++ b/test/ConcreteOperations/isdisjoint.jl @@ -1,6 +1,4 @@ using LazySets, Test -IA = LazySets.IA -using LazySets.IA: IntervalBox if !isdefined(@__MODULE__, Symbol("@tN")) macro tN(v) return v diff --git a/test/ConcreteOperations/issubset.jl b/test/ConcreteOperations/issubset.jl index 493653f594..f9ae52dad5 100644 --- a/test/ConcreteOperations/issubset.jl +++ b/test/ConcreteOperations/issubset.jl @@ -1,6 +1,4 @@ using LazySets, Test -IA = LazySets.IA -using LazySets.IA: IntervalBox if !isdefined(@__MODULE__, Symbol("@tN")) macro tN(v) return v @@ -54,13 +52,15 @@ for N in @tN([Float64, Float32, Rational{Int}]) res, w = ⊆(Z, H, true) @test !res && w isa Vector{N} && w ∈ Z && w ∉ H - B = Hyperrectangle(N[0, 0], N[1, 1]) - U = UnionSetArray([Hyperrectangle(N[0, 1], N[3, 1]), Hyperrectangle(N[0, -1], N[3, 1])]) - res, w = ⊆(B, U, true) - @test B ⊆ U && res && w == N[] - U = UnionSetArray([Hyperrectangle(N[0, 1], N[3, 1]), Hyperrectangle(N[3, -1], N[3, 1])]) - res, w = ⊆(B, U, true) - @test !(B ⊆ U) && !res && w ∈ B && w ∉ U + if isdefined(@__MODULE__, :IntervalBoxes) + B = Hyperrectangle(N[0, 0], N[1, 1]) + U = UnionSetArray([Hyperrectangle(N[0, 1], N[3, 1]), Hyperrectangle(N[0, -1], N[3, 1])]) + res, w = ⊆(B, U, true) + @test B ⊆ U && res && w == N[] + U = UnionSetArray([Hyperrectangle(N[0, 1], N[3, 1]), Hyperrectangle(N[3, -1], N[3, 1])]) + res, w = ⊆(B, U, true) + @test !(B ⊆ U) && !res && w ∈ B && w ∉ U + end # nonconvex set in polyhedron Pnc = Polygon([N[0, 0], N[0, 2], N[2, 2], N[2, 0], N[1, 1]]) diff --git a/test/Project.toml b/test/Project.toml index c70c291d97..517be9d825 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -4,8 +4,9 @@ CDDLib = "3391f64e-dcde-5f30-b752-e11513730f60" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" Expokit = "a1e7a1ef-7a5d-5822-a38c-be74e1bb89f4" ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" -GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" GR = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" +GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" +IntervalBoxes = "43d83c95-ebbb-40ec-8188-24586a1458ed" IntervalConstraintProgramming = "138f1668-1576-5ad7-91b9-7425abbf3153" IntervalMatrices = "5c1f47dc-42dd-5697-8aaa-4d102d140ba9" Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" @@ -32,20 +33,21 @@ CDDLib = "0.6 - 0.10" Distributions = "0.19 - 0.25" Expokit = "0.2" ExponentialUtilities = "1" -GeometryBasics = "0.3 - 0.5" GR = "0" -IntervalConstraintProgramming = "0.9 - 0.13" +GeometryBasics = "0.3 - 0.5" +IntervalBoxes = "0.2" +IntervalConstraintProgramming = "0.14" IntervalMatrices = "0.8 - 0.12" Ipopt = "1" MiniQhull = "0.1 - 0.4" Optim = "0.15 - 0.22, 1" PkgVersion = "0.3" Polyhedra = "0.6 - 0.8" -RangeEnclosures = "0.1.1, 0.2" +RangeEnclosures = "0.3" SCS = "1, 2" SetProg = "0.3 - 0.4" StaticArrays = "0.12, 1" SymEngine = "0.7 - 0.13" Symbolics = "1 - 5.30, 6.1" -TaylorModels = "0.0.1, 0.1 - 0.8" +TaylorModels = "0.9" WriteVTK = "1" diff --git a/test/Sets/BallInf.jl b/test/Sets/BallInf.jl index b13273f19b..8c72fd1f02 100644 --- a/test/Sets/BallInf.jl +++ b/test/Sets/BallInf.jl @@ -192,10 +192,13 @@ for N in @tN([Float64, Float32, Rational{Int}]) @test ispermutation(collect(vertices(B)), vertices_list(B)) # set difference - B = BallInf(N[0, 0, 0], N(1)) - @test isempty(difference(B, B)) + @static if isdefined(@__MODULE__, :IntervalBoxes) + B = BallInf(N[0, 0, 0], N(1)) + @test isempty(difference(B, B)) + end # volume + B = BallInf(N[0, 0, 0], N(1)) @test volume(B) ≈ N(8) # projection diff --git a/test/Sets/Hyperrectangle.jl b/test/Sets/Hyperrectangle.jl index dbff57b947..a99102a7fc 100644 --- a/test/Sets/Hyperrectangle.jl +++ b/test/Sets/Hyperrectangle.jl @@ -1,7 +1,6 @@ using LazySets, Test, SparseArrays, LinearAlgebra using LazySets.ReachabilityBase.Arrays: ispermutation, SingleEntryVector IA = LazySets.IA -using LazySets.IA: IntervalBox if !isdefined(@__MODULE__, Symbol("@tN")) macro tN(v) return v @@ -308,14 +307,17 @@ for N in @tN([Float64, Float32, Rational{Int}]) HalfSpace(N[-1, 0], N(1)), HalfSpace(N[0, -1], N(1))]) # conversion to and from IntervalArithmetic's IntervalBox type - B = IntervalBox(IA.interval(0, 1), IA.interval(0, 1)) - H = convert(Hyperrectangle, B) - @test convert(IntervalBox, H) == B + @static if isdefined(@__MODULE__, :IntervalBoxes) + import IntervalBoxes as IB + B = IB.IntervalBox(IA.interval(0, 1), IA.interval(0, 1)) + H = convert(Hyperrectangle, B) + @test convert(IB.IntervalBox, H) == B + end # conversion to and from IntervalArithmetic's Interval type I = IA.interval(N(0), N(1)) H = convert(Hyperrectangle, I) - @test convert(IA.Interval, H) == I + @test IA.isequal_interval(convert(IA.Interval, H), I) # conversion from Interval I = Interval(I) H = convert(Hyperrectangle, I) @@ -353,9 +355,11 @@ for N in @tN([Float64, Float32, Rational{Int}]) @test minkowski_sum(H1, H2) == Hyperrectangle(N[3, 3], N[3, 3]) # set difference - h = Hyperrectangle(; low=N[0], high=N[1]) - q = Hyperrectangle(; low=N[0], high=N[0.5]) - @test convert(Interval, difference(h, q).array[1]) == Interval(N(0.5), N(1)) + @static if isdefined(@__MODULE__, :IntervalBoxes) + h = Hyperrectangle(; low=N[0], high=N[1]) + q = Hyperrectangle(; low=N[0], high=N[0.5]) + @test convert(Interval, difference(h, q).array[1]) == Interval(N(0.5), N(1)) + end # concrete projection @test project(Hyperrectangle(N[4, 3, 2, 1], N[8, 7, 6, 5]), [2, 4]) == diff --git a/test/Sets/Interval.jl b/test/Sets/Interval.jl index 054fde00d7..e746b3e0c9 100644 --- a/test/Sets/Interval.jl +++ b/test/Sets/Interval.jl @@ -18,7 +18,7 @@ function isidentical(::Interval, ::Interval) end function isidentical(X1::Interval{N}, X2::Interval{N}) where {N} - return X1.dat == X2.dat + return X1 == X2 end for N in @tN([Float64, Float32, Rational{Int}]) @@ -30,7 +30,7 @@ for N in @tN([Float64, Float32, Rational{Int}]) # default constructor from IntervalArithmetic.Interval itv = IA.interval(N(0), N(2)) X = Interval(itv) - @test X isa Interval{N} && X.dat == itv + @test X isa Interval{N} && IA.isequal_interval(X.dat, itv) # constructors from two numbers, from a vector, and with promotion for Y in (Interval(N(0), N(2)), Interval(N[0, 2]), Interval(0, N(2))) @@ -48,7 +48,7 @@ for N in @tN([Float64, Float32, Rational{Int}]) # convert # to and from IntervalArithmetic.Interval Y = convert(IA.Interval, X) - @test Y == X.dat + @test IA.isequal_interval(Y, X.dat) Z = convert(Interval, Y) @test isidentical(Z, X) # from hyperrectangular set diff --git a/test/Sets/SparsePolynomialZonotope.jl b/test/Sets/SparsePolynomialZonotope.jl index a6d84c9ed1..480bba2dbd 100644 --- a/test/Sets/SparsePolynomialZonotope.jl +++ b/test/Sets/SparsePolynomialZonotope.jl @@ -1,7 +1,6 @@ using LazySets, Test, LinearAlgebra using LazySets.SparsePolynomialZonotopeModule: merge_id IA = LazySets.IA -using LazySets.IA: IntervalBox if !isdefined(@__MODULE__, Symbol("@tN")) macro tN(v) return v @@ -100,7 +99,7 @@ for N in @tN([Float64, Float32, Rational{Int}]) # cartesian_product SPZ/Z Z = overapproximate(PZ2, Zonotope) SSPZ2 = convert(SimpleSparsePolynomialZonotope, PZ2) - dom2 = IntervalBox(IA.interval(N(-1), N(1)), IA.interval(N(-1), N(1))) + dom2 = [IA.interval(N(-1), N(1)), IA.interval(N(-1), N(1))] Z2 = overapproximate(SSPZ2, Zonotope, dom2) @test isequivalent(Z, Z2) CPPZ = cartesian_product(PZ, Z) @@ -277,9 +276,8 @@ for Z in [rand(Zonotope), rand(Hyperrectangle)] @test expmat(ZS) == I end -let +for N in [Float64] @static if isdefined(@__MODULE__, :TaylorModels) - N = Float64 PZS = SimpleSparsePolynomialZonotope(N[0.2, -0.6], N[1 0; 0 0.4], [1 0; 0 1]) PZ = convert(SparsePolynomialZonotope, PZS) @test center(PZ) == center(PZS) @@ -291,8 +289,8 @@ let # conversion from Taylor model x₁, x₂, x₃ = TaylorModels.set_variables(Float64, ["x₁", "x₂", "x₃"]; order=3) dom1 = IA.interval(N(-1), N(1)) - dom = dom1 × dom1 × dom1 - x0 = IntervalBox(IA.mid.(dom)...) + dom = [dom1, dom1, dom1] + x0 = [IA.interval(IA.mid(di)) for di in dom] rem = IA.interval(N(0), N(0)) p₁ = 33 + 2x₁ + 3x₂ + 4x₃ + 5x₁^2 + 6x₂ * x₃ + 7x₃^2 + 8x₁ * x₂ * x₃ p₂ = x₃ - x₁ diff --git a/test/runtests.jl b/test/runtests.jl index f051b5fcfa..cbf4209d1d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -49,9 +49,9 @@ Random.seed!(seed) @ts begin # only load the packages (no symbols) import CDDLib, Distributions, ExponentialUtilities, Expokit, GeometryBasics, - IntervalConstraintProgramming, IntervalMatrices, Ipopt, MiniQhull, - Optim, PkgVersion, Polyhedra, RangeEnclosures, SCS, StaticArrays, - TaylorModels + IntervalBoxes, IntervalConstraintProgramming, IntervalMatrices, + Ipopt, MiniQhull, Optim, PkgVersion, Polyhedra, RangeEnclosures, SCS, + StaticArrays, TaylorModels if VERSION < v"1.12" import SetProg # TODO add back unconditionally once it works in v1.12 end From 55f584251713ed0492258e1319df708ec88e1712 Mon Sep 17 00:00:00 2001 From: schillic Date: Sun, 16 Nov 2025 17:15:03 +0100 Subject: [PATCH 2/4] remove method for 'IntervalBox'es --- src/Approximations/init.jl | 1 - src/Approximations/init_IntervalBoxes.jl | 1 - src/Approximations/overapproximate.jl | 41 ------------------------ test/Approximations/overapproximate.jl | 3 +- 4 files changed, 2 insertions(+), 44 deletions(-) delete mode 100644 src/Approximations/init_IntervalBoxes.jl diff --git a/src/Approximations/init.jl b/src/Approximations/init.jl index b12aaa050b..951bfd98e8 100644 --- a/src/Approximations/init.jl +++ b/src/Approximations/init.jl @@ -1,7 +1,6 @@ function __init__() @require Expokit = "a1e7a1ef-7a5d-5822-a38c-be74e1bb89f4" (nothing,) @require ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" (nothing,) - @require IntervalBoxes = "43d83c95-ebbb-40ec-8188-24586a1458ed" include("init_IntervalBoxes.jl") @require IntervalConstraintProgramming = "138f1668-1576-5ad7-91b9-7425abbf3153" include("init_IntervalConstraintProgramming.jl") @require IntervalMatrices = "5c1f47dc-42dd-5697-8aaa-4d102d140ba9" include("init_IntervalMatrices.jl") @require Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" include("init_Ipopt.jl") diff --git a/src/Approximations/init_IntervalBoxes.jl b/src/Approximations/init_IntervalBoxes.jl deleted file mode 100644 index 364b4b3a5c..0000000000 --- a/src/Approximations/init_IntervalBoxes.jl +++ /dev/null @@ -1 +0,0 @@ -eval(load_IntervalBoxes_overapproximate_paving()) diff --git a/src/Approximations/overapproximate.jl b/src/Approximations/overapproximate.jl index e71934e1d6..ad875d4d68 100644 --- a/src/Approximations/overapproximate.jl +++ b/src/Approximations/overapproximate.jl @@ -676,47 +676,6 @@ function overapproximate(P::AbstractSparsePolynomialZonotope{N}, ::Type{<:VPolyt return VPolytope(vlist) end -function load_IntervalBoxes_overapproximate_paving() - return quote - import .IntervalBoxes as IB - - """ - overapproximate(boundary::Vector{<:IB.IntervalBox}, dirs::AbstractDirections) - - Overapproximate a vector of `IntervalBox`es ("paving") with a polyhedron in constraint - representation. - - ### Input - - - `boundary` -- vector of `IntervalBox`es - - `dirs` -- template directions - - ### Output - - An overapproximation in constraint representation (`HPolyhedron`) with constraints in - direction `dirs`. - - ### Algorithm - - This implementation first converts the boxes into `Hyperrectangle`s and then calculates the - support function of the set along each direction in `dirs` to compute the `HPolyhedron` - constraints. - """ - function overapproximate(boundary::Vector{<:IB.IntervalBox}, dirs::AbstractDirections) - # enclose outer approximation - Uouter = UnionSetArray(convert.(Hyperrectangle, boundary)) - constraints = [HalfSpace(d, ρ(d, Uouter)) for d in dirs] - return HPolyhedron(constraints) - end - - # alias with HPolyhedron type as second argument - function overapproximate(boundary::Vector{<:IB.IntervalBox}, ::Type{<:HPolyhedron}, - dirs::AbstractDirections) - return overapproximate(boundary, dirs) - end - end -end # quote / load_IntervalBoxes_overapproximate_paving - """ # Extended help diff --git a/test/Approximations/overapproximate.jl b/test/Approximations/overapproximate.jl index 0d37ce8b72..6cace67d23 100644 --- a/test/Approximations/overapproximate.jl +++ b/test/Approximations/overapproximate.jl @@ -675,7 +675,8 @@ for N in [Float64] # (`invokelatest` to avoid world-age issue) inner, boundary = invokelatest(IntervalConstraintProgramming.pave, dom, C, 0.01) dirs = OctDirections(2) - H = overapproximate(boundary, dirs) + Uouter = UnionSetArray(convert.(Hyperrectangle, boundary)) + H = overapproximate(Uouter, dirs) B2 = Ball2(N[0, 0], N(1)) @test B2 ⊆ H end From 73ddd02a27ea5745ee762da4746e3f8c2254622c Mon Sep 17 00:00:00 2001 From: schillic Date: Sun, 16 Nov 2025 20:14:50 +0100 Subject: [PATCH 3/4] require Julia v1.10 --- .github/workflows/test-pull-request.yml | 2 +- Project.toml | 2 +- src/Approximations/overapproximate_zonotope.jl | 11 +++-------- src/Initialization/init_Symbolics.jl | 7 +------ src/Interfaces/AbstractZonotope.jl | 9 +-------- src/LazySets.jl | 4 ---- src/Utils/helper_functions.jl | 11 ++--------- test/LazyOperations/Intersection.jl | 8 +------- test/Sets/EmptySet.jl | 3 +-- test/Sets/Interval.jl | 12 +----------- test/Sets/SimpleSparsePolynomialZonotope.jl | 10 +--------- 11 files changed, 13 insertions(+), 66 deletions(-) diff --git a/.github/workflows/test-pull-request.yml b/.github/workflows/test-pull-request.yml index 11d1e6f0f8..88bc642e1d 100644 --- a/.github/workflows/test-pull-request.yml +++ b/.github/workflows/test-pull-request.yml @@ -25,7 +25,7 @@ jobs: arch: - x64 include: - - version: '1.6' # test on oldest supported version + - version: '1.10' # test on oldest supported version arch: x64 os: ubuntu-latest env: diff --git a/Project.toml b/Project.toml index f26dba94ec..5e91648e50 100644 --- a/Project.toml +++ b/Project.toml @@ -33,4 +33,4 @@ Requires = "0.5, 1" SharedArrays = "<0.0.1, 1.6" SparseArrays = "<0.0.1, 1.6" StaticArraysCore = "1" -julia = "1.6" +julia = "1.10" diff --git a/src/Approximations/overapproximate_zonotope.jl b/src/Approximations/overapproximate_zonotope.jl index 8d48430b58..5ba54b5fa7 100644 --- a/src/Approximations/overapproximate_zonotope.jl +++ b/src/Approximations/overapproximate_zonotope.jl @@ -1167,12 +1167,7 @@ function _overapproximate_zonotope_hyperplane(Z::AbstractZonotope, H::Hyperplane s = G' * a d = b - dot(a, c) - @static if VERSION >= v"1.7" - sT = s' - else - sT = s' .+ 0 # convert to Vector (`nullspace` fails for lazy transpose) - end - V0 = nullspace(sT) + V0 = nullspace(s') cs = s * d / dot(s, s) Gs = V0 * V0' @@ -1257,8 +1252,8 @@ function load_overapproximate_ICP() ICP.Separator($e, $vars) end) # smallest box containing all points in domain X satisfying constraint - # (`invokelatest` to avoid world-age issue; `Base.` for VERSION < v"1.9") - boundary, _, _ = Base.invokelatest(separator, IB.IntervalBox(X...)) + # (`invokelatest` to avoid world-age issue) + boundary, _, _ = invokelatest(separator, IB.IntervalBox(X...)) return boundary end end diff --git a/src/Initialization/init_Symbolics.jl b/src/Initialization/init_Symbolics.jl index 74ae681ca8..9e3b27bc0e 100644 --- a/src/Initialization/init_Symbolics.jl +++ b/src/Initialization/init_Symbolics.jl @@ -7,12 +7,7 @@ _vec(vars::Vector{Symbolics.Arr{Num,1}}) = reduce(vcat, vars) _vec(vars::Vector{Vector{Num}}) = reduce(vcat, vars) _vec(vars::Vector{Real}) = reduce(vcat, vars) -# `sort` argument was introduced in Symbolics v6.1 -@static if VERSION < v"1.10" - _get_variables(expr::Num) = convert(Vector{Num}, Symbolics.get_variables(expr)) -else - _get_variables(expr::Num) = convert(Vector{Num}, Symbolics.get_variables(expr; sort=true)) -end +_get_variables(expr::Num) = convert(Vector{Num}, Symbolics.get_variables(expr; sort=true)) function _get_variables(expr::Vector{<:Num}) return unique(reduce(vcat, _get_variables(ex) for ex in expr)) end diff --git a/src/Interfaces/AbstractZonotope.jl b/src/Interfaces/AbstractZonotope.jl index 240a711269..dd8e8f9137 100644 --- a/src/Interfaces/AbstractZonotope.jl +++ b/src/Interfaces/AbstractZonotope.jl @@ -638,11 +638,7 @@ end function flat_dimensions(Z::AbstractZonotope) G = genmat(Z) - @static if VERSION >= v"1.7" - res = findall(iszero, eachrow(G)) - else - res = findall(iszero, collect(eachrow(G))) - end + res = findall(iszero, eachrow(G)) return res end @@ -856,9 +852,6 @@ function remove_redundant_generators(G::AbstractMatrix) # sort column in ascending order cols = eachcol(Gnorm) - if VERSION < v"1.9" - cols = collect(cols) - end ord = sortperm(cols) merged = Vector{Vector{eltype(G)}}() diff --git a/src/LazySets.jl b/src/LazySets.jl index 54b271cd5f..abebd05f70 100644 --- a/src/LazySets.jl +++ b/src/LazySets.jl @@ -33,10 +33,6 @@ import IntervalArithmetic as IA using LinearAlgebra: checksquare using Random: AbstractRNG, GLOBAL_RNG, SamplerType, randperm -@static if VERSION < v"1.9" - stack(vecs) = hcat(vecs...) # COV_EXCL_LINE -end - # ================ # ReachabilityBase # ================ diff --git a/src/Utils/helper_functions.jl b/src/Utils/helper_functions.jl index a01cd7ebde..99e9f78564 100644 --- a/src/Utils/helper_functions.jl +++ b/src/Utils/helper_functions.jl @@ -272,14 +272,7 @@ _to_colVector(M::AbstractMatrix) = convert(Vector, [M[:, j] for j in axes(M, 2)] _to_colVector(M::Matrix) = [M[:, j] for j in axes(M, 2)] function load_StaticArraysCore_to_colVector() - @static if VERSION < v"1.9" - # in pre-v1.9 Julia versions, `collect` returned a `SizedVector` - return quote - _to_colVector(M::SMatrix) = [eachcol(M)...] - end - else - return quote - _to_colVector(M::SMatrix) = collect(eachcol(M)) - end + return quote + _to_colVector(M::SMatrix) = collect(eachcol(M)) end end # load_StaticArraysCore_to_colVector() diff --git a/test/LazyOperations/Intersection.jl b/test/LazyOperations/Intersection.jl index 812dc0664a..90d882bb73 100644 --- a/test/LazyOperations/Intersection.jl +++ b/test/LazyOperations/Intersection.jl @@ -1,11 +1,5 @@ using LazySets, Test using LazySets.ReachabilityBase.Arrays: SingleEntryVector, ispermutation -@static if VERSION >= v"1.9" - vGLPK = pkgversion(LazySets.GLPK) -else - import PkgVersion - vGLPK = PkgVersion.Version(LazySets.GLPK) -end if !isdefined(@__MODULE__, Symbol("@tN")) macro tN(v) return v @@ -70,7 +64,7 @@ for N in @tN([Float64, Float32, Rational{Int}]) I2 = Hyperplane(ones(N, 2), N(1)) ∩ HalfSpace(ones(N, 2), N(1)) # the next test fails with the "EXACT" solver GLPK older than v0.15.3 # see https://github.com/jump-dev/GLPK.jl/issues/207 - if N != Rational{Int} || vGLPK >= v"0.15.3" + if N != Rational{Int} || pkgversion(LazySets.GLPK) >= v"0.15.3" @test !isbounded(I2) && !isboundedtype(typeof(I2)) end diff --git a/test/Sets/EmptySet.jl b/test/Sets/EmptySet.jl index c4a3852239..c82040e4b6 100644 --- a/test/Sets/EmptySet.jl +++ b/test/Sets/EmptySet.jl @@ -177,8 +177,7 @@ for N in @tN([Float64, Float32, Rational{Int}]) # singleton_list res = singleton_list(E) - T = VERSION < v"1.7" ? Singleton : Singleton{N,Vector{N}} - @test res isa Vector{T} && isempty(res) + @test res isa Vector{Singleton{N,Vector{N}}} && isempty(res) # tosimplehrep @test_throws MethodError tosimplehrep(E) # TODO this should maybe change diff --git a/test/Sets/Interval.jl b/test/Sets/Interval.jl index e746b3e0c9..84aa9df72d 100644 --- a/test/Sets/Interval.jl +++ b/test/Sets/Interval.jl @@ -1,12 +1,6 @@ using LazySets, Test using LazySets.ReachabilityBase.Arrays: ispermutation, SingleEntryVector IA = LazySets.IA -@static if VERSION >= v"1.9" - vIA = pkgversion(IA) -else - import PkgVersion - vIA = PkgVersion.Version(IA) -end if !isdefined(@__MODULE__, Symbol("@tN")) macro tN(v) return v @@ -350,11 +344,7 @@ for N in @tN([Float64, Float32, Rational{Int}]) @test isidentical(Y, Interval(N(0), N(4))) Y = linear_map(zeros(N, 1, 1), X) # zero map @test Y isa Interval{N} - if vIA == v"0.21.0" - @test_broken isequivalent(Y, Interval(N(0), N(0))) # bug in IntervalArithmetic: 0 * I == I - else - @test isequivalent(Y, Interval(N(0), N(0))) - end + @test isequivalent(Y, Interval(N(0), N(0))) Y = linear_map(ones(N, 2, 1), X) # higher dimension @test Y isa LazySet{N} && isequivalent(Y, LineSegment(N[0, 0], N[2, 2])) Y = linear_map(zeros(N, 2, 1), X) # zero map in higher dimension diff --git a/test/Sets/SimpleSparsePolynomialZonotope.jl b/test/Sets/SimpleSparsePolynomialZonotope.jl index 4e46586c06..dbfaa3442d 100644 --- a/test/Sets/SimpleSparsePolynomialZonotope.jl +++ b/test/Sets/SimpleSparsePolynomialZonotope.jl @@ -1,11 +1,5 @@ using LazySets, Test, LinearAlgebra IA = LazySets.IA -@static if VERSION >= v"1.9" - vIA = pkgversion(IA) -else - import PkgVersion - vIA = PkgVersion.Version(IA) -end if !isdefined(@__MODULE__, Symbol("@tN")) macro tN(v) return v @@ -39,9 +33,7 @@ for N in @tN([Float64, Float32, Rational{Int}]) @test overapproximate(S, Zonotope) == Z @test overapproximate(S, UnionSetArray{Zonotope}; nsdiv=1) == UnionSetArray([Z]) @test length(overapproximate(S, UnionSetArray{Zonotope}; nsdiv=3)) == 9 - if vIA >= v"0.19.0" # `mince` with non-uniform partition was introduced in IA v0.19.0 - @test length(overapproximate(S, UnionSetArray{Zonotope}; partition=(2, 3))) == 6 - end + @test length(overapproximate(S, UnionSetArray{Zonotope}; partition=(2, 3))) == 6 LMS = linear_map(N[1 2; 3 4], S) @test LMS isa SimpleSparsePolynomialZonotope{N} From 5cd8b17e90c02c2ea8910a688734d85b1234c1c6 Mon Sep 17 00:00:00 2001 From: schillic Date: Sun, 30 Nov 2025 11:58:08 +0100 Subject: [PATCH 4/4] v6.0.0 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 5e91648e50..33d886693d 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "LazySets" uuid = "b4f0291d-fe17-52bc-9479-3d1a343d9043" -version = "5.1.0" +version = "6.0.0" [deps] Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"