Implement lazy callbacks & two-phase gap

This commit is contained in:
2020-09-25 06:02:07 -05:00
parent 86e7b1981f
commit a221740ac5
10 changed files with 288 additions and 75 deletions

View File

@@ -21,14 +21,29 @@ class LazyConstraint:
class StaticLazyConstraintsComponent(Component):
def __init__(self,
classifier=CountingClassifier(),
threshold=0.05):
threshold=0.05,
use_two_phase_gap=True,
large_gap=1e-2,
violation_tolerance=-0.5,
):
self.threshold = threshold
self.classifier_prototype = classifier
self.classifiers = {}
self.pool = []
self.original_gap = None
self.large_gap = large_gap
self.is_gap_large = False
self.use_two_phase_gap = use_two_phase_gap
self.violation_tolerance = violation_tolerance
def before_solve(self, solver, instance, model):
self.pool = []
if not solver.use_lazy_cb and self.use_two_phase_gap:
logger.info("Increasing gap tolerance to %f", self.large_gap)
self.original_gap = solver.gap_tolerance
self.is_gap_large = True
solver.internal_solver.set_gap_tolerance(self.large_gap)
instance.found_violated_lazy_constraints = []
if instance.has_static_lazy_constraints():
self._extract_and_predict_static(solver, instance)
@@ -37,23 +52,41 @@ class StaticLazyConstraintsComponent(Component):
pass
def after_iteration(self, solver, instance, model):
logger.info("Finding violated lazy constraints...")
if solver.use_lazy_cb:
return False
else:
should_repeat = self._check_and_add(instance, solver)
if should_repeat:
return True
else:
if self.is_gap_large:
logger.info("Restoring gap tolerance to %f", self.original_gap)
solver.internal_solver.set_gap_tolerance(self.original_gap)
self.is_gap_large = False
return True
else:
return False
def on_lazy_callback(self, solver, instance, model):
self._check_and_add(instance, solver)
def _check_and_add(self, instance, solver):
logger.debug("Finding violated lazy constraints...")
constraints_to_add = []
for c in self.pool:
if not solver.internal_solver.is_constraint_satisfied(c.obj):
if not solver.internal_solver.is_constraint_satisfied(c.obj,
tol=self.violation_tolerance):
constraints_to_add.append(c)
for c in constraints_to_add:
self.pool.remove(c)
solver.internal_solver.add_constraint(c.obj)
instance.found_violated_lazy_constraints += [c.cid]
if len(constraints_to_add) > 0:
logger.info("Added %d lazy constraints back into the model" % len(constraints_to_add))
logger.info("Lazy constraint pool has %d constraints" % len(self.pool))
logger.info("%8d lazy constraints added %8d in the pool" % (len(constraints_to_add), len(self.pool)))
return True
else:
logger.info("Found no violated lazy constraints")
return False
def fit(self, training_instances):
training_instances = [t
for t in training_instances
@@ -92,7 +125,7 @@ class StaticLazyConstraintsComponent(Component):
obj=solver.internal_solver.extract_constraint(cid))
constraints[category] += [c]
self.pool.append(c)
logger.info("Extracted %d lazy constraints" % len(self.pool))
logger.info("%8d lazy constraints extracted" % len(self.pool))
logger.info("Predicting required lazy constraints...")
n_added = 0
for (category, x_values) in x.items():
@@ -108,8 +141,7 @@ class StaticLazyConstraintsComponent(Component):
self.pool.remove(c)
solver.internal_solver.add_constraint(c.obj)
instance.found_violated_lazy_constraints += [c.cid]
logger.info("Added %d lazy constraints back into the model" % n_added)
logger.info("Lazy constraint pool has %d constraints" % len(self.pool))
logger.info("%8d lazy constraints added %8d in the pool" % (n_added, len(self.pool)))
def _collect_constraints(self, train_instances):
constraints = {}