From 6b3ba244bffb471ddb7b5124c985ddb590628f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 10 Nov 2023 10:03:41 +0100 Subject: [PATCH 1/9] Add support for starting values --- src/MOI_wrapper.jl | 127 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 17 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 2d1d8135..58f12bd8 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -322,9 +322,57 @@ function _get_at_index( return _get(optimizer, attr, ci_primal, ci_dual)[idx] end +_minus(::Nothing) = nothing +_minus(x) = -x + +function _dual_attribute(attr::MOI.VariablePrimal) + return MOI.ConstraintDual(attr.result_index) +end + +function _dual_attribute(attr::MOI.VariablePrimalStart) + return MOI.ConstraintDualStart() +end + +function _dual_attribute(attr::MOI.ConstraintDual) + return MOI.ConstraintPrimal(attr.result_index) +end + +function _dual_attribute(attr::MOI.ConstraintDualStart) + return MOI.ConstraintPrimalStart() +end + +function _variable_dual_attribute(attr::MOI.ConstraintDual) + return MOI.VariablePrimal(attr.result_index) +end + +function _variable_dual_attribute(attr::MOI.ConstraintDualStart) + return MOI.VariablePrimalStart() +end + + +function MOI.set( + optimizer::DualOptimizer, + ::MOI.VariablePrimalStart, + vi::MOI.VariableIndex, + value, +) + primal_dual_map = optimizer.dual_problem.primal_dual_map + if vi in keys(primal_dual_map.constrained_var_idx) + error("Setting starting value for variables constrained at creation is not supported yet") + else + MOI.set( + optimizer.dual_problem.dual_model, + _dual_attribute(attr), + get_ci_dual_problem(optimizer, vi), + _minus(value), + ) + end + return +end + function MOI.get( optimizer::DualOptimizer, - ::MOI.VariablePrimal, + ::Union{MOI.VariablePrimal,MOI.VariablePrimalStart}, vi::MOI.VariableIndex, ) primal_dual_map = optimizer.dual_problem.primal_dual_map @@ -333,7 +381,7 @@ function MOI.get( ci_dual = primal_dual_map.constrained_var_dual[ci_primal] return _get_at_index( optimizer, - MOI.ConstraintDual(), + _dual_attribute(attr), ci_primal, ci_dual, idx, @@ -341,15 +389,35 @@ function MOI.get( else return -MOI.get( optimizer.dual_problem.dual_model, - MOI.ConstraintDual(), + _dual_attribute(attr), get_ci_dual_problem(optimizer, vi), ) end end +function MOI.set( + optimizer::DualOptimizer, + attr::MOI.ConstraintDualStart, + ci::MOI.ConstraintIndex, + value, +) + primal_dual_map = optimizer.dual_problem.primal_dual_map + if ci in keys(primal_dual_map.constrained_var_dual) + error("Setting starting value for variables constrained at creation is not supported yet") + else + MOI.set( + optimizer.dual_problem.dual_model, + _variable_dual_attribute(attr), + get_vi_dual_problem(optimizer, ci), + value, + ) + end + return +end + function MOI.get( optimizer::DualOptimizer, - attr::MOI.ConstraintDual, + attr::Union{MOI.ConstraintDual,MOI.ConstraintDualStart}, ci::MOI.ConstraintIndex{F,S}, ) where {F<:MOI.AbstractScalarFunction,S<:MOI.AbstractScalarSet} primal_dual_map = optimizer.dual_problem.primal_dual_map @@ -361,7 +429,7 @@ function MOI.get( ) do vi return MOI.get( optimizer.dual_problem.dual_model, - MOI.VariablePrimal(), + _variable_dual_attribute(attr), vi, ) end @@ -373,13 +441,13 @@ function MOI.get( ) return MOI.get( optimizer.dual_problem.dual_model, - MOI.ConstraintPrimal(), + _dual_attribute(attr), ci_dual, ) - MOI.constant(set) else return MOI.get( optimizer.dual_problem.dual_model, - MOI.VariablePrimal(), + _variable_dual_attribute(attr), get_vi_dual_problem(optimizer, ci), ) end @@ -387,7 +455,7 @@ end function MOI.get( optimizer::DualOptimizer, - ::MOI.ConstraintDual, + attr::Union{MOI.ConstraintDual,MOI.ConstraintDualStart}, ci::MOI.ConstraintIndex{F,S}, ) where {F<:MOI.AbstractVectorFunction,S<:MOI.AbstractVectorSet} primal_dual_map = optimizer.dual_problem.primal_dual_map @@ -399,35 +467,60 @@ function MOI.get( ) do vi return MOI.get( optimizer.dual_problem.dual_model, - MOI.VariablePrimal(), + _variable_dual_attribute(attr), vi, ) end end return MOI.get( optimizer.dual_problem.dual_model, - MOI.ConstraintPrimal(), + _dual_attribute(attr), primal_dual_map.constrained_var_dual[ci], ) else return MOI.get.( optimizer.dual_problem.dual_model, - MOI.VariablePrimal(), + _variable_dual_attribute(attr), get_vis_dual_problem(optimizer, ci), ) end end +function MOI.set( + optimizer::DualOptimizer, + attr::MOI.ConstraintPrimalStart, + ci::MOI.ConstraintIndex{F}, + value, +) where {F<:MOI.AbstractScalarFunction} + primal_dual_map = optimizer.dual_problem.primal_dual_map + if ci in keys(primal_dual_map.constrained_var_dual) + error("Setting starting value for variables constrained at creation is not supported yet") + elseif haskey(primal_dual_map.primal_con_dual_con, ci) + # If it has no key then there is no dual constraint + ci_dual_problem = get_ci_dual_problem(optimizer, ci) + if !isnothing(value) && (F <: MOI.AbstractScalarFunction) + value -= get_primal_ci_constant(optimizer, ci) + end + MOI.set( + optimizer.dual_problem.dual_model, + _dual_attribute(attr), + ci_dual_problem, + value, + ) + end + return +end + function MOI.get( optimizer::DualOptimizer, - ::MOI.ConstraintPrimal, + attr::Union{MOI.ConstraintPrimal,MOI.ConstraintPrimalStart}, ci::MOI.ConstraintIndex{F,S}, ) where {F<:MOI.AbstractScalarFunction,S<:MOI.AbstractScalarSet} primal_dual_map = optimizer.dual_problem.primal_dual_map if ci in keys(primal_dual_map.constrained_var_dual) return _get( optimizer, - MOI.ConstraintDual(), + _dual_attribute(attr), ci, primal_dual_map.constrained_var_dual[ci], ) @@ -440,7 +533,7 @@ function MOI.get( ci_dual_problem = get_ci_dual_problem(optimizer, ci) return MOI.get( optimizer.dual_problem.dual_model, - MOI.ConstraintDual(), + _dual_attribute(attr), ci_dual_problem, ) - primal_ci_constant end @@ -448,14 +541,14 @@ end function MOI.get( optimizer::DualOptimizer{T}, - ::MOI.ConstraintPrimal, + attr::Union{MOI.ConstraintPrimal,MOI.ConstraintPrimalStart}, ci::MOI.ConstraintIndex{F,S}, ) where {T,F<:MOI.AbstractVectorFunction,S<:MOI.AbstractVectorSet} primal_dual_map = optimizer.dual_problem.primal_dual_map if ci in keys(primal_dual_map.constrained_var_dual) return _get( optimizer, - MOI.ConstraintDual(), + _dual_attribute(attr), ci, primal_dual_map.constrained_var_dual[ci], ) @@ -469,7 +562,7 @@ function MOI.get( ci_dual_problem = get_ci_dual_problem(optimizer, ci) return MOI.get( optimizer.dual_problem.dual_model, - MOI.ConstraintDual(), + _dual_attribute(attr), ci_dual_problem, ) end From b2a7ef47336ce66064e5717d93e015e9961f417f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 10 Nov 2023 10:13:30 +0100 Subject: [PATCH 2/9] Fix format --- src/MOI_wrapper.jl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 58f12bd8..f6904939 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -349,7 +349,6 @@ function _variable_dual_attribute(attr::MOI.ConstraintDualStart) return MOI.VariablePrimalStart() end - function MOI.set( optimizer::DualOptimizer, ::MOI.VariablePrimalStart, @@ -358,7 +357,9 @@ function MOI.set( ) primal_dual_map = optimizer.dual_problem.primal_dual_map if vi in keys(primal_dual_map.constrained_var_idx) - error("Setting starting value for variables constrained at creation is not supported yet") + error( + "Setting starting value for variables constrained at creation is not supported yet", + ) else MOI.set( optimizer.dual_problem.dual_model, @@ -403,7 +404,9 @@ function MOI.set( ) primal_dual_map = optimizer.dual_problem.primal_dual_map if ci in keys(primal_dual_map.constrained_var_dual) - error("Setting starting value for variables constrained at creation is not supported yet") + error( + "Setting starting value for variables constrained at creation is not supported yet", + ) else MOI.set( optimizer.dual_problem.dual_model, @@ -494,7 +497,9 @@ function MOI.set( ) where {F<:MOI.AbstractScalarFunction} primal_dual_map = optimizer.dual_problem.primal_dual_map if ci in keys(primal_dual_map.constrained_var_dual) - error("Setting starting value for variables constrained at creation is not supported yet") + error( + "Setting starting value for variables constrained at creation is not supported yet", + ) elseif haskey(primal_dual_map.primal_con_dual_con, ci) # If it has no key then there is no dual constraint ci_dual_problem = get_ci_dual_problem(optimizer, ci) From 255b59020f9f48b7d6cac547c9d737f7ae2effea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 10 Nov 2023 10:15:44 +0100 Subject: [PATCH 3/9] Add supports --- src/MOI_wrapper.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index f6904939..b94597b6 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -349,6 +349,8 @@ function _variable_dual_attribute(attr::MOI.ConstraintDualStart) return MOI.VariablePrimalStart() end +MOI.supports(::DualOptimizer, ::MOI.VariablePrimalStart, ::Type{MOI.VariableIndex}) = true + function MOI.set( optimizer::DualOptimizer, ::MOI.VariablePrimalStart, @@ -396,6 +398,14 @@ function MOI.get( end end +function MOI.supports( + ::DualOptimizer, + ::Union{MOI.ConstraintDualStart,MOI.ConstraintPrimalStart}, + ::Type{<:MOI.ConstraintIndex}, +) + return true +end + function MOI.set( optimizer::DualOptimizer, attr::MOI.ConstraintDualStart, From ea5532b8bba3cd01e2135f2311869a9a9a7ce452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 10 Nov 2023 10:32:18 +0100 Subject: [PATCH 4/9] Fixes --- src/MOI_wrapper.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index b94597b6..a5333449 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -325,11 +325,11 @@ end _minus(::Nothing) = nothing _minus(x) = -x -function _dual_attribute(attr::MOI.VariablePrimal) +function _dual_attribute(attr::Union{MOI.VariablePrimal,MOI.ConstraintPrimal}) return MOI.ConstraintDual(attr.result_index) end -function _dual_attribute(attr::MOI.VariablePrimalStart) +function _dual_attribute(::Union{MOI.VariablePrimalStart,MOI.ConstraintPrimalStart}) return MOI.ConstraintDualStart() end @@ -337,7 +337,7 @@ function _dual_attribute(attr::MOI.ConstraintDual) return MOI.ConstraintPrimal(attr.result_index) end -function _dual_attribute(attr::MOI.ConstraintDualStart) +function _dual_attribute(::MOI.ConstraintDualStart) return MOI.ConstraintPrimalStart() end @@ -345,7 +345,7 @@ function _variable_dual_attribute(attr::MOI.ConstraintDual) return MOI.VariablePrimal(attr.result_index) end -function _variable_dual_attribute(attr::MOI.ConstraintDualStart) +function _variable_dual_attribute(::MOI.ConstraintDualStart) return MOI.VariablePrimalStart() end @@ -353,7 +353,7 @@ MOI.supports(::DualOptimizer, ::MOI.VariablePrimalStart, ::Type{MOI.VariableInde function MOI.set( optimizer::DualOptimizer, - ::MOI.VariablePrimalStart, + attr::MOI.VariablePrimalStart, vi::MOI.VariableIndex, value, ) @@ -375,7 +375,7 @@ end function MOI.get( optimizer::DualOptimizer, - ::Union{MOI.VariablePrimal,MOI.VariablePrimalStart}, + attr::Union{MOI.VariablePrimal,MOI.VariablePrimalStart}, vi::MOI.VariableIndex, ) primal_dual_map = optimizer.dual_problem.primal_dual_map From 0666fbb5b42401d5477025773f2a9b5763d89f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 10 Nov 2023 10:32:23 +0100 Subject: [PATCH 5/9] Fix format --- src/MOI_wrapper.jl | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index a5333449..eb72b62e 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -329,7 +329,9 @@ function _dual_attribute(attr::Union{MOI.VariablePrimal,MOI.ConstraintPrimal}) return MOI.ConstraintDual(attr.result_index) end -function _dual_attribute(::Union{MOI.VariablePrimalStart,MOI.ConstraintPrimalStart}) +function _dual_attribute( + ::Union{MOI.VariablePrimalStart,MOI.ConstraintPrimalStart}, +) return MOI.ConstraintDualStart() end @@ -349,7 +351,13 @@ function _variable_dual_attribute(::MOI.ConstraintDualStart) return MOI.VariablePrimalStart() end -MOI.supports(::DualOptimizer, ::MOI.VariablePrimalStart, ::Type{MOI.VariableIndex}) = true +function MOI.supports( + ::DualOptimizer, + ::MOI.VariablePrimalStart, + ::Type{MOI.VariableIndex}, +) + return true +end function MOI.set( optimizer::DualOptimizer, @@ -399,9 +407,9 @@ function MOI.get( end function MOI.supports( - ::DualOptimizer, - ::Union{MOI.ConstraintDualStart,MOI.ConstraintPrimalStart}, - ::Type{<:MOI.ConstraintIndex}, + ::DualOptimizer, + ::Union{MOI.ConstraintDualStart,MOI.ConstraintPrimalStart}, + ::Type{<:MOI.ConstraintIndex}, ) return true end From 63acded98853b25b0c9148d5db44ce38258837e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 10 Nov 2023 21:57:54 +0100 Subject: [PATCH 6/9] Improve supports --- src/MOI_wrapper.jl | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index eb72b62e..4b510cbf 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -407,11 +407,15 @@ function MOI.get( end function MOI.supports( - ::DualOptimizer, - ::Union{MOI.ConstraintDualStart,MOI.ConstraintPrimalStart}, + optimizer::DualOptimizer, + attr::MOI.ConstraintDualStart, ::Type{<:MOI.ConstraintIndex}, ) - return true + return MOI.supports( + optimizer.dual_problem.dual_model, + _variable_dual_attribute(attr), + MOI.VariableIndex, + ) end function MOI.set( @@ -507,6 +511,18 @@ function MOI.get( end end +function MOI.supports( + ::DualOptimizer, + attr::MOI.ConstraintPrimalStart, + C::Type{<:MOI.ConstraintIndex}, +) + return MOI.supports( + optimizer.dual_problem.dual_model, + _dual_attribute(attr), + C, + ) +end + function MOI.set( optimizer::DualOptimizer, attr::MOI.ConstraintPrimalStart, From 227a7ea0dede9417637438af5a3a23fcb651cc7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 13 Nov 2023 23:14:00 +0100 Subject: [PATCH 7/9] Add tests --- src/MOI_wrapper.jl | 4 +++- test/Tests/test_MOI_wrapper.jl | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 4b510cbf..4b085396 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -209,9 +209,11 @@ end function MOI.copy_to(dest::DualOptimizer, src::MOI.ModelLike) dualize(src, dest.dual_problem) idx_map = MOI.Utilities.IndexMap() - for vi in MOI.get(src, MOI.ListOfVariableIndices()) + vis_src = MOI.get(src, MOI.ListOfVariableIndices()) + for vi in vis_src setindex!(idx_map, vi, vi) end + MOI.Utilities.pass_attributes(dest, src, idx_map, vis_src) for (F, S) in MOI.get(src, MOI.ListOfConstraintTypesPresent()) for con in MOI.get(src, MOI.ListOfConstraintIndices{F,S}()) setindex!(idx_map, con, con) diff --git a/test/Tests/test_MOI_wrapper.jl b/test/Tests/test_MOI_wrapper.jl index c8741a4a..cfa86fc5 100644 --- a/test/Tests/test_MOI_wrapper.jl +++ b/test/Tests/test_MOI_wrapper.jl @@ -127,4 +127,18 @@ DualOptimizer{Float32,Caching_OptimizerType} end end + + @testset "Start" begin + model = MOI.Utilities.UniversalFallback(TestModel{Float64}()) + x = MOI.add_variable(model) + c = MOI.add_constraint(model, 2.0 * x, MOI.GreaterThan(0.0)) + MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) + MOI.set(model, MOI.VariablePrimalStart(), x, 1.0) + MOI.set(model, MOI.ConstraintPrimalStart(), c, 3.0) + MOI.set(model, MOI.ConstraintDualStart(), c, 4.0) + dual_problem = Dualization.DualProblem{Float64}(TestModel{Float64}()) + OptimizerType = typeof(dual_problem.dual_model) + dual = DualOptimizer{Float64,OptimizerType}(dual_problem) + index_map = MOI.copy_to(dual, model) + end end From de1379d20c86906b5c016b3df588f9adcdf2f2ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sun, 10 Dec 2023 23:13:58 +0100 Subject: [PATCH 8/9] Use result_index --- src/MOI_wrapper.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 4b085396..f5069e06 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -628,20 +628,20 @@ function dual_status(term::MOI.TerminationStatusCode) return term end -function MOI.get(optimizer::DualOptimizer, ::MOI.ObjectiveValue) - return MOI.get(optimizer.dual_problem.dual_model, MOI.DualObjectiveValue()) +function MOI.get(optimizer::DualOptimizer, attr::MOI.ObjectiveValue) + return MOI.get(optimizer.dual_problem.dual_model, MOI.DualObjectiveValue(attr.result_index)) end -function MOI.get(optimizer::DualOptimizer, ::MOI.DualObjectiveValue) - return MOI.get(optimizer.dual_problem.dual_model, MOI.ObjectiveValue()) +function MOI.get(optimizer::DualOptimizer, attr::MOI.DualObjectiveValue) + return MOI.get(optimizer.dual_problem.dual_model, MOI.ObjectiveValue(attr.result_index)) end -function MOI.get(optimizer::DualOptimizer, ::MOI.PrimalStatus) - return MOI.get(optimizer.dual_problem.dual_model, MOI.DualStatus()) +function MOI.get(optimizer::DualOptimizer, attr::MOI.PrimalStatus) + return MOI.get(optimizer.dual_problem.dual_model, MOI.DualStatus(attr.result_index)) end -function MOI.get(optimizer::DualOptimizer, ::MOI.DualStatus) - return MOI.get(optimizer.dual_problem.dual_model, MOI.PrimalStatus()) +function MOI.get(optimizer::DualOptimizer, attr::MOI.DualStatus) + return MOI.get(optimizer.dual_problem.dual_model, MOI.PrimalStatus(attr.result_index)) end function MOI.set( From e003f13a76013a7abdb4d4c9e8b262610532f27b Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 11 Apr 2025 15:51:29 +1200 Subject: [PATCH 9/9] Change error types --- src/MOI_wrapper.jl | 51 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index f5069e06..a6ff81eb 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -369,17 +369,15 @@ function MOI.set( ) primal_dual_map = optimizer.dual_problem.primal_dual_map if vi in keys(primal_dual_map.constrained_var_idx) - error( - "Setting starting value for variables constrained at creation is not supported yet", - ) - else - MOI.set( - optimizer.dual_problem.dual_model, - _dual_attribute(attr), - get_ci_dual_problem(optimizer, vi), - _minus(value), - ) + msg = "Setting starting value for variables constrained at creation is not supported yet" + throw(MOI.SetAttributeNotAllowed(attr, msg)) end + MOI.set( + optimizer.dual_problem.dual_model, + _dual_attribute(attr), + get_ci_dual_problem(optimizer, vi), + _minus(value), + ) return end @@ -399,13 +397,16 @@ function MOI.get( ci_dual, idx, ) - else - return -MOI.get( - optimizer.dual_problem.dual_model, - _dual_attribute(attr), - get_ci_dual_problem(optimizer, vi), - ) end + ret = MOI.get( + optimizer.dual_problem.dual_model, + _dual_attribute(attr), + get_ci_dual_problem(optimizer, vi), + ) + if ret === nothing + return ret + end + return -ret end function MOI.supports( @@ -428,17 +429,15 @@ function MOI.set( ) primal_dual_map = optimizer.dual_problem.primal_dual_map if ci in keys(primal_dual_map.constrained_var_dual) - error( - "Setting starting value for variables constrained at creation is not supported yet", - ) - else - MOI.set( - optimizer.dual_problem.dual_model, - _variable_dual_attribute(attr), - get_vi_dual_problem(optimizer, ci), - value, - ) + msg = "Setting starting value for variables constrained at creation is not supported yet" + throw(MOI.SetAttributeNotAllowed(attr, msg)) end + MOI.set( + optimizer.dual_problem.dual_model, + _variable_dual_attribute(attr), + get_vi_dual_problem(optimizer, ci), + value, + ) return end