add Reversible immutable multi-map; reimplement propagation tracing using the new protocol, changed flags to cp_trace_propagation
; Add PDP local search moves; Split RevAlloc into RevAlloc and RevAllocArray
This commit is contained in:
@@ -37,7 +37,10 @@
|
||||
#include "constraint_solver/model.pb.h"
|
||||
#include "util/const_int_array.h"
|
||||
|
||||
DEFINE_bool(cp_trace_demons, false, "trace all demon executions.");
|
||||
DEFINE_bool(cp_trace_propagation,
|
||||
false,
|
||||
"Trace propagation events(constraint and demon executions,"
|
||||
"variable modifications).");
|
||||
DEFINE_bool(cp_show_constraints, false,
|
||||
"show all constraints added to the solver.");
|
||||
DEFINE_bool(cp_print_model, false,
|
||||
@@ -48,7 +51,6 @@ DEFINE_string(cp_export_file, "", "Export model to file using CPModelProto.");
|
||||
DEFINE_bool(cp_no_solve, false, "Force failure at the beginning of a search.");
|
||||
DEFINE_string(cp_profile_file, "", "Export profiling overview to file.");
|
||||
DEFINE_bool(cp_verbose_fail, false, "Verbose output when failing.");
|
||||
DEFINE_bool(cp_trace_variables, false, "Trace propagation on all variables.");
|
||||
|
||||
void ConstraintSolverFailsHere() {
|
||||
VLOG(3) << "Fail";
|
||||
@@ -78,13 +80,19 @@ extern void DeleteDemonMonitor(DemonMonitor* const monitor);
|
||||
// We need the double test because parameters are set too late when using
|
||||
// python in the open source. This is the cheapest work-around.
|
||||
bool Solver::InstrumentsDemons() const {
|
||||
return parameters_.profile_level != SolverParameters::NO_PROFILING ||
|
||||
FLAGS_cp_trace_propagation ||
|
||||
!FLAGS_cp_profile_file.empty();
|
||||
}
|
||||
|
||||
bool Solver::IsProfilingEnabled() const {
|
||||
return parameters_.profile_level != SolverParameters::NO_PROFILING ||
|
||||
!FLAGS_cp_profile_file.empty();
|
||||
}
|
||||
|
||||
bool Solver::InstrumentsVariables() const {
|
||||
return parameters_.trace_level != SolverParameters::NO_TRACE ||
|
||||
FLAGS_cp_trace_variables;
|
||||
FLAGS_cp_trace_propagation;
|
||||
}
|
||||
|
||||
// ------------------ Demon class ----------------
|
||||
@@ -243,10 +251,6 @@ class Queue {
|
||||
Demon* const demon = containers_[prio]->NextDemon();
|
||||
// A NULL demon will just be ignored
|
||||
if (demon != NULL) {
|
||||
if (FLAGS_cp_trace_demons) {
|
||||
LG << "### Running demon (" << prio << "):"
|
||||
<< demon->DebugString() << " ###";
|
||||
}
|
||||
demon->set_stamp(stamp_ - 1);
|
||||
DCHECK_EQ(prio, demon->priority());
|
||||
solver_->demon_runs_[prio]++;
|
||||
@@ -770,48 +774,48 @@ void Solver::InternalSaveValue(bool* valptr) {
|
||||
trail_->rev_bool_value_.push_back(*valptr);
|
||||
}
|
||||
|
||||
int* Solver::SafeRevAlloc(int* ptr) {
|
||||
check_alloc_state();
|
||||
trail_->rev_int_memory_.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int64* Solver::SafeRevAlloc(int64* ptr) {
|
||||
check_alloc_state();
|
||||
trail_->rev_int64_memory_.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint64* Solver::SafeRevAlloc(uint64* ptr) {
|
||||
check_alloc_state();
|
||||
trail_->rev_int64_memory_.push_back(reinterpret_cast<int64*>(ptr));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
BaseObject* Solver::SafeRevAlloc(BaseObject* ptr) {
|
||||
check_alloc_state();
|
||||
trail_->rev_object_memory_.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
BaseObject** Solver::SafeRevAlloc(BaseObject** ptr) {
|
||||
int* Solver::SafeRevAllocArray(int* ptr) {
|
||||
check_alloc_state();
|
||||
trail_->rev_int_memory_.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int64* Solver::SafeRevAllocArray(int64* ptr) {
|
||||
check_alloc_state();
|
||||
trail_->rev_int64_memory_.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint64* Solver::SafeRevAllocArray(uint64* ptr) {
|
||||
check_alloc_state();
|
||||
trail_->rev_int64_memory_.push_back(reinterpret_cast<int64*>(ptr));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
BaseObject** Solver::SafeRevAllocArray(BaseObject** ptr) {
|
||||
check_alloc_state();
|
||||
trail_->rev_object_array_memory_.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
IntVar** Solver::SafeRevAlloc(IntVar** ptr) {
|
||||
BaseObject** in = SafeRevAlloc(reinterpret_cast<BaseObject**>(ptr));
|
||||
IntVar** Solver::SafeRevAllocArray(IntVar** ptr) {
|
||||
BaseObject** in = SafeRevAllocArray(reinterpret_cast<BaseObject**>(ptr));
|
||||
return reinterpret_cast<IntVar**>(in);
|
||||
}
|
||||
|
||||
IntExpr** Solver::SafeRevAlloc(IntExpr** ptr) {
|
||||
BaseObject** in = SafeRevAlloc(reinterpret_cast<BaseObject**>(ptr));
|
||||
IntExpr** Solver::SafeRevAllocArray(IntExpr** ptr) {
|
||||
BaseObject** in = SafeRevAllocArray(reinterpret_cast<BaseObject**>(ptr));
|
||||
return reinterpret_cast<IntExpr**>(in);
|
||||
}
|
||||
|
||||
Constraint** Solver::SafeRevAlloc(Constraint** ptr) {
|
||||
BaseObject** in = SafeRevAlloc(reinterpret_cast<BaseObject**>(ptr));
|
||||
Constraint** Solver::SafeRevAllocArray(Constraint** ptr) {
|
||||
BaseObject** in = SafeRevAllocArray(reinterpret_cast<BaseObject**>(ptr));
|
||||
return reinterpret_cast<Constraint**>(in);
|
||||
}
|
||||
|
||||
@@ -1337,7 +1341,7 @@ Solver::Solver(const string& name, const SolverParameters& parameters)
|
||||
additional_constraint_index_(0),
|
||||
model_cache_(NULL),
|
||||
dependency_graph_(NULL),
|
||||
trace_(NULL) {
|
||||
propagation_monitor_(NULL) {
|
||||
Init();
|
||||
}
|
||||
|
||||
@@ -1370,13 +1374,14 @@ Solver::Solver(const string& name)
|
||||
additional_constraint_index_(0),
|
||||
model_cache_(NULL),
|
||||
dependency_graph_(NULL),
|
||||
trace_(NULL) {
|
||||
propagation_monitor_(NULL) {
|
||||
Init();
|
||||
}
|
||||
|
||||
extern ModelCache* BuildModelCache(Solver* const solver);
|
||||
extern DependencyGraph* BuildDependencyGraph(Solver* const solver);
|
||||
extern PropagationMonitor* BuildTrace();
|
||||
extern PropagationMonitor* BuildPrintTrace();
|
||||
|
||||
void Solver::Init() {
|
||||
for (int i = 0; i < kNumPriorities; ++i) {
|
||||
@@ -1390,8 +1395,11 @@ void Solver::Init() {
|
||||
timer_->Restart();
|
||||
model_cache_.reset(BuildModelCache(this));
|
||||
dependency_graph_.reset(BuildDependencyGraph(this));
|
||||
trace_.reset(BuildTrace());
|
||||
propagation_monitor_.reset(BuildTrace());
|
||||
AddPropagationMonitor(reinterpret_cast<PropagationMonitor*>(demon_monitor_));
|
||||
if (FLAGS_cp_trace_propagation) {
|
||||
AddPropagationMonitor(RevAlloc(BuildPrintTrace()));
|
||||
}
|
||||
}
|
||||
|
||||
Solver::~Solver() {
|
||||
@@ -1703,9 +1711,9 @@ void Solver::ProcessConstraints() {
|
||||
constraint_index_ < constraints_size;
|
||||
++constraint_index_) {
|
||||
Constraint* const constraint = constraints_list_[constraint_index_];
|
||||
trace_->StartConstraintInitialPropagation(constraint);
|
||||
propagation_monitor_->BeginConstraintInitialPropagation(constraint);
|
||||
constraint->PostAndPropagate();
|
||||
trace_->EndConstraintInitialPropagation(constraint);
|
||||
propagation_monitor_->EndConstraintInitialPropagation(constraint);
|
||||
}
|
||||
CHECK_EQ(constraints_list_.size(), constraints_size);
|
||||
|
||||
@@ -1718,9 +1726,10 @@ void Solver::ProcessConstraints() {
|
||||
const int parent_index =
|
||||
additional_constraints_parent_list_[additional_constraint_index_];
|
||||
const Constraint* const parent = constraints_list_[parent_index];
|
||||
trace_->StartNestedConstraintInitialPropagation(parent, nested);
|
||||
propagation_monitor_->BeginNestedConstraintInitialPropagation(parent,
|
||||
nested);
|
||||
nested->PostAndPropagate();
|
||||
trace_->EndNestedConstraintInitialPropagation(parent, nested);
|
||||
propagation_monitor_->EndNestedConstraintInitialPropagation(parent, nested);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1952,7 +1961,7 @@ void Solver::RestartSearch() {
|
||||
PushSentinel(INITIAL_SEARCH_SENTINEL);
|
||||
}
|
||||
|
||||
trace_->RestartSearch();
|
||||
propagation_monitor_->RestartSearch();
|
||||
search->RestartSearch();
|
||||
}
|
||||
|
||||
@@ -2074,9 +2083,11 @@ bool Solver::NextSolution() {
|
||||
case OUTSIDE_SEARCH: {
|
||||
state_ = IN_ROOT_NODE;
|
||||
search->BeginInitialPropagation();
|
||||
propagation_monitor_->BeginInitialPropagation();
|
||||
CP_TRY(search) {
|
||||
ProcessConstraints();
|
||||
search->EndInitialPropagation();
|
||||
propagation_monitor_->EndInitialPropagation();
|
||||
PushSentinel(ROOT_NODE_SENTINEL);
|
||||
state_ = IN_SEARCH;
|
||||
search->ClearBuffer();
|
||||
@@ -2109,9 +2120,11 @@ bool Solver::NextSolution() {
|
||||
search->left_search_depth()); // 1 for right branch
|
||||
PushState(CHOICE_POINT, i1);
|
||||
search->RefuteDecision(fd);
|
||||
propagation_monitor_->RefuteDecision(fd);
|
||||
branches_++;
|
||||
fd->Refute(this);
|
||||
search->AfterDecision(fd, false);
|
||||
propagation_monitor_->AfterDecision(fd);
|
||||
search->RightMove();
|
||||
fd = NULL;
|
||||
}
|
||||
@@ -2137,20 +2150,24 @@ bool Solver::NextSolution() {
|
||||
search->left_search_depth()); // 0 for left branch
|
||||
PushState(CHOICE_POINT, i2);
|
||||
search->ApplyDecision(d);
|
||||
propagation_monitor_->ApplyDecision(d);
|
||||
branches_++;
|
||||
d->Apply(this);
|
||||
search->AfterDecision(d, true);
|
||||
propagation_monitor_->AfterDecision(d);
|
||||
search->LeftMove();
|
||||
break;
|
||||
}
|
||||
case KEEP_LEFT: {
|
||||
search->ApplyDecision(d);
|
||||
propagation_monitor_->ApplyDecision(d);
|
||||
d->Apply(this);
|
||||
search->AfterDecision(d, true);
|
||||
break;
|
||||
}
|
||||
case KEEP_RIGHT: {
|
||||
search->RefuteDecision(d);
|
||||
propagation_monitor_->RefuteDecision(d);
|
||||
d->Refute(this);
|
||||
search->AfterDecision(d, false);
|
||||
break;
|
||||
@@ -2165,6 +2182,7 @@ bool Solver::NextSolution() {
|
||||
}
|
||||
if (search->AcceptSolution()) {
|
||||
search->IncrementSolutionCounter();
|
||||
propagation_monitor_->FindSolution();
|
||||
if (!search->AtSolution() || !CurrentlyInSolve()) {
|
||||
result = true;
|
||||
finish = true;
|
||||
@@ -2217,7 +2235,7 @@ void Solver::EndSearch() {
|
||||
Search* const search = searches_.back();
|
||||
BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
|
||||
search->ExitSearch();
|
||||
trace_->ExitSearch();
|
||||
propagation_monitor_->ExitSearch();
|
||||
search->Clear();
|
||||
state_ = OUTSIDE_SEARCH;
|
||||
if (!FLAGS_cp_profile_file.empty()) {
|
||||
@@ -2240,18 +2258,20 @@ bool Solver::CheckAssignment(Assignment* const solution) {
|
||||
|
||||
// Push monitors and enter search.
|
||||
search->EnterSearch();
|
||||
trace_->EnterSearch();
|
||||
propagation_monitor_->EnterSearch();
|
||||
|
||||
// Push sentinel and set decision builder.
|
||||
DCHECK_EQ(1, searches_.size());
|
||||
PushSentinel(INITIAL_SEARCH_SENTINEL);
|
||||
search->BeginInitialPropagation();
|
||||
propagation_monitor_->BeginInitialPropagation();
|
||||
CP_TRY(search) {
|
||||
state_ = IN_ROOT_NODE;
|
||||
DecisionBuilder * const restore = MakeRestoreAssignment(solution);
|
||||
restore->Next(this);
|
||||
ProcessConstraints();
|
||||
search->EndInitialPropagation();
|
||||
propagation_monitor_->EndInitialPropagation();
|
||||
BacktrackToSentinel(INITIAL_SEARCH_SENTINEL);
|
||||
search->ClearBuffer();
|
||||
state_ = OUTSIDE_SEARCH;
|
||||
@@ -2385,11 +2405,8 @@ void Solver::Fail() {
|
||||
}
|
||||
ConstraintSolverFailsHere();
|
||||
fails_++;
|
||||
trace_->RaiseFailure();
|
||||
propagation_monitor_->RaiseFailure();
|
||||
searches_.back()->BeginFail();
|
||||
if (FLAGS_cp_trace_demons || FLAGS_cp_verbose_fail) {
|
||||
LOG(INFO) << "### Failure ###";
|
||||
}
|
||||
searches_.back()->JumpBack();
|
||||
}
|
||||
|
||||
@@ -2403,7 +2420,13 @@ string Solver::GetName(const PropagationBaseObject* object) const {
|
||||
const IntegerCastInfo* const cast_info =
|
||||
FindOrNull(cast_information_, object);
|
||||
if (cast_info != NULL && cast_info->expression != NULL) {
|
||||
return StringPrintf("Var<%s>", cast_info->expression->name().c_str());
|
||||
if (cast_info->expression->HasName()) {
|
||||
return StringPrintf("Var<%s>",
|
||||
cast_info->expression->name().c_str());
|
||||
} else {
|
||||
return StringPrintf("Var<%s>",
|
||||
cast_info->expression->DebugString().c_str());
|
||||
}
|
||||
}
|
||||
return empty_name_;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
// demons Run = 25,
|
||||
// Run time = 0 ms)
|
||||
//
|
||||
// More infos: go/operations_research
|
||||
//
|
||||
// TODO(user): Remove C-style API and update following comment.
|
||||
// Global remark: many functions and methods in this file can take as argument
|
||||
@@ -819,23 +818,19 @@ class Solver {
|
||||
// factory methods (e.g., MakeIntVar(...), MakeAllDifferent(...) already take
|
||||
// care of the registration.
|
||||
template <typename T> T* RevAlloc(T* object) {
|
||||
// Note that if class MyObject inherits from BaseObject and has a default
|
||||
// constructor, then:
|
||||
// solver.RevAlloc(new MyObject()); compiles and does what you expect,
|
||||
// solver.RevAlloc(new MyObject[26]); compiles but should not be used:
|
||||
// it will NOT delete the array.
|
||||
// solver.RevAlloc(new MyObject*[53]); does not compile, because MyObject*
|
||||
// does not match BaseObject*.
|
||||
//
|
||||
// TODO(user): either make that solver.RevAlloc(new MyObject[26]) does
|
||||
// not compile, or make it not leak.
|
||||
// TODO(user): Split between a function that takes an array as argument and
|
||||
// a version that takes a pointer on a BaseObject, and rename to something
|
||||
// more explicit like RegisterReversibleObject / RegisterReversibleArray or
|
||||
// similar. Check whether this split fixes the leak mentioned above.
|
||||
return reinterpret_cast<T*>(SafeRevAlloc(object));
|
||||
}
|
||||
|
||||
// Like RevAlloc() above, but for an array of objects: the array
|
||||
// must have been allocated with the new[] operator. The entire array
|
||||
// will be deleted when backtracking out of the current state.
|
||||
//
|
||||
// This method is valid for arrays of int, int64, uint64, bool,
|
||||
// BaseObject*, IntVar*, IntExpr*, and Constraint*.
|
||||
template <typename T> T* RevAllocArray(T* object) {
|
||||
return reinterpret_cast<T*>(SafeRevAllocArray(object));
|
||||
}
|
||||
|
||||
// propagation
|
||||
|
||||
// Adds the constraint 'c' to the model.
|
||||
@@ -2723,14 +2718,16 @@ class Solver {
|
||||
ModelCache* Cache() const;
|
||||
// Returns wether we are instrumenting demons.
|
||||
bool InstrumentsDemons() const;
|
||||
// Returns wether we are profiling the solver.
|
||||
bool IsProfilingEnabled() const;
|
||||
// Returns wether we are tracing variables.
|
||||
bool InstrumentsVariables() const;
|
||||
// Returns the name of the model.
|
||||
string model_name() const;
|
||||
// Returns the dependency graph of the solver.
|
||||
DependencyGraph* Graph() const;
|
||||
// Returns the main trace object.
|
||||
PropagationMonitor* Trace() const;
|
||||
// Returns the propagation monitor.
|
||||
PropagationMonitor* GetPropagationMonitor() const;
|
||||
// Adds the propagation monitor to the solver. This should be done
|
||||
// before the search.
|
||||
void AddPropagationMonitor(PropagationMonitor* const monitor);
|
||||
@@ -2748,6 +2745,7 @@ class Solver {
|
||||
friend void InternalSaveBooleanVarValue(Solver* const, IntVar* const);
|
||||
friend void SetQueueCleanerOnFail(Solver* const, IntVar* const);
|
||||
template<class> friend class SimpleRevFIFO;
|
||||
template<class K, class V> friend class RevImmutableMultiMap;
|
||||
#endif
|
||||
|
||||
private:
|
||||
@@ -2779,14 +2777,15 @@ class Solver {
|
||||
InternalSaveValue(reinterpret_cast<void**>(valptr));
|
||||
}
|
||||
|
||||
int* SafeRevAlloc(int* ptr);
|
||||
int64* SafeRevAlloc(int64* ptr);
|
||||
uint64* SafeRevAlloc(uint64* ptr);
|
||||
BaseObject* SafeRevAlloc(BaseObject* ptr);
|
||||
BaseObject** SafeRevAlloc(BaseObject** ptr);
|
||||
IntVar** SafeRevAlloc(IntVar** ptr);
|
||||
IntExpr** SafeRevAlloc(IntExpr** ptr);
|
||||
Constraint** SafeRevAlloc(Constraint** ptr);
|
||||
|
||||
int* SafeRevAllocArray(int* ptr);
|
||||
int64* SafeRevAllocArray(int64* ptr);
|
||||
uint64* SafeRevAllocArray(uint64* ptr);
|
||||
BaseObject** SafeRevAllocArray(BaseObject** ptr);
|
||||
IntVar** SafeRevAllocArray(IntVar** ptr);
|
||||
IntExpr** SafeRevAllocArray(IntExpr** ptr);
|
||||
Constraint** SafeRevAllocArray(Constraint** ptr);
|
||||
// UnsafeRevAlloc is used internally for cells in SimpleRevFIFO
|
||||
// and other structures like this.
|
||||
void* UnsafeRevAllocAux(void* ptr);
|
||||
@@ -2860,7 +2859,7 @@ class Solver {
|
||||
|
||||
scoped_ptr<ModelCache> model_cache_;
|
||||
scoped_ptr<DependencyGraph> dependency_graph_;
|
||||
scoped_ptr<PropagationMonitor> trace_;
|
||||
scoped_ptr<PropagationMonitor> propagation_monitor_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Solver);
|
||||
};
|
||||
|
||||
@@ -22,13 +22,12 @@
|
||||
#include "constraint_solver/constraint_solver.h"
|
||||
#include "constraint_solver/constraint_solveri.h"
|
||||
|
||||
DECLARE_bool(cp_trace_demons);
|
||||
DECLARE_bool(cp_trace_propagation);
|
||||
DECLARE_bool(cp_print_model);
|
||||
DECLARE_bool(cp_model_stats);
|
||||
DECLARE_string(cp_export_file);
|
||||
DECLARE_bool(cp_no_solve);
|
||||
DECLARE_string(cp_profile_file);
|
||||
DECLARE_bool(cp_trace_variables);
|
||||
|
||||
struct FailureProtect {
|
||||
jmp_buf exception_buffer;
|
||||
@@ -226,8 +225,8 @@ namespace operations_research {
|
||||
%pythoncode {
|
||||
import gflags
|
||||
FLAGS=gflags.FLAGS
|
||||
gflags.DEFINE_boolean('cp_trace_demons', False,
|
||||
'trace all demon executions.')
|
||||
gflags.DEFINE_boolean('cp_trace_propagation', False,
|
||||
'trace all propagation events.')
|
||||
gflags.DEFINE_boolean('cp_print_model', False,
|
||||
'prints the model before solving it.')
|
||||
gflags.DEFINE_boolean('cp_model_stats', False,
|
||||
@@ -238,8 +237,6 @@ gflags.DEFINE_boolean('cp_no_solve', False,
|
||||
'force failures at the beginning of a search.')
|
||||
gflags.DEFINE_string('cp_profile_file', '',
|
||||
'exports profiling overview to file.')
|
||||
gflags.DEFINE_boolean('cp_trace_variables', False,
|
||||
'trace all variables modifications.')
|
||||
}
|
||||
%pythoncode {
|
||||
|
||||
@@ -882,31 +879,28 @@ namespace operations_research {
|
||||
// Indentation is critical here as the code is copied verbatim in the
|
||||
// python code.
|
||||
%feature("pythonappend") Solver::Solver %{
|
||||
Solver.SetPythonFlags(FLAGS.cp_trace_demons,
|
||||
Solver.SetPythonFlags(FLAGS.cp_trace_propagation,
|
||||
FLAGS.cp_print_model,
|
||||
FLAGS.cp_model_stats,
|
||||
FLAGS.cp_export_file,
|
||||
FLAGS.cp_no_solve,
|
||||
FLAGS.cp_profile_file,
|
||||
FLAGS.cp_trace_variables)
|
||||
FLAGS.cp_profile_file)
|
||||
%}
|
||||
|
||||
|
||||
%extend Solver {
|
||||
static void SetPythonFlags(bool trace_demon,
|
||||
static void SetPythonFlags(bool trace_propagation,
|
||||
bool print_model,
|
||||
bool model_stats,
|
||||
const string& export_file,
|
||||
bool no_solve,
|
||||
const string& profile_file,
|
||||
bool trace_variables) {
|
||||
FLAGS_cp_trace_demons = trace_demon;
|
||||
const string& profile_file) {
|
||||
FLAGS_cp_trace_propagation = trace_propagation;
|
||||
FLAGS_cp_print_model = print_model;
|
||||
FLAGS_cp_model_stats = model_stats;
|
||||
FLAGS_cp_export_file = export_file;
|
||||
FLAGS_cp_no_solve = no_solve;
|
||||
FLAGS_cp_profile_file = profile_file;
|
||||
FLAGS_cp_trace_variables = trace_variables;
|
||||
}
|
||||
|
||||
Constraint* TreeNoCycle(const std::vector<IntVar*>& nexts,
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// A reversible data structure is a data structure that reverts its
|
||||
// modifications when the search is going up in the search tree, usually
|
||||
// after a failure occurs.
|
||||
// - RevImmutableMultiMap a reversible immutable multimap.
|
||||
// - MakeConstraintDemon<n> and MakeDelayedConstraintDemon<n> to wrap methods
|
||||
// of a constraint as a demon.
|
||||
// - LocalSearchOperator, IntVarLocalSearchOperator, ChangeValue and
|
||||
@@ -65,6 +66,8 @@
|
||||
#include "base/map-util.h"
|
||||
#include "base/hash.h"
|
||||
#include "constraint_solver/constraint_solver.h"
|
||||
#include "util/const_int_array.h"
|
||||
#include "util/const_ptr_array.h"
|
||||
#include "util/vector_map.h"
|
||||
|
||||
template <typename T> class ResultCallback;
|
||||
@@ -210,6 +213,189 @@ template <class T> class SimpleRevFIFO {
|
||||
Chunk *chunks_;
|
||||
int pos_;
|
||||
};
|
||||
|
||||
// ---------- Reversible Hash Table ----------
|
||||
|
||||
// ----- Hash functions -----
|
||||
// TODO(user): use murmurhash.
|
||||
inline uint64 Hash1(uint64 value) {
|
||||
value = (~value) + (value << 21); // value = (value << 21) - value - 1;
|
||||
value ^= value >> 24;
|
||||
value += (value << 3) + (value << 8); // value * 265
|
||||
value ^= value >> 14;
|
||||
value += (value << 2) + (value << 4); // value * 21
|
||||
value ^= value >> 28;
|
||||
value += (value << 31);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline uint64 Hash1(uint32 value) {
|
||||
uint64 a = value;
|
||||
a = (a + 0x7ed55d16) + (a << 12);
|
||||
a = (a ^ 0xc761c23c) ^ (a >> 19);
|
||||
a = (a + 0x165667b1) + (a << 5);
|
||||
a = (a + 0xd3a2646c) ^ (a << 9);
|
||||
a = (a + 0xfd7046c5) + (a << 3);
|
||||
a = (a ^ 0xb55a4f09) ^ (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline uint64 Hash1(int64 value) {
|
||||
return Hash1(static_cast<uint64>(value));
|
||||
}
|
||||
|
||||
inline uint64 Hash1(int value) {
|
||||
return Hash1(static_cast<uint32>(value));
|
||||
}
|
||||
|
||||
inline uint64 Hash1(void* const ptr) {
|
||||
#if defined(ARCH_K8)
|
||||
return Hash1(reinterpret_cast<uint64>(ptr));
|
||||
#else
|
||||
return Hash1(reinterpret_cast<uint32>(ptr));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint64 Hash1(ConstIntArray* const values) {
|
||||
if (values->size() == 0) {
|
||||
return 0;
|
||||
} else if (values->size() == 1) {
|
||||
return Hash1(values->get(0));
|
||||
} else {
|
||||
uint64 hash = Hash1(values->get(0));
|
||||
for (int i = 1; i < values->size(); ++i) {
|
||||
hash = hash * i + Hash1(values->get(i));
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> uint64 Hash1(ConstPtrArray<T>* const ptrs) {
|
||||
if (ptrs->size() == 0) {
|
||||
return 0;
|
||||
} else if (ptrs->size() == 1) {
|
||||
return Hash1(ptrs->get(0));
|
||||
} else {
|
||||
uint64 hash = Hash1(ptrs->get(0));
|
||||
for (int i = 1; i < ptrs->size(); ++i) {
|
||||
hash = hash * i + Hash1(ptrs->get(i));
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
// ----- Immutable Multi Map -----
|
||||
|
||||
// Reversible Immutable MultiMap class.
|
||||
// Represents an immutable multi-map that backstracks with the solver.
|
||||
template <class K, class V> class RevImmutableMultiMap {
|
||||
public:
|
||||
RevImmutableMultiMap(Solver* const solver, int initial_size)
|
||||
: solver_(solver),
|
||||
array_(solver->UnsafeRevAllocArray(new Cell*[initial_size])),
|
||||
size_(initial_size),
|
||||
num_items_(0) {
|
||||
memset(array_, 0, sizeof(*array_) * size_);
|
||||
}
|
||||
|
||||
~RevImmutableMultiMap() {}
|
||||
|
||||
int num_items() const { return num_items_; }
|
||||
|
||||
// Returns true if the multi-map contains at least one instance of 'key'.
|
||||
bool ContainsKey(const K& key) const {
|
||||
uint64 code = Hash1(key) % size_;
|
||||
Cell* tmp = array_[code];
|
||||
while (tmp) {
|
||||
if (tmp->key() == key) {
|
||||
return true;
|
||||
}
|
||||
tmp = tmp->next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns one value attached to 'key', or 'defaut_value' if 'key'
|
||||
// is not in the multi-map. The actual value returned if more than one
|
||||
// values is attached to the same key is not specified.
|
||||
const V& FindWithDefault(const K& key, const V& default_value) const {
|
||||
uint64 code = Hash1(key) % size_;
|
||||
Cell* tmp = array_[code];
|
||||
while (tmp) {
|
||||
if (tmp->key() == key) {
|
||||
return tmp->value();
|
||||
}
|
||||
tmp = tmp->next();
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
// Inserts (key, value) in the multi-map.
|
||||
void Insert(const K& key, const V& value) {
|
||||
const int position = Hash1(key) % size_;
|
||||
Cell* const cell =
|
||||
solver_->UnsafeRevAlloc(new Cell(key, value, array_[position]));
|
||||
solver_->SaveAndSetValue(reinterpret_cast<void**>(&array_[position]),
|
||||
reinterpret_cast<void*>(cell));
|
||||
solver_->SaveAndAdd(&num_items_, 1);
|
||||
if (num_items_ > 2 * size_) {
|
||||
Double();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
class Cell {
|
||||
public:
|
||||
Cell(const K& key, const V& value, Cell* const next)
|
||||
: key_(key), value_(value), next_(next) {}
|
||||
|
||||
void SetRevNext(Solver* const solver, Cell* const next) {
|
||||
solver->SaveAndSetValue(reinterpret_cast<void**>(&next_),
|
||||
reinterpret_cast<void*>(next));
|
||||
}
|
||||
|
||||
Cell* next() const { return next_; }
|
||||
|
||||
const K& key() const { return key_; }
|
||||
|
||||
const V& value() const { return value_; }
|
||||
|
||||
private:
|
||||
const K key_;
|
||||
const V value_;
|
||||
Cell* next_;
|
||||
};
|
||||
|
||||
void Double() {
|
||||
Cell** const old_cell_array = array_;
|
||||
const int old_size = size_;
|
||||
solver_->SaveAndAdd(&size_, size_);
|
||||
solver_->SaveAndSetValue(
|
||||
reinterpret_cast<void**>(&array_),
|
||||
reinterpret_cast<void*>(
|
||||
solver_->UnsafeRevAllocArray(new Cell*[size_])));
|
||||
memset(array_, 0, size_ * sizeof(*array_));
|
||||
for (int i = 0; i < old_size; ++i) {
|
||||
Cell* tmp = old_cell_array[i];
|
||||
while (tmp != NULL) {
|
||||
Cell* const to_reinsert = tmp;
|
||||
tmp = tmp->next();
|
||||
const uint64 new_position = Hash1(to_reinsert->key()) % size_;
|
||||
to_reinsert->SetRevNext(solver_, array_[new_position]);
|
||||
solver_->SaveAndSetValue(
|
||||
reinterpret_cast<void**>(&array_[new_position]),
|
||||
reinterpret_cast<void*>(to_reinsert));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Solver* const solver_;
|
||||
Cell** array_;
|
||||
int size_;
|
||||
int num_items_;
|
||||
// TODO(user): Experiment with stamping 'array_'.
|
||||
};
|
||||
|
||||
// @{
|
||||
// These methods represent generic demons that will call back a
|
||||
// method on the constraint during their Run method.
|
||||
@@ -795,25 +981,64 @@ class IntVarLocalSearchFilter : public LocalSearchFilter {
|
||||
|
||||
class PropagationMonitor : public BaseObject {
|
||||
public:
|
||||
virtual void StartInitialPropagation() = 0;
|
||||
// Propagation events.
|
||||
virtual void BeginInitialPropagation() = 0;
|
||||
virtual void EndInitialPropagation() = 0;
|
||||
virtual void StartConstraintInitialPropagation(
|
||||
virtual void BeginConstraintInitialPropagation(
|
||||
const Constraint* const constraint) = 0;
|
||||
virtual void EndConstraintInitialPropagation(
|
||||
const Constraint* const constraint) = 0;
|
||||
virtual void StartNestedConstraintInitialPropagation(
|
||||
virtual void BeginNestedConstraintInitialPropagation(
|
||||
const Constraint* const parent,
|
||||
const Constraint* const nested) = 0;
|
||||
virtual void EndNestedConstraintInitialPropagation(
|
||||
const Constraint* const parent,
|
||||
const Constraint* const nested) = 0;
|
||||
virtual void RegisterDemon(const Demon* const demon) = 0;
|
||||
virtual void StartDemonRun(const Demon* const demon) = 0;
|
||||
virtual void BeginDemonRun(const Demon* const demon) = 0;
|
||||
virtual void EndDemonRun(const Demon* const demon) = 0;
|
||||
virtual void RaiseFailure() = 0;
|
||||
virtual void FindSolution() = 0;
|
||||
virtual void EnterSearch() = 0;
|
||||
virtual void ExitSearch() = 0;
|
||||
virtual void RestartSearch() = 0;
|
||||
virtual void ApplyDecision(Decision* const decision) = 0;
|
||||
virtual void RefuteDecision(Decision* const decision) = 0;
|
||||
virtual void AfterDecision(Decision* const decision) = 0;
|
||||
// IntExpr modifiers.
|
||||
virtual void SetMin(IntExpr* const expr, int64 new_min) = 0;
|
||||
virtual void SetMax(IntExpr* const expr, int64 new_max) = 0;
|
||||
virtual void SetRange(IntExpr* const expr, int64 new_min, int64 new_max) = 0;
|
||||
// IntVar modifiers.
|
||||
virtual void SetMin(IntVar* const var, int64 new_min) = 0;
|
||||
virtual void SetMax(IntVar* const var, int64 new_max) = 0;
|
||||
virtual void SetRange(IntVar* const var, int64 new_min, int64 new_max) = 0;
|
||||
virtual void RemoveValue(IntVar* const var, int64 value) = 0;
|
||||
virtual void SetValue(IntVar* const var, int64 value) = 0;
|
||||
virtual void RemoveInterval(IntVar* const var, int64 imin, int64 imax) = 0;
|
||||
virtual void SetValues(IntVar* const var,
|
||||
const int64* const values,
|
||||
int size) = 0;
|
||||
virtual void RemoveValues(IntVar* const var,
|
||||
const int64* const values,
|
||||
int size) = 0;
|
||||
// IntervalVar modifiers.
|
||||
virtual void SetStartMin(IntervalVar* const var, int64 new_min) = 0;
|
||||
virtual void SetStartMax(IntervalVar* const var, int64 new_max) = 0;
|
||||
virtual void SetStartRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) = 0;
|
||||
virtual void SetEndMin(IntervalVar* const var, int64 new_min) = 0;
|
||||
virtual void SetEndMax(IntervalVar* const var, int64 new_max) = 0;
|
||||
virtual void SetEndRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) = 0;
|
||||
virtual void SetDurationMin(IntervalVar* const var, int64 new_min) = 0;
|
||||
virtual void SetDurationMax(IntervalVar* const var, int64 new_max) = 0;
|
||||
virtual void SetDurationRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) = 0;
|
||||
virtual void SetPerformed(IntervalVar* const var, bool value) = 0;
|
||||
};
|
||||
|
||||
// ---------- SymmetryBreaker ----------
|
||||
|
||||
@@ -37,10 +37,12 @@ namespace operations_research {
|
||||
// after the end of a search.
|
||||
class DemonMonitor : public PropagationMonitor {
|
||||
public:
|
||||
DemonMonitor()
|
||||
: active_constraint_(NULL),
|
||||
active_demon_(NULL),
|
||||
DemonMonitor(Solver* const solver)
|
||||
: solver_(solver),
|
||||
active_constraint_(NULL),
|
||||
active_demon_(NULL),
|
||||
start_time_(WallTimer::GetTimeInMicroSeconds()) {}
|
||||
|
||||
virtual ~DemonMonitor() {
|
||||
STLDeleteContainerPairSecondPointers(constraint_map_.begin(),
|
||||
constraint_map_.end());
|
||||
@@ -50,8 +52,12 @@ start_time_(WallTimer::GetTimeInMicroSeconds()) {}
|
||||
return WallTimer::GetTimeInMicroSeconds() - start_time_;
|
||||
}
|
||||
|
||||
virtual void StartConstraintInitialPropagation(
|
||||
virtual void BeginConstraintInitialPropagation(
|
||||
const Constraint* const constraint) {
|
||||
if (solver_->state() == Solver::IN_SEARCH) {
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(active_constraint_ == NULL);
|
||||
CHECK(active_demon_ == NULL);
|
||||
CHECK_NOTNULL(constraint);
|
||||
@@ -69,15 +75,20 @@ return WallTimer::GetTimeInMicroSeconds() - start_time_;
|
||||
CHECK_NOTNULL(constraint);
|
||||
CHECK_EQ(constraint, active_constraint_);
|
||||
ConstraintRuns* const ct_run = constraint_map_[constraint];
|
||||
CHECK_NOTNULL(ct_run);
|
||||
ct_run->add_initial_propagation_end_time(CurrentTime());
|
||||
ct_run->set_failures(0);
|
||||
if (ct_run != NULL) {
|
||||
ct_run->add_initial_propagation_end_time(CurrentTime());
|
||||
ct_run->set_failures(0);
|
||||
}
|
||||
active_constraint_ = NULL;
|
||||
}
|
||||
|
||||
virtual void StartNestedConstraintInitialPropagation(
|
||||
virtual void BeginNestedConstraintInitialPropagation(
|
||||
const Constraint* const constraint,
|
||||
const Constraint* const delayed) {
|
||||
if (solver_->state() == Solver::IN_SEARCH) {
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(active_constraint_ == NULL);
|
||||
CHECK(active_demon_ == NULL);
|
||||
CHECK_NOTNULL(constraint);
|
||||
@@ -96,13 +107,18 @@ return WallTimer::GetTimeInMicroSeconds() - start_time_;
|
||||
CHECK_NOTNULL(delayed);
|
||||
CHECK_EQ(constraint, active_constraint_);
|
||||
ConstraintRuns* const ct_run = constraint_map_[constraint];
|
||||
CHECK_NOTNULL(ct_run);
|
||||
ct_run->add_initial_propagation_end_time(CurrentTime());
|
||||
ct_run->set_failures(0);
|
||||
if (ct_run != NULL) {
|
||||
ct_run->add_initial_propagation_end_time(CurrentTime());
|
||||
ct_run->set_failures(0);
|
||||
}
|
||||
active_constraint_ = NULL;
|
||||
}
|
||||
|
||||
virtual void RegisterDemon(const Demon* const demon) {
|
||||
if (solver_->state() == Solver::IN_SEARCH) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (demon_map_.find(demon) == demon_map_.end()) {
|
||||
CHECK_NOTNULL(active_constraint_);
|
||||
CHECK(active_demon_ == NULL);
|
||||
@@ -116,44 +132,99 @@ return WallTimer::GetTimeInMicroSeconds() - start_time_;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void StartDemonRun(const Demon* const demon) {
|
||||
virtual void BeginDemonRun(const Demon* const demon) {
|
||||
CHECK(active_demon_ == NULL);
|
||||
CHECK_NOTNULL(demon);
|
||||
active_demon_ = demon;
|
||||
DemonRuns* const demon_run = demon_map_[active_demon_];
|
||||
demon_run->add_start_time(CurrentTime());
|
||||
if (demon_run != NULL) {
|
||||
demon_run->add_start_time(CurrentTime());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void EndDemonRun(const Demon* const demon) {
|
||||
CHECK_EQ(active_demon_, demon);
|
||||
CHECK_NOTNULL(demon);
|
||||
DemonRuns* const demon_run = demon_map_[active_demon_];
|
||||
CHECK_NOTNULL(demon_run);
|
||||
demon_run->add_end_time(CurrentTime());
|
||||
if (demon_run != NULL) {
|
||||
demon_run->add_end_time(CurrentTime());
|
||||
}
|
||||
active_demon_ = NULL;
|
||||
}
|
||||
|
||||
virtual void RaiseFailure() {
|
||||
if (active_demon_ != NULL) {
|
||||
DemonRuns* const demon_run = demon_map_[active_demon_];
|
||||
demon_run->add_end_time(CurrentTime());
|
||||
demon_run->set_failures(demon_run->failures() + 1);
|
||||
if (demon_run != NULL) {
|
||||
demon_run->add_end_time(CurrentTime());
|
||||
demon_run->set_failures(demon_run->failures() + 1);
|
||||
}
|
||||
active_demon_ = NULL;
|
||||
// active_constraint_ can be non null in case of initial propagation.
|
||||
active_constraint_ = NULL;
|
||||
} else if (active_constraint_ != NULL) {
|
||||
ConstraintRuns* const ct_run = constraint_map_[active_constraint_];
|
||||
CHECK_NOTNULL(ct_run);
|
||||
ct_run->add_initial_propagation_end_time(CurrentTime());
|
||||
ct_run->set_failures(1);
|
||||
if (ct_run != NULL) {
|
||||
ct_run->add_initial_propagation_end_time(CurrentTime());
|
||||
ct_run->set_failures(1);
|
||||
}
|
||||
active_constraint_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void StartInitialPropagation() {}
|
||||
virtual void FindSolution() {}
|
||||
virtual void ApplyDecision(Decision* const decision) {}
|
||||
virtual void RefuteDecision(Decision* const decision) {}
|
||||
virtual void AfterDecision(Decision* const decision) {}
|
||||
|
||||
|
||||
// Restarts a search and clears all previously collected information.
|
||||
virtual void RestartSearch() {
|
||||
STLDeleteContainerPairSecondPointers(constraint_map_.begin(),
|
||||
constraint_map_.end());
|
||||
constraint_map_.clear();
|
||||
demon_map_.clear();
|
||||
demons_per_constraint_.clear();
|
||||
}
|
||||
|
||||
virtual void BeginInitialPropagation() {}
|
||||
virtual void EndInitialPropagation() {}
|
||||
virtual void EnterSearch() {}
|
||||
virtual void ExitSearch() {}
|
||||
// IntExpr modifiers.
|
||||
virtual void SetMin(IntExpr* const expr, int64 new_min) {}
|
||||
virtual void SetMax(IntExpr* const expr, int64 new_max) {}
|
||||
virtual void SetRange(IntExpr* const expr, int64 new_min, int64 new_max) {}
|
||||
// IntVar modifiers.
|
||||
virtual void SetMin(IntVar* const var, int64 new_min) {}
|
||||
virtual void SetMax(IntVar* const var, int64 new_max) {}
|
||||
virtual void SetRange(IntVar* const var, int64 new_min, int64 new_max) {}
|
||||
virtual void RemoveValue(IntVar* const var, int64 value) {}
|
||||
virtual void SetValue(IntVar* const var, int64 value) {}
|
||||
virtual void RemoveInterval(IntVar* const var, int64 imin, int64 imax) {}
|
||||
virtual void SetValues(IntVar* const var,
|
||||
const int64* const values,
|
||||
int size) {}
|
||||
virtual void RemoveValues(IntVar* const var,
|
||||
const int64* const values,
|
||||
int size) {}
|
||||
// IntervalVar modifiers.
|
||||
virtual void SetStartMin(IntervalVar* const var, int64 new_min) {}
|
||||
virtual void SetStartMax(IntervalVar* const var, int64 new_max) {}
|
||||
virtual void SetStartRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) {}
|
||||
virtual void SetEndMin(IntervalVar* const var, int64 new_min) {}
|
||||
virtual void SetEndMax(IntervalVar* const var, int64 new_max) {}
|
||||
virtual void SetEndRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) {}
|
||||
virtual void SetDurationMin(IntervalVar* const var, int64 new_min) {}
|
||||
virtual void SetDurationMax(IntervalVar* const var, int64 new_max) {}
|
||||
virtual void SetDurationRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) {}
|
||||
virtual void SetPerformed(IntervalVar* const var, bool value) {}
|
||||
|
||||
// Useful for unit tests.
|
||||
void AddFakeRun(const Demon* const demon,
|
||||
@@ -243,15 +314,6 @@ return WallTimer::GetTimeInMicroSeconds() - start_time_;
|
||||
file->Close();
|
||||
}
|
||||
|
||||
// Restarts a search and clears all previously collected information.
|
||||
void RestartSearch() {
|
||||
STLDeleteContainerPairSecondPointers(constraint_map_.begin(),
|
||||
constraint_map_.end());
|
||||
constraint_map_.clear();
|
||||
demon_map_.clear();
|
||||
demons_per_constraint_.clear();
|
||||
}
|
||||
|
||||
// Export Information
|
||||
void ExportInformation(const Constraint* const constraint,
|
||||
int64* const fails,
|
||||
@@ -341,6 +403,7 @@ return WallTimer::GetTimeInMicroSeconds() - start_time_;
|
||||
}
|
||||
|
||||
private:
|
||||
Solver* const solver_;
|
||||
const Constraint* active_constraint_;
|
||||
const Demon* active_demon_;
|
||||
const int64 start_time_;
|
||||
@@ -353,17 +416,15 @@ return WallTimer::GetTimeInMicroSeconds() - start_time_;
|
||||
// track the usage and perfomance of the demons.
|
||||
class DemonProfiler : public Demon {
|
||||
public:
|
||||
DemonProfiler(Demon* const demon, DemonMonitor* const monitor)
|
||||
: demon_(demon), monitor_(monitor) {
|
||||
explicit DemonProfiler(Demon* const demon) : demon_(demon) {
|
||||
CHECK_NOTNULL(demon);
|
||||
CHECK_NOTNULL(monitor);
|
||||
}
|
||||
|
||||
// This is the main callback of the demon.
|
||||
void Run(Solver* const s) {
|
||||
monitor_->StartDemonRun(demon_);
|
||||
demon_->Run(s);
|
||||
monitor_->EndDemonRun(demon_);
|
||||
void Run(Solver* const solver) {
|
||||
solver->GetPropagationMonitor()->BeginDemonRun(demon_);
|
||||
demon_->Run(solver);
|
||||
solver->GetPropagationMonitor()->EndDemonRun(demon_);
|
||||
}
|
||||
|
||||
// Returns the priority of the demon.
|
||||
@@ -373,12 +434,11 @@ class DemonProfiler : public Demon {
|
||||
|
||||
// DebugString of the contained demon.
|
||||
string DebugString() const {
|
||||
return StringPrintf("demon_profiler<%s>", demon_->DebugString().c_str());
|
||||
return demon_->DebugString();
|
||||
}
|
||||
|
||||
private:
|
||||
Demon* const demon_;
|
||||
DemonMonitor* const monitor_;
|
||||
};
|
||||
|
||||
|
||||
@@ -391,8 +451,8 @@ void Solver::ExportProfilingOverview(const string& filename) {
|
||||
// ----- Exported Functions -----
|
||||
|
||||
DemonMonitor* BuildDemonMonitor(Solver* const solver) {
|
||||
if (solver->InstrumentsDemons()) {
|
||||
return new DemonMonitor;
|
||||
if (solver->IsProfilingEnabled()) {
|
||||
return new DemonMonitor(solver);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
@@ -404,10 +464,9 @@ void DeleteDemonMonitor(DemonMonitor* const monitor) {
|
||||
|
||||
Demon* Solver::RegisterDemon(Demon* const demon) {
|
||||
CHECK_NOTNULL(demon);
|
||||
if (InstrumentsDemons() && state_ != IN_SEARCH) {
|
||||
CHECK_NOTNULL(demon_monitor_);
|
||||
demon_monitor_->RegisterDemon(demon);
|
||||
return RevAlloc(new DemonProfiler(demon, demon_monitor_));
|
||||
if (InstrumentsDemons()) {
|
||||
propagation_monitor_->RegisterDemon(demon);
|
||||
return RevAlloc(new DemonProfiler(demon));
|
||||
} else {
|
||||
return demon;
|
||||
}
|
||||
@@ -419,7 +478,7 @@ void BuildDemonProfiler(Solver* const solver,
|
||||
Demon* const demon,
|
||||
DemonMonitor* const monitor) {
|
||||
monitor->RegisterDemon(demon);
|
||||
solver->RevAlloc(new DemonProfiler(demon, monitor));
|
||||
solver->RevAlloc(new DemonProfiler(demon));
|
||||
}
|
||||
|
||||
void DeleteDemonProfiler(DemonProfiler* const profiler) {
|
||||
@@ -449,9 +508,9 @@ void DemonMonitorExportInformation(DemonMonitor* const monitor,
|
||||
demon_count);
|
||||
}
|
||||
|
||||
void DemonMonitorStartInitialPropagation(DemonMonitor* const monitor,
|
||||
void DemonMonitorBeginInitialPropagation(DemonMonitor* const monitor,
|
||||
const Constraint* const constraint) {
|
||||
monitor->StartConstraintInitialPropagation(constraint);
|
||||
monitor->BeginConstraintInitialPropagation(constraint);
|
||||
}
|
||||
|
||||
void DemonMonitorEndInitialPropagation(DemonMonitor* const monitor,
|
||||
|
||||
@@ -1414,6 +1414,9 @@ IntExpr* IntervalVar::StartExpr() {
|
||||
solver()->SaveValue(reinterpret_cast<void**>(&start_expr_));
|
||||
start_expr_ = solver()->RegisterIntExpr(
|
||||
solver()->RevAlloc(new IntervalVarStartExpr(this)));
|
||||
if (HasName()) {
|
||||
start_expr_->set_name(StringPrintf("start(%s)", name().c_str()));
|
||||
}
|
||||
}
|
||||
return start_expr_;
|
||||
}
|
||||
@@ -1423,6 +1426,9 @@ IntExpr* IntervalVar::DurationExpr() {
|
||||
solver()->SaveValue(reinterpret_cast<void**>(&duration_expr_));
|
||||
duration_expr_ = solver()->RegisterIntExpr(
|
||||
solver()->RevAlloc(new IntervalVarDurationExpr(this)));
|
||||
if (HasName()) {
|
||||
duration_expr_->set_name(StringPrintf("duration(%s)", name().c_str()));
|
||||
}
|
||||
}
|
||||
return duration_expr_;
|
||||
}
|
||||
@@ -1432,6 +1438,9 @@ IntExpr* IntervalVar::EndExpr() {
|
||||
solver()->SaveValue(reinterpret_cast<void**>(&end_expr_));
|
||||
end_expr_ = solver()->RegisterIntExpr(
|
||||
solver()->RevAlloc(new IntervalVarEndExpr(this)));
|
||||
if (HasName()) {
|
||||
end_expr_->set_name(StringPrintf("end(%s)", name().c_str()));
|
||||
}
|
||||
}
|
||||
return end_expr_;
|
||||
}
|
||||
@@ -1441,6 +1450,9 @@ IntExpr* IntervalVar::PerformedExpr() {
|
||||
solver()->SaveValue(reinterpret_cast<void**>(&performed_expr_));
|
||||
performed_expr_ = solver()->RegisterIntExpr(
|
||||
solver()->RevAlloc(new IntervalVarPerformedExpr(this)));
|
||||
if (HasName()) {
|
||||
performed_expr_->set_name(StringPrintf("performed(%s)", name().c_str()));
|
||||
}
|
||||
}
|
||||
return performed_expr_;
|
||||
}
|
||||
|
||||
@@ -54,69 +54,6 @@ template<class T> bool IsEqual(ConstPtrArray<T>* const a1,
|
||||
return a1->Equals(*a2);
|
||||
}
|
||||
|
||||
uint64 Hash1(uint64 value) {
|
||||
value = (~value) + (value << 21); // value = (value << 21) - value - 1;
|
||||
value = value ^ (value >> 24);
|
||||
value = (value + (value << 3)) + (value << 8); // value * 265
|
||||
value = value ^ (value >> 14);
|
||||
value = (value + (value << 2)) + (value << 4); // value * 21
|
||||
value = value ^ (value >> 28);
|
||||
value = value + (value << 31);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint64 Hash1(uint32 value) {
|
||||
uint64 a = value;
|
||||
a = (a + 0x7ed55d16) + (a << 12);
|
||||
a = (a ^ 0xc761c23c) ^ (a >> 19);
|
||||
a = (a + 0x165667b1) + (a << 5);
|
||||
a = (a + 0xd3a2646c) ^ (a << 9);
|
||||
a = (a + 0xfd7046c5) + (a << 3);
|
||||
a = (a ^ 0xb55a4f09) ^ (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
uint64 Hash1(int64 value) {
|
||||
return Hash1(static_cast<uint64>(value));
|
||||
}
|
||||
|
||||
uint64 Hash1(void* const ptr) {
|
||||
#if defined(ARCH_K8)
|
||||
return Hash1(reinterpret_cast<uint64>(ptr));
|
||||
#else
|
||||
return Hash1(reinterpret_cast<uint32>(ptr));
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64 Hash1(ConstIntArray* const values) {
|
||||
if (values->size() == 0) {
|
||||
return 0;
|
||||
} else if (values->size() == 1) {
|
||||
return Hash1(values->get(0));
|
||||
} else {
|
||||
uint64 hash = Hash1(values->get(0));
|
||||
for (int i = 1; i < values->size(); ++i) {
|
||||
hash = hash * i + Hash1(values->get(i));
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
uint64 Hash1(ConstPtrArray<T>* const ptrs) {
|
||||
if (ptrs->size() == 0) {
|
||||
return 0;
|
||||
} else if (ptrs->size() == 1) {
|
||||
return Hash1(ptrs->get(0));
|
||||
} else {
|
||||
uint64 hash = Hash1(ptrs->get(0));
|
||||
for (int i = 1; i < ptrs->size(); ++i) {
|
||||
hash = hash * i + Hash1(ptrs->get(i));
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
template <class A1, class A2> uint64 Hash2(const A1& a1, const A2& a2) {
|
||||
uint64 a = Hash1(a1);
|
||||
uint64 b = GG_ULONGLONG(0xe08c1d668b756f82); // more of the golden ratio
|
||||
|
||||
@@ -117,6 +117,177 @@ template<> size_t hash_value<operations_research::RoutingModel::NodeIndex>(
|
||||
|
||||
namespace operations_research {
|
||||
|
||||
// Pair-based neighborhood operators, designed to move nodes by pairs (pairs
|
||||
// are static and given). These neighborhoods are very useful for Pickup and
|
||||
// Delivery problems where pickup and delivery nodes must remain on the same
|
||||
// route.
|
||||
// TODO(user): Add option to prune neighbords where the order of node pairs
|
||||
// is violated (ie precedence between pickup and delivery nodes).
|
||||
// TODO(user): Move this to local_search.cc if it's generic enough.
|
||||
// TODO(user): Detect pairs automatically by parsing the constraint model;
|
||||
// we could then get rid of the pair API in the RoutingModel
|
||||
// class.
|
||||
|
||||
// Operator which inserts pairs of inactive nodes into a path.
|
||||
// Possible neighbors for the path 1 -> 2 -> 3 with pair (A, B) inactive
|
||||
// (where 1 and 3 are first and last nodes of the path) are:
|
||||
// 1 -> [A] -> [B] -> 2 -> 3
|
||||
// 1 -> [B] -> 2 -> [A] -> 3
|
||||
// 1 -> [A] -> 2 -> [B] -> 3
|
||||
// 1 -> 2 -> [A] -> [B] -> 3
|
||||
// Note that this operator does not expicitely insert the nodes of a pair one
|
||||
// after the other which forbids the following solutions:
|
||||
// 1 -> [B] -> [A] -> 2 -> 3
|
||||
// 1 -> 2 -> [B] -> [A] -> 3
|
||||
// which can only be obtained by inserting A after B.
|
||||
class MakePairActiveOperator : public PathOperator {
|
||||
public:
|
||||
MakePairActiveOperator(const IntVar* const* vars,
|
||||
const IntVar* const* secondary_vars,
|
||||
const RoutingModel::NodePairs& pairs,
|
||||
int size)
|
||||
: PathOperator(vars, secondary_vars, size, 2),
|
||||
inactive_pair_(0),
|
||||
pairs_(pairs) {}
|
||||
virtual ~MakePairActiveOperator() {}
|
||||
virtual bool MakeNextNeighbor(Assignment* delta, Assignment* deltadelta);
|
||||
virtual bool MakeNeighbor();
|
||||
|
||||
private:
|
||||
virtual void OnNodeInitialization();
|
||||
|
||||
int inactive_pair_;
|
||||
RoutingModel::NodePairs pairs_;
|
||||
};
|
||||
|
||||
void MakePairActiveOperator::OnNodeInitialization() {
|
||||
for (int i = 0; i < pairs_.size(); ++i) {
|
||||
if (IsInactive(pairs_[i].first) && IsInactive(pairs_[i].second)) {
|
||||
inactive_pair_ = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
inactive_pair_ = pairs_.size();
|
||||
}
|
||||
|
||||
bool MakePairActiveOperator::MakeNextNeighbor(Assignment* delta,
|
||||
Assignment* deltadelta) {
|
||||
while (inactive_pair_ < pairs_.size()) {
|
||||
if (!IsInactive(pairs_[inactive_pair_].first)
|
||||
|| !IsInactive(pairs_[inactive_pair_].second)
|
||||
|| !PathOperator::MakeNextNeighbor(delta, deltadelta)) {
|
||||
ResetPosition();
|
||||
++inactive_pair_;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MakePairActiveOperator::MakeNeighbor() {
|
||||
if (StartNode(0) != StartNode(1)) {
|
||||
return false;
|
||||
}
|
||||
// Inserting the second node of the pair before the first one which ensures
|
||||
// that the only solutions where both nodes are next to each other have the
|
||||
// first node before the second (the move is not symmetric and doing it this
|
||||
// way ensures that a potential precedence constraint between the nodes of the
|
||||
// pair is not violated).
|
||||
return MakeActive(pairs_[inactive_pair_].second, BaseNode(1))
|
||||
&& MakeActive(pairs_[inactive_pair_].first, BaseNode(0));
|
||||
}
|
||||
|
||||
LocalSearchOperator* MakePairActive(Solver* const solver,
|
||||
const IntVar* const* vars,
|
||||
const IntVar* const* secondary_vars,
|
||||
const RoutingModel::NodePairs& pairs,
|
||||
int size) {
|
||||
return solver->RevAlloc(new MakePairActiveOperator(vars,
|
||||
secondary_vars,
|
||||
pairs,
|
||||
size));
|
||||
}
|
||||
|
||||
// Operator which moves a pair of nodes to another position.
|
||||
// Possible neighbors for the path 1 -> A -> B -> 2 -> 3 (where (1, 3) are
|
||||
// first and last nodes of the path and can therefore not be moved, and (A, B)
|
||||
// is a pair of nodes):
|
||||
// 1 -> [A] -> 2 -> [B] -> 3
|
||||
// 1 -> 2 -> [A] -> [B] -> 3
|
||||
// 1 -> [B] -> [A] -> 2 -> 3
|
||||
// 1 -> [B] -> 2 -> [A] -> 3
|
||||
// 1 -> 2 -> [B] -> [A] -> 3
|
||||
class MakePairRelocateOperator : public PathOperator {
|
||||
public:
|
||||
MakePairRelocateOperator(const IntVar* const* vars,
|
||||
const IntVar* const* secondary_vars,
|
||||
const RoutingModel::NodePairs& pairs,
|
||||
int size)
|
||||
: PathOperator(vars, secondary_vars, size, 3) {
|
||||
int64 index_max = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
index_max = std::max(index_max, vars[i]->Max());
|
||||
}
|
||||
prevs_.resize(index_max + 1, -1);
|
||||
int max_pair_index = -1;
|
||||
for (int i = 0; i < pairs.size(); ++i) {
|
||||
max_pair_index = std::max(max_pair_index, pairs[i].first);
|
||||
max_pair_index = std::max(max_pair_index, pairs[i].second);
|
||||
}
|
||||
pairs_.resize(max_pair_index + 1, -1);
|
||||
for (int i = 0; i < pairs.size(); ++i) {
|
||||
pairs_[pairs[i].first] = pairs[i].second;
|
||||
pairs_[pairs[i].second] = pairs[i].first;
|
||||
}
|
||||
}
|
||||
virtual ~MakePairRelocateOperator() {}
|
||||
virtual bool MakeNeighbor();
|
||||
|
||||
private:
|
||||
virtual void OnNodeInitialization();
|
||||
|
||||
std::vector<int> pairs_;
|
||||
std::vector<int> prevs_;
|
||||
};
|
||||
|
||||
bool MakePairRelocateOperator::MakeNeighbor() {
|
||||
if (StartNode(1) != StartNode(2)) {
|
||||
return false;
|
||||
}
|
||||
const int64 prev = prevs_[BaseNode(0)];
|
||||
if (prev < 0) {
|
||||
return false;
|
||||
}
|
||||
const int sibling = BaseNode(0) < pairs_.size() ? pairs_[BaseNode(0)] : -1;
|
||||
if (sibling < 0) {
|
||||
return false;
|
||||
}
|
||||
const int64 prev_sibling = prevs_[sibling];
|
||||
if (prev_sibling < 0) {
|
||||
return false;
|
||||
}
|
||||
return MoveChain(prev_sibling, sibling, BaseNode(1))
|
||||
&& MoveChain(prev, BaseNode(0), BaseNode(2));
|
||||
}
|
||||
|
||||
void MakePairRelocateOperator::OnNodeInitialization() {
|
||||
for (int i = 0; i < Size(); ++i) {
|
||||
prevs_[Next(i)] = i;
|
||||
}
|
||||
}
|
||||
|
||||
LocalSearchOperator* MakePairRelocate(Solver* const solver,
|
||||
const IntVar* const* vars,
|
||||
const IntVar* const* secondary_vars,
|
||||
const RoutingModel::NodePairs& pairs,
|
||||
int size) {
|
||||
return solver->RevAlloc(new MakePairRelocateOperator(vars,
|
||||
secondary_vars,
|
||||
pairs,
|
||||
size));
|
||||
}
|
||||
|
||||
// Cached callbacks
|
||||
|
||||
class RoutingCache {
|
||||
@@ -842,6 +1013,27 @@ void RoutingModel::CloseModel() {
|
||||
SetUpSearch();
|
||||
}
|
||||
|
||||
// Decision builder to build a solution with all nodes inactive. It does no
|
||||
// branching and may fail if some nodes cannot be made inactive.
|
||||
|
||||
class AllUnperformed : public DecisionBuilder {
|
||||
public:
|
||||
// Does not take ownership of model.
|
||||
explicit AllUnperformed(RoutingModel* const model) : model_(model) {}
|
||||
virtual ~AllUnperformed() {}
|
||||
virtual Decision* Next(Solver* const solver) {
|
||||
for (int i = 0; i < model_->Size(); ++i) {
|
||||
if (!model_->IsStart(i)) {
|
||||
model_->ActiveVar(i)->SetValue(0);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
RoutingModel* const model_;
|
||||
};
|
||||
|
||||
// Flags override strategy selection
|
||||
RoutingModel::RoutingStrategy
|
||||
RoutingModel::GetSelectedFirstSolutionStrategy() const {
|
||||
@@ -851,6 +1043,8 @@ RoutingModel::GetSelectedFirstSolutionStrategy() const {
|
||||
return ROUTING_LOCAL_CHEAPEST_ARC;
|
||||
} else if (FLAGS_routing_first_solution.compare("PathCheapestArc") == 0) {
|
||||
return ROUTING_PATH_CHEAPEST_ARC;
|
||||
} else if (FLAGS_routing_first_solution.compare("AllUnperformed") == 0) {
|
||||
return ROUTING_ALL_UNPERFORMED;
|
||||
}
|
||||
return first_solution_strategy_;
|
||||
}
|
||||
@@ -1628,6 +1822,20 @@ void RoutingModel::SetUpSearch() {
|
||||
kint64max);
|
||||
|
||||
std::vector<LocalSearchOperator*> operators = extra_operators_;
|
||||
if (pickup_delivery_pairs_.size() > 0) {
|
||||
const IntVar* const* vehicle_vars =
|
||||
homogeneous_costs_ ? NULL : vehicle_vars_.get();
|
||||
operators.push_back(MakePairActive(solver_.get(),
|
||||
nexts_.get(),
|
||||
vehicle_vars,
|
||||
pickup_delivery_pairs_,
|
||||
size));
|
||||
operators.push_back(MakePairRelocate(solver_.get(),
|
||||
nexts_.get(),
|
||||
vehicle_vars,
|
||||
pickup_delivery_pairs_,
|
||||
size));
|
||||
}
|
||||
if (vehicles_ > 1) {
|
||||
if (!FLAGS_routing_no_relocate) {
|
||||
CP_ROUTING_PUSH_BACK_OPERATOR(Solver::RELOCATE);
|
||||
@@ -1676,6 +1884,7 @@ void RoutingModel::SetUpSearch() {
|
||||
CP_ROUTING_PUSH_BACK_OPERATOR(Solver::UNACTIVELNS);
|
||||
}
|
||||
}
|
||||
|
||||
LocalSearchOperator* local_search_operator =
|
||||
solver_->ConcatenateOperators(operators);
|
||||
|
||||
@@ -1726,6 +1935,10 @@ void RoutingModel::SetUpSearch() {
|
||||
case ROUTING_DEFAULT_STRATEGY:
|
||||
LG << "Using DEFAULT";
|
||||
break;
|
||||
case ROUTING_ALL_UNPERFORMED:
|
||||
first_solution =
|
||||
solver_->RevAlloc(new AllUnperformed(this));
|
||||
break;
|
||||
default:
|
||||
LOG(WARNING) << "Unknown argument for routing_first_solution, "
|
||||
"using default";
|
||||
@@ -1876,7 +2089,7 @@ IntVar** RoutingModel::GetOrMakeCumuls(int64 capacity, const string& name) {
|
||||
std::vector<IntVar*> cumuls;
|
||||
const int size = Size() + vehicles_;
|
||||
solver_->MakeIntVarArray(size, 0LL, capacity, name, &cumuls);
|
||||
IntVar** cumul_array = solver_->RevAlloc(new IntVar*[size]);
|
||||
IntVar** cumul_array = solver_->RevAllocArray(new IntVar*[size]);
|
||||
memcpy(cumul_array, cumuls.data(), cumuls.size() * sizeof(*cumuls.data()));
|
||||
cumuls_[name] = cumul_array;
|
||||
return cumul_array;
|
||||
@@ -1899,7 +2112,7 @@ IntVar** RoutingModel::GetOrMakeTransits(NodeEvaluator2* evaluator,
|
||||
if (named_transits == NULL) {
|
||||
std::vector<IntVar*> transits;
|
||||
const int size = Size();
|
||||
IntVar** transit_array = solver_->RevAlloc(new IntVar*[size]);
|
||||
IntVar** transit_array = solver_->RevAllocArray(new IntVar*[size]);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
IntVar* fixed_transit =
|
||||
solver_->MakeElement(NewPermanentCallback(
|
||||
@@ -1914,7 +2127,7 @@ IntVar** RoutingModel::GetOrMakeTransits(NodeEvaluator2* evaluator,
|
||||
IntVar* slack_var = solver_->MakeIntVar(0, slack_max, "slack");
|
||||
transit_array[i] = solver_->MakeSum(slack_var, fixed_transit)->Var();
|
||||
}
|
||||
transit_array[i]->SetMin(0);
|
||||
transit_array[i]->SetMin(-capacity);
|
||||
transit_array[i]->SetMax(capacity);
|
||||
}
|
||||
transits_[name] = transit_array;
|
||||
|
||||
@@ -179,31 +179,61 @@ class RoutingModel {
|
||||
public:
|
||||
// First solution strategies, used as starting point of local search.
|
||||
enum RoutingStrategy {
|
||||
ROUTING_DEFAULT_STRATEGY, // choose first unbound, assign min value
|
||||
// Select the first node with an unbound successor and connect it to the
|
||||
// first available node.
|
||||
// This is equivalent to the CHOOSE_FIRST_UNBOUND strategy combined with
|
||||
// ASSIGN_MIN_VALUE (cf. constraint_soler.h).
|
||||
ROUTING_DEFAULT_STRATEGY,
|
||||
// Iteratively connect two nodes which produce the cheapest route segment.
|
||||
ROUTING_GLOBAL_CHEAPEST_ARC,
|
||||
// Select the first node with an unbound successor and connect it to the
|
||||
// node which produces the cheapest route segment.
|
||||
ROUTING_LOCAL_CHEAPEST_ARC,
|
||||
// Starting from a route "start" node, connect it to the node which produces
|
||||
// the cheapest route segment, then extend the route by iterating on the
|
||||
// last node added to the route.
|
||||
ROUTING_PATH_CHEAPEST_ARC,
|
||||
ROUTING_EVALUATOR_STRATEGY
|
||||
// Same as ROUTING_PATH_CHEAPEST_ARC, except that arc costs are evaluated
|
||||
// using the function passed to RoutingModel::SetFirstSolutionEvaluator().
|
||||
ROUTING_EVALUATOR_STRATEGY,
|
||||
// Make all node inactive. Only finds a solution if nodes are optional (are
|
||||
// element of a disjunction constraint with a finite penalty cost).
|
||||
ROUTING_ALL_UNPERFORMED
|
||||
};
|
||||
|
||||
// Metaheuristics, to escape local minima.
|
||||
// Metaheuristics used to guide the search. Apart greedy descent, they will
|
||||
// try to escape local minima.
|
||||
enum RoutingMetaheuristic {
|
||||
ROUTING_GREEDY_DESCENT, // default
|
||||
// Accepts improving (cost-reducing) local search neighbors until a local
|
||||
// minimum is reached. This is the default heuristic.
|
||||
ROUTING_GREEDY_DESCENT,
|
||||
// Uses guided local search to escape local minima
|
||||
// (cf. http://en.wikipedia.org/wiki/Guided_Local_Search); this is
|
||||
// generally the most efficient metaheuristic for vehicle routing.
|
||||
ROUTING_GUIDED_LOCAL_SEARCH,
|
||||
// Uses simulated annealing to escape local minima
|
||||
// (cf. http://en.wikipedia.org/wiki/Simulated_annealing).
|
||||
ROUTING_SIMULATED_ANNEALING,
|
||||
// Uses tabu search to escape local minima
|
||||
// (cf. http://en.wikipedia.org/wiki/Tabu_search).
|
||||
ROUTING_TABU_SEARCH
|
||||
};
|
||||
|
||||
// Status of the search.
|
||||
enum Status {
|
||||
// Problem not solved yet (before calling RoutingModel::Solve()).
|
||||
ROUTING_NOT_SOLVED,
|
||||
// Problem solved successfully after calling RoutingModel::Solve().
|
||||
ROUTING_SUCCESS,
|
||||
// No solution found to the problem after calling RoutingModel::Solve().
|
||||
ROUTING_FAIL,
|
||||
// Time limit reached before finding a solution with RoutingModel::Solve().
|
||||
ROUTING_FAIL_TIMEOUT
|
||||
};
|
||||
|
||||
typedef _RoutingModel_NodeIndex NodeIndex;
|
||||
typedef ResultCallback2<int64, NodeIndex, NodeIndex> NodeEvaluator2;
|
||||
typedef std::vector<pair<int, int> > NodePairs;
|
||||
|
||||
// Constants with an index of the first node (to be used in for loops for
|
||||
// iteration), and a special index to signalize an invalid/unused value.
|
||||
@@ -292,6 +322,23 @@ class RoutingModel {
|
||||
AddDisjunction(nodes, penalty);
|
||||
}
|
||||
#endif // SWIGPYTHON
|
||||
// Notifies that node1 and node2 form a pair of nodes which should belong
|
||||
// to the same route. This methods helps the search find better solutions,
|
||||
// especially in the local search phase.
|
||||
// It should be called each time you have an equality constraint linking
|
||||
// the vehicle variables of two node (including for instance pickup and
|
||||
// delivery problems):
|
||||
// Solver* const solver = routing.solver();
|
||||
// solver->AddConstraint(solver->MakeEquality(
|
||||
// routing.VehicleVar(routing.NodeToIndex(node1)),
|
||||
// routing.VehicleVar(routing.NodeToIndex(node2))));
|
||||
// solver->AddPickupAndDelivery(node1, node2);
|
||||
//
|
||||
// TODO(user): Remove this when model introspection detects linked nodes.
|
||||
void AddPickupAndDelivery(NodeIndex node1, NodeIndex node2) {
|
||||
pickup_delivery_pairs_.push_back(std::make_pair(NodeToIndex(node1),
|
||||
NodeToIndex(node2)));
|
||||
}
|
||||
// Makes 'depot' the starting node of all routes.
|
||||
void SetDepot(NodeIndex depot);
|
||||
// Sets the cost function of the model such that the cost of a segment of a
|
||||
@@ -619,6 +666,7 @@ class RoutingModel {
|
||||
std::vector<RoutingCache*> routing_caches_;
|
||||
std::vector<Disjunction> disjunctions_;
|
||||
hash_map<int64, int> node_to_disjunction_;
|
||||
NodePairs pickup_delivery_pairs_;
|
||||
IntVar* cost_;
|
||||
std::vector<int64> fixed_costs_;
|
||||
int nodes_;
|
||||
|
||||
@@ -567,7 +567,7 @@ class CompactPositiveTableConstraint : public BasePositiveTableConstraint {
|
||||
DCHECK_LT(value_index, masks_[var_index].size());
|
||||
uint64* mask = masks_[var_index][value_index];
|
||||
if (!mask) {
|
||||
mask = solver()->RevAlloc(new uint64[length_]);
|
||||
mask = solver()->RevAllocArray(new uint64[length_]);
|
||||
memset(mask, 0, length_ * sizeof(*mask));
|
||||
masks_[var_index][value_index] = mask;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class TraceIntVar : public IntVar {
|
||||
|
||||
virtual void SetMin(int64 m) {
|
||||
if (m > inner_->Min()) {
|
||||
LOG(INFO) << "SetMin(" << inner_->DebugString() << ", " << m << ")";
|
||||
solver()->GetPropagationMonitor()->SetMin(inner_, m);
|
||||
inner_->SetMin(m);
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ class TraceIntVar : public IntVar {
|
||||
|
||||
virtual void SetMax(int64 m) {
|
||||
if (m < inner_->Max()) {
|
||||
LOG(INFO) << "SetMax(" << inner_->DebugString() << ", " << m << ")";
|
||||
solver()->GetPropagationMonitor()->SetMax(inner_, m);
|
||||
inner_->SetMax(m);
|
||||
}
|
||||
}
|
||||
@@ -68,8 +68,7 @@ class TraceIntVar : public IntVar {
|
||||
|
||||
virtual void SetRange(int64 l, int64 u) {
|
||||
if (l > inner_->Min() || u < inner_->Max()) {
|
||||
LOG(INFO) << "SetRange(" << inner_->DebugString() << ", ["
|
||||
<< l << ".." << u << "])";
|
||||
solver()->GetPropagationMonitor()->SetRange(inner_, l, u);
|
||||
inner_->SetRange(l, u);
|
||||
}
|
||||
}
|
||||
@@ -88,31 +87,28 @@ class TraceIntVar : public IntVar {
|
||||
|
||||
virtual void RemoveValue(int64 v) {
|
||||
if (inner_->Contains(v)) {
|
||||
LOG(INFO) << "RemoveValue(" << inner_->DebugString() << ", " << v << ")";
|
||||
solver()->GetPropagationMonitor()->RemoveValue(inner_, v);
|
||||
inner_->RemoveValue(v);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetValue(int64 v) {
|
||||
LOG(INFO) << "SetValue(" << inner_->DebugString() << ", " << v << ")";
|
||||
solver()->GetPropagationMonitor()->SetValue(inner_, v);
|
||||
inner_->SetValue(v);
|
||||
}
|
||||
|
||||
virtual void RemoveInterval(int64 l, int64 u) {
|
||||
LOG(INFO) << "RemoveInterval(" << inner_->DebugString() << ", ["
|
||||
<< l << ".." << u << "])";
|
||||
solver()->GetPropagationMonitor()->RemoveInterval(inner_, l, u);
|
||||
inner_->RemoveInterval(l, u);
|
||||
}
|
||||
|
||||
virtual void RemoveValues(const int64* const values, int size) {
|
||||
LOG(INFO) << "RemoveValues(" << inner_->DebugString() << ", ["
|
||||
<< Int64ArrayToString(values, size, ", ") << "])";
|
||||
solver()->GetPropagationMonitor()->RemoveValues(inner_, values, size);
|
||||
inner_->RemoveValues(values, size);
|
||||
}
|
||||
|
||||
virtual void SetValues(const int64* const values, int size) {
|
||||
LOG(INFO) << "SetValues(" << inner_->DebugString() << ", ["
|
||||
<< Int64ArrayToString(values, size, ", ") << "])";
|
||||
solver()->GetPropagationMonitor()->SetValues(inner_, values, size);
|
||||
inner_->SetValues(values, size);
|
||||
}
|
||||
|
||||
@@ -184,14 +180,14 @@ class TraceIntExpr : public IntExpr {
|
||||
virtual int64 Min() const { return inner_->Min(); }
|
||||
|
||||
virtual void SetMin(int64 m) {
|
||||
LOG(INFO) << "SetMin(" << inner_->DebugString() << ", " << m << ")";
|
||||
solver()->GetPropagationMonitor()->SetMin(inner_, m);
|
||||
inner_->SetMin(m);
|
||||
}
|
||||
|
||||
virtual int64 Max() const { return inner_->Max(); }
|
||||
|
||||
virtual void SetMax(int64 m) {
|
||||
LOG(INFO) << "SetMax(" << inner_->DebugString() << ", " << m << ")";
|
||||
solver()->GetPropagationMonitor()->SetMax(inner_, m);
|
||||
inner_->SetMax(m);
|
||||
}
|
||||
|
||||
@@ -201,8 +197,7 @@ class TraceIntExpr : public IntExpr {
|
||||
|
||||
virtual void SetRange(int64 l, int64 u) {
|
||||
if (l > inner_->Min() || u < inner_->Max()) {
|
||||
LOG(INFO) << "SetRange(" << inner_->DebugString() << ", ["
|
||||
<< l << ".." << u << "])";
|
||||
solver()->GetPropagationMonitor()->SetRange(inner_, l, u);
|
||||
inner_->SetRange(l, u);
|
||||
}
|
||||
}
|
||||
@@ -238,168 +233,160 @@ class TraceIntExpr : public IntExpr {
|
||||
|
||||
class TraceIntervalVar : public IntervalVar {
|
||||
public:
|
||||
TraceIntervalVar(Solver* const solver, IntervalVar* const interval)
|
||||
: IntervalVar(solver, ""), interval_(interval) {
|
||||
if (interval->HasName()) {
|
||||
set_name(interval->name());
|
||||
TraceIntervalVar(Solver* const solver, IntervalVar* const inner)
|
||||
: IntervalVar(solver, ""), inner_(inner) {
|
||||
if (inner->HasName()) {
|
||||
set_name(inner->name());
|
||||
}
|
||||
}
|
||||
virtual ~TraceIntervalVar() {}
|
||||
|
||||
virtual int64 StartMin() const {
|
||||
return interval_->StartMin();
|
||||
return inner_->StartMin();
|
||||
}
|
||||
|
||||
virtual int64 StartMax() const {
|
||||
return interval_->StartMax();
|
||||
return inner_->StartMax();
|
||||
}
|
||||
|
||||
virtual void SetStartMin(int64 m) {
|
||||
if (m > interval_->StartMin()) {
|
||||
LOG(INFO) << "SetStartMin(" << interval_->DebugString() << ", "
|
||||
<< m << ")";
|
||||
interval_->SetStartMin(m);
|
||||
if (m > inner_->StartMin()) {
|
||||
solver()->GetPropagationMonitor()->SetStartMin(inner_, m);
|
||||
inner_->SetStartMin(m);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetStartMax(int64 m) {
|
||||
if (m < interval_->StartMax()) {
|
||||
LOG(INFO) << "SetStartMax(" << interval_->DebugString() << ", "
|
||||
<< m << ")";
|
||||
interval_->SetStartMax(m);
|
||||
if (m < inner_->StartMax()) {
|
||||
solver()->GetPropagationMonitor()->SetStartMax(inner_, m);
|
||||
inner_->SetStartMax(m);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetStartRange(int64 mi, int64 ma) {
|
||||
if (mi > interval_->StartMin() || ma < interval_->StartMax()) {
|
||||
LOG(INFO) << "SetStartRange(" << interval_->DebugString() << ", ["
|
||||
<< mi << ".." << ma << "])";
|
||||
interval_->SetStartRange(mi, ma);
|
||||
if (mi > inner_->StartMin() || ma < inner_->StartMax()) {
|
||||
solver()->GetPropagationMonitor()->SetStartRange(inner_, mi, ma);
|
||||
inner_->SetStartRange(mi, ma);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void WhenStartRange(Demon* const d) {
|
||||
interval_->WhenStartRange(d);
|
||||
inner_->WhenStartRange(d);
|
||||
}
|
||||
|
||||
virtual void WhenStartBound(Demon* const d) {
|
||||
interval_->WhenStartBound(d);
|
||||
inner_->WhenStartBound(d);
|
||||
}
|
||||
|
||||
virtual int64 EndMin() const {
|
||||
return interval_->EndMin();
|
||||
return inner_->EndMin();
|
||||
}
|
||||
|
||||
virtual int64 EndMax() const {
|
||||
return interval_->EndMax();
|
||||
return inner_->EndMax();
|
||||
}
|
||||
|
||||
virtual void SetEndMin(int64 m) {
|
||||
if (m > interval_->EndMin()) {
|
||||
LOG(INFO) << "SetEndMin(" << interval_->DebugString() << ", " << m << ")";
|
||||
interval_->SetEndMin(m);
|
||||
if (m > inner_->EndMin()) {
|
||||
solver()->GetPropagationMonitor()->SetEndMin(inner_, m);
|
||||
inner_->SetEndMin(m);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetEndMax(int64 m) {
|
||||
if (m < interval_->EndMax()) {
|
||||
LOG(INFO) << "SetEndMax(" << interval_->DebugString() << ", " << m << ")";
|
||||
interval_->SetEndMax(m);
|
||||
if (m < inner_->EndMax()) {
|
||||
solver()->GetPropagationMonitor()->SetEndMax(inner_, m);
|
||||
inner_->SetEndMax(m);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetEndRange(int64 mi, int64 ma) {
|
||||
if (mi > interval_->EndMin() || ma < interval_->EndMax()) {
|
||||
LOG(INFO) << "SetEndRange(" << interval_->DebugString() << ", ["
|
||||
<< mi << ".." << ma << "])";
|
||||
interval_->SetEndRange(mi, ma);
|
||||
if (mi > inner_->EndMin() || ma < inner_->EndMax()) {
|
||||
solver()->GetPropagationMonitor()->SetEndRange(inner_, mi, ma);
|
||||
inner_->SetEndRange(mi, ma);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void WhenEndRange(Demon* const d) {
|
||||
interval_->WhenEndRange(d);
|
||||
inner_->WhenEndRange(d);
|
||||
}
|
||||
|
||||
virtual void WhenEndBound(Demon* const d) {
|
||||
interval_->WhenStartBound(d);
|
||||
inner_->WhenStartBound(d);
|
||||
}
|
||||
|
||||
virtual int64 DurationMin() const {
|
||||
return interval_->DurationMin();
|
||||
return inner_->DurationMin();
|
||||
}
|
||||
|
||||
virtual int64 DurationMax() const {
|
||||
return interval_->DurationMax();
|
||||
return inner_->DurationMax();
|
||||
}
|
||||
|
||||
virtual void SetDurationMin(int64 m) {
|
||||
if (m > interval_->DurationMin()) {
|
||||
LOG(INFO) << "SetDurationMin(" << interval_->DebugString() << ", "
|
||||
<< m << ")";
|
||||
interval_->SetDurationMin(m);
|
||||
if (m > inner_->DurationMin()) {
|
||||
solver()->GetPropagationMonitor()->SetDurationMin(inner_, m);
|
||||
inner_->SetDurationMin(m);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetDurationMax(int64 m) {
|
||||
if (m < interval_->DurationMax()) {
|
||||
LOG(INFO) << "SetDurationMax(" << interval_->DebugString() << ", "
|
||||
<< m << ")";
|
||||
interval_->SetDurationMax(m);
|
||||
if (m < inner_->DurationMax()) {
|
||||
solver()->GetPropagationMonitor()->SetDurationMax(inner_, m);
|
||||
inner_->SetDurationMax(m);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetDurationRange(int64 mi, int64 ma) {
|
||||
if (mi > interval_->DurationMin() || ma < interval_->DurationMax()) {
|
||||
LOG(INFO) << "SetDurationRange(" << interval_->DebugString() << ", ["
|
||||
<< mi << ".." << ma << "])";
|
||||
interval_->SetDurationRange(mi, ma);
|
||||
if (mi > inner_->DurationMin() || ma < inner_->DurationMax()) {
|
||||
solver()->GetPropagationMonitor()->SetDurationRange(inner_, mi, ma);
|
||||
inner_->SetDurationRange(mi, ma);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void WhenDurationRange(Demon* const d) {
|
||||
interval_->WhenDurationRange(d);
|
||||
inner_->WhenDurationRange(d);
|
||||
}
|
||||
|
||||
virtual void WhenDurationBound(Demon* const d) {
|
||||
interval_->WhenDurationBound(d);
|
||||
inner_->WhenDurationBound(d);
|
||||
}
|
||||
|
||||
virtual bool MustBePerformed() const {
|
||||
return interval_->MustBePerformed();
|
||||
return inner_->MustBePerformed();
|
||||
}
|
||||
|
||||
virtual bool MayBePerformed() const {
|
||||
return interval_->MayBePerformed();
|
||||
return inner_->MayBePerformed();
|
||||
}
|
||||
|
||||
virtual void SetPerformed(bool val) {
|
||||
if ((val && !interval_->MustBePerformed()) ||
|
||||
(!val && interval_->MayBePerformed())) {
|
||||
LOG(INFO) << "SetPerformed(" << interval_->DebugString() << ", "
|
||||
<< val << ")";
|
||||
interval_->SetPerformed(val);
|
||||
virtual void SetPerformed(bool value) {
|
||||
if ((value && !inner_->MustBePerformed()) ||
|
||||
(!value && inner_->MayBePerformed())) {
|
||||
solver()->GetPropagationMonitor()->SetPerformed(inner_, value);
|
||||
inner_->SetPerformed(value);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void WhenPerformedBound(Demon* const d) {
|
||||
interval_->WhenPerformedBound(d);
|
||||
inner_->WhenPerformedBound(d);
|
||||
}
|
||||
|
||||
virtual void Accept(ModelVisitor* const visitor) const {
|
||||
interval_->Accept(visitor);
|
||||
inner_->Accept(visitor);
|
||||
}
|
||||
|
||||
private:
|
||||
IntervalVar* const interval_;
|
||||
IntervalVar* const inner_;
|
||||
};
|
||||
|
||||
// ---------- Trace ----------
|
||||
|
||||
class Trace : public PropagationMonitor {
|
||||
public:
|
||||
virtual void StartInitialPropagation() {
|
||||
virtual void BeginInitialPropagation() {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->StartInitialPropagation();
|
||||
monitors_[i]->BeginInitialPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,10 +396,10 @@ class Trace : public PropagationMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void StartConstraintInitialPropagation(
|
||||
virtual void BeginConstraintInitialPropagation(
|
||||
const Constraint* const constraint) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->StartConstraintInitialPropagation(constraint);
|
||||
monitors_[i]->BeginConstraintInitialPropagation(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,11 +410,11 @@ class Trace : public PropagationMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void StartNestedConstraintInitialPropagation(
|
||||
virtual void BeginNestedConstraintInitialPropagation(
|
||||
const Constraint* const parent,
|
||||
const Constraint* const nested) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->StartNestedConstraintInitialPropagation(parent, nested);
|
||||
monitors_[i]->BeginNestedConstraintInitialPropagation(parent, nested);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,9 +432,9 @@ class Trace : public PropagationMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void StartDemonRun(const Demon* const demon) {
|
||||
virtual void BeginDemonRun(const Demon* const demon) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->StartDemonRun(demon);
|
||||
monitors_[i]->BeginDemonRun(demon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,6 +450,30 @@ class Trace : public PropagationMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void FindSolution() {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->FindSolution();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void ApplyDecision(Decision* const decision) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->ApplyDecision(decision);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void RefuteDecision(Decision* const decision) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->RefuteDecision(decision);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void AfterDecision(Decision* const decision) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->AfterDecision(decision);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void EnterSearch() {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->EnterSearch();
|
||||
@@ -481,6 +492,145 @@ class Trace : public PropagationMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
// IntExpr modifiers.
|
||||
virtual void SetMin(IntExpr* const expr, int64 new_min) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetMin(expr, new_min);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetMax(IntExpr* const expr, int64 new_max) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetMax(expr, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetRange(IntExpr* const expr, int64 new_min, int64 new_max) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetRange(expr, new_min, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
// IntVar modifiers.
|
||||
virtual void SetMin(IntVar* const var, int64 new_min) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetMin(var, new_min);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetMax(IntVar* const var, int64 new_max) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetMax(var, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetRange(IntVar* const var, int64 new_min, int64 new_max) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetRange(var, new_min, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void RemoveValue(IntVar* const var, int64 value) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->RemoveValue(var, value);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetValue(IntVar* const var, int64 value) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetValue(var, value);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void RemoveInterval(IntVar* const var, int64 imin, int64 imax) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->RemoveInterval(var, imin, imax);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetValues(IntVar* const var,
|
||||
const int64* const values,
|
||||
int size) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetValues(var, values, size);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void RemoveValues(IntVar* const var,
|
||||
const int64* const values,
|
||||
int size) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->RemoveValues(var, values, size);
|
||||
}
|
||||
}
|
||||
|
||||
// IntervalVar modifiers.
|
||||
virtual void SetStartMin(IntervalVar* const var, int64 new_min) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetStartMin(var, new_min);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetStartMax(IntervalVar* const var, int64 new_max) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetStartMax(var, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetStartRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetStartRange(var, new_min, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetEndMin(IntervalVar* const var, int64 new_min) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetEndMin(var, new_min);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetEndMax(IntervalVar* const var, int64 new_max) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetEndMax(var, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetEndRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetEndRange(var, new_min, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetDurationMin(IntervalVar* const var, int64 new_min) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetDurationMin(var, new_min);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetDurationMax(IntervalVar* const var, int64 new_max) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetDurationMax(var, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetDurationRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetDurationRange(var, new_min, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetPerformed(IntervalVar* const var, bool value) {
|
||||
for (int i = 0; i < monitors_.size(); ++i) {
|
||||
monitors_[i]->SetPerformed(var, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Add(PropagationMonitor* const monitor) {
|
||||
if (monitor != NULL) {
|
||||
monitors_.push_back(monitor);
|
||||
@@ -490,6 +640,303 @@ class Trace : public PropagationMonitor {
|
||||
private:
|
||||
std::vector<PropagationMonitor*> monitors_;
|
||||
};
|
||||
|
||||
// ---------- PrintTrace ----------
|
||||
|
||||
class PrintTrace : public PropagationMonitor {
|
||||
public:
|
||||
PrintTrace() : indent_(0) {}
|
||||
virtual ~PrintTrace() {}
|
||||
|
||||
// Propagation events.
|
||||
virtual void BeginInitialPropagation() {
|
||||
CheckNoDelayed();
|
||||
Display("Initial Propagation {");
|
||||
IncreaseIndent();
|
||||
}
|
||||
virtual void EndInitialPropagation() {
|
||||
DecreaseIndent();
|
||||
Display("} Starting Search");
|
||||
}
|
||||
|
||||
virtual void BeginConstraintInitialPropagation(
|
||||
const Constraint* const constraint) {
|
||||
DelayPrintAndIndent(StringPrintf("InitialPropagate(%s)",
|
||||
constraint->DebugString().c_str()));
|
||||
}
|
||||
|
||||
virtual void EndConstraintInitialPropagation(
|
||||
const Constraint* const constraint) {
|
||||
DelayCloseAndUnindent();
|
||||
}
|
||||
|
||||
virtual void BeginNestedConstraintInitialPropagation(
|
||||
const Constraint* const parent,
|
||||
const Constraint* const nested) {
|
||||
DelayPrintAndIndent(StringPrintf("InitialPropagate(%s)",
|
||||
nested->DebugString().c_str()));
|
||||
}
|
||||
virtual void EndNestedConstraintInitialPropagation(
|
||||
const Constraint* const parent,
|
||||
const Constraint* const nested) {
|
||||
DelayCloseAndUnindent();
|
||||
}
|
||||
|
||||
virtual void RegisterDemon(const Demon* const demon) {}
|
||||
|
||||
virtual void BeginDemonRun(const Demon* const demon) {
|
||||
in_demon_ = true;
|
||||
DelayPrintAndIndent(StringPrintf("Run(%s)", demon->DebugString().c_str()));
|
||||
}
|
||||
|
||||
virtual void EndDemonRun(const Demon* const demon) {
|
||||
in_demon_ = false;
|
||||
DelayCloseAndUnindent();
|
||||
}
|
||||
|
||||
virtual void RaiseFailure() {
|
||||
in_demon_ = false;
|
||||
const bool top_level = indent_ == 0;
|
||||
DelayCloseAndUnindent();
|
||||
ClearIndent();
|
||||
if (top_level) {
|
||||
Display(" -------------------- Failure --------------------");
|
||||
} else {
|
||||
Display("} -------------------- Failure --------------------");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void FindSolution() {
|
||||
Display("++++++++++++++++++++ Solution ++++++++++++++++++++");
|
||||
}
|
||||
|
||||
virtual void ApplyDecision(Decision* const decision) {
|
||||
Display(StringPrintf("----- Apply(%s) {", decision->DebugString().c_str()));
|
||||
IncreaseIndent();
|
||||
}
|
||||
|
||||
virtual void RefuteDecision(Decision* const decision) {
|
||||
Display(StringPrintf("----- Refute(%s) {",
|
||||
decision->DebugString().c_str()));
|
||||
IncreaseIndent();
|
||||
}
|
||||
|
||||
virtual void AfterDecision(Decision* const decision) {
|
||||
DecreaseIndent();
|
||||
Display("}");
|
||||
}
|
||||
|
||||
virtual void EnterSearch() {
|
||||
ClearIndent();
|
||||
}
|
||||
|
||||
virtual void ExitSearch() {
|
||||
DCHECK_EQ(0, indent_);
|
||||
}
|
||||
|
||||
virtual void RestartSearch() {
|
||||
DCHECK_EQ(0, indent_);
|
||||
}
|
||||
|
||||
// IntExpr modifiers.
|
||||
virtual void SetMin(IntExpr* const expr, int64 new_min) {
|
||||
DisplayModification(StringPrintf("SetMin(%s, %lld)",
|
||||
expr->DebugString().c_str(),
|
||||
new_min));
|
||||
}
|
||||
|
||||
virtual void SetMax(IntExpr* const expr, int64 new_max) {
|
||||
DisplayModification(StringPrintf("SetMax(%s, %lld)",
|
||||
expr->DebugString().c_str(),
|
||||
new_max));
|
||||
}
|
||||
|
||||
virtual void SetRange(IntExpr* const expr, int64 new_min, int64 new_max) {
|
||||
DisplayModification(StringPrintf("SetRange(%s, [%lld .. %lld])",
|
||||
expr->DebugString().c_str(),
|
||||
new_min,
|
||||
new_max));
|
||||
}
|
||||
|
||||
// IntVar modifiers.
|
||||
virtual void SetMin(IntVar* const var, int64 new_min) {
|
||||
DisplayModification(StringPrintf("SetMin(%s, %lld)",
|
||||
var->DebugString().c_str(),
|
||||
new_min));
|
||||
}
|
||||
|
||||
virtual void SetMax(IntVar* const var, int64 new_max) {
|
||||
DisplayModification(StringPrintf("SetMax(%s, %lld)",
|
||||
var->DebugString().c_str(),
|
||||
new_max));
|
||||
}
|
||||
|
||||
virtual void SetRange(IntVar* const var, int64 new_min, int64 new_max) {
|
||||
DisplayModification(StringPrintf("SetRange(%s, [%lld .. %lld])",
|
||||
var->DebugString().c_str(),
|
||||
new_min,
|
||||
new_max));
|
||||
}
|
||||
|
||||
virtual void RemoveValue(IntVar* const var, int64 value) {
|
||||
DisplayModification(StringPrintf("RemoveValue(%s, %lld)",
|
||||
var->DebugString().c_str(),
|
||||
value));
|
||||
}
|
||||
|
||||
virtual void SetValue(IntVar* const var, int64 value) {
|
||||
DisplayModification(StringPrintf("SetValue(%s, %lld)",
|
||||
var->DebugString().c_str(),
|
||||
value));
|
||||
}
|
||||
|
||||
virtual void RemoveInterval(IntVar* const var, int64 imin, int64 imax) {
|
||||
DisplayModification(StringPrintf("RemoveInterval(%s, [%lld .. %lld])",
|
||||
var->DebugString().c_str(),
|
||||
imin,
|
||||
imax));
|
||||
}
|
||||
|
||||
virtual void SetValues(IntVar* const var,
|
||||
const int64* const values,
|
||||
int size) {}
|
||||
|
||||
virtual void RemoveValues(IntVar* const var,
|
||||
const int64* const values,
|
||||
int size) {}
|
||||
// IntervalVar modifiers.
|
||||
virtual void SetStartMin(IntervalVar* const var, int64 new_min) {
|
||||
DisplayModification(StringPrintf("SetStartMin(%s, %lld)",
|
||||
var->DebugString().c_str(),
|
||||
new_min));
|
||||
}
|
||||
|
||||
virtual void SetStartMax(IntervalVar* const var, int64 new_max) {
|
||||
DisplayModification(StringPrintf("SetStartMax(%s, %lld)",
|
||||
var->DebugString().c_str(),
|
||||
new_max));
|
||||
}
|
||||
|
||||
virtual void SetStartRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) {
|
||||
DisplayModification(StringPrintf("SetStartRange(%s, [%lld .. %lld])",
|
||||
var->DebugString().c_str(),
|
||||
new_min,
|
||||
new_max));
|
||||
}
|
||||
|
||||
virtual void SetEndMin(IntervalVar* const var, int64 new_min) {
|
||||
DisplayModification(StringPrintf("SetEndMin(%s, %lld)",
|
||||
var->DebugString().c_str(),
|
||||
new_min));
|
||||
}
|
||||
|
||||
virtual void SetEndMax(IntervalVar* const var, int64 new_max) {
|
||||
DisplayModification(StringPrintf("SetEndMax(%s, %lld)",
|
||||
var->DebugString().c_str(),
|
||||
new_max));
|
||||
}
|
||||
|
||||
virtual void SetEndRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) {
|
||||
DisplayModification(StringPrintf("SetEndRange(%s, [%lld .. %lld])",
|
||||
var->DebugString().c_str(),
|
||||
new_min,
|
||||
new_max));
|
||||
}
|
||||
|
||||
virtual void SetDurationMin(IntervalVar* const var, int64 new_min) {
|
||||
DisplayModification(StringPrintf("SetDurationMin(%s, %lld)",
|
||||
var->DebugString().c_str(),
|
||||
new_min));
|
||||
}
|
||||
|
||||
virtual void SetDurationMax(IntervalVar* const var, int64 new_max) {
|
||||
DisplayModification(StringPrintf("SetDurationMax(%s, %lld)",
|
||||
var->DebugString().c_str(),
|
||||
new_max));
|
||||
}
|
||||
|
||||
virtual void SetDurationRange(IntervalVar* const var,
|
||||
int64 new_min,
|
||||
int64 new_max) {
|
||||
DisplayModification(StringPrintf("SetDurationRange(%s, [%lld .. %lld])",
|
||||
var->DebugString().c_str(),
|
||||
new_min,
|
||||
new_max));
|
||||
}
|
||||
|
||||
virtual void SetPerformed(IntervalVar* const var, bool value) {
|
||||
DisplayModification(StringPrintf("SetPerformed(%s, %d)",
|
||||
var->DebugString().c_str(),
|
||||
value));
|
||||
}
|
||||
|
||||
private:
|
||||
void DelayPrintAndIndent(const string& delayed) {
|
||||
CHECK(delayed_string_.empty());
|
||||
delayed_string_ = delayed;
|
||||
}
|
||||
|
||||
void DelayCloseAndUnindent() {
|
||||
if (delayed_string_.empty() && indent_ > 0) {
|
||||
DecreaseIndent();
|
||||
Display("}");
|
||||
} else {
|
||||
delayed_string_ = "";
|
||||
}
|
||||
}
|
||||
|
||||
void CheckNoDelayed() {
|
||||
CHECK(delayed_string_.empty());
|
||||
}
|
||||
|
||||
void DisplayModification(const string& to_print) {
|
||||
if (!delayed_string_.empty()) {
|
||||
LOG(INFO) << Indent() << delayed_string_ << " {";
|
||||
IncreaseIndent();
|
||||
delayed_string_ = "";
|
||||
}
|
||||
if (in_demon_) { // Inside a demon, normal print.
|
||||
LOG(INFO) << Indent() << to_print;
|
||||
} else if (indent_ == 0) { // Top level, modification pushed by the
|
||||
// objective.
|
||||
LOG(INFO) << Indent() << "Objective: " << to_print;
|
||||
} else { // Not top level, but not in a demon -> Decision.
|
||||
LOG(INFO) << Indent() << "Decision: " << to_print;
|
||||
}
|
||||
}
|
||||
|
||||
void Display(const string& to_print) {
|
||||
LOG(INFO) << Indent() << to_print;
|
||||
}
|
||||
|
||||
string Indent() {
|
||||
string output = " @ ";
|
||||
for (int i = 0; i < indent_; ++i) {
|
||||
output.append(" ");
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
void IncreaseIndent() {
|
||||
indent_++;
|
||||
}
|
||||
|
||||
void DecreaseIndent() {
|
||||
indent_--;
|
||||
}
|
||||
|
||||
void ClearIndent() {
|
||||
indent_ = 0;
|
||||
}
|
||||
|
||||
int indent_;
|
||||
string delayed_string_;
|
||||
bool in_demon_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
IntExpr* Solver::RegisterIntExpr(IntExpr* const expr) {
|
||||
@@ -525,12 +972,16 @@ PropagationMonitor* BuildTrace() {
|
||||
return new Trace();
|
||||
}
|
||||
|
||||
PropagationMonitor* Solver::Trace() const {
|
||||
return trace_.get();
|
||||
}
|
||||
|
||||
void Solver::AddPropagationMonitor(PropagationMonitor* const monitor) {
|
||||
// TODO(user): Check solver state?
|
||||
reinterpret_cast<class Trace*>(trace_.get())->Add(monitor);
|
||||
reinterpret_cast<class Trace*>(propagation_monitor_.get())->Add(monitor);
|
||||
}
|
||||
|
||||
PropagationMonitor* Solver::GetPropagationMonitor() const {
|
||||
return propagation_monitor_.get();
|
||||
}
|
||||
|
||||
PropagationMonitor* BuildPrintTrace() {
|
||||
return new PrintTrace();
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
Reference in New Issue
Block a user