support failure in constraints propagation and demon executions
This commit is contained in:
@@ -64,7 +64,7 @@ def test_search_monitor():
|
||||
solver.Solve(db, monitor)
|
||||
|
||||
|
||||
class DemonTest(pywrapcp.Demon):
|
||||
class DemonTest(pywrapcp.PyDemon):
|
||||
def __init__(self, x):
|
||||
pywrapcp.Demon.__init__(self)
|
||||
self._x = x
|
||||
@@ -74,7 +74,7 @@ class DemonTest(pywrapcp.Demon):
|
||||
print 'in Run(), saw ' + str(self._x)
|
||||
|
||||
|
||||
class ConstraintTest(pywrapcp.Constraint):
|
||||
class ConstraintTest(pywrapcp.PyConstraint):
|
||||
def __init__(self, solver, x):
|
||||
pywrapcp.Constraint.__init__(self, solver)
|
||||
self._x = x
|
||||
@@ -92,6 +92,14 @@ class ConstraintTest(pywrapcp.Constraint):
|
||||
print self._x
|
||||
print 'out of InitialPropagate()'
|
||||
|
||||
class InitialPropagateDemon(pywrapcp.PyDemon):
|
||||
def __init__(self, ct):
|
||||
pywrapcp.Demon.__init__(self)
|
||||
self._ct = ct
|
||||
|
||||
def Run(self, solver):
|
||||
self._ct.InitialPropagate()
|
||||
|
||||
|
||||
def test_demon():
|
||||
solver = pywrapcp.Solver('test export')
|
||||
@@ -109,6 +117,32 @@ def test_constraint():
|
||||
solver.Solve(db)
|
||||
|
||||
|
||||
class DumbGreaterOrEqualToFive(pywrapcp.PyConstraint):
|
||||
def __init__(self, solver, x):
|
||||
pywrapcp.Constraint.__init__(self, solver)
|
||||
self._x = x
|
||||
|
||||
def Post(self):
|
||||
self._demon = InitialPropagateDemon(self)
|
||||
self._x.WhenBound(self._demon)
|
||||
|
||||
def InitialPropagate(self):
|
||||
if self._x.Bound():
|
||||
if self._x.Value() < 5:
|
||||
print 'Reject %d' % self._x.Value()
|
||||
self.solver().Fail()
|
||||
else:
|
||||
print 'Accept %d' % self._x.Value()
|
||||
|
||||
|
||||
def test_failing_constraint():
|
||||
solver = pywrapcp.Solver('test export')
|
||||
x = solver.IntVar(1, 10, 'x')
|
||||
myct = DumbGreaterOrEqualToFive(solver, x)
|
||||
solver.Add(myct)
|
||||
db = solver.Phase([x], solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)
|
||||
solver.Solve(db)
|
||||
|
||||
|
||||
def main():
|
||||
test_member()
|
||||
@@ -119,6 +153,7 @@ def main():
|
||||
test_search_monitor()
|
||||
test_demon()
|
||||
test_constraint()
|
||||
test_failing_constraint()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -242,12 +242,14 @@ class Queue {
|
||||
solver_->TopPeriodicCheck();
|
||||
}
|
||||
demon->Run(solver_);
|
||||
solver_->CheckFail();
|
||||
} else {
|
||||
solver_->GetPropagationMonitor()->BeginDemonRun(demon);
|
||||
if (++solver_->demon_runs_[demon->priority()] % kTestPeriod == 0) {
|
||||
solver_->TopPeriodicCheck();
|
||||
}
|
||||
demon->Run(solver_);
|
||||
solver_->CheckFail();
|
||||
solver_->GetPropagationMonitor()->EndDemonRun(demon);
|
||||
}
|
||||
}
|
||||
@@ -257,6 +259,7 @@ class Queue {
|
||||
solver_->TopPeriodicCheck();
|
||||
}
|
||||
demon->Run(solver_);
|
||||
solver_->CheckFail();
|
||||
}
|
||||
|
||||
void ProcessInstrumentedNormalDemon(Demon* const demon) {
|
||||
@@ -265,6 +268,7 @@ class Queue {
|
||||
solver_->TopPeriodicCheck();
|
||||
}
|
||||
demon->Run(solver_);
|
||||
solver_->CheckFail();
|
||||
solver_->GetPropagationMonitor()->EndDemonRun(demon);
|
||||
}
|
||||
|
||||
@@ -307,6 +311,7 @@ class Queue {
|
||||
solver_->TopPeriodicCheck();
|
||||
}
|
||||
demon->Run(solver_);
|
||||
solver_->CheckFail();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1420,7 +1425,8 @@ Solver::Solver(const std::string& name, const SolverParameters& parameters)
|
||||
additional_constraint_index_(0),
|
||||
propagation_monitor_(BuildTrace(this)),
|
||||
print_trace_(nullptr),
|
||||
anonymous_variable_index_(0) {
|
||||
anonymous_variable_index_(0) ,
|
||||
should_fail_(false) {
|
||||
Init();
|
||||
}
|
||||
|
||||
@@ -1453,7 +1459,8 @@ Solver::Solver(const std::string& name)
|
||||
additional_constraint_index_(0),
|
||||
propagation_monitor_(BuildTrace(this)),
|
||||
print_trace_(nullptr),
|
||||
anonymous_variable_index_(0) {
|
||||
anonymous_variable_index_(0),
|
||||
should_fail_(false) {
|
||||
Init();
|
||||
}
|
||||
|
||||
@@ -2460,6 +2467,17 @@ void Solver::Fail() {
|
||||
searches_.back()->JumpBack();
|
||||
}
|
||||
|
||||
void Solver::ShouldFail() {
|
||||
should_fail_ = true;
|
||||
}
|
||||
|
||||
void Solver::CheckFail() {
|
||||
if (should_fail_) {
|
||||
should_fail_ = false;
|
||||
Fail();
|
||||
}
|
||||
}
|
||||
|
||||
// ----- Cast Expression -----
|
||||
|
||||
IntExpr* Solver::CastExpression(const IntVar* const var) const {
|
||||
@@ -3214,6 +3232,7 @@ void Constraint::PostAndPropagate() {
|
||||
FreezeQueue();
|
||||
Post();
|
||||
InitialPropagate();
|
||||
solver()->CheckFail();
|
||||
UnfreezeQueue();
|
||||
}
|
||||
|
||||
|
||||
@@ -2883,6 +2883,10 @@ class Solver {
|
||||
// method returns expr, nullptr otherwise.
|
||||
IntExpr* CastExpression(const IntVar* const var) const;
|
||||
|
||||
// Support for swig.
|
||||
void ShouldFail();
|
||||
void CheckFail();
|
||||
|
||||
private:
|
||||
void Init(); // Initialization. To be called by the constructors only.
|
||||
void PushState(MarkerType t, const StateInfo& info);
|
||||
@@ -3021,6 +3025,7 @@ class Solver {
|
||||
std::unique_ptr<PropagationMonitor> propagation_monitor_;
|
||||
PropagationMonitor* print_trace_;
|
||||
int anonymous_variable_index_;
|
||||
bool should_fail_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Solver);
|
||||
};
|
||||
|
||||
@@ -260,22 +260,14 @@ gflags.DEFINE_boolean('cp_no_solve', False,
|
||||
gflags.DEFINE_string('cp_profile_file', '',
|
||||
'exports profiling overview to file.')
|
||||
}
|
||||
%pythoncode {
|
||||
|
||||
class PyDecisionBuilder(object):
|
||||
def NextWrapper(self, solver):
|
||||
result = None
|
||||
try:
|
||||
result = self.Next(solver)
|
||||
except Exception:
|
||||
return solver.FailDecision()
|
||||
return result
|
||||
|
||||
def DebugString(self):
|
||||
return "PyDecisionBuilder"
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
// Rename rules for directors
|
||||
%rename (InitialPropagateWrapper)
|
||||
operations_research::Constraint::InitialPropagate;
|
||||
%rename (RunWrapper) operations_research::Demon::Run;
|
||||
|
||||
|
||||
// Rename rules on SolutionCollector.
|
||||
%rename (Branches) operations_research::SolutionCollector::branches;
|
||||
%rename (Failures) operations_research::SolutionCollector::failures;
|
||||
@@ -1260,7 +1252,7 @@ struct FailureProtect {
|
||||
// Generic rename rule.
|
||||
%rename("%(camelcase)s", %$isfunction) "";
|
||||
|
||||
// Rename rule on DecisionBuilder;
|
||||
// Rename rule on directors;
|
||||
%rename (NextWrap) operations_research::DecisionBuilder::Next;
|
||||
|
||||
// Rename rule on SearchLimit
|
||||
@@ -2098,3 +2090,49 @@ namespace operations_research {
|
||||
typedef Assignment::AssignmentContainer AssignmentContainer;
|
||||
%template(AssignmentIntContainer) AssignmentContainer<IntVar, IntVarElement>;
|
||||
}
|
||||
|
||||
#if defined(SWIGPYTHON)
|
||||
%pythoncode {
|
||||
class PyDecisionBuilder(object):
|
||||
def NextWrapper(self, solver):
|
||||
result = None
|
||||
try:
|
||||
result = self.Next(solver)
|
||||
except Exception:
|
||||
return solver.FailDecision()
|
||||
return result
|
||||
|
||||
def DebugString(self):
|
||||
return "PyDecisionBuilder"
|
||||
|
||||
|
||||
class PyConstraint(Constraint):
|
||||
def __init__(self, solver):
|
||||
pywrapcp.Constraint.__init__(self, solver)
|
||||
|
||||
def InitialPropagateWrapper(self):
|
||||
try:
|
||||
self.InitialPropagate()
|
||||
except:
|
||||
self.solver().ShouldFail()
|
||||
|
||||
def DebugString(self):
|
||||
return "PyConstraint"
|
||||
|
||||
|
||||
class PyDemon(Demon):
|
||||
def __init__(self):
|
||||
pywrapcp.Demon.__init__(self)
|
||||
|
||||
def RunWrapper(self, solver):
|
||||
try:
|
||||
self.Run(solver)
|
||||
except:
|
||||
solver.ShouldFail()
|
||||
|
||||
def DebugString(self):
|
||||
return "PyDemon"
|
||||
|
||||
}
|
||||
#endif // SWIGPYTHON
|
||||
|
||||
|
||||
Reference in New Issue
Block a user