diff --git a/Project.toml b/Project.toml index 57b1baf2..8e55e4de 100644 --- a/Project.toml +++ b/Project.toml @@ -5,14 +5,12 @@ version = "0.5.0" [deps] Dualization = "191a621a-6537-11e9-281d-650236a99e60" -IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" [compat] Dualization = "0.5.4" -IntervalArithmetic = "< 0.18.0" JuMP = "1.0" MathOptInterface = "1.0" julia = "1.6" diff --git a/src/BilevelJuMP.jl b/src/BilevelJuMP.jl index 8381e418..85840b54 100644 --- a/src/BilevelJuMP.jl +++ b/src/BilevelJuMP.jl @@ -6,7 +6,6 @@ const MOIU = MathOptInterface.Utilities using JuMP using Dualization using LinearAlgebra -using IntervalArithmetic export BilevelModel, @@ -15,6 +14,7 @@ DualOf, BilevelAffExpr, BilevelQuadExpr @enum Level LOWER_BOTH UPPER_BOTH LOWER_ONLY UPPER_ONLY DUAL_OF_LOWER +include("intervals.jl") include("moi.jl") include("moi_utilities.jl") diff --git a/src/intervals.jl b/src/intervals.jl new file mode 100644 index 00000000..f8531d54 --- /dev/null +++ b/src/intervals.jl @@ -0,0 +1,74 @@ +# Function in this file are heavily inspired in IntervalArithmetic.jl, +# which is licensed under the MIT "Expat" License: +# +# Copyright (c) 2014-2021: David P. Sanders & Luis Benet +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import Base.:+, Base.:-, Base.:* + +struct Interval{T} + lo::T + hi::T +end +function Interval(lo::T, hi::T) where {T <: Real} + # if hi < lo <= hi + eps(T) + # lo = hi + # end + @assert lo <= hi + Interval{T}(lo, hi) +end + +function Base.iszero(a::Interval) + iszero(a.hi) && iszero(a.lo) +end + ++(a::Interval) = a +-(a::Interval) = Interval(-a.hi, -a.lo) + +function +(a::Interval{T}, b::T) where {T<:Real} + Interval(a.lo + b, a.hi + b) +end ++(b::T, a::Interval{T}) where {T<:Real} = a+b + +function -(a::Interval{T}, b::T) where {T<:Real} + Interval(a.lo - b, a.hi - b) +end +function -(b::T, a::Interval{T}) where {T<:Real} + Interval(b - a.hi, b - a.lo) +end + +function +(a::Interval{T}, b::Interval{T}) where T<:Real + Interval(a.lo + b.lo, a.hi + b.hi) +end + +function -(a::Interval{T}, b::Interval{T}) where T<:Real + Interval(a.lo - b.hi, a.hi - b.lo) +end + +## Multiplication +function *(x::T, a::Interval{T}) where {T<:Real} + (iszero(a) || iszero(x)) && return Interval(zero(T), zero(T)) + if x ≥ 0.0 + return Interval(a.lo*x, a.hi*x) + else + return Interval(a.hi*x, a.lo*x) + end +end + +*(a::Interval{T}, x::T) where {T<:Real} = x*a diff --git a/src/moi.jl b/src/moi.jl index c95465de..0d98832f 100644 --- a/src/moi.jl +++ b/src/moi.jl @@ -907,18 +907,18 @@ function get_bounds(var, map, fallback_bound = Inf) # TODO deal with precision and performance lower = ifelse(info.lower != -Inf, info.lower, -fallback_bound) upper = ifelse(info.upper != +Inf, info.upper, +fallback_bound) - return IntervalArithmetic.interval(lower, upper) + return Interval(lower, upper) elseif 0.0 <= fallback_bound <= Inf - return IntervalArithmetic.interval(-fallback_bound, fallback_bound) + return Interval(-fallback_bound, fallback_bound) else error("variable $var has no finite bounds defined") end end -function set_bound(inter::IntervalArithmetic.Interval, ::LT{T}) where T +function set_bound(inter::Interval, ::LT{T}) where T return inter.hi end -function set_bound(inter::IntervalArithmetic.Interval, ::GT{T}) where T +function set_bound(inter::Interval, ::GT{T}) where T return inter.lo end