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:
lperron@google.com
2011-11-14 20:55:35 +00:00
parent bc859ea0f4
commit 5b859743d1
11 changed files with 1260 additions and 299 deletions

View File

@@ -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_;
}

View File

@@ -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);
};

View File

@@ -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,

View File

@@ -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 ----------

View File

@@ -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,

View File

@@ -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_;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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_;

View File

@@ -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;
}

View File

@@ -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