Working with the optimization log
AnsweredHello,
I am looking to benchmark my model, for example by plotting the objective bounds over time, for which I would obviously need the bounds.
My initial idea was to extract them directly from the log file, but since that would require parsing a plain text file, I suspect there is a more efficient way. I tried changing the log format by >>> model.Params.LogFile = 'log.csv', but this seems to not affect the file format.
Since I want to use the bounds in the same program, avoiding writing to the hard drive all together would be ideal.
If there are better approaches to benchmarking, I am of course also open to them. It should probably be mentioned that I am using the official Python API.
Thanks in advance!
-
Hi Felix,
You could do this with a callback. For example, this callback creates a list of times, objective values, and objective bounds, then writes the data to a CSV file:
import gurobipy as gp
import csv
import time
def data_cb(model, where):
if where == gp.GRB.Callback.MIP:
cur_obj = model.cbGet(gp.GRB.Callback.MIP_OBJBST)
cur_bd = model.cbGet(gp.GRB.Callback.MIP_OBJBND)
# Did objective value or best bound change?
if model._obj != cur_obj or model._bd != cur_bd:
model._obj = cur_obj
model._bd = cur_bd
model._data.append([time.time() - m._start, cur_obj, cur_bd])
# Build model m here
m._obj = None
m._bd = None
m._data = []
m._start = time.time()
m.optimize(callback=data_cb)
with open('data.csv', 'w') as f:
writer = csv.writer(f)
writer.writerows(m._data)Does this help?
Eli
2 -
Thank you, yes, this allowed me to do exactly what I had in mind. Special thanks for the working code!
0 -
Following this one up, would this be the right kind of approach for getting the log information to integrate with our python logger (logging package). I'm thinking we create a callback that if gurobi logs something, we collect that information and parse into our logging file. Any advice on this is welcome!
1 -
Good day,
I would like to save the Gaps (16.1, 12.5, 2.86)that I get in the output log:
Nodes | Current Node | Objective Bounds | Work Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time 0 0 36.00000 0 11 31.00000 36.00000 16.1% - 0s H 0 0 32.0000000 36.00000 12.5% - 0s H 0 0 35.0000000 36.00000 2.86% - 0s
I used
def data_cb(model, where):
if where == gp.GRB.Callback.MIP:
cur_obj = model.cbGet(gp.GRB.Callback.MIP_OBJBST)
cur_bd = model.cbGet(gp.GRB.Callback.MIP_OBJBND)
model._data.append([cur_obj, cur_bd])
I returns
31.0,50.0
31.0,50.0
31.0,36.0
while the correct MIP_OBJBST (Incumbent in the outputlog) are [31,32,35]
and the correct MIP_OBJBND (BestBd in in the outputlog) are [36,36,36].
Can anyone help with this?0 -
Hi Shadi,
One approach you could use is via the MESSAGE callback to get each line that is logged and extract the gap from that using regex.
import re
import gurobipy as gp
m = # define model
def mycallback(model, where):
if where == gp.GRB.Callback.MESSAGE:
# Message callback
msg = model.cbGet(gp.GRB.Callback.MSG_STRING)
match = re.findall("(\d+\.\d+%).*s", msg)
gap = None if not match else match[0]
if gap:
print("gap", gap)
# do something with your gap string, eg strip % and convert to float
m.optimize(mycallback)Note that there may be changes in the gap which are not logged.
In your attempt, the gap is changing due to the incumbent improving, so you may be able to include the MIPSOL callback to make it work the way you would like.
- Riley
0
Please sign in to leave a comment.
Comments
5 comments