forked from jump-dev/MathOptInterface.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add bridge to that converts upper/lower constraints to interval const…
…raints. Closes jump-dev#1193
- Loading branch information
1 parent
b768681
commit d3f88a6
Showing
8 changed files
with
257 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ docs/build/ | |
docs/site/ | ||
test/Benchmarks/*.json | ||
Manifest.toml | ||
*.swp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# The code here is mostly copied from the flip_sign.jl code for FlipSignBridge and GreaterToLessBridge | ||
|
||
""" | ||
AbstractToIntervalBridge{T, S1, F} | ||
Bridge a `F`-in-`S1` constraint into an `F`-in-`Interval` constraint where we have either: | ||
* `S1 = MOI.GreaterThan{T}` | ||
* `S1 = MOI.LessThan{T}` | ||
The `F`-in-`S1` constraint is stored in the `constraint` | ||
field by convention. | ||
""" | ||
abstract type AbstractToIntervalBridge{ | ||
T, S1<:MOI.AbstractSet, | ||
F<:MOI.AbstractFunction} <: SetMapBridge{T, MOI.Interval{T}, S1, F, F} end | ||
|
||
# The function map is the identity. It is also an involution, symmetric, and a symmetric involution. | ||
map_function(::Type{<:AbstractToIntervalBridge{T}}, func) where {T} = func | ||
inverse_map_function(BT::Type{<:AbstractToIntervalBridge}, func) = func | ||
adjoint_map_function(BT::Type{<:AbstractToIntervalBridge}, func) = func | ||
inverse_adjoint_map_function(BT::Type{<:AbstractToIntervalBridge}, func) = func | ||
|
||
# FIXME are these modify functions necessary? | ||
function MOI.modify(model::MOI.ModelLike, bridge::AbstractToIntervalBridge, | ||
change::MOI.ScalarCoefficientChange) | ||
MOI.modify( | ||
model, bridge.constraint, | ||
MOI.ScalarCoefficientChange(change.variable, change.new_coefficient)) | ||
end | ||
function MOI.modify(model::MOI.ModelLike, bridge::AbstractToIntervalBridge, | ||
change::MOI.MultirowChange{T}) where T | ||
MOI.modify(model, bridge.constraint, | ||
MOI.MultirowChange(change.variable, | ||
change.new_coefficients)) | ||
end | ||
|
||
""" | ||
GreaterToIntervalBridge{T, F<:MOI.AbstractScalarFunction} <: | ||
AbstractToIntervalBridge{T, MOI.GreaterThan{T}, F} | ||
Transforms a `F`-in-`GreaterThan{T}` constraint into an `F`-in-`Interval{T}` | ||
constraint. | ||
""" | ||
struct GreaterToIntervalBridge{T, F<:MOI.AbstractScalarFunction} <: | ||
AbstractToIntervalBridge{T, MOI.GreaterThan{T}, F} | ||
constraint::CI{F, MOI.Interval{T}} | ||
end | ||
map_set(::Type{<:GreaterToIntervalBridge}, set::MOI.GreaterThan) = MOI.Interval(set.lower, Inf) | ||
inverse_map_set(::Type{<:GreaterToIntervalBridge}, set::MOI.Interval) = MOI.GreaterThan(set.lower) | ||
function concrete_bridge_type(::Type{<:GreaterToIntervalBridge{T}}, | ||
F::Type{<:MOI.AbstractScalarFunction}, | ||
::Type{MOI.GreaterThan{T}}) where T | ||
return GreaterToIntervalBridge{T, F} | ||
end | ||
|
||
""" | ||
LessToIntervalBridge{T, F<:MOI.AbstractScalarFunction} <: | ||
AbstractToIntervalBridge{T, MOI.LessThan{T}, F} | ||
Transforms a `F`-in-`LessThan{T}` constraint into an `F`-in-`Interval{T}` | ||
constraint. | ||
""" | ||
struct LessToIntervalBridge{T, F<:MOI.AbstractScalarFunction} <: | ||
AbstractToIntervalBridge{T, MOI.LessThan{T}, F} | ||
constraint::CI{F, MOI.Interval{T}} | ||
end | ||
map_set(::Type{<:LessToIntervalBridge}, set::MOI.LessThan) = MOI.Interval(-Inf, set.upper) | ||
inverse_map_set(::Type{<:LessToIntervalBridge}, set::MOI.Interval) = MOI.LessThan(set.upper) | ||
function concrete_bridge_type(::Type{<:LessToIntervalBridge{T}}, | ||
F::Type{<:MOI.AbstractScalarFunction}, | ||
::Type{MOI.LessThan{T}}) where T | ||
return LessToIntervalBridge{T, F} | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
# These tests are mostly copies of the flip_sign.jl tests for GreaterToLess | ||
|
||
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() | ||
|
||
@testset "GreaterToInterval" begin | ||
bridged_mock = MOIB.Constraint.GreaterToInterval{Float64}(mock) | ||
|
||
MOIT.basic_constraint_tests( | ||
bridged_mock, config, | ||
include = [(F, S) | ||
for F in [MOI.ScalarAffineFunction{Float64}, | ||
MOI.ScalarQuadraticFunction{Float64}] | ||
for S in [MOI.GreaterThan{Float64}]]) | ||
|
||
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, -100.0])) | ||
MOIT.linear6test(bridged_mock, config) | ||
|
||
ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}())) | ||
|
||
@testset "$attr" for attr in [MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart()] | ||
@test MOI.supports(bridged_mock, attr, typeof(ci)) | ||
MOI.set(bridged_mock, attr, ci, 2.0) | ||
@test MOI.get(bridged_mock, attr, ci) ≈ 2.0 | ||
end | ||
|
||
test_delete_bridge(bridged_mock, ci, 2, | ||
((MOI.ScalarAffineFunction{Float64}, | ||
MOI.Interval{Float64}, 0), | ||
)) | ||
end | ||
|
||
|
||
@testset "LessToInterval2" begin | ||
bridged_mock = MOIB.Constraint.LessToInterval{Float64}(mock) | ||
|
||
MOIT.basic_constraint_tests( | ||
bridged_mock, config, | ||
include = [(F, S) | ||
for F in [MOI.SingleVariable, MOI.ScalarAffineFunction{Float64}, | ||
MOI.ScalarQuadraticFunction{Float64}] | ||
for S in [MOI.LessThan{Float64}]]) | ||
|
||
MOIU.set_mock_optimize!(mock, | ||
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, | ||
MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [1.0]), | ||
MOI.FEASIBLE_POINT, | ||
(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [1.0] | ||
), | ||
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, | ||
MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [2.0]), | ||
MOI.FEASIBLE_POINT, | ||
(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [1.0] | ||
) | ||
) | ||
MOIT.solve_set_scalaraffine_lessthan2(bridged_mock, config) | ||
|
||
MOIU.set_mock_optimize!(mock, | ||
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, | ||
MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [1.0]), | ||
MOI.FEASIBLE_POINT, | ||
(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [1.0] | ||
), | ||
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, | ||
MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.5]), | ||
MOI.FEASIBLE_POINT, | ||
(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [0.5] | ||
) | ||
) | ||
MOIT.solve_coef_scalaraffine_lessthan2(bridged_mock, config) | ||
|
||
ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}())) | ||
|
||
@testset "$attr" for attr in [MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart()] | ||
@test MOI.supports(bridged_mock, attr, typeof(ci)) | ||
MOI.set(bridged_mock, attr, ci, 2.0) | ||
@test MOI.get(bridged_mock, attr, ci) ≈ 2.0 | ||
end | ||
|
||
test_delete_bridge(bridged_mock, ci, 1, | ||
((MOI.ScalarAffineFunction{Float64}, | ||
MOI.Interval{Float64}, 0),)) | ||
end | ||
|
||
|
||
# FIXME SEGFAULTS | ||
#@testset "GreaterOrLessToInterval-unmocked" begin | ||
# """ | ||
# Dummy optimizer that supports Interval only | ||
# """ | ||
# module OnlyIntervalOptimizer | ||
# using MathOptInterface | ||
# const MOI = MathOptInterface | ||
# | ||
# mutable struct Optimizer <: MOI.AbstractOptimizer | ||
# function Optimizer() | ||
# return new() | ||
# end | ||
# end | ||
# | ||
# MOI.get(model::Optimizer, ::MOI.SolverName) = "OnlyIntervalOptimizer" | ||
# | ||
# MOI.supports_constraint(::Optimizer, ::Type{MOI.ScalarAffineFunction{Float64}}, ::Type{MOI.Interval{Float64}}) = true | ||
# end | ||
# | ||
# # model supports Interval but not LessThan or GreaterThan | ||
# model = OnlyIntervalOptimizer.Optimizer() | ||
# @test MOI.supports_constraint(model, MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) | ||
# @test !MOI.supports_constraint(model, MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) | ||
# @test !MOI.supports_constraint(model, MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) | ||
# | ||
# # bridged model supports all | ||
# bridged = GreaterToInterval{Float64}(LessToInterval{Float64}(model)) | ||
# @test MOI.supports_constraint(bridged, MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) | ||
# @test MOI.supports_constraint(bridged, MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) | ||
# @test MOI.supports_constraint(bridged, MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) | ||
#end |