-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcallback.py
executable file
·143 lines (122 loc) · 5 KB
/
callback.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python3.9
# Copyright 2022, Gurobi Optimization, LLC
# This example reads a model from a file, sets up a callback that
# monitors optimization progress and implements a custom
# termination strategy, and outputs progress information to the
# screen and to a log file.
#
# The termination strategy implemented in this callback stops the
# optimization of a MIP model once at least one of the following two
# conditions have been satisfied:
# 1) The optimality gap is less than 10%
# 2) At least 10000 nodes have been explored, and an integer feasible
# solution has been found.
# Note that termination is normally handled through Gurobi parameters
# (MIPGap, NodeLimit, etc.). You should only use a callback for
# termination if the available parameters don't capture your desired
# termination criterion.
import sys
import gurobipy as gp
from gurobipy import GRB
# Define my callback function
def mycallback(model, where):
if where == GRB.Callback.POLLING:
# Ignore polling callback
pass
elif where == GRB.Callback.PRESOLVE:
# Presolve callback
cdels = model.cbGet(GRB.Callback.PRE_COLDEL)
rdels = model.cbGet(GRB.Callback.PRE_ROWDEL)
if cdels or rdels:
print('%d columns and %d rows are removed' % (cdels, rdels))
elif where == GRB.Callback.SIMPLEX:
# Simplex callback
itcnt = model.cbGet(GRB.Callback.SPX_ITRCNT)
if itcnt - model._lastiter >= 100:
model._lastiter = itcnt
obj = model.cbGet(GRB.Callback.SPX_OBJVAL)
ispert = model.cbGet(GRB.Callback.SPX_ISPERT)
pinf = model.cbGet(GRB.Callback.SPX_PRIMINF)
dinf = model.cbGet(GRB.Callback.SPX_DUALINF)
if ispert == 0:
ch = ' '
elif ispert == 1:
ch = 'S'
else:
ch = 'P'
print('%d %g%s %g %g' % (int(itcnt), obj, ch, pinf, dinf))
elif where == GRB.Callback.MIP:
# General MIP callback
nodecnt = model.cbGet(GRB.Callback.MIP_NODCNT)
objbst = model.cbGet(GRB.Callback.MIP_OBJBST)
objbnd = model.cbGet(GRB.Callback.MIP_OBJBND)
solcnt = model.cbGet(GRB.Callback.MIP_SOLCNT)
if nodecnt - model._lastnode >= 100:
model._lastnode = nodecnt
actnodes = model.cbGet(GRB.Callback.MIP_NODLFT)
itcnt = model.cbGet(GRB.Callback.MIP_ITRCNT)
cutcnt = model.cbGet(GRB.Callback.MIP_CUTCNT)
print('%d %d %d %g %g %d %d' % (nodecnt, actnodes,
itcnt, objbst, objbnd, solcnt, cutcnt))
if abs(objbst - objbnd) < 0.1 * (1.0 + abs(objbst)):
print('Stop early - 10% gap achieved')
model.terminate()
if nodecnt >= 10000 and solcnt:
print('Stop early - 10000 nodes explored')
model.terminate()
elif where == GRB.Callback.MIPSOL:
# MIP solution callback
nodecnt = model.cbGet(GRB.Callback.MIPSOL_NODCNT)
obj = model.cbGet(GRB.Callback.MIPSOL_OBJ)
solcnt = model.cbGet(GRB.Callback.MIPSOL_SOLCNT)
x = model.cbGetSolution(model._vars)
print('**** New solution at node %d, obj %g, sol %d, '
'x[0] = %g ****' % (nodecnt, obj, solcnt, x[0]))
elif where == GRB.Callback.MIPNODE:
# MIP node callback
print('**** New node ****')
if model.cbGet(GRB.Callback.MIPNODE_STATUS) == GRB.OPTIMAL:
x = model.cbGetNodeRel(model._vars)
model.cbSetSolution(model.getVars(), x)
elif where == GRB.Callback.BARRIER:
# Barrier callback
itcnt = model.cbGet(GRB.Callback.BARRIER_ITRCNT)
primobj = model.cbGet(GRB.Callback.BARRIER_PRIMOBJ)
dualobj = model.cbGet(GRB.Callback.BARRIER_DUALOBJ)
priminf = model.cbGet(GRB.Callback.BARRIER_PRIMINF)
dualinf = model.cbGet(GRB.Callback.BARRIER_DUALINF)
cmpl = model.cbGet(GRB.Callback.BARRIER_COMPL)
print('%d %g %g %g %g %g' % (itcnt, primobj, dualobj,
priminf, dualinf, cmpl))
elif where == GRB.Callback.MESSAGE:
# Message callback
msg = model.cbGet(GRB.Callback.MSG_STRING)
model._logfile.write(msg)
if len(sys.argv) < 2:
print('Usage: callback.py filename')
sys.exit(0)
# Turn off display and heuristics
gp.setParam('OutputFlag', 0)
gp.setParam('Heuristics', 0)
# Read model from file
model = gp.read(sys.argv[1])
# Open log file
logfile = open('cb.log', 'w')
# Pass data into my callback function
model._lastiter = -GRB.INFINITY
model._lastnode = -GRB.INFINITY
model._logfile = logfile
model._vars = model.getVars()
# Solve model and capture solution information
model.optimize(mycallback)
print('')
print('Optimization complete')
if model.SolCount == 0:
print('No solution found, optimization status = %d' % model.Status)
else:
print('Solution found, objective = %g' % model.ObjVal)
for v in model.getVars():
if v.X != 0.0:
print('%s %g' % (v.VarName, v.X))
# Close log file
logfile.close()