-
-
Notifications
You must be signed in to change notification settings - Fork 393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Permit info callbacks in states other than MIPInfo #814
Conversation
push!(objs, MathProgBase.cbgetobj(cb)) | ||
push!(bestbounds, MathProgBase.cbgetbestbound(cb)) | ||
if MathProgBase.cbgetstate(cb) == :Other | ||
push!(nodes, MathProgBase.cbgetexplorednodes(cb)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this mean? It's invalid to call MathProgBase.cbgetexplorednodes
if state is not :Other
? How are people supposed to know what is valid to call inside an info callback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, the callback will only fire when the state is :MIPInfo
(which is supposed to be :Other
in MPB-land). It's to let current tests pass, since Gurobi.jl does not allow for MPB.cbgetobj
to work when the state is :MIPSol
.
Current coverage is 84.60% (diff: 16.66%)@@ master #814 diff @@
==========================================
Files 18 18
Lines 4327 4294 -33
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
- Hits 3671 3633 -38
- Misses 656 661 +5
Partials 0 0
|
I don't really get this |
From my reading (primarily of the master callback functions),
Which is how I imagine MPB came to have the current situation of The PR at jump-dev/Gurobi.jl#59 is to make the state information available in the info callback so that you can extract info at each MIPSol. In the process, I don't pretend this fixes the situation for the other solvers, or that all other state information should be coerced into |
This PR together with jump-dev/Gurobi.jl#59 breaks user code using Gurobi with info callbacks, I assume. If we're going to do this, it should be an obvious improvement and not unnecessarily introduce confusing things like |
I'm ok with removing the |
To summarise the issues here:
We can proceed in a number of ways. Two possibilities that comes to mind:
Some other auxiliary comments:
|
Could we start out by thinking about what people might want to do with info callbacks and how we can make it possible and easy to do so? Checking |
I'll personally prefer start with a couple of documented examples of "here's how you can do X (with info callbacks)" that interested users can copy+paste. And maybe generalise only after we elicit a couple of use-cases, rather than upfront trying to figure it all out. The anxiety over
and not with this PR (to permit info callbacks to fire in other states of the B&B tree).
The check of Here's how that can be done (with this PR): function myinfo(cb)
entered[1] = true
if MathProgBase.cbgetstate(cb) == :Other
push!(nodes, MathProgBase.cbgetexplorednodes(cb))
push!(objs, MathProgBase.cbgetobj(cb))
push!(bestbounds, MathProgBase.cbgetbestbound(cb))
end
if MathProgBase.cbgetstate(cb) == :MIPSol
# Update all variable values so that `getvalue` works
MathProgBase.cbgetmipsolution(cb, mod.colVal)
println(JuMP.getvalue(x[1:15])) # print just 15 values to not overwhelm the example screen
end
end Giving something like [callback] Test informational callback
> With solver Gurobi.GurobiSolver
[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0]
[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]
[-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0]
[-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0]
[-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0,-0.0]
5 facts verified. Alternatively, I can store them all into an array, rather than printing them out. And again, I'll like to reiterate that the need to check for |
How about being clear about when we want the info callback to be called? Something like addinfocallback(mod, myinfo, when = :Feasible) # MIPSOL in Gurobi
addinfocallback(mod, myinfo, when = :Fractional) # MIPNODE
addinfocallback(mod, myinfo, when = :BnBNode) # MIP
addinfocallback(mod, myinfo, when = :Iteration) # For barrier/simplex iterations, etc.. For |
Update: I just realized the callback data has the raw/original information, so I was worrying for nothing.
Sure. |
Thinking about it more, I remain unconvinced that addinfocallback(mod, myinfo1, when = :Feasible) # MIPSOL in Gurobi
addinfocallback(mod, myinfo2, when = :Fractional) # MIPNODE
addinfocallback(mod, myinfo3, when = :BnBNode) # MIP
addinfocallback(mod, myinfo4, when = :Iteration) # For barrier/simplex iterations, etc.. is any better than function myinfo(cbdata)
cbdata.state == :Feasible && myinfo1(cbdata)
cbdata.state == :Fractional && myinfo2(cbdata)
cbdata.state == :BnBNode && myinfo3(cbdata)
cbdata.state == :Iteration && myinfo4(cbdata)
end
addinfocallback(mod, myinfo) or equivalently addinfocallback(mod, cbdata -> begin
cbdata.state == :Feasible && myinfo1(cbdata)
cbdata.state == :Fractional && myinfo2(cbdata)
cbdata.state == :BnBNode && myinfo3(cbdata)
cbdata.state == :Iteration && myinfo4(cbdata)
end)
Both require the user to think about when the infocallback should be fired, and the latter results in a lot less work for the master callback function to keep track of all possible infocallback functions ( |
@@ -38,9 +39,9 @@ function addheuristiccallback(m::Model, f::Function) | |||
m.internalModelLoaded = false | |||
push!(m.callbacks, HeuristicCallback(f)) | |||
end | |||
function addinfocallback(m::Model, f::Function) | |||
function addinfocallback(m::Model, f::Function, when::Symbol) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keyword argument?
Edit: see latest comment |
I think I'm alright with this change, but throwing the error in |
@@ -41,7 +41,15 @@ function addheuristiccallback(m::Model, f::Function) | |||
end | |||
function addinfocallback(m::Model, f::Function; when::Symbol = :Undefined) | |||
if when == :Undefined | |||
error("Info Callbacks without a `when` clause are unsupported.") | |||
when = :Intermediate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't really matter, but I think you could do something like:
function _not_specified()
warn("""Info Callbacks without a when clause will currently default
to fire only in the :Intermediate state to preserve its behavior
with previous versions of JuMP.
This behavior will be deprecated in subsequent versions of JuMP, so
please rewrite all invocations of addinfocallbacks(m, f) to
addinfocallbacks(m, f, when = :Intermediate) instead.
""")
:Intermediate
end
function addinfocallback(m::Model, f::Function; when::Symbol = _not_specified())
...
to avoid the corner case where I might pass in when=:Undefined
.
No objections, just note that we have to tag GLPKMathProgInterface, CPLEX, Gurobi, and JuMP all at the same time. JuMP release is currently broken against CPLEX master because of this change. |
Is this breaking enough that we can't backport to the release branch? |
It's fine to tag master+this as 0.14.1. On Aug 30, 2016 11:51, "Joey Huchette" notifications@github.com wrote:
|
Restarted Travis, will merge if passing. |
If this passes before GLPK is tagged then something is broken |
This would be really useful for Pajarito. Can I help? Would be very nice to have this feature available ASAP. |
I can tag everything tomorrow |
The use-case is to allow for the extraction of intermediate solutions with information callbacks.
ref: JuliaOpt/MathProgBase.jl#115, jump-dev/Gurobi.jl#59, jump-dev/CPLEX.jl#80, JuliaOpt/GLPKMathProgInterface.jl#32