From adc36fb12eb697a36696f40b157289288d21e86c Mon Sep 17 00:00:00 2001 From: "lperron@google.com" Date: Tue, 14 Feb 2012 14:16:12 +0000 Subject: [PATCH] clean up protocol on local search; regroup model visitors code --- constraint_solver/collect_variables.cc | 212 +---------------- constraint_solver/constraint_solver.cc | 57 +++-- constraint_solver/constraint_solver.h | 14 +- constraint_solver/constraint_solveri.h | 148 ++++++++++++ constraint_solver/hybrid.cc | 234 ++++--------------- constraint_solver/io.cc | 41 ++-- constraint_solver/local_search.cc | 23 +- constraint_solver/routing.cc | 167 ++++++++----- constraint_solver/routing.h | 6 +- constraint_solver/visitor.cc | 311 +++++++++++++++++++++++++ makefiles/Makefile.cpp.mk | 6 +- 11 files changed, 700 insertions(+), 519 deletions(-) create mode 100644 constraint_solver/visitor.cc diff --git a/constraint_solver/collect_variables.cc b/constraint_solver/collect_variables.cc index 7bf3b93b31..0bbc11bed6 100644 --- a/constraint_solver/collect_variables.cc +++ b/constraint_solver/collect_variables.cc @@ -27,104 +27,7 @@ namespace operations_research { namespace { - -class ArgumentHolder { - public: - struct Matrix { - Matrix() : values(NULL), rows(0), columns(0) {} - // We do not take ownership as the data will only be used temporarly. - Matrix(const int64 * const * v, int r, int c) - : values(v), rows(r), columns(c) {} - const int64* const * values; - int rows; - int columns; - }; - - const string& type_name() const { - return type_name_; - } - - void set_type_name(const string& type_name) { - type_name_ = type_name; - } - - void SetIntegerMatrixArgument(const string& arg_name, - const int64* const * const values, - int rows, - int columns) { - matrix_argument_[arg_name] = Matrix(values, rows, columns); - } - - void SetIntegerExpressionArgument(const string& arg_name, - const IntExpr* const expr) { - integer_expression_argument_[arg_name] = expr; - } - - void SetIntegerVariableArrayArgument(const string& arg_name, - const IntVar* const * const vars, - int size) { - for (int i = 0; i < size; ++i) { - integer_variable_array_argument_[arg_name].push_back(vars[i]); - } - } - - void SetIntervalArgument(const string& arg_name, - const IntervalVar* const var) { - interval_argument_[arg_name] = var; - } - - void SetIntervalArrayArgument(const string& arg_name, - const IntervalVar* const * const vars, - int size) { - for (int i = 0; i < size; ++i) { - interval_array_argument_[arg_name].push_back(vars[i]); - } - } - - void SetSequenceArgument(const string& arg_name, - const SequenceVar* const var) { - sequence_argument_[arg_name] = var; - } - - void SetSequenceArrayArgument(const string& arg_name, - const SequenceVar* const * const vars, - int size) { - for (int i = 0; i < size; ++i) { - sequence_array_argument_[arg_name].push_back(vars[i]); - } - } - - bool HasIntegerExpressionArgument(const string& arg_name) const { - return ContainsKey(integer_expression_argument_, arg_name); - } - - const IntExpr* FindIntegerExpressionArgumentOrDie( - const string& arg_name) const { - return FindOrDie(integer_expression_argument_, arg_name); - } - - const std::vector& FindIntegerVariableArrayArgumentOrDie( - const string& arg_name) { - return FindOrDie(integer_variable_array_argument_, arg_name); - } - - const Matrix& FindIntegerMatrixArgumentOrDie(const string& arg_name) const { - return FindOrDie(matrix_argument_, arg_name); - } - - private: - string type_name_; - hash_map integer_expression_argument_; - hash_map interval_argument_; - hash_map sequence_argument_; - hash_map > integer_variable_array_argument_; - hash_map > interval_array_argument_; - hash_map > sequence_array_argument_; - hash_map matrix_argument_; -}; - -class CollectVariablesVisitor : public ModelVisitor { +class CollectVariablesVisitor : public ModelParser { public: CollectVariablesVisitor(std::vector* const primary_integer_variables, std::vector* const secondary_integer_variables, @@ -135,14 +38,8 @@ class CollectVariablesVisitor : public ModelVisitor { sequences_(sequence_variables), intervals_(interval_variables) {} - virtual ~CollectVariablesVisitor() { - CHECK(holders_.empty()); - } + virtual ~CollectVariablesVisitor() {} - // Header/footers. - virtual void BeginVisitModel(const string& solver_name) { - PushArgumentHolder(); - } virtual void EndVisitModel(const string& solver_name) { PopArgumentHolder(); @@ -152,11 +49,6 @@ class CollectVariablesVisitor : public ModelVisitor { sequences_->assign(sequence_set_.begin(), sequence_set_.end()); } - virtual void BeginVisitConstraint(const string& type_name, - const Constraint* const constraint) { - PushArgumentHolder(); - } - virtual void EndVisitConstraint(const string& type_name, const Constraint* const constraint) { if (type_name.compare(ModelVisitor::kLinkExprVar) == 0 || @@ -169,22 +61,22 @@ class CollectVariablesVisitor : public ModelVisitor { type_name.compare(ModelVisitor::kIsLessOrEqual) == 0) { IntExpr* const target_expr = const_cast( - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kTargetArgument)); IntVar* const target_var = target_expr->Var(); IgnoreIntegerVariable(target_var); } else if (type_name.compare(ModelVisitor::kCountEqual) == 0 && - top()->HasIntegerExpressionArgument( + Top()->HasIntegerExpressionArgument( ModelVisitor::kCountArgument)) { IntExpr* const count_expr = const_cast( - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kCountArgument)); IntVar* const count_var = count_expr->Var(); IgnoreIntegerVariable(count_var); } else if (type_name.compare(ModelVisitor::kAllowedAssignments) == 0) { const ArgumentHolder::Matrix& matrix = - top()->FindIntegerMatrixArgumentOrDie(ModelVisitor::kTuplesArgument); + Top()->FindIntegerMatrixArgumentOrDie(ModelVisitor::kTuplesArgument); std::vector > counters(matrix.columns); for (int i = 0; i < matrix.rows; ++i) { for (int j = 0; j < matrix.columns; ++j) { @@ -194,7 +86,7 @@ class CollectVariablesVisitor : public ModelVisitor { for (int j = 0; j < matrix.columns; ++j) { if (counters[j].size() == matrix.rows) { const std::vector& vars = - top()->FindIntegerVariableArrayArgumentOrDie( + Top()->FindIntegerVariableArrayArgumentOrDie( ModelVisitor::kVarsArgument); for (int k = 0; k < matrix.columns; ++k) { if (j != k) { @@ -206,21 +98,21 @@ class CollectVariablesVisitor : public ModelVisitor { } } else if (type_name.compare(ModelVisitor::kNoCycle) == 0) { const std::vector& vars = - top()->FindIntegerVariableArrayArgumentOrDie( + Top()->FindIntegerVariableArrayArgumentOrDie( ModelVisitor::kActiveArgument); for (int i = 0; i < vars.size(); ++i) { IgnoreIntegerVariable(const_cast(vars[i])); } } else if (type_name.compare(ModelVisitor::kPathCumul) == 0) { const std::vector& vars = - top()->FindIntegerVariableArrayArgumentOrDie( + Top()->FindIntegerVariableArrayArgumentOrDie( ModelVisitor::kActiveArgument); for (int i = 0; i < vars.size(); ++i) { IgnoreIntegerVariable(const_cast(vars[i])); } } else if (type_name.compare(ModelVisitor::kDistribute) == 0) { const std::vector& vars = - top()->FindIntegerVariableArrayArgumentOrDie( + Top()->FindIntegerVariableArrayArgumentOrDie( ModelVisitor::kCardsArgument); for (int i = 0; i < vars.size(); ++i) { IgnoreIntegerVariable(const_cast(vars[i])); @@ -229,16 +121,6 @@ class CollectVariablesVisitor : public ModelVisitor { PopArgumentHolder(); } - virtual void BeginVisitIntegerExpression(const string& type_name, - const IntExpr* const expr) { - PushArgumentHolder(); - } - - virtual void EndVisitIntegerExpression(const string& type_name, - const IntExpr* const expr) { - PopArgumentHolder(); - } - virtual void VisitIntegerVariable(const IntVar* const variable, const IntExpr* const delegate) { IntVar* const var = const_cast(variable); @@ -293,80 +175,7 @@ class CollectVariablesVisitor : public ModelVisitor { } } - // Integer arguments - virtual void VisitIntegerMatrixArgument(const string& arg_name, - const int64* const * const values, - int rows, - int columns) { - top()->SetIntegerMatrixArgument(arg_name, values, rows, columns); - } - - // Variables. - virtual void VisitIntegerExpressionArgument( - const string& arg_name, - const IntExpr* const argument) { - top()->SetIntegerExpressionArgument(arg_name, argument); - argument->Accept(this); - } - - virtual void VisitIntegerVariableArrayArgument( - const string& arg_name, - const IntVar* const * arguments, - int size) { - top()->SetIntegerVariableArrayArgument(arg_name, arguments, size); - for (int i = 0; i < size; ++i) { - arguments[i]->Accept(this); - } - } - - // Visit interval argument. - virtual void VisitIntervalArgument(const string& arg_name, - const IntervalVar* const argument) { - top()->SetIntervalArgument(arg_name, argument); - argument->Accept(this); - } - - virtual void VisitIntervalArrayArgument(const string& arg_name, - const IntervalVar* const * arguments, - int size) { - top()->SetIntervalArrayArgument(arg_name, arguments, size); - for (int i = 0; i < size; ++i) { - arguments[i]->Accept(this); - } - } - - // Visit sequence argument. - virtual void VisitSequenceArgument(const string& arg_name, - const SequenceVar* const argument) { - top()->SetSequenceArgument(arg_name, argument); - argument->Accept(this); - } - - virtual void VisitSequenceArrayArgument(const string& arg_name, - const SequenceVar* const * arguments, - int size) { - top()->SetSequenceArrayArgument(arg_name, arguments, size); - for (int i = 0; i < size; ++i) { - arguments[i]->Accept(this); - } - } - private: - void PushArgumentHolder() { - holders_.push_back(new ArgumentHolder); - } - - void PopArgumentHolder() { - CHECK(!holders_.empty()); - delete holders_.back(); - holders_.pop_back(); - } - - ArgumentHolder* top() const { - CHECK(!holders_.empty()); - return holders_.back(); - } - void IgnoreIntegerVariable(IntVar* const var) { primary_set_.erase(var); secondary_set_.erase(var); @@ -386,7 +195,6 @@ class CollectVariablesVisitor : public ModelVisitor { hash_set ignored_set_; hash_set sequence_set_; hash_set interval_set_; - std::vector holders_; }; } // namespace diff --git a/constraint_solver/constraint_solver.cc b/constraint_solver/constraint_solver.cc index e92b1d9aa4..b8c5abaedf 100644 --- a/constraint_solver/constraint_solver.cc +++ b/constraint_solver/constraint_solver.cc @@ -1060,7 +1060,7 @@ DecisionBuilder* Solver::MakeApplyBranchSelector( } int Solver::SolveDepth() const { - return searches_.size() - 1; + return state_ == OUTSIDE_SEARCH ? 0 : searches_.size() - 1; } int Solver::SearchDepth() const { @@ -1297,7 +1297,23 @@ void Search::Accept(ModelVisitor* const visitor) const { } } +bool LocalOptimumReached(Search* const search) { + return search->LocalOptimum(); +} + +bool AcceptDelta(Search* const search, + Assignment* delta, + Assignment* deltadelta) { + return search->AcceptDelta(delta, deltadelta); +} + +void AcceptNeighbor(Search* const search) { + search->AcceptNeighbor(); +} + + namespace { + // ---------- Fail Decision ---------- class FailDecision : public Decision { @@ -1430,7 +1446,7 @@ void Solver::Init() { Solver::~Solver() { // solver destructor called with searches open. - CHECK_EQ(1, SolveDepth()); + CHECK_EQ(2, searches_.size()); BacktrackToSentinel(INITIAL_SEARCH_SENTINEL); StateInfo info; @@ -1439,14 +1455,7 @@ Solver::~Solver() { DCHECK_EQ(finalType, SENTINEL); // Not popping initial SENTINEL in Solver destructor. DCHECK_EQ(info.int_info, SOLVER_CTOR_SENTINEL); - - Search* search = searches_.back(); - searches_.pop_back(); - CHECK_EQ(0, SolveDepth()) - << "non empty list of searches when ending the solver"; - delete search; - CHECK_EQ(1, searches_.size()); - delete searches_.back(); + STLDeleteElements(&searches_); DeleteDemonProfiler(demon_profiler_); DeleteBuilders(); } @@ -1510,18 +1519,6 @@ int64 Solver::solutions() const { return TopLevelSearch()->solution_counter(); } -bool Solver::LocalOptimum() { - return TopLevelSearch()->LocalOptimum(); -} - -bool Solver::AcceptDelta(Assignment* delta, Assignment* deltadelta) { - return TopLevelSearch()->AcceptDelta(delta, deltadelta); -} - -void Solver::AcceptNeighbor() { - return TopLevelSearch()->AcceptNeighbor(); -} - void Solver::TopPeriodicCheck() { TopLevelSearch()->PeriodicCheck(); } @@ -1938,7 +1935,7 @@ void Solver::NewSearch(DecisionBuilder* const db, search->EnterSearch(); // Push sentinel and set decision builder. - DCHECK_EQ(1, SolveDepth()); + DCHECK_EQ(2, searches_.size()); PushSentinel(INITIAL_SEARCH_SENTINEL); search->set_decision_builder(db); } @@ -2063,10 +2060,10 @@ void Solver::BacktrackToSentinel(int magic_code) { void Solver::JumpToSentinelWhenNested() { CHECK_GT(SolveDepth(), 1) << "calling JumpToSentinel from top level"; Search* c = searches_.back(); - Search* p = searches_[SolveDepth() - 2]; + Search* p = ParentSearch(); bool found = false; while (!c->marker_stack_.empty()) { - StateMarker* m = c->marker_stack_.back(); + StateMarker* const m = c->marker_stack_.back(); if (m->type_ == REVERSIBLE_ACTION) { p->marker_stack_.push_back(m); } else { @@ -2119,9 +2116,10 @@ class ReverseDecision : public Decision { bool Solver::NextSolution() { Search* const search = searches_.back(); Decision* fd = NULL; - const bool top_level = (SolveDepth() == 1); + const int solve_depth = SolveDepth(); + const bool top_level = solve_depth <= 1; - if (top_level && state_ == OUTSIDE_SEARCH && !search->decision_builder()) { + if (solve_depth == 0 && !search->decision_builder()) { LOG(WARNING) << "NextSolution() called without a NewSearch before"; return false; } @@ -2282,7 +2280,7 @@ bool Solver::NextSolution() { } void Solver::EndSearch() { - CHECK_EQ(1, SolveDepth()); + CHECK_EQ(2, searches_.size()); Search* const search = searches_.back(); BacktrackToSentinel(INITIAL_SEARCH_SENTINEL); search->ExitSearch(); @@ -2310,7 +2308,8 @@ bool Solver::CheckAssignment(Assignment* const solution) { search->EnterSearch(); // Push sentinel and set decision builder. - DCHECK_EQ(1, SolveDepth()); + DCHECK_EQ(0, SolveDepth()); + DCHECK_EQ(2, searches_.size()); PushSentinel(INITIAL_SEARCH_SENTINEL); search->BeginInitialPropagation(); CP_TRY(search) { diff --git a/constraint_solver/constraint_solver.h b/constraint_solver/constraint_solver.h index 26518aeb3e..5338430961 100644 --- a/constraint_solver/constraint_solver.h +++ b/constraint_solver/constraint_solver.h @@ -2665,12 +2665,6 @@ class Solver { Solver::LocalSearchFilterBound filter_enum, Solver::LocalSearchOperation op_enum); - // Ensures communication of local optima between monitors and search - bool LocalOptimum(); - // Checks with monitors if delta is acceptable - bool AcceptDelta(Assignment* delta, Assignment* deltadelta); - // Ensures communication of accepted neighbors between monitors and search - void AcceptNeighbor(); // Performs PeriodicCheck on the top-level search; can be called from a nested // solve to check top-level limits for instance. void TopPeriodicCheck(); @@ -2881,6 +2875,14 @@ class Solver { Search* TopLevelSearch() const { return searches_.at(1); } + // Returns the Search object which is the parent of the active search, i.e. + // the search below the top of the stack. If the active search is at the + // bottom of the stack, returns the active search. + Search* ParentSearch() const { + const size_t search_size = searches_.size(); + DCHECK_GT(search_size, 1); + return searches_[search_size - 2]; + } // Naming string GetName(const PropagationBaseObject* object); diff --git a/constraint_solver/constraint_solveri.h b/constraint_solver/constraint_solveri.h index 1583d26a5f..b859354647 100644 --- a/constraint_solver/constraint_solveri.h +++ b/constraint_solver/constraint_solveri.h @@ -1617,6 +1617,154 @@ class DependencyGraph : public BaseObject { std::vector managed_nodes_; }; #endif + +// Argument Holder: useful when visiting a model. +#if !defined(SWIG) +class ArgumentHolder { + public: + // Internal structure to store an integer matrix. + struct Matrix { + Matrix() : values(NULL), rows(0), columns(0) {} + // We do not take ownership as the data will only be used temporarly. + Matrix(const int64 * const * v, int r, int c) + : values(v), rows(r), columns(c) {} + const int64* const * values; + int rows; + int columns; + }; + + // Type of the argument. + const string& TypeName() const; + void SetTypeName(const string& type_name); + + // Setters. + void SetIntegerArgument(const string& arg_name, int64 value); + void SetIntegerArrayArgument(const string& arg_name, + const int64* const values, + int size); + void SetIntegerMatrixArgument(const string& arg_name, + const int64* const * const values, + int rows, + int columns); + void SetIntegerExpressionArgument(const string& arg_name, + const IntExpr* const expr); + void SetIntegerVariableArrayArgument(const string& arg_name, + const IntVar* const * const vars, + int size); + void SetIntervalArgument(const string& arg_name, + const IntervalVar* const var); + void SetIntervalArrayArgument(const string& arg_name, + const IntervalVar* const * const vars, + int size); + void SetSequenceArgument(const string& arg_name, + const SequenceVar* const var); + void SetSequenceArrayArgument(const string& arg_name, + const SequenceVar* const * const vars, + int size); + + // Checks if arguments exist. + bool HasIntegerExpressionArgument(const string& arg_name) const; + bool HasIntegerVariableArrayArgument(const string& arg_name) const; + + // Getters. + int64 FindIntegerArgumentWithDefault( + const string& arg_name, + int64 def) const; + int64 FindIntegerArgumentOrDie(const string& arg_name) const; + const std::vector& FindIntegerArrayArgumentOrDie( + const string& arg_name) const; + const Matrix& FindIntegerMatrixArgumentOrDie(const string& arg_name) const; + + const IntExpr* FindIntegerExpressionArgumentOrDie( + const string& arg_name) const; + const std::vector& FindIntegerVariableArrayArgumentOrDie( + const string& arg_name) const; + + private: + string type_name_; + hash_map integer_argument_; + hash_map > integer_array_argument_; + hash_map matrix_argument_; + hash_map integer_expression_argument_; + hash_map interval_argument_; + hash_map sequence_argument_; + hash_map > integer_variable_array_argument_; + hash_map > interval_array_argument_; + hash_map > sequence_array_argument_; +}; + +// Model Parser + +class ModelParser : public ModelVisitor { + public: + ModelParser(); + + virtual ~ModelParser(); + + // Header/footers. + virtual void BeginVisitModel(const string& solver_name); + virtual void EndVisitModel(const string& solver_name); + virtual void BeginVisitConstraint(const string& type_name, + const Constraint* const constraint); + virtual void EndVisitConstraint(const string& type_name, + const Constraint* const constraint); + virtual void BeginVisitIntegerExpression(const string& type_name, + const IntExpr* const expr); + virtual void EndVisitIntegerExpression(const string& type_name, + const IntExpr* const expr); + virtual void VisitIntegerVariable(const IntVar* const variable, + const IntExpr* const delegate); + virtual void VisitIntegerVariable(const IntVar* const variable, + const string& operation, + int64 value, + const IntVar* const delegate); + virtual void VisitIntervalVariable(const IntervalVar* const variable, + const string& operation, + const IntervalVar* const delegate); + virtual void VisitIntervalVariable(const IntervalVar* const variable, + const string& operation, + const IntervalVar* const * delegates, + int size); + virtual void VisitSequenceVariable(const SequenceVar* const variable); + // Integer arguments + virtual void VisitIntegerArgument(const string& arg_name, int64 value); + virtual void VisitIntegerArrayArgument(const string& arg_name, + const int64* const values, + int size); + virtual void VisitIntegerMatrixArgument(const string& arg_name, + const int64* const * const values, + int rows, + int columns); + // Variables. + virtual void VisitIntegerExpressionArgument( + const string& arg_name, + const IntExpr* const argument); + virtual void VisitIntegerVariableArrayArgument( + const string& arg_name, + const IntVar* const * arguments, + int size); + // Visit interval argument. + virtual void VisitIntervalArgument(const string& arg_name, + const IntervalVar* const argument); + virtual void VisitIntervalArrayArgument(const string& arg_name, + const IntervalVar* const * arguments, + int size); + // Visit sequence argument. + virtual void VisitSequenceArgument(const string& arg_name, + const SequenceVar* const argument); + virtual void VisitSequenceArrayArgument(const string& arg_name, + const SequenceVar* const * arguments, + int size); + + protected: + void PushArgumentHolder(); + void PopArgumentHolder(); + ArgumentHolder* Top() const; + + private: + std::vector holders_; +}; +#endif // SWIG } // namespace operations_research #endif // OR_TOOLS_CONSTRAINT_SOLVER_CONSTRAINT_SOLVERI_H_ diff --git a/constraint_solver/hybrid.cc b/constraint_solver/hybrid.cc index a770482e41..74d17b9ad1 100644 --- a/constraint_solver/hybrid.cc +++ b/constraint_solver/hybrid.cc @@ -20,6 +20,7 @@ #include "base/scoped_ptr.h" #include "base/stl_util.h" #include "constraint_solver/constraint_solver.h" +#include "constraint_solver/constraint_solveri.h" #include "linear_solver/linear_solver.h" #include "util/string_array.h" @@ -121,134 +122,11 @@ class SimplexConnection : public SearchMonitor { typedef hash_map ExprTranslation; -// ----- Context to represent a linear sum ----- - -class ArgumentHolder { - public: - struct Matrix { - Matrix() : values(NULL), rows(0), columns(0) {} - Matrix(const int64 * const * v, int r, int c) - : values(v), rows(r), columns(c) {} - const int64* const * values; - int rows; - int columns; - }; - - const string& type_name() const { - return type_name_; - } - - void set_type_name(const string& type_name) { - type_name_ = type_name; - } - - void set_integer_argument(const string& arg_name, int64 value) { - integer_argument_[arg_name] = value; - } - - void set_integer_array_argument(const string& arg_name, - const int64* const values, - int size) { - for (int i = 0; i < size; ++i) { - integer_array_argument_[arg_name].push_back(values[i]); - } - } - - void set_integer_matrix_argument(const string& arg_name, - const int64* const * const values, - int rows, - int columns) { - matrix_argument_[arg_name] = Matrix(values, rows, columns); - } - - void set_integer_expression_argument(const string& arg_name, - const IntExpr* const expr) { - integer_expression_argument_[arg_name] = expr; - } - - void set_integer_variable_array_argument(const string& arg_name, - const IntVar* const * const vars, - int size) { - for (int i = 0; i < size; ++i) { - integer_variable_array_argument_[arg_name].push_back(vars[i]); - } - } - - void set_interval_argument(const string& arg_name, - const IntervalVar* const var) { - interval_argument_[arg_name] = var; - } - - void set_interval_array_argument(const string& arg_name, - const IntervalVar* const * const vars, - int size) { - for (int i = 0; i < size; ++i) { - interval_array_argument_[arg_name].push_back(vars[i]); - } - } - - void set_sequence_argument(const string& arg_name, - const SequenceVar* const var) { - sequence_argument_[arg_name] = var; - } - - void set_sequence_array_argument(const string& arg_name, - const SequenceVar* const * const vars, - int size) { - for (int i = 0; i < size; ++i) { - sequence_array_argument_[arg_name].push_back(vars[i]); - } - } - - const IntExpr* FindIntegerExpressionArgumentOrDie(const string& arg_name) { - return FindOrDie(integer_expression_argument_, arg_name); - } - - const std::vector& FindIntegerVariableArrayArgumentOrDie( - const string& arg_name) { - return FindOrDie(integer_variable_array_argument_, arg_name); - } - - int64 FindIntegerArgumentOrDie(const string& arg_name) { - return FindOrDie(integer_argument_, arg_name); - } - - const std::vector& FindIntegerArrayArgumentOrDie( - const string& arg_name) { - return FindOrDie(integer_array_argument_, arg_name); - } - - const Matrix& FindIntegerMatrixArgumentOrDie(const string& arg_name) { - return FindOrDie(matrix_argument_, arg_name); - } - - bool HasIntegerExpression(const string& arg_name) { - return ContainsKey(integer_expression_argument_, arg_name); - } - - bool HasIntegerVariableArray(const string& arg_name) { - return ContainsKey(integer_variable_array_argument_, arg_name); - } - - private: - string type_name_; - hash_map integer_expression_argument_; - hash_map interval_argument_; - hash_map sequence_argument_; - hash_map > integer_variable_array_argument_; - hash_map > interval_array_argument_; - hash_map > sequence_array_argument_; - hash_map integer_argument_; - hash_map > integer_array_argument_; - hash_map matrix_argument_; -}; - #define IS_TYPE(type, tag) type.compare(ModelVisitor::tag) == 0 // ----- Actual Linearization ----- -class Linearizer : public ModelVisitor { +class Linearizer : public ModelParser { public: Linearizer(MPSolver* const mp_solver, ExprTranslation* tr, @@ -372,7 +250,7 @@ class Linearizer : public ModelVisitor { // Visit integer arguments. virtual void VisitIntegerArgument(const string& arg_name, int64 value) { if (DoVisit()) { - top()->set_integer_argument(arg_name, value); + Top()->SetIntegerArgument(arg_name, value); } } @@ -380,7 +258,7 @@ class Linearizer : public ModelVisitor { const int64* const values, int size) { if (DoVisit()) { - top()->set_integer_array_argument(arg_name, values, size); + Top()->SetIntegerArrayArgument(arg_name, values, size); } } @@ -389,7 +267,7 @@ class Linearizer : public ModelVisitor { int rows, int columns) { if (DoVisit()) { - top()->set_integer_matrix_argument(arg_name, values, rows, columns); + Top()->SetIntegerMatrixArgument(arg_name, values, rows, columns); } } @@ -398,7 +276,7 @@ class Linearizer : public ModelVisitor { const string& arg_name, const IntExpr* const argument) { if (DoVisit()) { - top()->set_integer_expression_argument(arg_name, argument); + Top()->SetIntegerExpressionArgument(arg_name, argument); VisitSubExpression(argument); } } @@ -408,7 +286,7 @@ class Linearizer : public ModelVisitor { const IntVar* const * arguments, int size) { if (DoVisit()) { - top()->set_integer_variable_array_argument(arg_name, arguments, size); + Top()->SetIntegerVariableArrayArgument(arg_name, arguments, size); for (int i = 0; i < size; ++i) { VisitSubExpression(arguments[i]); } @@ -446,36 +324,6 @@ class Linearizer : public ModelVisitor { actives_.pop_back(); } - void PushArgumentHolder() { - holders_.push_back(new ArgumentHolder); - } - - void PopArgumentHolder() { - CHECK(!holders_.empty()); - delete holders_.back(); - holders_.pop_back(); - STLDeleteElements(&extensions_); - extensions_.clear(); - } - - void PushExtension(const string& type_name) { - PushActive(true); - PushArgumentHolder(); - holders_.back()->set_type_name(type_name); - } - - void PopAndSaveExtension() { - CHECK(!holders_.empty()); - extensions_.push_back(holders_.back()); - holders_.pop_back(); - PopActive(); - } - - ArgumentHolder* top() const { - CHECK(!holders_.empty()); - return holders_.back(); - } - void RegisterExpression(const IntExpr* const cp_expr) { if (!ContainsKey(*translation_, cp_expr)) { MPVariable* const mp_var = mp_solver_->MakeIntVar(cp_expr->Min(), @@ -505,60 +353,60 @@ class Linearizer : public ModelVisitor { void VisitBinaryRowConstraint(double lhs, double rhs) { MPConstraint* const ct = mp_solver_->MakeRowConstraint(lhs, rhs); const IntExpr* const left = - top()->FindIntegerExpressionArgumentOrDie(ModelVisitor::kLeftArgument); + Top()->FindIntegerExpressionArgumentOrDie(ModelVisitor::kLeftArgument); const IntExpr* const right = - top()->FindIntegerExpressionArgumentOrDie(ModelVisitor::kRightArgument); + Top()->FindIntegerExpressionArgumentOrDie(ModelVisitor::kRightArgument); ct->SetCoefficient(Translated(left), 1.0); ct->SetCoefficient(Translated(right), -1.0); } void VisitUnaryRowConstraint(double lhs, double rhs) { const IntExpr* const expr = - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kExpressionArgument); MPConstraint* const ct = mp_solver_->MakeRowConstraint(lhs, rhs); ct->SetCoefficient(Translated(expr), 1.0); } void VisitEquality() { - if (top()->HasIntegerExpression(ModelVisitor::kLeftArgument)) { + if (Top()->HasIntegerExpressionArgument(ModelVisitor::kLeftArgument)) { VisitBinaryRowConstraint(0.0, 0.0); } else { const int64 value = - top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); + Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); VisitUnaryRowConstraint(value, value); } } void VisitLessOrEqual() { - if (top()->HasIntegerExpression(ModelVisitor::kLeftArgument)) { + if (Top()->HasIntegerExpressionArgument(ModelVisitor::kLeftArgument)) { VisitBinaryRowConstraint(-mp_solver_->infinity(), 0.0); } else { const int64 value = - top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); + Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); VisitUnaryRowConstraint(-mp_solver_->infinity(), value); } } void VisitGreaterOrEqual() { - if (top()->HasIntegerExpression(ModelVisitor::kLeftArgument)) { + if (Top()->HasIntegerExpressionArgument(ModelVisitor::kLeftArgument)) { VisitBinaryRowConstraint(0.0, mp_solver_->infinity()); } else { const int64 value = - top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); + Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); VisitUnaryRowConstraint(value, mp_solver_->infinity()); } } void VisitScalProdLessOrEqual() { const std::vector& cp_vars = - top()->FindIntegerVariableArrayArgumentOrDie( + Top()->FindIntegerVariableArrayArgumentOrDie( ModelVisitor::kVarsArgument); const std::vector& cp_coefficients = - top()->FindIntegerArrayArgumentOrDie( + Top()->FindIntegerArrayArgumentOrDie( ModelVisitor::kCoefficientsArgument); const int64 constant = - top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); + Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); MPConstraint* const ct = mp_solver_->MakeRowConstraint(-mp_solver_->infinity(), constant); @@ -571,10 +419,10 @@ class Linearizer : public ModelVisitor { } void VisitSum(const IntExpr* const cp_expr) { - if (top()->HasIntegerVariableArray(ModelVisitor::kVarsArgument)) { + if (Top()->HasIntegerVariableArrayArgument(ModelVisitor::kVarsArgument)) { MPConstraint* const ct = mp_solver_->MakeRowConstraint(0.0, 0.0); const std::vector& cp_vars = - top()->FindIntegerVariableArrayArgumentOrDie( + Top()->FindIntegerVariableArrayArgumentOrDie( ModelVisitor::kVarsArgument); for (int i = 0; i < cp_vars.size(); ++i) { MPVariable* const mp_var = Translated(cp_vars[i]); @@ -582,13 +430,14 @@ class Linearizer : public ModelVisitor { } RegisterExpression(cp_expr); ct->SetCoefficient(Translated(cp_expr), -1.0); - } else if (top()->HasIntegerExpression(ModelVisitor::kLeftArgument)) { + } else if (Top()->HasIntegerExpressionArgument( + ModelVisitor::kLeftArgument)) { MPConstraint* const ct = mp_solver_->MakeRowConstraint(0.0, 0.0); const IntExpr* const left = - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kLeftArgument); const IntExpr* const right = - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kRightArgument); if (left != right) { ct->SetCoefficient(Translated(left), 1.0); @@ -600,10 +449,10 @@ class Linearizer : public ModelVisitor { ct->SetCoefficient(Translated(cp_expr), -1.0); } else { const IntExpr* const expr = - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kExpressionArgument); const int64 value = - top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); + Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); MPConstraint* const ct = mp_solver_->MakeRowConstraint(-value, -value); ct->SetCoefficient(Translated(expr), 1.0); RegisterExpression(cp_expr); @@ -613,10 +462,10 @@ class Linearizer : public ModelVisitor { void VisitScalProd(const IntExpr* const cp_expr) { const std::vector& cp_vars = - top()->FindIntegerVariableArrayArgumentOrDie( + Top()->FindIntegerVariableArrayArgumentOrDie( ModelVisitor::kVarsArgument); const std::vector& cp_coefficients = - top()->FindIntegerArrayArgumentOrDie( + Top()->FindIntegerArrayArgumentOrDie( ModelVisitor::kCoefficientsArgument); CHECK_EQ(cp_vars.size(), cp_coefficients.size()); MPConstraint* const ct = mp_solver_->MakeRowConstraint(0.0, 0.0); @@ -630,13 +479,13 @@ class Linearizer : public ModelVisitor { } void VisitDifference(const IntExpr* const cp_expr) { - if (top()->HasIntegerExpression(ModelVisitor::kLeftArgument)) { + if (Top()->HasIntegerExpressionArgument(ModelVisitor::kLeftArgument)) { MPConstraint* const ct = mp_solver_->MakeRowConstraint(0.0, 0.0); const IntExpr* const left = - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kLeftArgument); const IntExpr* const right = - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kRightArgument); ct->SetCoefficient(Translated(left), 1.0); ct->SetCoefficient(Translated(right), -1.0); @@ -644,10 +493,10 @@ class Linearizer : public ModelVisitor { ct->SetCoefficient(Translated(cp_expr), -1.0); } else { const IntExpr* const expr = - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kExpressionArgument); const int64 value = - top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); + Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); MPConstraint* const ct = mp_solver_->MakeRowConstraint(value, value); ct->SetCoefficient(Translated(expr), 1.0); RegisterExpression(cp_expr); @@ -657,7 +506,7 @@ class Linearizer : public ModelVisitor { void VisitOpposite(const IntExpr* const cp_expr) { const IntExpr* const expr = - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kExpressionArgument); MPConstraint* const ct = mp_solver_->MakeRowConstraint(0.0, 0.0); ct->SetCoefficient(Translated(expr), 1.0); @@ -666,12 +515,13 @@ class Linearizer : public ModelVisitor { } void VisitProduct(const IntExpr* const cp_expr) { - if (top()->HasIntegerExpression(ModelVisitor::kExpressionArgument)) { + if (Top()->HasIntegerExpressionArgument( + ModelVisitor::kExpressionArgument)) { const IntExpr* const expr = - top()->FindIntegerExpressionArgumentOrDie( + Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kExpressionArgument); const int64 value = - top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); + Top()->FindIntegerArgumentOrDie(ModelVisitor::kValueArgument); MPConstraint* const ct = mp_solver_->MakeRowConstraint(0.0, 0.0); ct->SetCoefficient(Translated(expr), value); RegisterExpression(cp_expr); @@ -687,9 +537,9 @@ class Linearizer : public ModelVisitor { void VisitObjective() { *maximize_ = - top()->FindIntegerArgumentOrDie(ModelVisitor::kMaximizeArgument); + Top()->FindIntegerArgumentOrDie(ModelVisitor::kMaximizeArgument); *objective_ = - const_cast(top()->FindIntegerExpressionArgumentOrDie( + const_cast(Top()->FindIntegerExpressionArgumentOrDie( ModelVisitor::kExpressionArgument))->Var(); mp_solver_->SetObjectiveCoefficient(Translated(*objective_), 1.0); mp_solver_->SetOptimizationDirection(*maximize_); @@ -699,8 +549,6 @@ class Linearizer : public ModelVisitor { ExprTranslation* const translation_; IntVar** objective_; bool* maximize_; - std::vector holders_; - std::vector extensions_; std::vector actives_; }; diff --git a/constraint_solver/io.cc b/constraint_solver/io.cc index 463dd0250b..6eb42c0ae5 100644 --- a/constraint_solver/io.cc +++ b/constraint_solver/io.cc @@ -636,7 +636,7 @@ class SecondPassVisitor : public ModelVisitor { const string& arg_name, const IntExpr* const argument) { top()->set_integer_expression_argument(arg_name, - FindExpressionIndex(argument)); + FindExpressionIndexOrDie(argument)); } virtual void VisitIntegerVariableArrayArgument( @@ -645,7 +645,7 @@ class SecondPassVisitor : public ModelVisitor { int size) { std::vector indices; for (int i = 0; i < size; ++i) { - indices.push_back(FindExpressionIndex(arguments[i])); + indices.push_back(FindExpressionIndexOrDie(arguments[i])); } top()->set_integer_variable_array_argument(arg_name, indices.data(), @@ -655,7 +655,7 @@ class SecondPassVisitor : public ModelVisitor { virtual void VisitIntervalArgument( const string& arg_name, const IntervalVar* argument) { - top()->set_interval_argument(arg_name, FindIntervalIndex(argument)); + top()->set_interval_argument(arg_name, FindIntervalIndexOrDie(argument)); } virtual void VisitIntervalArrayArgument( @@ -664,7 +664,7 @@ class SecondPassVisitor : public ModelVisitor { int size) { std::vector indices; for (int i = 0; i < size; ++i) { - indices.push_back(FindIntervalIndex(arguments[i])); + indices.push_back(FindIntervalIndexOrDie(arguments[i])); } top()->set_interval_array_argument(arg_name, indices.data(), @@ -674,7 +674,7 @@ class SecondPassVisitor : public ModelVisitor { virtual void VisitSequenceArgument( const string& arg_name, const SequenceVar* argument) { - top()->set_sequence_argument(arg_name, FindSequenceIndex(argument)); + top()->set_sequence_argument(arg_name, FindSequenceIndexOrDie(argument)); } virtual void VisitSequenceArrayArgument( @@ -683,7 +683,7 @@ class SecondPassVisitor : public ModelVisitor { int size) { std::vector indices; for (int i = 0; i < size; ++i) { - indices.push_back(FindSequenceIndex(arguments[i])); + indices.push_back(FindSequenceIndexOrDie(arguments[i])); } top()->set_sequence_array_argument(arg_name, indices.data(), @@ -701,7 +701,8 @@ class SecondPassVisitor : public ModelVisitor { CPArgumentProto* const sub_proto = var_proto->add_arguments(); sub_proto->set_argument_index( TagIndex(ModelVisitor::kExpressionArgument)); - sub_proto->set_integer_expression_index(FindExpressionIndex(delegate)); + sub_proto->set_integer_expression_index( + FindExpressionIndexOrDie(delegate)); } else { const int index = model_proto_->expressions_size(); CPIntegerExpressionProto* const var_proto = @@ -744,7 +745,7 @@ class SecondPassVisitor : public ModelVisitor { CPArgumentProto* const sub_proto = var_proto->add_arguments(); sub_proto->set_argument_index( TagIndex(ModelVisitor::kVariableArgument)); - sub_proto->set_integer_expression_index(FindExpressionIndex(delegate)); + sub_proto->set_integer_expression_index(FindExpressionIndexOrDie(delegate)); CPArgumentProto* const value_proto = var_proto->add_arguments(); value_proto->set_argument_index(TagIndex(operation)); value_proto->set_integer_value(value); @@ -760,7 +761,7 @@ class SecondPassVisitor : public ModelVisitor { var_proto->set_type_index(TagIndex(ModelVisitor::kIntervalVariable)); CPArgumentProto* const sub_proto = var_proto->add_arguments(); sub_proto->set_argument_index(TagIndex(operation)); - sub_proto->set_interval_index(FindIntervalIndex(delegate)); + sub_proto->set_interval_index(FindIntervalIndexOrDie(delegate)); } else { const int index = model_proto_->intervals_size(); CPIntervalVariableProto* const var_proto = model_proto_->add_intervals(); @@ -816,7 +817,7 @@ class SecondPassVisitor : public ModelVisitor { CPArgumentProto* const sub_proto = var_proto->add_arguments(); sub_proto->set_argument_index(TagIndex(operation)); for (int i = 0; i < size; ++i) { - sub_proto->add_interval_array(FindIntervalIndex(delegates[i])); + sub_proto->add_interval_array(FindIntervalIndexOrDie(delegates[i])); } } @@ -832,7 +833,7 @@ class SecondPassVisitor : public ModelVisitor { sub_proto->set_argument_index(TagIndex(ModelVisitor::kIntervalsArgument)); for (int i = 0; i < sequence->size(); ++i) { IntervalVar* const interval = sequence->Interval(i); - sub_proto->add_interval_array(FindIntervalIndex(interval)); + sub_proto->add_interval_array(FindIntervalIndexOrDie(interval)); } } @@ -942,22 +943,16 @@ class SecondPassVisitor : public ModelVisitor { return holders_.back(); } - int FindExpressionIndex(const IntExpr* const expression) const { - const int result = FindWithDefault(expression_map_, expression, -1); - CHECK_NE(-1, result); - return result; + int FindExpressionIndexOrDie(const IntExpr* const expression) const { + return FindOrDie(expression_map_, expression); } - int FindIntervalIndex(const IntervalVar* const interval) const { - const int result = FindWithDefault(interval_map_, interval, -1); - CHECK_NE(-1, result); - return result; + int FindIntervalIndexOrDie(const IntervalVar* const interval) const { + return FindOrDie(interval_map_, interval); } - int FindSequenceIndex(const SequenceVar* const sequence) const { - const int result = FindWithDefault(sequence_map_, sequence, -1); - CHECK_NE(-1, result); - return result; + int FindSequenceIndexOrDie(const SequenceVar* const sequence) const { + return FindOrDie(sequence_map_, sequence); } diff --git a/constraint_solver/local_search.cc b/constraint_solver/local_search.cc index 2fbb888b28..08db08fdf7 100644 --- a/constraint_solver/local_search.cc +++ b/constraint_solver/local_search.cc @@ -47,6 +47,22 @@ DEFINE_int32(cp_local_search_tsp_lns_size, 10, namespace operations_research { +// Utility methods to ensure the communication between local search and the +// search. + +// Returns true if a local optimum has been reached and that it cannot be +// improved. +bool LocalOptimumReached(Search* const search); + +// Returns true if the search accepts the delta (actually checking this by +// calling AcceptDelta on the monitors of the search). +bool AcceptDelta(Search* const search, + Assignment* delta, + Assignment* deltadelta); + +// Notifies the search that a neighbor has been accepted by local search. +void AcceptNeighbor(Search* const search); + // ----- Base operator class for operators manipulating IntVars ----- IntVarLocalSearchOperator::IntVarLocalSearchOperator() @@ -2830,7 +2846,8 @@ Decision* FindOneNeighbor::Next(Solver* const solver) { // to resync filters on non-incremental (empty) moves. // TODO(user): Don't call both if no filter is incremental and one // of them returned false. - const bool mh_filter = solver->AcceptDelta(delta, deltadelta); + const bool mh_filter = + AcceptDelta(solver->ParentSearch(), delta, deltadelta); const bool move_filter = FilterAccept(delta, deltadelta); if (mh_filter && move_filter) { solver->filtered_neighbors_ += 1; @@ -2845,7 +2862,7 @@ Decision* FindOneNeighbor::Next(Solver* const solver) { } } else { if (neighbor_found_) { - solver->AcceptNeighbor(); + AcceptNeighbor(solver->ParentSearch()); // Keeping the code in case a performance problem forces us to // use the old code with a zero test on pool_. // reference_assignment_->Copy(assignment_); @@ -3208,7 +3225,7 @@ Decision* LocalSearch::Next(Solver* const solver) { const int state = decision->state(); switch (state) { case NestedSolveDecision::DECISION_FAILED: { - if (!solver->LocalOptimum()) { + if (!LocalOptimumReached(solver->ActiveSearch())) { nested_decision_index_ = -1; // Stop the search } solver->Fail(); diff --git a/constraint_solver/routing.cc b/constraint_solver/routing.cc index f19d2af848..9aa62e3b32 100644 --- a/constraint_solver/routing.cc +++ b/constraint_solver/routing.cc @@ -1186,6 +1186,8 @@ RoutingModel::GetSelectedFirstSolutionStrategy() const { return ROUTING_PATH_CHEAPEST_ARC; } else if (FLAGS_routing_first_solution.compare("AllUnperformed") == 0) { return ROUTING_ALL_UNPERFORMED; + } else if (FLAGS_routing_first_solution.compare("BestInsertion") == 0) { + return ROUTING_BEST_INSERTION; } return first_solution_strategy_; } @@ -1963,19 +1965,32 @@ void RoutingModel::SetUpSearch() { kint64max); std::vector operators = extra_operators_; + LocalSearchOperator* insertion_operator = NULL; 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)); + insertion_operator = MakePairActive(solver_.get(), + nexts_.get(), + vehicle_vars, + pickup_delivery_pairs_, + size); + operators.push_back(insertion_operator); operators.push_back(MakePairRelocate(solver_.get(), nexts_.get(), vehicle_vars, pickup_delivery_pairs_, size)); + } else { + if (homogeneous_costs_) { + insertion_operator = solver_->MakeOperator(nexts_.get(), + size, + Solver::MAKEACTIVE); + } else { + insertion_operator = solver_->MakeOperator(nexts_.get(), + vehicle_vars_.get(), + size, + Solver::MAKEACTIVE); + } } if (vehicles_ > 1) { if (!FLAGS_routing_no_relocate) { @@ -2034,62 +2049,6 @@ void RoutingModel::SetUpSearch() { Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE); - DecisionBuilder* first_solution = finalize_solution; - switch (GetSelectedFirstSolutionStrategy()) { - case ROUTING_GLOBAL_CHEAPEST_ARC: - LG << "Using ROUTING_GLOBAL_CHEAPEST_ARC"; - first_solution = - solver_->MakePhase(nexts_.get(), size, - NewPermanentCallback( - this, - &RoutingModel::GetFirstSolutionCost), - Solver::CHOOSE_STATIC_GLOBAL_BEST); - break; - case ROUTING_LOCAL_CHEAPEST_ARC: - LG << "Using ROUTING_LOCAL_CHEAPEST_ARC"; - first_solution = - solver_->MakePhase(nexts_.get(), size, - Solver::CHOOSE_FIRST_UNBOUND, - NewPermanentCallback( - this, - &RoutingModel::GetFirstSolutionCost)); - break; - case ROUTING_PATH_CHEAPEST_ARC: - LG << "Using ROUTING_PATH_CHEAPEST_ARC"; - first_solution = - solver_->MakePhase(nexts_.get(), size, - Solver::CHOOSE_PATH, - NewPermanentCallback( - this, - &RoutingModel::GetFirstSolutionCost)); - break; - case ROUTING_EVALUATOR_STRATEGY: - LG << "Using ROUTING_EVALUATOR_STRATEGY"; - CHECK(first_solution_evaluator_ != NULL); - first_solution = - solver_->MakePhase(nexts_.get(), size, - Solver::CHOOSE_PATH, - NewPermanentCallback( - first_solution_evaluator_.get(), - &Solver::IndexEvaluator2::Run)); - break; - 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"; - } - if (FLAGS_routing_use_first_solution_dive) { - DecisionBuilder* apply = - solver_->MakeApplyBranchSelector(NewPermanentCallback(&LeftDive)); - first_solution = solver_->Compose(apply, first_solution); - } - std::vector filters; if (FLAGS_routing_use_objective_filter) { if (homogeneous_costs_) { @@ -2145,6 +2104,92 @@ void RoutingModel::SetUpSearch() { ls_limit_, filters); + DecisionBuilder* first_solution = finalize_solution; + switch (GetSelectedFirstSolutionStrategy()) { + case ROUTING_GLOBAL_CHEAPEST_ARC: + LG << "Using ROUTING_GLOBAL_CHEAPEST_ARC"; + first_solution = + solver_->MakePhase(nexts_.get(), size, + NewPermanentCallback( + this, + &RoutingModel::GetFirstSolutionCost), + Solver::CHOOSE_STATIC_GLOBAL_BEST); + break; + case ROUTING_LOCAL_CHEAPEST_ARC: + LG << "Using ROUTING_LOCAL_CHEAPEST_ARC"; + first_solution = + solver_->MakePhase(nexts_.get(), size, + Solver::CHOOSE_FIRST_UNBOUND, + NewPermanentCallback( + this, + &RoutingModel::GetFirstSolutionCost)); + break; + case ROUTING_PATH_CHEAPEST_ARC: + LG << "Using ROUTING_PATH_CHEAPEST_ARC"; + first_solution = + solver_->MakePhase(nexts_.get(), size, + Solver::CHOOSE_PATH, + NewPermanentCallback( + this, + &RoutingModel::GetFirstSolutionCost)); + break; + case ROUTING_EVALUATOR_STRATEGY: + LG << "Using ROUTING_EVALUATOR_STRATEGY"; + CHECK(first_solution_evaluator_ != NULL); + first_solution = + solver_->MakePhase(nexts_.get(), size, + Solver::CHOOSE_PATH, + NewPermanentCallback( + first_solution_evaluator_.get(), + &Solver::IndexEvaluator2::Run)); + break; + case ROUTING_DEFAULT_STRATEGY: + LG << "Using DEFAULT"; + break; + case ROUTING_ALL_UNPERFORMED: + first_solution = + solver_->RevAlloc(new AllUnperformed(this)); + break; + case ROUTING_BEST_INSERTION: { + LG << "Using ROUTING_BEST_INSERTION"; + SearchLimit* const ls_limit = solver_->MakeLimit(time_limit_ms_, + kint64max, + kint64max, + kint64max, + true); + DecisionBuilder* const finalize = + solver_->MakeSolveOnce(finalize_solution, lns_limit_); + LocalSearchPhaseParameters* const insertion_parameters = + solver_->MakeLocalSearchPhaseParameters( + insertion_operator, + finalize, + ls_limit, + filters); + std::vector monitors; + monitors.push_back(limit_); + first_solution = solver_->MakeNestedOptimize( + solver_->MakeLocalSearchPhase( + nexts_.get(), + size, + solver_->RevAlloc(new AllUnperformed(this)), + insertion_parameters), + assignment_, + false, + FLAGS_routing_optimization_step, + monitors); + first_solution = solver_->Compose(first_solution, finalize); + break; + } + default: + LOG(WARNING) << "Unknown argument for routing_first_solution, " + "using default"; + } + if (FLAGS_routing_use_first_solution_dive) { + DecisionBuilder* apply = + solver_->MakeApplyBranchSelector(NewPermanentCallback(&LeftDive)); + first_solution = solver_->Compose(apply, first_solution); + } + if (FLAGS_routing_dfs) { solve_db_ = finalize_solution; } else { diff --git a/constraint_solver/routing.h b/constraint_solver/routing.h index 542f582429..4b33670215 100644 --- a/constraint_solver/routing.h +++ b/constraint_solver/routing.h @@ -198,7 +198,11 @@ class RoutingModel { 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 + ROUTING_ALL_UNPERFORMED, + // Iteratively build a solution by inserting nodes at their cheapest (best) + // position. As of 2/2012, only works on models with optional nodes + // (with finite penalty costs). + ROUTING_BEST_INSERTION }; // Metaheuristics used to guide the search. Apart greedy descent, they will diff --git a/constraint_solver/visitor.cc b/constraint_solver/visitor.cc new file mode 100644 index 0000000000..f52471d98b --- /dev/null +++ b/constraint_solver/visitor.cc @@ -0,0 +1,311 @@ +// Copyright 2010-2011 Google +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "base/hash.h" +#include "base/hash.h" +#include +#include + +#include "base/integral_types.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/scoped_ptr.h" +#include "base/concise_iterator.h" +#include "base/map-util.h" +#include "base/stl_util.h" +#include "constraint_solver/constraint_solver.h" +#include "constraint_solver/constraint_solveri.h" + +namespace operations_research { +// ---------- ArgumentHolder ---------- + +const string& ArgumentHolder::TypeName() const { + return type_name_; +} + +void ArgumentHolder::SetTypeName(const string& type_name) { + type_name_ = type_name; +} + +void ArgumentHolder::SetIntegerArgument(const string& arg_name, int64 value) { + integer_argument_[arg_name] = value; +} + +void ArgumentHolder::SetIntegerArrayArgument( + const string& arg_name, + const int64* const values, + int size) { + for (int i = 0; i < size; ++i) { + integer_array_argument_[arg_name].push_back(values[i]); + } +} + +void ArgumentHolder::SetIntegerMatrixArgument( + const string& arg_name, + const int64* const * const values, + int rows, + int columns) { + matrix_argument_[arg_name] = Matrix(values, rows, columns); +} + +void ArgumentHolder::SetIntegerExpressionArgument( + const string& arg_name, + const IntExpr* const expr) { + integer_expression_argument_[arg_name] = expr; +} + +void ArgumentHolder::SetIntegerVariableArrayArgument( + const string& arg_name, + const IntVar* const * const vars, + int size) { + for (int i = 0; i < size; ++i) { + integer_variable_array_argument_[arg_name].push_back(vars[i]); + } +} + +void ArgumentHolder::SetIntervalArgument( + const string& arg_name, + const IntervalVar* const var) { + interval_argument_[arg_name] = var; +} + +void ArgumentHolder::SetIntervalArrayArgument( + const string& arg_name, + const IntervalVar* const * const vars, + int size) { + for (int i = 0; i < size; ++i) { + interval_array_argument_[arg_name].push_back(vars[i]); + } +} + +void ArgumentHolder::SetSequenceArgument( + const string& arg_name, + const SequenceVar* const var) { + sequence_argument_[arg_name] = var; +} + +void ArgumentHolder::SetSequenceArrayArgument( + const string& arg_name, + const SequenceVar* const * const vars, + int size) { + for (int i = 0; i < size; ++i) { + sequence_array_argument_[arg_name].push_back(vars[i]); + } +} + +bool ArgumentHolder::HasIntegerExpressionArgument( + const string& arg_name) const { + return ContainsKey(integer_expression_argument_, arg_name); +} + +bool ArgumentHolder::HasIntegerVariableArrayArgument( + const string& arg_name) const { + return ContainsKey(integer_variable_array_argument_, arg_name); +} + + +int64 ArgumentHolder::FindIntegerArgumentWithDefault( + const string& arg_name, + int64 def) const { + return FindWithDefault(integer_argument_, arg_name, def); +} + +int64 ArgumentHolder::FindIntegerArgumentOrDie(const string& arg_name) const { + return FindOrDie(integer_argument_, arg_name); +} + +const std::vector& ArgumentHolder::FindIntegerArrayArgumentOrDie( + const string& arg_name) const { + return FindOrDie(integer_array_argument_, arg_name); +} + + +const IntExpr* ArgumentHolder::FindIntegerExpressionArgumentOrDie( + const string& arg_name) const { + return FindOrDie(integer_expression_argument_, arg_name); +} + +const std::vector& +ArgumentHolder::FindIntegerVariableArrayArgumentOrDie( + const string& arg_name) const { + return FindOrDie(integer_variable_array_argument_, arg_name); +} + +const ArgumentHolder::Matrix& ArgumentHolder::FindIntegerMatrixArgumentOrDie( + const string& arg_name) const { + return FindOrDie(matrix_argument_, arg_name); +} + +// ---------- ModelParser --------- + +ModelParser::ModelParser() {} + +ModelParser::~ModelParser() { + CHECK(holders_.empty()); +} + +void ModelParser::BeginVisitModel(const string& solver_name) { + PushArgumentHolder(); +} + +void ModelParser::EndVisitModel(const string& solver_name) { + PopArgumentHolder(); +} + +void ModelParser::BeginVisitConstraint(const string& type_name, + const Constraint* const constraint) { + PushArgumentHolder(); +} + +void ModelParser::EndVisitConstraint(const string& type_name, + const Constraint* const constraint) { + // Constraint parsing is usually done here. + PopArgumentHolder(); +} + +void ModelParser::BeginVisitIntegerExpression(const string& type_name, + const IntExpr* const expr) { + PushArgumentHolder(); +} + +void ModelParser::EndVisitIntegerExpression(const string& type_name, + const IntExpr* const expr) { + // Expression parsing is usually done here. + PopArgumentHolder(); +} + +void ModelParser::VisitIntegerVariable(const IntVar* const variable, + const IntExpr* const delegate) { + // Usual place for parsing. +} + +void ModelParser::VisitIntegerVariable(const IntVar* const variable, + const string& operation, + int64 value, + const IntVar* const delegate) { + delegate->Accept(this); + // Usual place for parsing. +} + +void ModelParser::VisitIntervalVariable(const IntervalVar* const variable, + const string& operation, + const IntervalVar* const delegate) { + if (delegate != NULL) { + delegate->Accept(this); + } + // Usual place for parsing. +} + +void ModelParser::VisitIntervalVariable(const IntervalVar* const variable, + const string& operation, + const IntervalVar* const * delegates, + int size) { + for (int i = 0; i < size; ++i) { + delegates[i]->Accept(this); + } + // Usual place for parsing. +} + +void ModelParser::VisitSequenceVariable(const SequenceVar* const variable) { + // Usual place for parsing. +} + +// Integer arguments +void ModelParser::VisitIntegerArgument(const string& arg_name, int64 value) { + Top()->SetIntegerArgument(arg_name, value); +} + +void ModelParser::VisitIntegerArrayArgument(const string& arg_name, + const int64* const values, + int size) { + Top()->SetIntegerArrayArgument(arg_name, values, size); +} + +void ModelParser::VisitIntegerMatrixArgument(const string& arg_name, + const int64* const * const values, + int rows, + int columns) { + Top()->SetIntegerMatrixArgument(arg_name, values, rows, columns); +} + +// Variables. +void ModelParser::VisitIntegerExpressionArgument( + const string& arg_name, + const IntExpr* const argument) { + Top()->SetIntegerExpressionArgument(arg_name, argument); + argument->Accept(this); +} + +void ModelParser::VisitIntegerVariableArrayArgument( + const string& arg_name, + const IntVar* const * arguments, + int size) { + Top()->SetIntegerVariableArrayArgument(arg_name, arguments, size); + for (int i = 0; i < size; ++i) { + arguments[i]->Accept(this); + } +} + +// Visit interval argument. +void ModelParser::VisitIntervalArgument( + const string& arg_name, + const IntervalVar* const argument) { + Top()->SetIntervalArgument(arg_name, argument); + argument->Accept(this); +} + +void ModelParser::VisitIntervalArrayArgument( + const string& arg_name, + const IntervalVar* const * arguments, + int size) { + Top()->SetIntervalArrayArgument(arg_name, arguments, size); + for (int i = 0; i < size; ++i) { + arguments[i]->Accept(this); + } +} + +// Visit sequence argument. +void ModelParser::VisitSequenceArgument( + const string& arg_name, + const SequenceVar* const argument) { + Top()->SetSequenceArgument(arg_name, argument); + argument->Accept(this); +} + +void ModelParser::VisitSequenceArrayArgument( + const string& arg_name, + const SequenceVar* const * arguments, + int size) { + Top()->SetSequenceArrayArgument(arg_name, arguments, size); + for (int i = 0; i < size; ++i) { + arguments[i]->Accept(this); + } +} + +void ModelParser::PushArgumentHolder() { + holders_.push_back(new ArgumentHolder); +} + +void ModelParser::PopArgumentHolder() { + CHECK(!holders_.empty()); + delete holders_.back(); + holders_.pop_back(); +} + +ArgumentHolder* ModelParser::Top() const { + CHECK(!holders_.empty()); + return holders_.back(); +} +} // namespace operations_research diff --git a/makefiles/Makefile.cpp.mk b/makefiles/Makefile.cpp.mk index 5221681457..1dfc0ccf5e 100644 --- a/makefiles/Makefile.cpp.mk +++ b/makefiles/Makefile.cpp.mk @@ -171,7 +171,8 @@ CONSTRAINT_SOLVER_LIB_OS = \ objs/timetabling.$O\ objs/trace.$O\ objs/tree_monitor.$O\ - objs/utilities.$O + objs/utilities.$O \ + objs/visitor.$O objs/alldiff_cst.$O:constraint_solver/alldiff_cst.cc $(CCC) $(CFLAGS) -c constraint_solver/alldiff_cst.cc $(OBJOUT)objs/alldiff_cst.$O @@ -295,6 +296,9 @@ objs/tree_monitor.$O:constraint_solver/tree_monitor.cc objs/utilities.$O:constraint_solver/utilities.cc $(CCC) $(CFLAGS) -c constraint_solver/utilities.cc $(OBJOUT)objs/utilities.$O +objs/visitor.$O:constraint_solver/visitor.cc + $(CCC) $(CFLAGS) -c constraint_solver/visitor.cc $(OBJOUT)objs/visitor.$O + $(LIBPREFIX)constraint_solver.$(LIBSUFFIX): $(CONSTRAINT_SOLVER_LIB_OS) $(LINKCMD) $(LINKPREFIX)$(LIBPREFIX)constraint_solver.$(LIBSUFFIX) $(CONSTRAINT_SOLVER_LIB_OS)