7.7 Progress and data callback¶
Callbacks are a very useful mechanism that allow the caller to track the progress of the MOSEK optimizer. A callback function provided by the user is regularly called during the optimization and can be used to
obtain a customized log of the solver execution,
collect information for debugging purposes or
ask the solver to terminate.
Optimizer API for Python has the following callback mechanisms:
progress callback, which provides only the basic status of the solver.
data callback, which provides the solver status and a complete set of information items that describe the progress of the optimizer in detail.
Warning
The callbacks functions must not invoke any functions of the solver, environment or task. Otherwise the state of the solver and its outcome are undefined. The only exception is the possibility to retrieve an integer solution, see below.
Retrieving mixed-integer solutions
If the mixed-integer optimizer is used, the callback will take place, in particular, every time an improved integer solution is found. In that case it is possible to retrieve the current values of the best integer solution from within the callback function. It can be useful for implementing complex termination criteria for integer optimization. The example in Listing 7.5 shows how to do it by handling the callback code callbackcode.new_int_mio
.
7.7.1 Data callback¶
In the data callback MOSEK passes a callback code and values of all information items to a user-defined function. The callback function is called, in particular, at the beginning of each iteration of the interior-point optimizer. For the simplex optimizers iparam.log_sim_freq
controls how frequently the call-back is called.
The callback is set by calling the method Task.set_InfoCallback
and providing a handle to a user-defined function callbackfunc
.
Non-zero return value of the callback function indicates that the optimizer should be terminated.
7.7.2 Progress callback¶
In the progress callback MOSEK provides a single code indicating the current stage of the optimization process.
The callback is set by calling the method Task.set_Progress
and providing a handle to a user-defined function progresscallbackfunc
.
Non-zero return value of the callback function indicates that the optimizer should be terminated.
7.7.3 Working example: Data callback¶
The following example defines a data callback function that prints out some of the information items. It interrupts the solver after a certain time limit.
def makeUserCallback(maxtime, task):
pass
def userCallback(caller,
douinf,
intinf,
lintinf):
opttime = 0.0
if caller == callbackcode.begin_intpnt:
print("Starting interior-point optimizer")
elif caller == callbackcode.intpnt:
itrn = intinf[iinfitem.intpnt_iter]
pobj = douinf[dinfitem.intpnt_primal_obj]
dobj = douinf[dinfitem.intpnt_dual_obj]
stime = douinf[dinfitem.intpnt_time]
opttime = douinf[dinfitem.optimizer_time]
print("Iterations: %-3d" % itrn)
print(" Elapsed time: %6.2f(%.2f) " % (opttime, stime))
print(" Primal obj.: %-18.6e Dual obj.: %-18.6e" % (pobj, dobj))
elif caller == callbackcode.end_intpnt:
print("Interior-point optimizer finished.")
elif caller == callbackcode.begin_primal_simplex:
print("Primal simplex optimizer started.")
elif caller == callbackcode.update_primal_simplex:
itrn = intinf[iinfitem.sim_primal_iter]
pobj = douinf[dinfitem.sim_obj]
stime = douinf[dinfitem.sim_time]
opttime = douinf[dinfitem.optimizer_time]
print("Iterations: %-3d" % itrn)
print(" Elapsed time: %6.2f(%.2f)" % (opttime, stime))
print(" Obj.: %-18.6e" % pobj)
elif caller == callbackcode.end_primal_simplex:
print("Primal simplex optimizer finished.")
elif caller == callbackcode.begin_dual_simplex:
print("Dual simplex optimizer started.")
elif caller == callbackcode.update_dual_simplex:
itrn = intinf[iinfitem.sim_dual_iter]
pobj = douinf[dinfitem.sim_obj]
stime = douinf[dinfitem.sim_time]
opttime = douinf[dinfitem.optimizer_time]
print("Iterations: %-3d" % itrn)
print(" Elapsed time: %6.2f(%.2f)" % (opttime, stime))
print(" Obj.: %-18.6e" % pobj)
elif caller == callbackcode.end_dual_simplex:
print("Dual simplex optimizer finished.")
elif caller == callbackcode.new_int_mio:
print("New integer solution has been located.")
xx = task.getxx(soltype.itg)
print(xx)
print("Obj.: %f" % douinf[dinfitem.mio_obj_int])
else:
pass
if opttime >= maxtime:
# mosek is spending too much time. Terminate it.
print("Terminating.")
return 1
return 0
return userCallback
Assuming that we have defined a task task
and a time limit maxtime
, the callback function is attached as follows:
usercallback = makeUserCallback(maxtime=0.05, task=task)
task.set_InfoCallback(usercallback)