Solving Fixed-MILP Problem

Hello to all. I’m trying to solve some generation schedule problem and we need access to the dual variables for pricing. The problem is MILP and, since the dual variables are no available, we used some suggestion to fix integers and solving again (code below). This works fine for GLPK, but for example Cbc is not a LP solver, so we had to change to Clp solver. The problem we have is that when Clp initializes with the previous model, the MIP parameters are copied creating an exception in Clp.
I guess our questions are 2:

  1. Is there a better way to solve the fixed problem? I know solvers like Xpress or Cplex have an API to do this in 1 instruction. But how to do it in JuMP?
  2. How can we “remove” (or ask not to copy) these MIP parameters from model so CLP doesn’t throw an exception?
    Thank you all
function solve_fixed_model!(model)
for v in all_variables(model)
    if is_binary(v)
        unset_binary(v)
        val_v = JuMP.value(v)
        set_lower_bound(v, val_v)
        set_upper_bound(v, val_v)
    end
end
JuMP.set_optimizer(model, Clp.Optimizer)
JuMP.optimize!(model)
end`

see https://jump.dev/JuMP.jl/v0.21.5/variables/#JuMP.relax_integrality

For the second quesition, maybe you can do as follows

  1. use Clp solver to solve
  2. undo relaxation
  3. use Cbc solver and set MIP-specific attributes.

You’re looking for something like

using JuMP, Cbc, Clp

function fix!(model::Model)
    solution = Dict(
        v => value(v) for v in all_variables(model)
    )
    for v in all_variables(model)
        if is_binary(v)
            unset_binary(v)
            fix(v, solution[v]; force = true)
        end
    end
    return
end

model = Model(Cbc.Optimizer)
@variable(model, x, Bin)
@objective(model, Max, 2 * x)
optimize!(model)
fix!(model)
set_optimizer(model, Clp.Optimizer)
optimize!(model)
dual(FixRef(x))
2 Likes

Thanks a lot @odow! Yes, it’s very similar but if you introduce a Cbc’s parameter you can’t “undo” that parameter. In other words, if you see in a copy of your own code below, I have only introduced a parameter “ratioGap”. And you can reproduce that function set_optimizer(model, Clp.Optimizer) throws an exception: “ERROR: LoadError: MathOptInterface.UnsupportedAttribute{MathOptInterface.RawParameter}(MathOptInterface.RawParameter(“ratioGap”), “”)”

It seems like when Clp initializes, it copies Cbc-specific parameters from model (and thus creating the exception). Any idea how to “remove” the Cbc-specific parameters from model so Clp can run?
Thanks a lot!

using JuMP, Cbc, Clp

function fix!(model::Model)
    solution = Dict(
        v => value(v) for v in all_variables(model)
    )
    for v in all_variables(model)
        if is_binary(v)
            unset_binary(v)
            fix(v, solution[v]; force = true)
        end
    end
    return
end

model = Model(Cbc.Optimizer)
set_optimizer_attribute(model, "ratioGap", 0.001) # <-CBC PARAMETER
@variable(model, x, Bin)
@objective(model, Max, 2 * x)
optimize!(model)
fix!(model)
set_optimizer(model, Clp.Optimizer)
optimize!(model)
dual(FixRef(x))
1 Like

Thanks a lot @metab0t
It is very useful the relax_integrality(model) function. It works great with GLPK (as I mentioned). But not with Cbc because it does not compute the dual values. So that’s why we had to switch to Clp to solver the relaxed problem but the it throws an error if you (previously) introduced a Cbc-specific parameter. I guess there must be a way to tell Clp to ignore solver’s parameters but I haven’t figured out how.

1 Like

I try the following code and it works fine

model = Model()
set_optimizer(model, optimizer_with_attributes(Cbc.Optimizer, "ratioGap"=>0.001))
...
...

It seems that optimizer_with_attributes set the attributes to the Cbc.Optimizer directly while set_optimizer_attribute will cache the attribute in model.

1 Like

Oh brilliant, nice workaround! Thanks a lot

1 Like

This is a nice work-around. But set_optimizer_attribute should really do the same thing.

I’ve opened an issue to track this: reset_optimizer attempts to pass RawParameters between models · Issue #1220 · jump-dev/MathOptInterface.jl · GitHub

1 Like

Hello. I am trying to fix my MILP model with a simple instruction. Have you ever found a built-in function to do that? fixed_model(model) was supposed to work, but it gives an error, which I do not understand. I would really appreciate your help.

There is no simple instruction to create a fixed model.

You need to write a function like the ones above to loop through the variables and fix if they are is_integer or is_binary.

Thank you so much. It works on a simple example, but I have not tried it yet in my actual model. I will let you know if I have more questions.

It works on my actual model. Thank you again for your suggestions. For reference, I have the following function:

function FixModel!(model::Model)
    solution = Dict(
        v => value(v) for v in all_variables(model)
    )
    for v in all_variables(model)
        if is_binary(v)
            unset_binary(v)
            fix(v, solution[v]; force = true)
        elseif is_integer(v)
            unset_integer(v)
            fix(v, solution[v]; force = true)
        else
            nothing
        end
    end
    return
end
1 Like