Dualization.jl icon indicating copy to clipboard operation
Dualization.jl copied to clipboard

Find primal solution from dual one and vice-versa?

Open dourouc05 opened this issue 6 years ago • 7 comments

Sometimes, I would find it useful to have a way to get the primal solution from the dual one (and vice-versa), especially when I don't get this solution from a solver (read from a file, got from a heuristic, etc.). For instance, just solving the complementary slackness equations?

I would say that this is low priority: nice to have, but not necessarily soon.

dourouc05 avatar Aug 02 '19 15:08 dourouc05

Just to plus one this, this would be super valuable to me. The primary issue seems to be the naming of the new dual constraints, as when variables are in containers, they seem to create dual constraint names which cannot be accessed through the constraint name function. For instance, for the following toy model:

model = Model(Gurobi.Optimizer)
@variable(model, x[1:5])
@constraints(model, begin
       c1, x[1] >= 2
       c2, x .>=0
       c3, x[2] >= 4
       end)
@objective(model, Min, sum(x))

when you run dualize, you get the following:

print(dual_model)

Max 4 dualc3_1 + 2 dualc1_1
Subject to
 x[1] : dualc1_1 + dualc2_1 == 1
 x[2] : dualc2_1 + dualc3_1 == 1
 x[3] : dualc2_1 == 1
 x[4] : dualc2_1 == 1
 x[5] : dualc2_1 == 1
 dualc1_1 >= 0
 dualc2_1 >= 0
 dualc2_1 >= 0
 dualc2_1 >= 0
 dualc2_1 >= 0
 dualc2_1 >= 0
 dualc3_1 >= 0

This has duals, but when you try to access them, you get:

dual(dual_model[:x[1]])
ERROR: MethodError: no method matching getindex(::Symbol, ::Int64)
Stacktrace:
 [1] top-level scope
   @ REPL[55]:1

Seems like something that could be fixed through dual constraint naming conventions? i.e. x_1 instead of x[1].

Thank you for your help!

ml6802 avatar Jan 23 '25 04:01 ml6802

Can I ask why are you using Dualization.jl with Gurobi?

odow avatar Jan 23 '25 04:01 odow

I assume you need constraint_by_name(dual_model, "x[1]") rather than dual_model[:x[1]].

odow avatar Jan 23 '25 04:01 odow

You need

julia> using JuMP, Dualization, Gurobi

julia> model = Model()
A JuMP Model
├ solver: none
├ objective_sense: FEASIBILITY_SENSE
├ num_variables: 0
├ num_constraints: 0
└ Names registered in the model: none

julia> @variable(model, x[1:5])
5-element Vector{VariableRef}:
 x[1]
 x[2]
 x[3]
 x[4]
 x[5]

julia> @constraints(model, begin
           c1, x[1] >= 2
           c2, x .>=0
           c3, x[2] >= 4
       end)
(c1 : x[1] ≥ 2, ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.GreaterThan{Float64}}, ScalarShape}[c2 : x[1] ≥ 0, c2 : x[2] ≥ 0, c2 : x[3] ≥ 0, c2 : x[4] ≥ 0, c2 : x[5] ≥ 0], c3 : x[2] ≥ 4)

julia> @objective(model, Min, sum(x))
x[1] + x[2] + x[3] + x[4] + x[5]

julia> dual_model = dualize(model, Gurobi.Optimizer; dual_names = DualNames("dual", ""))
Set parameter LicenseID to value 890341
A JuMP Model
├ solver: Gurobi
├ objective_sense: MAX_SENSE
│ └ objective_function_type: AffExpr
├ num_variables: 7
├ num_constraints: 12
│ ├ AffExpr in MOI.EqualTo{Float64}: 5
│ └ VariableRef in MOI.GreaterThan{Float64}: 7
└ Names registered in the model
  └ :dualc1_1, :dualc2_1, :dualc3_1, :x[1], :x[2], :x[3], :x[4], :x[5]

julia> dual_model[Symbol("x[1]")]
x[1] : dualc1_1 + dualc2_1 = 1

julia> constraint_by_name(dual_model, "x[1]")
x[1] : dualc1_1 + dualc2_1 = 1

odow avatar Jan 23 '25 04:01 odow

Ah fantastic, so just a syntax mistake on my end then. Thank you! I'm using Dualization.jl because I need to repeatedly resolve the dual of a large model while modifying the objective, which seemed much easier with a full JuMP model.

ml6802 avatar Jan 23 '25 12:01 ml6802

I'm using Dualization.jl because I need to repeatedly resolve the dual of a large model while modifying the objective

Why not modify the right-hand side? If you are solving an LP, there is essentially never a need to use Dualization.jl.

odow avatar Jan 23 '25 20:01 odow

Perhaps post on https://discourse.julialang.org/c/domain/opt/13 with a reproducible example of the problem you are trying to solve and we can point you in the right direction.

odow avatar Jan 23 '25 20:01 odow