1+ from pyscipopt import Model , Eventhdlr , SCIP_EVENTTYPE , Eventhdlr
2+
3+ def attach_primal_dual_evolution_eventhdlr (model : Model ):
4+ """
5+ Attaches an event handler to a given SCIP model that collects primal and dual solutions,
6+ along with the solving time when they were found.
7+ The data is saved in model.data["primal_log"] and model.data["dual_log"]. They consist of
8+ a list of tuples, each tuple containing the solving time and the corresponding solution.
9+
10+ A usage example can be found in examples/finished/plot_primal_dual_evolution.py. The
11+ example takes the information provided by this recipe and uses it to plot the evolution
12+ of the dual and primal bounds over time.
13+ """
14+ class GapEventhdlr (Eventhdlr ):
15+
16+ def eventinit (self ): # we want to collect best primal solutions and best dual solutions
17+ self .model .catchEvent (SCIP_EVENTTYPE .BESTSOLFOUND , self )
18+ self .model .catchEvent (SCIP_EVENTTYPE .LPSOLVED , self )
19+ self .model .catchEvent (SCIP_EVENTTYPE .NODESOLVED , self )
20+
21+
22+ def eventexec (self , event ):
23+ # if a new best primal solution was found, we save when it was found and also its objective
24+ if event .getType () == SCIP_EVENTTYPE .BESTSOLFOUND :
25+ self .model .data ["primal_log" ].append ([self .model .getSolvingTime (), self .model .getPrimalbound ()])
26+
27+ if not self .model .data ["dual_log" ]:
28+ self .model .data ["dual_log" ].append ([self .model .getSolvingTime (), self .model .getDualbound ()])
29+
30+ if self .model .getObjectiveSense () == "minimize" :
31+ if self .model .isGT (self .model .getDualbound (), self .model .data ["dual_log" ][- 1 ][1 ]):
32+ self .model .data ["dual_log" ].append ([self .model .getSolvingTime (), self .model .getDualbound ()])
33+ else :
34+ if self .model .isLT (self .model .getDualbound (), self .model .data ["dual_log" ][- 1 ][1 ]):
35+ self .model .data ["dual_log" ].append ([self .model .getSolvingTime (), self .model .getDualbound ()])
36+
37+
38+ if not hasattr (model , "data" ) or model .data == None :
39+ model .data = {}
40+
41+ model .data ["primal_log" ] = []
42+ model .data ["dual_log" ] = []
43+ hdlr = GapEventhdlr ()
44+ model .includeEventhdlr (hdlr , "gapEventHandler" , "Event handler which collects primal and dual solution evolution" )
45+
46+ return model
0 commit comments