From 58b89d856567f98576dcb995f72cdaefbb856bec Mon Sep 17 00:00:00 2001 From: "lperron@google.com" Date: Tue, 26 Apr 2011 08:59:55 +0000 Subject: [PATCH] new LS operator to reach a given assignment --- constraint_solver/constraint_solver.h | 26 ++++++- constraint_solver/constraint_solveri.h | 1 + constraint_solver/local_search.cc | 102 ++++++++++++++++++++++++- 3 files changed, 127 insertions(+), 2 deletions(-) diff --git a/constraint_solver/constraint_solver.h b/constraint_solver/constraint_solver.h index e290059a65..d11e399d94 100644 --- a/constraint_solver/constraint_solver.h +++ b/constraint_solver/constraint_solver.h @@ -1796,6 +1796,23 @@ class Solver { int number_of_variables, int32 seed); + // Creates a local search operator that tries to move the assignment of some + // variables toward a target. The target is given as an Assignment. This + // operator generates neighbors in which the only difference compared to the + // current state is that one variable that belongs to the target assignment is + // set to its target value. + LocalSearchOperator* MakeMoveTowardTargetOperator(const Assignment& target); + + // Creates a local search operator that tries to move the assignment of some + // variables toward a target. The target is given either as two vectors: a + // vector of variables and a vector of associated target values. The two + // vectors should be of the same length. This operator generates neighbors in + // which the only difference compared to the current state is that one + // variable that belongs to the given vector is set to its target value. + LocalSearchOperator* MakeMoveTowardTargetOperator( + const vector& variables, + const vector& target_values); + // Creates a local search operator which concatenates a vector of operators. // Each operator from the vector is called sequentially. By default, when a // neighbor is found the neighborhood exploration restarts from the last @@ -3186,6 +3203,7 @@ template class AssignmentContainer { DCHECK(found); return Element(index); } + const vector& elements() const { return elements_; } E& MutableElement(int index) { return elements_[index]; } const E& Element(int index) const { return elements_[index]; } int Size() const { return elements_.size(); } @@ -3239,7 +3257,13 @@ class Assignment : public PropagationBaseObject { return int_var_container_.Empty() && interval_var_container_.Empty(); } int Size() const { - return int_var_container_.Size() + interval_var_container_.Size(); + return NumIntVars() + NumIntervalVars(); + } + int NumIntVars() const { + return int_var_container_.Size(); + } + int NumIntervalVars() const { + return interval_var_container_.Size(); } void Store(); void Restore(); diff --git a/constraint_solver/constraint_solveri.h b/constraint_solver/constraint_solveri.h index 9ef64d114c..f92cd21ac6 100644 --- a/constraint_solver/constraint_solveri.h +++ b/constraint_solver/constraint_solveri.h @@ -414,6 +414,7 @@ class LocalSearchOperator : public BaseObject { class IntVarLocalSearchOperator : public LocalSearchOperator { public: + IntVarLocalSearchOperator(); IntVarLocalSearchOperator(const IntVar* const* vars, int size); virtual ~IntVarLocalSearchOperator(); // This method should not be overridden. Override OnStart() instead which is diff --git a/constraint_solver/local_search.cc b/constraint_solver/local_search.cc index c330a0ada5..ac478bc6bc 100644 --- a/constraint_solver/local_search.cc +++ b/constraint_solver/local_search.cc @@ -24,6 +24,7 @@ #include "constraint_solver/constraint_solveri.h" #include "graph/hamiltonian_path.h" + DEFINE_int32(cp_local_search_sync_frequency, 16, "Frequency of checks for better solutions in the solution pool."); @@ -40,6 +41,17 @@ namespace operations_research { // ----- Base operator class for operators manipulating IntVars ----- +IntVarLocalSearchOperator::IntVarLocalSearchOperator() +: vars_(NULL), + size_(0), + values_(NULL), + old_values_(NULL), + activated_(0, false), + was_activated_(0, false), + has_changed_(0, false), + has_delta_changed_(0, false), + cleared_(true) {} + IntVarLocalSearchOperator::IntVarLocalSearchOperator(const IntVar* const* vars, int size) : vars_(NULL), @@ -51,8 +63,8 @@ IntVarLocalSearchOperator::IntVarLocalSearchOperator(const IntVar* const* vars, has_changed_(size, false), has_delta_changed_(size, false), cleared_(true) { - AddVars(vars, size); CHECK_GE(size_, 0); + AddVars(vars, size); } IntVarLocalSearchOperator::~IntVarLocalSearchOperator() {} @@ -290,6 +302,94 @@ LocalSearchOperator* Solver::MakeRandomLNSOperator(const IntVar* const* vars, return RevAlloc(new RandomLNS(vars, size, number_of_variables, seed)); } +// ----- Move Toward Target Local Search operator ----- + +// A local search operator that compares the current assignment with a target +// one, and that generates neighbors corresponding to a single variable being +// changed from its current value to its target value. +class MoveTowardTargetLS: public IntVarLocalSearchOperator { + public: + explicit MoveTowardTargetLS(const vector& variables, + const vector& target_values) + : IntVarLocalSearchOperator(variables.data(), variables.size()), + target_(target_values), + // Initialize variable_index_ at the number of the of variables minus + // one, so that the first to be tried (after one increment) is the one + // of index 0. + variable_index_(Size() - 1) { + CHECK_EQ(target_values.size(), variables.size()) << "Illegal arguments."; + } + + virtual ~MoveTowardTargetLS() {} + virtual void OnStart() { + // Do not change the value of variable_index_: this way, we keep going from + // where we last modified something. This is because we expect that most + // often, the variables we have just checked are less likely to be able + // to be changed to their target values than the ones we have not yet + // checked. + // + // Consider the case where oddly indexed variables can be assigned to their + // target values (no matter in what order they are considered), while even + // indexed ones cannot. Restarting at index 0 each time an odd-indexed + // variable is modified will cause a total of Theta(n^2) neighbors to be + // generated, while not restarting will produce only Theta(n) neighbors. + CHECK_GE(variable_index_, 0); + CHECK_LT(variable_index_, Size()); + num_var_since_last_start_ = 0; + } + + // Make a neighbor assigning one variable to its target value. + virtual bool MakeNextNeighbor(Assignment* delta, Assignment* deltadelta) { + CHECK_NOTNULL(delta); + while (num_var_since_last_start_ < Size()) { + ++num_var_since_last_start_; + variable_index_ = (variable_index_ + 1) % Size(); + const int64 target_value = target_.at(variable_index_); + const int64 current_value = OldValue(variable_index_); + if (current_value != target_value) { + RevertChanges(false); + SetValue(variable_index_, target_value); + if (ApplyChanges(delta, deltadelta)) { + return true; + } + } + } + return false; + } + + private: + // Target values + const vector target_; + + // Index of the next variable to try to restore + int64 variable_index_; + + // Number of variables checked since the last call to OnStart(). + int64 num_var_since_last_start_; +}; + +LocalSearchOperator* Solver::MakeMoveTowardTargetOperator( + const Assignment& target) { + typedef vector Elements; + const Elements& elements = target.IntVarContainer().elements(); + // Copy target values and construct the vector of variables + vector vars; + vector values; + vars.reserve(target.NumIntVars()); + values.reserve(target.NumIntVars()); + for (ConstIter it(elements); !it.at_end(); ++it) { + vars.push_back(it->Var()); + values.push_back(it->Value()); + } + return MakeMoveTowardTargetOperator(vars, values); +} + +LocalSearchOperator* Solver::MakeMoveTowardTargetOperator( + const vector& variables, + const vector& target_values) { + return RevAlloc(new MoveTowardTargetLS(variables, target_values)); +} + // ----- ChangeValue Operators ----- ChangeValue::ChangeValue(const IntVar* const* vars, int size)