-
Notifications
You must be signed in to change notification settings - Fork 0
/
environments.py
124 lines (95 loc) · 4.44 KB
/
environments.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
import ecole
import pyscipopt
class DefaultInformationFunction():
def before_reset(self, model):
pass
def extract(self, model, done):
m = model.as_pyscipopt()
stage = m.getStage()
sense = 1 if m.getObjectiveSense() == "minimize" else -1
primal_bound = sense * m.infinity()
dual_bound = sense * -m.infinity()
nlpiters = 0
nlp = 0
nnodes = 0
solvingtime = 0
status = m.getStatus()
if stage >= pyscipopt.scip.PY_SCIP_STAGE.PROBLEM:
primal_bound = m.getObjlimit()
nnodes = m.getNNodes()
solvingtime = m.getSolvingTime()
nlp = m.getNLPs()
if stage >= pyscipopt.scip.PY_SCIP_STAGE.TRANSFORMED:
primal_bound = m.getPrimalbound()
dual_bound = m.getDualbound()
if stage >= pyscipopt.scip.PY_SCIP_STAGE.PRESOLVING:
nlpiters = m.getNLPIterations()
return {'primal_bound': primal_bound,
'dual_bound': dual_bound,
'nlps': nlp,
'nlpiters': nlpiters,
'nnodes': nnodes,
'solvingtime': solvingtime,
'status': status}
class RootPrimalSearchDynamics(ecole.dynamics.PrimalSearchDynamics):
def __init__(self, time_limit = 3600, n_trials=-1, presolve = True, toy_example = False):
super().__init__(trials_per_node=n_trials, depth_freq=1, depth_start=0, depth_stop=0) # only at the root node
self.time_limit = time_limit
self.presolve = presolve
self.toy_example = toy_example
def reset_dynamics(self, model):
pyscipopt_model = model.as_pyscipopt()
# disable SCIP heuristics
if self.toy_example:
pyscipopt_model.setPresolve(pyscipopt.scip.PY_SCIP_PARAMSETTING.OFF) # disable presolve
pyscipopt_model.disablePropagation() # disable propagation
pyscipopt_model.setHeuristics(pyscipopt.scip.PY_SCIP_PARAMSETTING.OFF)
if ~self.presolve:
pyscipopt_model.setPresolve(pyscipopt.scip.PY_SCIP_PARAMSETTING.OFF)
# set scip parameters, e.g. disable restarts
model.set_params({
'estimation/restarts/restartpolicy': 'n',
})
# process the root node
done, action_set = super().reset_dynamics(model)
# set time limit after reset
reset_time = pyscipopt_model.getSolvingTime()
pyscipopt_model.setParam("limits/time", self.time_limit + reset_time)
return done, action_set
class ObjectiveLimitEnvironment(ecole.environment.Environment):
def reset(self, instance, objective_limit=None, *dynamics_args, **dynamics_kwargs):
"""We add one optional parameter not supported by Ecole yet: the instance's objective limit."""
self.can_transition = True
try:
if isinstance(instance, ecole.core.scip.Model):
self.model = instance.copy_orig()
else:
self.model = ecole.core.scip.Model.from_file(instance)
self.model.set_params(self.scip_params)
# changes specific to this environment
if objective_limit is not None:
self.model.as_pyscipopt().setObjlimit(objective_limit)
self.dynamics.set_dynamics_random_state(self.model, self.rng)
# Reset data extraction functions
self.reward_function.before_reset(self.model)
self.observation_function.before_reset(self.model)
self.information_function.before_reset(self.model)
# Place the environment in its initial state
done, action_set = self.dynamics.reset_dynamics(
self.model, *dynamics_args, **dynamics_kwargs
)
self.can_transition = not done
# Extract additional data to be returned by reset
reward_offset = self.reward_function.extract(self.model, done)
if not done:
observation = self.observation_function.extract(self.model, done)
else:
observation = None
information = self.information_function.extract(self.model, done)
return observation, action_set, reward_offset, done, information
except Exception as e:
self.can_transition = False
raise e
class RootPrimalSearch(ObjectiveLimitEnvironment):
__Dynamics__ = RootPrimalSearchDynamics
__DefaultInformationFunction__ = DefaultInformationFunction