clean up protocol on local search; regroup model visitors code

This commit is contained in:
lperron@google.com
2012-02-14 14:16:12 +00:00
parent 659bab6225
commit adc36fb12e
11 changed files with 700 additions and 519 deletions

View File

@@ -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<const IntVar*>& 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<string, const IntExpr*> integer_expression_argument_;
hash_map<string, const IntervalVar*> interval_argument_;
hash_map<string, const SequenceVar*> sequence_argument_;
hash_map<string,
std::vector<const IntVar*> > integer_variable_array_argument_;
hash_map<string, std::vector<const IntervalVar*> > interval_array_argument_;
hash_map<string, std::vector<const SequenceVar*> > sequence_array_argument_;
hash_map<string, Matrix> matrix_argument_;
};
class CollectVariablesVisitor : public ModelVisitor {
class CollectVariablesVisitor : public ModelParser {
public:
CollectVariablesVisitor(std::vector<IntVar*>* const primary_integer_variables,
std::vector<IntVar*>* 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<IntExpr*>(
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<IntExpr*>(
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<hash_set<int> > 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<const IntVar*>& 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<const IntVar*>& vars =
top()->FindIntegerVariableArrayArgumentOrDie(
Top()->FindIntegerVariableArrayArgumentOrDie(
ModelVisitor::kActiveArgument);
for (int i = 0; i < vars.size(); ++i) {
IgnoreIntegerVariable(const_cast<IntVar*>(vars[i]));
}
} else if (type_name.compare(ModelVisitor::kPathCumul) == 0) {
const std::vector<const IntVar*>& vars =
top()->FindIntegerVariableArrayArgumentOrDie(
Top()->FindIntegerVariableArrayArgumentOrDie(
ModelVisitor::kActiveArgument);
for (int i = 0; i < vars.size(); ++i) {
IgnoreIntegerVariable(const_cast<IntVar*>(vars[i]));
}
} else if (type_name.compare(ModelVisitor::kDistribute) == 0) {
const std::vector<const IntVar*>& vars =
top()->FindIntegerVariableArrayArgumentOrDie(
Top()->FindIntegerVariableArrayArgumentOrDie(
ModelVisitor::kCardsArgument);
for (int i = 0; i < vars.size(); ++i) {
IgnoreIntegerVariable(const_cast<IntVar*>(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<IntVar*>(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<IntVar*> ignored_set_;
hash_set<SequenceVar*> sequence_set_;
hash_set<IntervalVar*> interval_set_;
std::vector<ArgumentHolder*> holders_;
};
} // namespace

View File

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

View File

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

View File

@@ -1617,6 +1617,154 @@ class DependencyGraph : public BaseObject {
std::vector<DependencyGraphNode*> 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<int64>& 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<const IntVar*>& FindIntegerVariableArrayArgumentOrDie(
const string& arg_name) const;
private:
string type_name_;
hash_map<string, int64> integer_argument_;
hash_map<string, std::vector<int64> > integer_array_argument_;
hash_map<string, Matrix> matrix_argument_;
hash_map<string, const IntExpr*> integer_expression_argument_;
hash_map<string, const IntervalVar*> interval_argument_;
hash_map<string, const SequenceVar*> sequence_argument_;
hash_map<string, std::vector<const IntVar*> > integer_variable_array_argument_;
hash_map<string, std::vector<const IntervalVar*> > interval_array_argument_;
hash_map<string, std::vector<const SequenceVar*> > 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<ArgumentHolder*> holders_;
};
#endif // SWIG
} // namespace operations_research
#endif // OR_TOOLS_CONSTRAINT_SOLVER_CONSTRAINT_SOLVERI_H_

View File

@@ -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<const IntExpr*, MPVariable*> 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<const IntVar*>& 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<int64>& 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<string, const IntExpr*> integer_expression_argument_;
hash_map<string, const IntervalVar*> interval_argument_;
hash_map<string, const SequenceVar*> sequence_argument_;
hash_map<string,
std::vector<const IntVar*> > integer_variable_array_argument_;
hash_map<string, std::vector<const IntervalVar*> > interval_array_argument_;
hash_map<string, std::vector<const SequenceVar*> > sequence_array_argument_;
hash_map<string, int64> integer_argument_;
hash_map<string, std::vector<int64> > integer_array_argument_;
hash_map<string, Matrix> 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<const IntVar*>& cp_vars =
top()->FindIntegerVariableArrayArgumentOrDie(
Top()->FindIntegerVariableArrayArgumentOrDie(
ModelVisitor::kVarsArgument);
const std::vector<int64>& 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<const IntVar*>& 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<const IntVar*>& cp_vars =
top()->FindIntegerVariableArrayArgumentOrDie(
Top()->FindIntegerVariableArrayArgumentOrDie(
ModelVisitor::kVarsArgument);
const std::vector<int64>& 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<IntExpr*>(top()->FindIntegerExpressionArgumentOrDie(
const_cast<IntExpr*>(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<ArgumentHolder*> holders_;
std::vector<ArgumentHolder*> extensions_;
std::vector<bool> actives_;
};

View File

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

View File

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

View File

@@ -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<LocalSearchOperator*> 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<LocalSearchFilter*> 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<SearchMonitor*> 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 {

View File

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

View File

@@ -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 <stddef.h>
#include <string.h>
#include "base/hash.h"
#include "base/hash.h"
#include <string>
#include <vector>
#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<int64>& 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<const IntVar*>&
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

View File

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