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