diff --git a/Project.toml b/Project.toml index d73a81b42..b8ec5c553 100644 --- a/Project.toml +++ b/Project.toml @@ -20,6 +20,6 @@ ChainRulesCore = "1" IterativeSolvers = "0.9" JuMP = "1" LazyArrays = "0.21, 0.22, 1" -MathOptInterface = "1.14.1" +MathOptInterface = "1.18" MathOptSetDistances = "0.2.7" julia = "1.6" diff --git a/src/copy_dual.jl b/src/copy_dual.jl index acb203ff4..a7c24d23b 100644 --- a/src/copy_dual.jl +++ b/src/copy_dual.jl @@ -11,45 +11,6 @@ struct ObjectiveFunctionAttribute{A,F} <: MOI.AbstractModelAttribute attr::A end -""" - struct ObjectiveDualStart <: MOI.AbstractModelAttribute end - -If the objective function had a dual, it would be `-1` for the Lagrangian -function to be the same. -When the `MOI.Bridges.Objective.SlackBridge` is used, it creates a constraint. -The dual of this constraint is therefore `-1` as well. -When setting this attribute, it allows to set the constraint dual of this -constraint. -""" -struct ObjectiveDualStart <: MOI.AbstractModelAttribute end -# Defining it for `MOI.set` leads to ambiguity -function MOI.throw_set_error_fallback( - ::MOI.ModelLike, - ::ObjectiveDualStart, - value, -) - return nothing -end - -""" - struct ObjectiveSlackGapPrimalStart <: MOI.AbstractModelAttribute end - -If the objective function had a dual, it would be `-1` for the Lagrangian -function to be the same. -When the `MOI.Bridges.Objective.SlackBridge` is used, it creates a constraint. -The dual of this constraint is therefore `-1` as well. -When setting this attribute, it allows to set the constraint dual of this -constraint. -""" -struct ObjectiveSlackGapPrimalStart <: MOI.AbstractModelAttribute end -function MOI.throw_set_error_fallback( - ::MOI.ModelLike, - ::ObjectiveSlackGapPrimalStart, - value, -) - return nothing -end - function MOI.get( b::MOI.Bridges.AbstractBridgeOptimizer, attr::ObjectiveFunctionAttribute{A,F}, @@ -100,11 +61,7 @@ end function MOI.set( b::MOI.Bridges.AbstractBridgeOptimizer, - attr::Union{ - ObjectiveDualStart, - ObjectiveSlackGapPrimalStart, - ForwardObjectiveFunction, - }, + attr::ForwardObjectiveFunction, value, ) if MOI.Bridges.is_objective_bridged(b) @@ -121,34 +78,6 @@ function MOI.set( end end -function MOI.set( - model::MOI.ModelLike, - ::ObjectiveFunctionAttribute{ObjectiveDualStart}, - b::MOI.Bridges.Objective.SlackBridge, - value, -) - return MOI.set(model, MOI.ConstraintDualStart(), b.constraint, value) -end - -function MOI.set( - model::MOI.ModelLike, - ::ObjectiveFunctionAttribute{ObjectiveSlackGapPrimalStart}, - b::MOI.Bridges.Objective.SlackBridge{T}, - value, -) where {T} - # `f(x) - slack = value` so `slack = f(x) - value` - fun = MOI.get(model, MOI.ConstraintFunction(), b.constraint) - set = MOI.get(model, MOI.ConstraintSet(), b.constraint) - MOI.Utilities.operate!(-, T, fun, MOI.constant(set)) - # `fun = f - slack` so we remove the term `-slack` to get `f` - f = MOI.Utilities.remove_variable(fun, b.slack) - f_val = MOI.Utilities.eval_variables(f) do v - return MOI.get(model, MOI.VariablePrimalStart(), v) - end - MOI.set(model, MOI.VariablePrimalStart(), b.slack, f_val - value) - return MOI.set(model, MOI.ConstraintPrimalStart(), b.constraint, value) -end - function _copy_dual(dest::MOI.ModelLike, src::MOI.ModelLike, index_map) vis_src = MOI.get(src, MOI.ListOfVariableIndices()) MOI.set( @@ -173,8 +102,10 @@ function _copy_dual(dest::MOI.ModelLike, src::MOI.ModelLike, index_map) MOI.ConstraintDual(), ) end - MOI.set(dest, ObjectiveDualStart(), -1.0) - return MOI.set(dest, ObjectiveSlackGapPrimalStart(), 0.0) + # Same as in `JuMP.set_start_values` + # Needed for models which bridge `min f(x)` into `min t such that t >= f(x)`. + MOI.set(dest, MOI.Bridges.Objective.SlackBridgePrimalDualStart(), nothing) + return end function _copy_constraint_start( diff --git a/src/diff_opt.jl b/src/diff_opt.jl index 77ba7d968..22781eec3 100644 --- a/src/diff_opt.jl +++ b/src/diff_opt.jl @@ -257,6 +257,25 @@ function _enlarge_set(vec::Vector, idx, value) return end +# The following `supports` methods are needed because +# `MOI.set(::MOI.ModelLike, ::SlackBridgePrimalDualStart, ::SlackBridge, ::Nothing)` +# checks that the model supports these starting value attributes. +function MOI.supports( + ::AbstractModel, + ::MOI.VariablePrimalStart, + ::Type{<:MOI.VariableIndex}, +) + return true +end + +function MOI.supports( + ::AbstractModel, + ::Union{MOI.ConstraintDualStart,MOI.ConstraintPrimalStart}, + ::Type{<:MOI.ConstraintIndex}, +) + return true +end + function MOI.get( model::AbstractModel, ::MOI.VariablePrimalStart, diff --git a/test/jump.jl b/test/jump.jl index cacb27aed..8055f1f10 100644 --- a/test/jump.jl +++ b/test/jump.jl @@ -465,7 +465,7 @@ function test_differentiating_simple_socp() db = zeros(5) dc = zeros(3) MOI.set.(model, DiffOpt.ReverseVariablePrimal(), vv, 1.0) - @test_broken DiffOpt.reverse_differentiate!(model) + DiffOpt.reverse_differentiate!(model) # TODO add tests return end