From 18147ef1829a84287c794523be124ce7907f2bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 9 Aug 2019 17:07:54 +0200 Subject: [PATCH 1/2] Add Variable.FreeBridge --- src/Bridges/Variable/Variable.jl | 2 + src/Bridges/Variable/free.jl | 127 ++++++++++++++++++++++++++++++ test/Bridges/Variable/Variable.jl | 3 + test/Bridges/Variable/free.jl | 110 ++++++++++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 src/Bridges/Variable/free.jl create mode 100644 test/Bridges/Variable/free.jl diff --git a/src/Bridges/Variable/Variable.jl b/src/Bridges/Variable/Variable.jl index 0f41b3860c..a3a68aa6ab 100644 --- a/src/Bridges/Variable/Variable.jl +++ b/src/Bridges/Variable/Variable.jl @@ -17,6 +17,8 @@ include("single_bridge_optimizer.jl") # Variable bridges include("zeros.jl") const Zeros{T, OT<:MOI.ModelLike} = SingleBridgeOptimizer{ZerosBridge{T}, OT} +include("free.jl") +const Free{T, OT<:MOI.ModelLike} = SingleBridgeOptimizer{FreeBridge{T}, OT} include("flip_sign.jl") const NonposToNonneg{T, OT<:MOI.ModelLike} = SingleBridgeOptimizer{NonposToNonnegBridge{T}, OT} include("vectorize.jl") diff --git a/src/Bridges/Variable/free.jl b/src/Bridges/Variable/free.jl new file mode 100644 index 0000000000..46e28e707e --- /dev/null +++ b/src/Bridges/Variable/free.jl @@ -0,0 +1,127 @@ +""" + FreeBridge{T} <: Bridges.Variable.AbstractBridge + +Transforms constrained variables in [`MathOptInterface.Reals`](@ref) +to the sum of constrained variables in [`MathOptInterface.Nonnegatives`](@ref) +and constrained variables in [`MathOptInterface.Nonpositives`](@ref). +""" +struct FreeBridge{T} <: AbstractBridge + nonneg_variables::Vector{MOI.VariableIndex} + nonneg_constraint::MOI.ConstraintIndex{MOI.VectorOfVariables, MOI.Nonnegatives} + nonpos_variables::Vector{MOI.VariableIndex} + nonpos_constraint::MOI.ConstraintIndex{MOI.VectorOfVariables, MOI.Nonpositives} +end +function bridge_constrained_variable(::Type{FreeBridge{T}}, + model::MOI.ModelLike, + set::MOI.Reals) where T + nonneg_variables, nonneg_constraint = MOI.add_constrained_variables( + model, MOI.Nonnegatives(MOI.dimension(set))) + nonpos_variables, nonpos_constraint = MOI.add_constrained_variables( + model, MOI.Nonpositives(MOI.dimension(set))) + return FreeBridge{T}(nonneg_variables, nonneg_constraint, + nonpos_variables, nonpos_constraint) +end + +function supports_constrained_variable( + ::Type{<:FreeBridge}, ::Type{MOI.Reals}) + return true +end +function MOIB.added_constrained_variable_types(::Type{<:FreeBridge}) + return [(MOI.Nonnegatives,), (MOI.Nonpositives,)] +end +function MOIB.added_constraint_types(::Type{FreeBridge{T}}) where T + return Tuple{DataType, DataType}[] +end + +# Attributes, Bridge acting as a model +function MOI.get(bridge::FreeBridge, ::MOI.NumberOfVariables) + return length(bridge.nonneg_variables) + length(bridge.nonpos_variables) +end +function MOI.get(bridge::FreeBridge, ::MOI.ListOfVariableIndices) + return vcat(bridge.nonneg_variables, bridge.nonpos_variables) +end +function MOI.get(bridge::FreeBridge, + ::MOI.NumberOfConstraints{MOI.VectorOfVariables, + MOI.Nonnegatives}) + return 1 +end +function MOI.get(bridge::FreeBridge, + ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables, + MOI.Nonnegatives}) + return [bridge.nonneg_constraint] +end +function MOI.get(bridge::FreeBridge, + ::MOI.NumberOfConstraints{MOI.VectorOfVariables, + MOI.Nonpositives}) + return 1 +end +function MOI.get(bridge::FreeBridge, + ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables, + MOI.Nonpositives}) + return [bridge.nonpos_constraint] +end + +# References +function MOI.delete(model::MOI.ModelLike, bridge::FreeBridge) + MOI.delete(model, bridge.nonneg_variables) + MOI.delete(model, bridge.nonpos_variables) +end + +function MOI.delete(model::MOI.ModelLike, bridge::FreeBridge, i::IndexInVector) + MOI.delete(model, bridge.nonneg_variables[i.value]) + deleteat!(bridge.nonneg_variables, i.value) + MOI.delete(model, bridge.nonpos_variables[i.value]) + deleteat!(bridge.nonpos_variables, i.value) +end + + +# Attributes, Bridge acting as a constraint + +function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, + bridge::FreeBridge{T}) where T + return MOI.get(model, attr, bridge.nonneg_constraint) + + MOI.get(model, attr, bridge.nonpos_constraint) +end +# The transformation is x_free = [I I] * [x_nonneg; x_nonpos] +# so the transformation of the dual is +# [y_nonneg; y_nonpos] = [I; I] * y_free +# that is +# y_nonneg = y_nonpos = y_free +# We can therefore take either of them, let's take y_nonneg. +function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintDual, + bridge::FreeBridge{T}) where T + return MOI.get(model, attr, bridge.nonneg_constraint) +end + +function MOI.get(model::MOI.ModelLike, attr::MOI.VariablePrimal, + bridge::FreeBridge{T}, i::IndexInVector) where T + return MOI.get(model, attr, bridge.nonneg_variables[i.value]) + + MOI.get(model, attr, bridge.nonpos_variables[i.value]) +end + +function MOIB.bridged_function(bridge::FreeBridge{T}, i::IndexInVector) where T + return MOIU.operate(+, T, MOI.SingleVariable(bridge.nonneg_variables[i.value]), + MOI.SingleVariable(bridge.nonpos_variables[i.value])) +end +# x_free has been replaced by x_nonneg + x_nonpos. +# To undo it we replace x_nonneg by x_free and x_nonpos by 0. +function unbridged_map(bridge::FreeBridge{T}, vi::MOI.VariableIndex, + i::IndexInVector) where T + sv = MOI.SingleVariable(vi) + func = convert(MOI.ScalarAffineFunction{T}, sv) + return bridge.nonneg_variables[i.value] => func, + bridge.nonpos_variables[i.value] => zero(MOI.ScalarAffineFunction{T}) +end + +function MOI.set(model::MOI.ModelLike, attr::MOI.VariablePrimalStart, + bridge::FreeBridge, value, i::IndexInVector) + if value < 0 + nonneg = zero(value) + nonpos = value + else + nonneg = value + nonpos = zero(value) + end + MOI.set(model, attr, bridge.nonneg_variables[i.value], nonneg) + MOI.set(model, attr, bridge.nonpos_variables[i.value], nonpos) +end diff --git a/test/Bridges/Variable/Variable.jl b/test/Bridges/Variable/Variable.jl index e6520c5c23..c8c601430c 100644 --- a/test/Bridges/Variable/Variable.jl +++ b/test/Bridges/Variable/Variable.jl @@ -5,6 +5,9 @@ end @testset "Zeros" begin include("zeros.jl") end +@testset "Free" begin + include("free.jl") +end @testset "FlipSign" begin include("flip_sign.jl") end diff --git a/test/Bridges/Variable/free.jl b/test/Bridges/Variable/free.jl new file mode 100644 index 0000000000..ba144cbb63 --- /dev/null +++ b/test/Bridges/Variable/free.jl @@ -0,0 +1,110 @@ +using Test + +using MathOptInterface +const MOI = MathOptInterface +const MOIT = MathOptInterface.Test +const MOIU = MathOptInterface.Utilities +const MOIB = MathOptInterface.Bridges + +include("../utilities.jl") + +mock = MOIU.MockOptimizer(MOIU.UniversalFallback(MOIU.Model{Float64}())) +config = MOIT.TestConfig() + +bridged_mock = MOIB.Variable.Free{Float64}(mock) + +@testset "solve_multirow_vectoraffine_nonpos" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.5, 0.0]) + ), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.25, 0.0]) + ) + ) + MOIT.solve_multirow_vectoraffine_nonpos(bridged_mock, config) +end + +@testset "Linear6" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0, 0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 0, -100], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1.0], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1.0] + )) + MOIT.linear6test(bridged_mock, config) + + loc = MOI.get(bridged_mock, MOI.ListOfConstraints()) + @test length(loc) == 2 + @test !((MOI.VectorOfVariables, MOI.Reals) in loc) + @test (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) in loc + @test (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) in loc + @test MOI.get(mock, MOI.NumberOfVariables()) == 4 + @test MOI.get(bridged_mock, MOI.NumberOfVariables()) == 2 + vis = MOI.get(bridged_mock, MOI.ListOfVariableIndices()) + @test vis == MOI.VariableIndex.([-1, -2]) + + cx = MOI.ConstraintIndex{MOI.VectorOfVariables, MOI.Reals}(vis[1].value) + @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), cx) == [100.0] + @test MOI.get(bridged_mock, MOI.ConstraintDual(), cx) == [0.0] + cy = MOI.ConstraintIndex{MOI.VectorOfVariables, MOI.Reals}(vis[2].value) + @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), cy) == [-100.0] + @test MOI.get(bridged_mock, MOI.ConstraintDual(), cy) == [0.0] + + test_delete_bridged_variable(bridged_mock, vis[1], MOI.Reals, 2, ( + (MOI.VectorOfVariables, MOI.Nonnegatives, 0), + (MOI.VectorOfVariables, MOI.Nonpositives, 0) + )) + test_delete_bridged_variable(bridged_mock, vis[2], MOI.Reals, 1, ( + (MOI.VectorOfVariables, MOI.Nonnegatives, 0), + (MOI.VectorOfVariables, MOI.Nonpositives, 0) + )) +end + +@testset "Linear7" begin + function set_mock_optimize_linear7Test!(mock) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0, 0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 0, -100], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[1.0]], + (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[-1.0]] + )) + end + set_mock_optimize_linear7Test!(mock) + MOIT.linear7test(bridged_mock, config) + + x, y = MOI.get(bridged_mock, MOI.ListOfVariableIndices()) + + cx = MOI.ConstraintIndex{MOI.VectorOfVariables, MOI.Reals}(x.value) + @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), cx) == [100.0] + @test MOI.get(bridged_mock, MOI.ConstraintDual(), cx) == [0.0] + cy = MOI.ConstraintIndex{MOI.VectorOfVariables, MOI.Reals}(y.value) + @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), cy) == [-100.0] + @test MOI.get(bridged_mock, MOI.ConstraintDual(), cy) == [0.0] + + @test MOI.supports(bridged_mock, MOI.VariablePrimalStart(), MOI.VariableIndex) + MOI.set(bridged_mock, MOI.VariablePrimalStart(), [x, y], [1.0, -1.0]) + xa, xb, ya, yb = MOI.get(mock, MOI.ListOfVariableIndices()) + @test MOI.get(mock, MOI.VariablePrimalStart(), [xa, xb, ya, yb]) == [1.0, 0.0, 0.0, -1.0] +end + +@testset "Linear11" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0, 1.0, 0.0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.5, 0.0, 0.5, 0.0])) + MOIT.linear11test(bridged_mock, config) + + vis = MOI.get(bridged_mock, MOI.ListOfVariableIndices()) + @test vis == MOI.VariableIndex.([-1, -2]) + + test_delete_bridged_variable(bridged_mock, vis[1], MOI.Reals, 2, ( + (MOI.VectorOfVariables, MOI.Nonnegatives, 0), + (MOI.VectorOfVariables, MOI.Nonpositives, 0) + ), used_bridges = 0, used_constraints = 0) + test_delete_bridged_variable(bridged_mock, vis[2], MOI.Reals, 1, ( + (MOI.VectorOfVariables, MOI.Nonnegatives, 0), + (MOI.VectorOfVariables, MOI.Nonpositives, 0) + )) +end From 9d0731ca7b8b9b09ab20d043caec576bee8ab0f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 9 Aug 2019 18:13:20 +0200 Subject: [PATCH 2/2] Add model tests and create only nonnegative variables --- src/Bridges/Variable/free.jl | 92 ++++++++++++++++------------------- test/Bridges/Variable/free.jl | 87 +++++++++++++++++++++++++++++++-- 2 files changed, 123 insertions(+), 56 deletions(-) diff --git a/src/Bridges/Variable/free.jl b/src/Bridges/Variable/free.jl index 46e28e707e..7dfaef304f 100644 --- a/src/Bridges/Variable/free.jl +++ b/src/Bridges/Variable/free.jl @@ -1,25 +1,19 @@ """ FreeBridge{T} <: Bridges.Variable.AbstractBridge -Transforms constrained variables in [`MathOptInterface.Reals`](@ref) -to the sum of constrained variables in [`MathOptInterface.Nonnegatives`](@ref) -and constrained variables in [`MathOptInterface.Nonpositives`](@ref). +Transforms constrained variables in [`MOI.Reals`](@ref) to the difference of +constrained variables in [`MOI.Nonnegatives`](@ref). """ struct FreeBridge{T} <: AbstractBridge - nonneg_variables::Vector{MOI.VariableIndex} - nonneg_constraint::MOI.ConstraintIndex{MOI.VectorOfVariables, MOI.Nonnegatives} - nonpos_variables::Vector{MOI.VariableIndex} - nonpos_constraint::MOI.ConstraintIndex{MOI.VectorOfVariables, MOI.Nonpositives} + variables::Vector{MOI.VariableIndex} + constraint::MOI.ConstraintIndex{MOI.VectorOfVariables, MOI.Nonnegatives} end function bridge_constrained_variable(::Type{FreeBridge{T}}, model::MOI.ModelLike, set::MOI.Reals) where T - nonneg_variables, nonneg_constraint = MOI.add_constrained_variables( - model, MOI.Nonnegatives(MOI.dimension(set))) - nonpos_variables, nonpos_constraint = MOI.add_constrained_variables( - model, MOI.Nonpositives(MOI.dimension(set))) - return FreeBridge{T}(nonneg_variables, nonneg_constraint, - nonpos_variables, nonpos_constraint) + variables, constraint = MOI.add_constrained_variables( + model, MOI.Nonnegatives(2MOI.dimension(set))) + return FreeBridge{T}(variables, constraint) end function supports_constrained_variable( @@ -27,7 +21,7 @@ function supports_constrained_variable( return true end function MOIB.added_constrained_variable_types(::Type{<:FreeBridge}) - return [(MOI.Nonnegatives,), (MOI.Nonpositives,)] + return [(MOI.Nonnegatives,)] end function MOIB.added_constraint_types(::Type{FreeBridge{T}}) where T return Tuple{DataType, DataType}[] @@ -35,10 +29,10 @@ end # Attributes, Bridge acting as a model function MOI.get(bridge::FreeBridge, ::MOI.NumberOfVariables) - return length(bridge.nonneg_variables) + length(bridge.nonpos_variables) + return length(bridge.variables) end function MOI.get(bridge::FreeBridge, ::MOI.ListOfVariableIndices) - return vcat(bridge.nonneg_variables, bridge.nonpos_variables) + return vcat(bridge.variables) end function MOI.get(bridge::FreeBridge, ::MOI.NumberOfConstraints{MOI.VectorOfVariables, @@ -48,30 +42,19 @@ end function MOI.get(bridge::FreeBridge, ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables, MOI.Nonnegatives}) - return [bridge.nonneg_constraint] -end -function MOI.get(bridge::FreeBridge, - ::MOI.NumberOfConstraints{MOI.VectorOfVariables, - MOI.Nonpositives}) - return 1 -end -function MOI.get(bridge::FreeBridge, - ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables, - MOI.Nonpositives}) - return [bridge.nonpos_constraint] + return [bridge.constraint] end # References function MOI.delete(model::MOI.ModelLike, bridge::FreeBridge) - MOI.delete(model, bridge.nonneg_variables) - MOI.delete(model, bridge.nonpos_variables) + MOI.delete(model, bridge.variables) end function MOI.delete(model::MOI.ModelLike, bridge::FreeBridge, i::IndexInVector) - MOI.delete(model, bridge.nonneg_variables[i.value]) - deleteat!(bridge.nonneg_variables, i.value) - MOI.delete(model, bridge.nonpos_variables[i.value]) - deleteat!(bridge.nonpos_variables, i.value) + n = div(length(bridge.variables), 2) + MOI.delete(model, bridge.variables[i.value]) + MOI.delete(model, bridge.variables[n + i.value]) + deleteat!(bridge.variables, [i.value, n + i.value]) end @@ -79,49 +62,56 @@ end function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, bridge::FreeBridge{T}) where T - return MOI.get(model, attr, bridge.nonneg_constraint) + - MOI.get(model, attr, bridge.nonpos_constraint) + n = div(length(bridge.variables), 2) + primal = MOI.get(model, attr, bridge.constraint) + return primal[1:n] - primal[n .+ (1:n)] end -# The transformation is x_free = [I I] * [x_nonneg; x_nonpos] +# The transformation is x_free = [I -I] * x # so the transformation of the dual is -# [y_nonneg; y_nonpos] = [I; I] * y_free +# y = [I; -I] * y_free # that is -# y_nonneg = y_nonpos = y_free -# We can therefore take either of them, let's take y_nonneg. +# y[1:n] = -y[n .+ (1:n)] = y_free +# We can therefore compute `y_free` from either of them, let's take `y[1:n]`. function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintDual, bridge::FreeBridge{T}) where T - return MOI.get(model, attr, bridge.nonneg_constraint) + n = div(length(bridge.variables), 2) + return MOI.get(model, attr, bridge.constraint)[1:n] end function MOI.get(model::MOI.ModelLike, attr::MOI.VariablePrimal, bridge::FreeBridge{T}, i::IndexInVector) where T - return MOI.get(model, attr, bridge.nonneg_variables[i.value]) + - MOI.get(model, attr, bridge.nonpos_variables[i.value]) + n = div(length(bridge.variables), 2) + return MOI.get(model, attr, bridge.variables[i.value]) - + MOI.get(model, attr, bridge.variables[n + i.value]) end function MOIB.bridged_function(bridge::FreeBridge{T}, i::IndexInVector) where T - return MOIU.operate(+, T, MOI.SingleVariable(bridge.nonneg_variables[i.value]), - MOI.SingleVariable(bridge.nonpos_variables[i.value])) + n = div(length(bridge.variables), 2) + return MOIU.operate(-, T, MOI.SingleVariable(bridge.variables[i.value]), + MOI.SingleVariable(bridge.variables[n + i.value])) end -# x_free has been replaced by x_nonneg + x_nonpos. -# To undo it we replace x_nonneg by x_free and x_nonpos by 0. +# x_free has been replaced by x[i] - x[n + i]. +# To undo it we replace x[i] by x_free and x[n + i] by 0. function unbridged_map(bridge::FreeBridge{T}, vi::MOI.VariableIndex, i::IndexInVector) where T sv = MOI.SingleVariable(vi) + # `unbridged_map` is required to return a `MOI.ScalarAffineFunction`. func = convert(MOI.ScalarAffineFunction{T}, sv) - return bridge.nonneg_variables[i.value] => func, - bridge.nonpos_variables[i.value] => zero(MOI.ScalarAffineFunction{T}) + n = div(length(bridge.variables), 2) + return bridge.variables[i.value] => func, + bridge.variables[n + i.value] => zero(MOI.ScalarAffineFunction{T}) end function MOI.set(model::MOI.ModelLike, attr::MOI.VariablePrimalStart, bridge::FreeBridge, value, i::IndexInVector) if value < 0 nonneg = zero(value) - nonpos = value + nonpos = -value else nonneg = value nonpos = zero(value) end - MOI.set(model, attr, bridge.nonneg_variables[i.value], nonneg) - MOI.set(model, attr, bridge.nonpos_variables[i.value], nonpos) + n = div(length(bridge.variables), 2) + MOI.set(model, attr, bridge.variables[i.value], nonneg) + MOI.set(model, attr, bridge.variables[n + i.value], nonpos) end diff --git a/test/Bridges/Variable/free.jl b/test/Bridges/Variable/free.jl index ba144cbb63..d1c1212723 100644 --- a/test/Bridges/Variable/free.jl +++ b/test/Bridges/Variable/free.jl @@ -23,13 +23,47 @@ bridged_mock = MOIB.Variable.Free{Float64}(mock) ) ) MOIT.solve_multirow_vectoraffine_nonpos(bridged_mock, config) + + MOI.set(bridged_mock, MOI.ConstraintName(), + MOI.get(mock, MOI.ListOfConstraintIndices{ + MOI.VectorAffineFunction{Float64}, MOI.Nonpositives}()), + ["c"]) + + @testset "Mock model" begin + var_names = ["xpos", "xneg"] + MOI.set(mock, MOI.VariableName(), + MOI.get(mock, MOI.ListOfVariableIndices()), var_names) + MOI.set(bridged_mock, MOI.ConstraintName(), + MOI.get(mock, MOI.ListOfConstraintIndices{ + MOI.VectorOfVariables, MOI.Nonnegatives}()), + ["nonneg"]) + s = """ + variables: xpos, xneg + nonneg: [xpos, xneg] in MathOptInterface.Nonnegatives(2) + c: [4.0xpos + -4.0xneg + -1.0, 3.0xpos + -3.0xneg + -1.0] in MathOptInterface.Nonpositives(2) + maxobjective: xpos + -1.0xneg + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(mock, model, var_names, ["nonneg", "c"]) + end + @testset "Bridged model" begin + s = """ + variables: x + c: [4.0x + -1.0, 3.0x + -1.0] in MathOptInterface.Nonpositives(2) + maxobjective: 1.0x + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(bridged_mock, model, ["x"], ["c"]) + end end @testset "Linear6" begin MOIU.set_mock_optimize!(mock, (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0, 0, 0]), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 0, -100], + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 0, 100], (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1.0], (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1.0] )) @@ -67,7 +101,7 @@ end MOIU.set_mock_optimize!(mock, (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0, 0, 0]), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 0, -100], + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 0, 100], (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[1.0]], (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[-1.0]] )) @@ -87,18 +121,61 @@ end @test MOI.supports(bridged_mock, MOI.VariablePrimalStart(), MOI.VariableIndex) MOI.set(bridged_mock, MOI.VariablePrimalStart(), [x, y], [1.0, -1.0]) xa, xb, ya, yb = MOI.get(mock, MOI.ListOfVariableIndices()) - @test MOI.get(mock, MOI.VariablePrimalStart(), [xa, xb, ya, yb]) == [1.0, 0.0, 0.0, -1.0] + @test MOI.get(mock, MOI.VariablePrimalStart(), [xa, xb, ya, yb]) == [1.0, 0.0, 0.0, 1.0] end @testset "Linear11" begin MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0, 1.0, 0.0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.5, 0.0, 0.5, 0.0])) + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0, 0.0, 0.0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.5, 0.5, 0.0, 0.0])) MOIT.linear11test(bridged_mock, config) vis = MOI.get(bridged_mock, MOI.ListOfVariableIndices()) @test vis == MOI.VariableIndex.([-1, -2]) + MOI.set(bridged_mock, MOI.ConstraintName(), + MOI.get(mock, MOI.ListOfConstraintIndices{ + MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}()), + ["c1"]) + MOI.set(bridged_mock, MOI.ConstraintName(), + MOI.get(mock, MOI.ListOfConstraintIndices{ + MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}()), + ["c2"]) + + @testset "Mock model" begin + var_names = ["v1pos", "v2pos", "v1neg", "v2neg"] + MOI.set(mock, MOI.VariableName(), + MOI.get(mock, MOI.ListOfVariableIndices()), var_names) + MOI.set(bridged_mock, MOI.ConstraintName(), + MOI.get(mock, MOI.ListOfConstraintIndices{ + MOI.VectorOfVariables, MOI.Nonnegatives}()), + ["nonneg"]) + s = """ + variables: v1pos, v2pos, v1neg, v2neg + nonneg: [v1pos, v2pos, v1neg, v2neg] in MathOptInterface.Nonnegatives(4) + c1: v1pos + -1.0v1neg + v2pos + -1.0v2neg >= 1.0 + c2: v1pos + -1.0v1neg + v2pos + -1.0v2neg <= 2.0 + minobjective: v1pos + -1.0v1neg + v2pos + -1.0v2neg + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(mock, model, var_names, ["nonneg", "c1", "c2"]) + end + @testset "Bridged model" begin + var_names = ["v1", "v2"] + MOI.set(bridged_mock, MOI.VariableName(), + vis, var_names) + s = """ + variables: v1, v2 + c1: v1 + v2 >= 1.0 + c2: v1 + v2 <= 2.0 + minobjective: v1 + v2 + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(bridged_mock, model, var_names, ["c1", "c2"]) + end + test_delete_bridged_variable(bridged_mock, vis[1], MOI.Reals, 2, ( (MOI.VectorOfVariables, MOI.Nonnegatives, 0), (MOI.VectorOfVariables, MOI.Nonpositives, 0)