plasmo-dev / Plasmo.jl

A Platform for Scalable Modeling and Optimization
Other
143 stars 20 forks source link

Retrieving callback data for lazy constraints fails #89

Closed tso-martin closed 10 months ago

tso-martin commented 11 months ago

I try to use lazy constraints on a OptiGraph using Gurobi, but unfortunately I get this error: ERROR: Cannot query MathOptInterface.CallbackVariablePrimal{Gurobi.CallbackData}(Gurobi.CallbackData( sense : minimize ... , Ptr{Nothing} @0x000002be63f18ad0, 4)) from caching optimizer because no optimizer is attached.

The code a ran was this:

function plasmo_lazy_constraint()
    graph = OptiGraph()
    @optinode(graph, n1)
    @variable(n1, 0 <= x <= 2.5, Int)
    @variable(n1, 0 <= y <= 2.5, Int)
    @objective(n1, Max, y)
    # set_optimizer(n1.model, Gurobi.Optimizer)

    set_optimizer(graph, Gurobi.Optimizer)

    function my_callback_function(cb_data)
        x_val = callback_value(cb_data, x)
        y_val = callback_value(cb_data, y)

        status = callback_node_status(cb_data, graph)
      if status == MOI.CALLBACK_NODE_STATUS_FRACTIONAL
            println(" - Solution is integer infeasible!")
        elseif status == MOI.CALLBACK_NODE_STATUS_INTEGER
            println(" - Solution is integer feasible!")
        else
            @assert status == MOI.CALLBACK_NODE_STATUS_UNKNOWN
            println(" - I don't know if the solution is integer feasible :(")
        end
        if y_val - x_val > 1 + 1e-6
            con = @build_constraint(y - x <= 1)
            MOI.submit(graph, MOI.LazyConstraint(cb_data), con)
        elseif y_val + x_val > 3 + 1e-6
            con = @build_constraint(y + x <= 3)
            MOI.submit(graph, MOI.LazyConstraint(cb_data), con)
        end
    end
    set_attribute(graph, MOI.LazyConstraintCallback(), my_callback_function)
    optimize!(graph)
end
plasmo_lazy_constraint()

Of course, there is currently only one node, but I want to run the OptiGraph with multiple nodes and with PIPS-NLP afterwards. I appreciate your help.

jalving commented 11 months ago

Thanks for reporting @tso-martin. I will have a look at this over the weeekend. I am pretty sure Plasmo.jl just needs to correctly wrap the JuMP callback functions.

tso-martin commented 11 months ago

Dear Jordan, I made an successful attempt to add lazy constraints via callbacks. Setting the callback attribute requires an attached solver. Since this is only done in the Plasmo override of JuMP.optimize!, I set the callback attribute there. My solution may not be perfect, but maybe you can get some inspiration from https://github.com/tso-martin/Plasmo.jl/commit/3473f46a9205d6c6bc9cae94e74933c8bed2f610.

jalving commented 10 months ago

Hello @tso-martin, thank you for sharing your solution. I ended up using some of your code to get this working. However, I did not need to use the .ext dictionary in the call to JuMP.optimize!. Just using set_attribute seems to work as intended.

This should be supported now by PR #95, but please re-open if the issue persists.

jalving commented 10 months ago

Actually, i made a mistake. The variable index here: https://github.com/plasmo-dev/Plasmo.jl/blob/42f3242182d8492b58bad9de01aba53768b0f11c/src/optigraph.jl#L967-L973 needs to be mapped to the actual graph index. index(x) returns the node index. I'll fix this and release v0.5.5 shortly after.

tso-martin commented 10 months ago

Dear @jalving , Thank you for this update. I'll try that out once v0.5.5 is released.