diff --git a/src/Bridges/Constraint/interval.jl b/src/Bridges/Constraint/interval.jl index 29e99313f4..d6a7a82c0c 100644 --- a/src/Bridges/Constraint/interval.jl +++ b/src/Bridges/Constraint/interval.jl @@ -1,5 +1,5 @@ -_lower_set(set::MOI.Interval) = MOI.GreaterThan(set.lower) -_upper_set(set::MOI.Interval) = MOI.LessThan(set.upper) +_lower_set(set::MOI.Interval) = isinf(set.lower) ? MOI.ExtendedGreaterThan(set.lower) : MOI.GreaterThan(set.lower) +_upper_set(set::MOI.Interval) = isinf(set.upper) ? MOI.ExtendedLessThan(set.upper) : MOI.LessThan(set.upper) _lower_set(set::MOI.EqualTo) = MOI.GreaterThan(set.value) _upper_set(set::MOI.EqualTo) = MOI.LessThan(set.value) _lower_set(set::MOI.Zeros) = MOI.Nonnegatives(set.dimension) @@ -267,3 +267,31 @@ function MOI.get( ) where {T,F} return MOI.Zeros(MOI.get(model, attr, bridge.lower).dimension) end + + +# guimarqu : new bridge (to improve) +""" + UnextendBridge + +Bridge for ExtendedGreatherThan to GreaterThan ... +""" +struct UnextendBridge{ + T, + F<:MOI.AbstractFunction, + ES<:MOI.AbstractSet, + S<:MOI.AbstractSet +} <: AbstractBridge + non_extended::Union{Nothing, CI{F,S}} +end + +function bridge_constraint( + ::Type{UnextendBridge{T,F,ES,S}}, + model::MOI.ModelLike, + f::F, + set::S, +) where {T,F,ES,S} + if isinf(set.value) + return UnextendBridge{T,F,ES,S}(nothing) + end + return UnextendBridge{T,F,ES,S}(MOI.GreaterThan(3)) +end diff --git a/src/Test/UnitTests/constraints.jl b/src/Test/UnitTests/constraints.jl index 1788b96474..8019479fa2 100644 --- a/src/Test/UnitTests/constraints.jl +++ b/src/Test/UnitTests/constraints.jl @@ -521,3 +521,54 @@ function solve_zero_one_with_bounds_3(model::MOI.ModelLike, config::TestConfig) end end unittests["solve_zero_one_with_bounds_3"] = solve_zero_one_with_bounds_3 + +function solve_one_sided_intervals(model::MOI.ModelLike, config::TestConfig) + MOI.empty!(model) + MOIU.loadfromstring!( + model, + """ + variables: x, y, z + maxobjective: x + -1y + z + c1: x in Interval(-Inf, 1.0) + c2: y in Interval(-1.0, Inf) + c3: z in Interval(-Inf, Inf) + c4: 1z <= 1.0 +""", + ) + + x = MOI.get(model, MOI.VariableIndex, "x") + y = MOI.get(model, MOI.VariableIndex, "y") + z = MOI.get(model, MOI.VariableIndex, "z") + + c1 = MOI.get( + model, + MOI.ConstraintIndex{MOI.SingleVariable, MOI.Interval{Float64}}, + "c1" + ) + c2 = MOI.get( + model, + MOI.ConstraintIndex{MOI.SingleVariable, MOI.Interval{Float64}}, + "c2" + ) + c3 = MOI.get( + model, + MOI.ConstraintIndex{MOI.SingleVariable, MOI.Interval{Float64}}, + "c3" + ) + + @test MOI.get(model, MOI.ConstraintIndex, "c1") == c1 + @test MOI.get(model, MOI.ConstraintIndex, "c2") == c2 + @test MOI.get(model, MOI.ConstraintIndex, "c3") == c3 + + @test MOI.is_valid(model, c1) + @test MOI.is_valid(model, c2) + @test MOI.is_valid(model, c3) + + return test_model_solution( + model, + config; + objective_value = 3.0, + variable_primal = [(x, 1.0), (y, -1.0), (z, 1.0)], + ) +end +unittests["solve_one_sided_intervals"] = solve_one_sided_intervals \ No newline at end of file diff --git a/src/sets.jl b/src/sets.jl index 2b8772d500..ba935365c7 100644 --- a/src/sets.jl +++ b/src/sets.jl @@ -162,6 +162,11 @@ struct GreaterThan{T<:Real} <: AbstractScalarSet lower::T end +# guimarqu +struct ExtendedGreaterThan{T<:Real} <: AbstractScalarSet + lower::T +end + """ LessThan{T <: Real}(upper::T) @@ -171,6 +176,11 @@ struct LessThan{T<:Real} <: AbstractScalarSet upper::T end +# guimarqu +struct ExtendedLessThan{T<:Real} <: AbstractScalarSet + lower::T +end + """ EqualTo{T <: Number}(value::T) diff --git a/test/Bridges/Constraint/interval.jl b/test/Bridges/Constraint/interval.jl index 2635522e9a..d444efe91e 100644 --- a/test/Bridges/Constraint/interval.jl +++ b/test/Bridges/Constraint/interval.jl @@ -12,6 +12,7 @@ mock = MOIU.MockOptimizer(MOIU.UniversalFallback(MOIU.Model{Float64}())) config = MOIT.TestConfig() config_with_basis = MOIT.TestConfig(basis = true) + @testset "Split" begin T = Float64 bridged_mock = MOIB.Constraint.SplitInterval{T}(mock) @@ -32,6 +33,46 @@ config_with_basis = MOIT.TestConfig(basis = true) ) end +@testset "my test" begin + bridged_mock = MOIB.Constraint.SplitInterval{Float64}(mock) + + MOIU.set_mock_optimize!( + mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( + mock, + [1.0, -1.0, 1.0], + ), + ) + + # variables: x, y, z + # maxobjective: x + -1y + z + # c1: x in Interval(-Inf, 1.0) + # c2: y in Interval(-1.0, Inf) + # c3: z in Interval(-Inf, Inf) + # c4: 1z <= 1.0 + MOIT.solve_one_sided_intervals(bridged_mock, config_with_basis) + + println("====== ****** ======") + for (i, b) in bridged_mock.map.single_variable_constraints + @show MOI.get(bridged_mock.model, MOI.ConstraintSet(), b.lower) + @show MOI.get(bridged_mock.model, MOI.ConstraintSet(), b.upper) + end + + println("====== ****** ======") + + @show MOI.get( + bridged_mock, + MOI.ListOfConstraintIndices{ + MOI.SingleVariable, + MOI.Interval{Float64}, + }(), + ) + + + +end +exit() + @testset "Interval" begin bridged_mock = MOIB.Constraint.SplitInterval{Float64}(mock) MOIU.set_mock_optimize!( diff --git a/test/Test/unit.jl b/test/Test/unit.jl index 6b62fee2c9..398000e9aa 100644 --- a/test/Test/unit.jl +++ b/test/Test/unit.jl @@ -53,6 +53,7 @@ end "solve_zero_one_with_bounds_1", "solve_zero_one_with_bounds_2", "solve_zero_one_with_bounds_3", + "solve_one_sided_intervals", "solve_unbounded_model", "solve_single_variable_dual_min", "solve_single_variable_dual_max", @@ -447,6 +448,22 @@ end MOIT.solve_zero_one_with_bounds_3(mock, config) end + @testset "solve_one_sided_intervals" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> begin + MOIU.mock_optimize!( + mock, MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [1.0, -1.0]) + ) + end, + (mock::MOIU.MockOptimizer) -> begin + MOIU.mock_optimize!( + mock, MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [1.0, -1.0, 1.0]) + ) + end + ) + MOIT.solve_one_sided_intervals(mock, config) + end + @testset "solve_unbounded_model" begin MOIU.set_mock_optimize!( mock,