replace old expression cache implementation; move and hide LocalSearch and NestedSolveDecision classes
This commit is contained in:
@@ -1304,13 +1304,10 @@ Solver::Solver(const string& name, const SolverParameters& parameters)
|
||||
demon_monitor_(BuildDemonMonitor(parameters.profile_level)),
|
||||
true_constraint_(NULL),
|
||||
false_constraint_(NULL),
|
||||
equality_var_cst_cache_(NULL),
|
||||
unequality_var_cst_cache_(NULL),
|
||||
greater_equal_var_cst_cache_(NULL),
|
||||
less_equal_var_cst_cache_(NULL),
|
||||
fail_decision_(new FailDecision()),
|
||||
constraint_index_(0),
|
||||
additional_constraint_index_(0) {
|
||||
additional_constraint_index_(0),
|
||||
model_cache_(NULL) {
|
||||
Init();
|
||||
}
|
||||
|
||||
@@ -1338,16 +1335,15 @@ Solver::Solver(const string& name)
|
||||
demon_monitor_(BuildDemonMonitor(parameters_.profile_level)),
|
||||
true_constraint_(NULL),
|
||||
false_constraint_(NULL),
|
||||
equality_var_cst_cache_(NULL),
|
||||
unequality_var_cst_cache_(NULL),
|
||||
greater_equal_var_cst_cache_(NULL),
|
||||
less_equal_var_cst_cache_(NULL),
|
||||
fail_decision_(new FailDecision()),
|
||||
constraint_index_(0),
|
||||
additional_constraint_index_(0) {
|
||||
additional_constraint_index_(0),
|
||||
model_cache_(NULL) {
|
||||
Init();
|
||||
}
|
||||
|
||||
extern ModelCache* BuildModelCache(Solver* const solver);
|
||||
|
||||
void Solver::Init() {
|
||||
for (int i = 0; i < kNumPriorities; ++i) {
|
||||
demon_runs_[i] = 0;
|
||||
@@ -1356,9 +1352,9 @@ void Solver::Init() {
|
||||
PushSentinel(SOLVER_CTOR_SENTINEL);
|
||||
InitCachedIntConstants(); // to be called after the SENTINEL is set.
|
||||
InitCachedConstraint(); // Cache the true constraint.
|
||||
InitBoolVarCaches();
|
||||
InitBuilders();
|
||||
timer_->Restart();
|
||||
model_cache_.reset(BuildModelCache(this));
|
||||
}
|
||||
|
||||
Solver::~Solver() {
|
||||
|
||||
@@ -114,9 +114,7 @@ class Demon;
|
||||
class DemonMonitor;
|
||||
class DemonProfiler;
|
||||
class Dimension;
|
||||
class EqualityVarCstCache;
|
||||
class ExpressionCache;
|
||||
class GreaterEqualCstCache;
|
||||
class IntExpr;
|
||||
class IntVar;
|
||||
class IntVarAssignmentProto;
|
||||
@@ -124,10 +122,10 @@ class IntVarElement;
|
||||
class IntervalVar;
|
||||
class IntervalVarAssignmentProto;
|
||||
class IntervalVarElement;
|
||||
class LessEqualCstCache;
|
||||
class LocalSearchFilter;
|
||||
class LocalSearchOperator;
|
||||
class LocalSearchPhaseParameters;
|
||||
class ModelCache;
|
||||
class ModelVisitor;
|
||||
class MPSolver;
|
||||
class NoGoodManager;
|
||||
@@ -145,7 +143,6 @@ class SolutionCollector;
|
||||
class SolutionPool;
|
||||
class Solver;
|
||||
class SymmetryBreaker;
|
||||
class UnequalityVarCstCache;
|
||||
struct StateInfo;
|
||||
struct Trail;
|
||||
template <class T> class ConstPtrArray;
|
||||
@@ -2275,6 +2272,8 @@ class Solver {
|
||||
Demon* RegisterDemon(Demon* const d);
|
||||
// Returns the active search, NULL outside search.
|
||||
Search* ActiveSearch() const;
|
||||
// Returns the cache of the model.
|
||||
ModelCache* Cache() const;
|
||||
|
||||
friend class BaseIntExpr;
|
||||
friend class Constraint;
|
||||
@@ -2285,7 +2284,6 @@ class Solver {
|
||||
friend class PropagationBaseObject;
|
||||
friend class Queue;
|
||||
friend class SearchMonitor;
|
||||
friend class VarCstCache;
|
||||
|
||||
#ifndef SWIG
|
||||
friend void InternalSaveBooleanVarValue(Solver* const, IntVar* const);
|
||||
@@ -2345,7 +2343,6 @@ class Solver {
|
||||
|
||||
void InitCachedIntConstants();
|
||||
void InitCachedConstraint();
|
||||
void InitBoolVarCaches();
|
||||
void InitBuilders();
|
||||
void DeleteBuilders();
|
||||
|
||||
@@ -2393,11 +2390,6 @@ class Solver {
|
||||
Constraint* true_constraint_;
|
||||
Constraint* false_constraint_;
|
||||
|
||||
// status var caches:
|
||||
EqualityVarCstCache* equality_var_cst_cache_;
|
||||
UnequalityVarCstCache* unequality_var_cst_cache_;
|
||||
GreaterEqualCstCache* greater_equal_var_cst_cache_;
|
||||
LessEqualCstCache* less_equal_var_cst_cache_;
|
||||
scoped_ptr<Decision> fail_decision_;
|
||||
int constraint_index_;
|
||||
int additional_constraint_index_;
|
||||
@@ -2407,6 +2399,8 @@ class Solver {
|
||||
hash_map<string, ConstraintBuilder*> constraint_builders_;
|
||||
hash_map<string, IntervalVariableBuilder*> interval_builders_;
|
||||
|
||||
scoped_ptr<ModelCache> model_cache_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Solver);
|
||||
};
|
||||
|
||||
|
||||
@@ -384,8 +384,6 @@ Demon* MakeDelayedConstraintDemon2(Solver* const s,
|
||||
|
||||
#endif // !defined(SWIG)
|
||||
|
||||
class NestedSolveDecision;
|
||||
|
||||
// ---------- Local search operators ----------
|
||||
|
||||
// A local search operator is an object which defines the neighborhood of a
|
||||
@@ -707,56 +705,6 @@ class IntVarLocalSearchFilter : public LocalSearchFilter {
|
||||
hash_map<const IntVar*, int64> var_to_index_;
|
||||
};
|
||||
|
||||
// ----- Local search decision builder -----
|
||||
|
||||
// Given a first solution (resulting from either an initial assignment or the
|
||||
// result of a decision builder), it searches for neighbors using a local
|
||||
// search operator. The first solution corresponds to the first leaf of the
|
||||
// search.
|
||||
// The local search applies to the variables contained either in the assignment
|
||||
// or the vector of variables passed.
|
||||
|
||||
class LocalSearch : public DecisionBuilder {
|
||||
public:
|
||||
LocalSearch(Assignment* const assignment,
|
||||
SolutionPool* const pool,
|
||||
LocalSearchOperator* const ls_operator,
|
||||
DecisionBuilder* const sub_decision_builder,
|
||||
SearchLimit* const limit,
|
||||
const std::vector<LocalSearchFilter*>& filters);
|
||||
// TODO(user): find a way to not have to pass vars here: redundant with
|
||||
// variables in operators
|
||||
LocalSearch(IntVar* const* vars,
|
||||
int size,
|
||||
SolutionPool* const pool,
|
||||
DecisionBuilder* const first_solution,
|
||||
LocalSearchOperator* const ls_operator,
|
||||
DecisionBuilder* const sub_decision_builder,
|
||||
SearchLimit* const limit,
|
||||
const std::vector<LocalSearchFilter*>& filters);
|
||||
virtual ~LocalSearch();
|
||||
virtual Decision* Next(Solver* const solver);
|
||||
virtual string DebugString() const {
|
||||
return "LocalSearch";
|
||||
}
|
||||
virtual void Accept(ModelVisitor* const visitor) const;
|
||||
|
||||
protected:
|
||||
void PushFirstSolutionDecision(DecisionBuilder* first_solution);
|
||||
void PushLocalSearchDecision();
|
||||
|
||||
private:
|
||||
Assignment* assignment_;
|
||||
SolutionPool* const pool_;
|
||||
LocalSearchOperator* const ls_operator_;
|
||||
DecisionBuilder* const sub_decision_builder_;
|
||||
std::vector<NestedSolveDecision*> nested_decisions_;
|
||||
int nested_decision_index_;
|
||||
SearchLimit* const limit_;
|
||||
const std::vector<LocalSearchFilter*> filters_;
|
||||
bool has_started_;
|
||||
};
|
||||
|
||||
// ---------- SymmetryBreaker ----------
|
||||
|
||||
class SymmetryManager;
|
||||
@@ -951,6 +899,10 @@ class ModelCache {
|
||||
VAR_CONSTANT_MAX,
|
||||
VAR_CONSTANT_MIN,
|
||||
VAR_CONSTANT_SUM,
|
||||
VAR_CONSTANT_IS_EQUAL,
|
||||
VAR_CONSTANT_IS_NOT_EQUAL,
|
||||
VAR_CONSTANT_IS_GREATER_OR_EQUAL,
|
||||
VAR_CONSTANT_IS_LESS_OR_EQUAL,
|
||||
VAR_CONSTANT_EXPRESSION_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -333,128 +333,6 @@ class IsEqualCstCt : public Constraint {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// ---------- VarCstCache ----------
|
||||
|
||||
class VarCstCache : public BaseObject {
|
||||
public:
|
||||
explicit VarCstCache(Solver* const s)
|
||||
: solver_(s), size_(FLAGS_cache_initial_size), counter_(0) {
|
||||
array_ = s->UnsafeRevAllocArray(new Cell*[size_]);
|
||||
for (int i = 0; i < size_; ++i) {
|
||||
array_[i] = NULL;
|
||||
}
|
||||
}
|
||||
virtual ~VarCstCache() {}
|
||||
|
||||
void Insert(IntVar* const var,
|
||||
int64 value,
|
||||
IntVar* const boolvar) {
|
||||
int code = HashCode(var, value) % size_;
|
||||
Cell* tmp = array_[code];
|
||||
while (tmp != NULL) {
|
||||
if (tmp->value == value && tmp->var == var) {
|
||||
return;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
UnsafeInsert(var, value, boolvar);
|
||||
}
|
||||
|
||||
Solver* const solver() const { return solver_; }
|
||||
|
||||
protected:
|
||||
IntVar* Find(IntVar* const var, int64 value) const {
|
||||
int code = HashCode(var, value) % size_;
|
||||
Cell* tmp = array_[code];
|
||||
while (tmp) {
|
||||
if (tmp->value == value && tmp->var == var) {
|
||||
return tmp->boolvar;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
return NULL;
|
||||
// TODO(user): bench optim that moves the found cell first in the list.
|
||||
}
|
||||
|
||||
void UnsafeInsert(IntVar* const var, int64 value, IntVar* const boolvar) {
|
||||
int code = HashCode(var, value) % size_;
|
||||
Cell* tmp = array_[code];
|
||||
Cell* cell = solver_->UnsafeRevAlloc(new Cell(var, value, boolvar, tmp));
|
||||
solver_->SaveValue(reinterpret_cast<void**>(&array_[code]));
|
||||
array_[code] = cell;
|
||||
solver_->SaveAndAdd(&counter_, 1);
|
||||
if (counter_ > 2 * size_) {
|
||||
Double();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct Cell {
|
||||
public:
|
||||
Cell(IntVar* const v, int64 c, IntVar* b, Cell* n)
|
||||
: var(v), value(c), boolvar(b), next(n) {}
|
||||
IntVar* const var;
|
||||
const int64 value;
|
||||
IntVar* const boolvar;
|
||||
Cell* next;
|
||||
};
|
||||
|
||||
static uint64 HashCode(IntVar* const var, int64 value) {
|
||||
return ((reinterpret_cast<uint64>(var) >> 4) * 3 + value * 5);
|
||||
}
|
||||
|
||||
void Double() {
|
||||
Cell** old_cell_array = array_;
|
||||
const int old_size = size_;
|
||||
solver_->SaveValue(&size_);
|
||||
size_ *= 2;
|
||||
solver_->SaveValue(reinterpret_cast<void**>(&array_));
|
||||
array_ = solver_->UnsafeRevAllocArray(new Cell*[size_]);
|
||||
for (int i = 0; i < size_; ++i) {
|
||||
array_[i] = NULL;
|
||||
}
|
||||
for (int i = 0; i < old_size; ++i) {
|
||||
Cell* tmp = old_cell_array[i];
|
||||
while (tmp != NULL) {
|
||||
Cell* to_reinsert = tmp;
|
||||
tmp = tmp->next;
|
||||
int code = HashCode(to_reinsert->var, to_reinsert->value) % size_;
|
||||
Cell* new_next = array_[code];
|
||||
solver_->SaveValue(reinterpret_cast<void**>(&to_reinsert->next));
|
||||
to_reinsert->next = new_next;
|
||||
array_[code] = to_reinsert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Solver* const solver_;
|
||||
Cell** array_;
|
||||
int size_;
|
||||
int counter_;
|
||||
};
|
||||
|
||||
// ---------- EqualityVarCstCache ----------
|
||||
|
||||
class EqualityVarCstCache : public VarCstCache {
|
||||
public:
|
||||
explicit EqualityVarCstCache(Solver* const s) : VarCstCache(s) {}
|
||||
virtual ~EqualityVarCstCache() {}
|
||||
|
||||
IntVar* VarEqCstStatus(IntVar* const var, int64 value) {
|
||||
IntVar* boolvar = Find(var, value);
|
||||
if (!boolvar) {
|
||||
boolvar = solver()->MakeBoolVar(
|
||||
StringPrintf("StatusVar<%s == %" GG_LL_FORMAT "d>",
|
||||
var->name().c_str(), value));
|
||||
Constraint* const maintain =
|
||||
solver()->RevAlloc(new IsEqualCstCt(solver(), var, value, boolvar));
|
||||
solver()->AddConstraint(maintain);
|
||||
UnsafeInsert(var, value, boolvar);
|
||||
}
|
||||
return boolvar;
|
||||
}
|
||||
};
|
||||
|
||||
IntVar* Solver::MakeIsEqualCstVar(IntVar* const var, int64 value) {
|
||||
if (value == var->Min()) {
|
||||
return MakeIsLessOrEqualCstVar(var, value);
|
||||
@@ -468,23 +346,47 @@ IntVar* Solver::MakeIsEqualCstVar(IntVar* const var, int64 value) {
|
||||
if (var->Bound() && var->Value() == value) {
|
||||
return MakeIntConst(1LL);
|
||||
}
|
||||
return equality_var_cst_cache_->VarEqCstStatus(var, value);
|
||||
IntExpr* const cache = model_cache_->FindVarConstantExpression(
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_EQUAL);
|
||||
if (cache != NULL) {
|
||||
return cache->Var();
|
||||
} else {
|
||||
IntVar* const boolvar = MakeBoolVar(
|
||||
StringPrintf("StatusVar<%s == %" GG_LL_FORMAT "d>",
|
||||
var->name().c_str(), value));
|
||||
Constraint* const maintain =
|
||||
RevAlloc(new IsEqualCstCt(this, var, value, boolvar));
|
||||
AddConstraint(maintain);
|
||||
model_cache_->InsertVarConstantExpression(
|
||||
boolvar,
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_EQUAL);
|
||||
return boolvar;
|
||||
}
|
||||
}
|
||||
|
||||
Constraint* Solver::MakeIsEqualCstCt(IntVar* const v, int64 c,
|
||||
IntVar* const b) {
|
||||
CHECK_EQ(this, v->solver());
|
||||
CHECK_EQ(this, b->solver());
|
||||
if (c == v->Min()) {
|
||||
return MakeIsLessOrEqualCstCt(v, c, b);
|
||||
Constraint* Solver::MakeIsEqualCstCt(IntVar* const var,
|
||||
int64 value,
|
||||
IntVar* const boolvar) {
|
||||
CHECK_EQ(this, var->solver());
|
||||
CHECK_EQ(this, boolvar->solver());
|
||||
if (value == var->Min()) {
|
||||
return MakeIsLessOrEqualCstCt(var, value, boolvar);
|
||||
}
|
||||
if (c == v->Max()) {
|
||||
return MakeIsGreaterOrEqualCstCt(v, c, b);
|
||||
if (value == var->Max()) {
|
||||
return MakeIsGreaterOrEqualCstCt(var, value, boolvar);
|
||||
}
|
||||
// TODO(user) : what happens if the constraint is not posted?
|
||||
// The cache becomes tainted.
|
||||
equality_var_cst_cache_->Insert(v, c, b);
|
||||
return RevAlloc(new IsEqualCstCt(this, v, c, b));
|
||||
model_cache_->InsertVarConstantExpression(
|
||||
boolvar,
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_EQUAL);
|
||||
return RevAlloc(new IsEqualCstCt(this, var, value, boolvar));
|
||||
}
|
||||
|
||||
// ----- is_diff_cst Constraint -----
|
||||
@@ -544,29 +446,6 @@ class IsDiffCstCt : public Constraint {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// ---------- UnequalityVarCstCache ----------
|
||||
|
||||
class UnequalityVarCstCache : public VarCstCache {
|
||||
public:
|
||||
explicit UnequalityVarCstCache(Solver* const s) : VarCstCache(s) {}
|
||||
virtual ~UnequalityVarCstCache() {}
|
||||
|
||||
IntVar* VarNonEqCstStatus(IntVar* const var, int64 value) {
|
||||
IntVar* boolvar = Find(var, value);
|
||||
if (!boolvar) {
|
||||
boolvar = solver()->MakeBoolVar(StringPrintf("StatusVar<%s == %"
|
||||
GG_LL_FORMAT "d>",
|
||||
var->name().c_str(),
|
||||
value));
|
||||
Constraint* const maintain =
|
||||
solver()->RevAlloc(new IsDiffCstCt(solver(), var, value, boolvar));
|
||||
solver()->AddConstraint(maintain);
|
||||
UnsafeInsert(var, value, boolvar);
|
||||
}
|
||||
return boolvar;
|
||||
}
|
||||
};
|
||||
|
||||
IntVar* Solver::MakeIsDifferentCstVar(IntVar* const var, int64 value) {
|
||||
if (value == var->Min()) {
|
||||
return MakeIsGreaterOrEqualCstVar(var, value + 1);
|
||||
@@ -580,21 +459,45 @@ IntVar* Solver::MakeIsDifferentCstVar(IntVar* const var, int64 value) {
|
||||
if (var->Bound() && var->Value() == value) {
|
||||
return MakeIntConst(0LL);
|
||||
}
|
||||
return unequality_var_cst_cache_->VarNonEqCstStatus(var, value);
|
||||
IntExpr* const cache = model_cache_->FindVarConstantExpression(
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_NOT_EQUAL);
|
||||
if (cache != NULL) {
|
||||
return cache->Var();
|
||||
} else {
|
||||
IntVar* const boolvar = MakeBoolVar(
|
||||
StringPrintf("StatusVar<%s != %" GG_LL_FORMAT "d>",
|
||||
var->name().c_str(), value));
|
||||
Constraint* const maintain =
|
||||
RevAlloc(new IsDiffCstCt(this, var, value, boolvar));
|
||||
AddConstraint(maintain);
|
||||
model_cache_->InsertVarConstantExpression(
|
||||
boolvar,
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_NOT_EQUAL);
|
||||
return boolvar;
|
||||
}
|
||||
}
|
||||
|
||||
Constraint* Solver::MakeIsDifferentCstCt(IntVar* const v, int64 c,
|
||||
IntVar* const b) {
|
||||
CHECK_EQ(this, v->solver());
|
||||
CHECK_EQ(this, b->solver());
|
||||
if (c == v->Min()) {
|
||||
return MakeIsGreaterOrEqualCstCt(v, c + 1, b);
|
||||
Constraint* Solver::MakeIsDifferentCstCt(IntVar* const var,
|
||||
int64 value,
|
||||
IntVar* const boolvar) {
|
||||
CHECK_EQ(this, var->solver());
|
||||
CHECK_EQ(this, boolvar->solver());
|
||||
if (value == var->Min()) {
|
||||
return MakeIsGreaterOrEqualCstCt(var, value + 1, boolvar);
|
||||
}
|
||||
if (c == v->Max()) {
|
||||
return MakeIsLessOrEqualCstCt(v, c - 1, b);
|
||||
if (value == var->Max()) {
|
||||
return MakeIsLessOrEqualCstCt(var, value - 1, boolvar);
|
||||
}
|
||||
unequality_var_cst_cache_->Insert(v, c, b);
|
||||
return RevAlloc(new IsDiffCstCt(this, v, c, b));
|
||||
model_cache_->InsertVarConstantExpression(
|
||||
boolvar,
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_NOT_EQUAL);
|
||||
return RevAlloc(new IsDiffCstCt(this, var, value, boolvar));
|
||||
}
|
||||
|
||||
// ----- is_greater_equal_cst Constraint -----
|
||||
@@ -652,31 +555,6 @@ class IsGreaterEqualCstCt : public Constraint {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// ---------- GreaterEqualCstCache ----------
|
||||
|
||||
class GreaterEqualCstCache : public VarCstCache {
|
||||
public:
|
||||
explicit GreaterEqualCstCache(Solver* const s) : VarCstCache(s) {}
|
||||
virtual ~GreaterEqualCstCache() {}
|
||||
|
||||
IntVar* VarGreaterEqCstStatus(IntVar* const var, int64 value) {
|
||||
IntVar* boolvar = Find(var, value);
|
||||
if (!boolvar) {
|
||||
boolvar = solver()->MakeBoolVar(
|
||||
StringPrintf("StatusVar<%s >= %" GG_LL_FORMAT "d>",
|
||||
var->name().c_str(), value));
|
||||
Constraint* const maintain =
|
||||
solver()->RevAlloc(new IsGreaterEqualCstCt(solver(),
|
||||
var,
|
||||
value,
|
||||
boolvar));
|
||||
solver()->AddConstraint(maintain);
|
||||
UnsafeInsert(var, value, boolvar);
|
||||
}
|
||||
return boolvar;
|
||||
}
|
||||
};
|
||||
|
||||
IntVar* Solver::MakeIsGreaterOrEqualCstVar(IntVar* const var, int64 value) {
|
||||
if (var->Min() >= value) {
|
||||
return MakeIntConst(1LL);
|
||||
@@ -684,19 +562,43 @@ IntVar* Solver::MakeIsGreaterOrEqualCstVar(IntVar* const var, int64 value) {
|
||||
if (var->Max() < value) {
|
||||
return MakeIntConst(0LL);
|
||||
}
|
||||
return greater_equal_var_cst_cache_->VarGreaterEqCstStatus(var, value);
|
||||
IntExpr* const cache = model_cache_->FindVarConstantExpression(
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_GREATER_OR_EQUAL);
|
||||
if (cache != NULL) {
|
||||
return cache->Var();
|
||||
} else {
|
||||
IntVar* const boolvar = MakeBoolVar(
|
||||
StringPrintf("StatusVar<%s >= %" GG_LL_FORMAT "d>",
|
||||
var->name().c_str(), value));
|
||||
Constraint* const maintain =
|
||||
RevAlloc(new IsGreaterEqualCstCt(this, var, value, boolvar));
|
||||
AddConstraint(maintain);
|
||||
model_cache_->InsertVarConstantExpression(
|
||||
boolvar,
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_GREATER_OR_EQUAL);
|
||||
return boolvar;
|
||||
}
|
||||
}
|
||||
|
||||
IntVar* Solver::MakeIsGreaterCstVar(IntVar* const var, int64 value) {
|
||||
return greater_equal_var_cst_cache_->VarGreaterEqCstStatus(var, value + 1);
|
||||
return MakeIsGreaterOrEqualCstVar(var, value + 1);
|
||||
}
|
||||
|
||||
Constraint* Solver::MakeIsGreaterOrEqualCstCt(IntVar* const v, int64 c,
|
||||
IntVar* const b) {
|
||||
CHECK_EQ(this, v->solver());
|
||||
CHECK_EQ(this, b->solver());
|
||||
greater_equal_var_cst_cache_->Insert(v, c, b);
|
||||
return RevAlloc(new IsGreaterEqualCstCt(this, v, c, b));
|
||||
Constraint* Solver::MakeIsGreaterOrEqualCstCt(IntVar* const var,
|
||||
int64 value,
|
||||
IntVar* const boolvar) {
|
||||
CHECK_EQ(this, var->solver());
|
||||
CHECK_EQ(this, boolvar->solver());
|
||||
model_cache_->InsertVarConstantExpression(
|
||||
boolvar,
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_GREATER_OR_EQUAL);
|
||||
return RevAlloc(new IsGreaterEqualCstCt(this, var, value, boolvar));
|
||||
}
|
||||
|
||||
Constraint* Solver::MakeIsGreaterCstCt(IntVar* const v, int64 c,
|
||||
@@ -761,30 +663,6 @@ class IsLessEqualCstCt : public Constraint {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// ---------- LessEqualCstCache ----------
|
||||
|
||||
class LessEqualCstCache : public VarCstCache {
|
||||
public:
|
||||
explicit LessEqualCstCache(Solver* const s) : VarCstCache(s) {}
|
||||
virtual ~LessEqualCstCache() {}
|
||||
|
||||
IntVar* VarLessEqCstStatus(IntVar* const var, int64 value) {
|
||||
IntVar* boolvar = Find(var, value);
|
||||
if (!boolvar) {
|
||||
boolvar = solver()->MakeBoolVar(
|
||||
StringPrintf("StatusVar<%s <= %" GG_LL_FORMAT "d>",
|
||||
var->name().c_str(), value));
|
||||
Constraint* const maintain =
|
||||
solver()->RevAlloc(new IsLessEqualCstCt(solver(),
|
||||
var,
|
||||
value,
|
||||
boolvar));
|
||||
solver()->AddConstraint(maintain);
|
||||
UnsafeInsert(var, value, boolvar);
|
||||
}
|
||||
return boolvar;
|
||||
}
|
||||
};
|
||||
|
||||
IntVar* Solver::MakeIsLessOrEqualCstVar(IntVar* const var, int64 value) {
|
||||
if (var->Max() <= value) {
|
||||
@@ -793,19 +671,43 @@ IntVar* Solver::MakeIsLessOrEqualCstVar(IntVar* const var, int64 value) {
|
||||
if (var->Min() > value) {
|
||||
return MakeIntConst(0LL);
|
||||
}
|
||||
return less_equal_var_cst_cache_->VarLessEqCstStatus(var, value);
|
||||
IntExpr* const cache = model_cache_->FindVarConstantExpression(
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_LESS_OR_EQUAL);
|
||||
if (cache != NULL) {
|
||||
return cache->Var();
|
||||
} else {
|
||||
IntVar* const boolvar = MakeBoolVar(
|
||||
StringPrintf("StatusVar<%s <= %" GG_LL_FORMAT "d>",
|
||||
var->name().c_str(), value));
|
||||
Constraint* const maintain =
|
||||
RevAlloc(new IsLessEqualCstCt(this, var, value, boolvar));
|
||||
AddConstraint(maintain);
|
||||
model_cache_->InsertVarConstantExpression(
|
||||
boolvar,
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_LESS_OR_EQUAL);
|
||||
return boolvar;
|
||||
}
|
||||
}
|
||||
|
||||
IntVar* Solver::MakeIsLessCstVar(IntVar* const var, int64 value) {
|
||||
return MakeIsLessOrEqualCstVar(var, value - 1);
|
||||
}
|
||||
|
||||
Constraint* Solver::MakeIsLessOrEqualCstCt(IntVar* const v, int64 c,
|
||||
IntVar* const b) {
|
||||
CHECK_EQ(this, v->solver());
|
||||
CHECK_EQ(this, b->solver());
|
||||
less_equal_var_cst_cache_->Insert(v, c, b);
|
||||
return RevAlloc(new IsLessEqualCstCt(this, v, c, b));
|
||||
Constraint* Solver::MakeIsLessOrEqualCstCt(IntVar* const var,
|
||||
int64 value,
|
||||
IntVar* const boolvar) {
|
||||
CHECK_EQ(this, var->solver());
|
||||
CHECK_EQ(this, boolvar->solver());
|
||||
model_cache_->InsertVarConstantExpression(
|
||||
boolvar,
|
||||
var,
|
||||
value,
|
||||
ModelCache::VAR_CONSTANT_IS_LESS_OR_EQUAL);
|
||||
return RevAlloc(new IsLessEqualCstCt(this, var, value, boolvar));
|
||||
}
|
||||
|
||||
Constraint* Solver::MakeIsLessCstCt(IntVar* const v, int64 c,
|
||||
@@ -1140,14 +1042,4 @@ IntVar* Solver::MakeIsMemberVar(IntVar* const var,
|
||||
IntVar* Solver::MakeIsMemberVar(IntVar* const var, const std::vector<int>& values) {
|
||||
return MakeIsMemberVar(var, values.data(), values.size());
|
||||
}
|
||||
|
||||
// ---------- Init Caches ----------
|
||||
|
||||
void Solver::InitBoolVarCaches() {
|
||||
equality_var_cst_cache_ = RevAlloc(new EqualityVarCstCache(this));
|
||||
unequality_var_cst_cache_ = RevAlloc(new UnequalityVarCstCache(this));
|
||||
greater_equal_var_cst_cache_ = RevAlloc(new GreaterEqualCstCache(this));
|
||||
less_equal_var_cst_cache_ = RevAlloc(new LessEqualCstCache(this));
|
||||
}
|
||||
|
||||
} // namespace operations_research
|
||||
|
||||
@@ -2512,71 +2512,6 @@ LocalSearchFilter* Solver::MakeLocalSearchObjectiveFilter(
|
||||
OperationFromEnum(op_enum)));
|
||||
}
|
||||
|
||||
// ----- NestedSolve decision wrapper -----
|
||||
// This decision calls a nested Solve on the given DecisionBuilder in its
|
||||
// left branch; does nothing in the left branch.
|
||||
// The state of the decision corresponds to the result of the nested Solve:
|
||||
// DECISION_PENDING - Nested Solve not called yet
|
||||
// DECISION_FAILED - Nested Solve failed
|
||||
// DECISION_FOUND - Nested Solve succeeded
|
||||
|
||||
class NestedSolveDecision : public Decision {
|
||||
public:
|
||||
// This enum is used internally to tag states in the local search tree.
|
||||
enum StateType {
|
||||
DECISION_PENDING,
|
||||
DECISION_FAILED,
|
||||
DECISION_FOUND
|
||||
};
|
||||
|
||||
NestedSolveDecision(DecisionBuilder* const db,
|
||||
bool restore,
|
||||
const std::vector<SearchMonitor*>& monitors);
|
||||
NestedSolveDecision(DecisionBuilder* const db,
|
||||
bool restore);
|
||||
virtual ~NestedSolveDecision() {}
|
||||
virtual void Apply(Solver* const solver);
|
||||
virtual void Refute(Solver* const solver);
|
||||
virtual string DebugString() const {
|
||||
return "NestedSolveDecision";
|
||||
}
|
||||
int state() const { return state_; }
|
||||
|
||||
private:
|
||||
DecisionBuilder* const db_;
|
||||
bool restore_;
|
||||
std::vector<SearchMonitor*> monitors_;
|
||||
int state_;
|
||||
};
|
||||
|
||||
NestedSolveDecision::NestedSolveDecision(DecisionBuilder* const db,
|
||||
bool restore,
|
||||
const std::vector<SearchMonitor*>& monitors)
|
||||
: db_(db),
|
||||
restore_(restore),
|
||||
monitors_(monitors),
|
||||
state_(DECISION_PENDING) {
|
||||
CHECK(NULL != db);
|
||||
}
|
||||
|
||||
NestedSolveDecision::NestedSolveDecision(DecisionBuilder* const db,
|
||||
bool restore)
|
||||
: db_(db), restore_(restore), state_(DECISION_PENDING) {
|
||||
CHECK(NULL != db);
|
||||
}
|
||||
|
||||
void NestedSolveDecision::Apply(Solver* const solver) {
|
||||
CHECK(NULL != solver);
|
||||
if (solver->NestedSolve(db_, restore_,
|
||||
monitors_.data(), monitors_.size())) {
|
||||
solver->SaveAndSetValue(&state_, static_cast<int>(DECISION_FOUND));
|
||||
} else {
|
||||
solver->SaveAndSetValue(&state_, static_cast<int>(DECISION_FAILED));
|
||||
}
|
||||
}
|
||||
|
||||
void NestedSolveDecision::Refute(Solver* const solver) {}
|
||||
|
||||
// ----- Finds a neighbor of the assignment passed -----
|
||||
|
||||
class FindOneNeighbor : public DecisionBuilder {
|
||||
@@ -2849,8 +2784,123 @@ LocalSearchPhaseParameters* Solver::MakeLocalSearchPhaseParameters(
|
||||
filters));
|
||||
}
|
||||
|
||||
namespace {
|
||||
// ----- NestedSolve decision wrapper -----
|
||||
|
||||
// This decision calls a nested Solve on the given DecisionBuilder in its
|
||||
// left branch; does nothing in the left branch.
|
||||
// The state of the decision corresponds to the result of the nested Solve:
|
||||
// DECISION_PENDING - Nested Solve not called yet
|
||||
// DECISION_FAILED - Nested Solve failed
|
||||
// DECISION_FOUND - Nested Solve succeeded
|
||||
|
||||
class NestedSolveDecision : public Decision {
|
||||
public:
|
||||
// This enum is used internally to tag states in the local search tree.
|
||||
enum StateType {
|
||||
DECISION_PENDING,
|
||||
DECISION_FAILED,
|
||||
DECISION_FOUND
|
||||
};
|
||||
|
||||
NestedSolveDecision(DecisionBuilder* const db,
|
||||
bool restore,
|
||||
const std::vector<SearchMonitor*>& monitors);
|
||||
NestedSolveDecision(DecisionBuilder* const db,
|
||||
bool restore);
|
||||
virtual ~NestedSolveDecision() {}
|
||||
virtual void Apply(Solver* const solver);
|
||||
virtual void Refute(Solver* const solver);
|
||||
virtual string DebugString() const {
|
||||
return "NestedSolveDecision";
|
||||
}
|
||||
int state() const { return state_; }
|
||||
|
||||
private:
|
||||
DecisionBuilder* const db_;
|
||||
bool restore_;
|
||||
std::vector<SearchMonitor*> monitors_;
|
||||
int state_;
|
||||
};
|
||||
|
||||
NestedSolveDecision::NestedSolveDecision(DecisionBuilder* const db,
|
||||
bool restore,
|
||||
const std::vector<SearchMonitor*>& monitors)
|
||||
: db_(db),
|
||||
restore_(restore),
|
||||
monitors_(monitors),
|
||||
state_(DECISION_PENDING) {
|
||||
CHECK(NULL != db);
|
||||
}
|
||||
|
||||
NestedSolveDecision::NestedSolveDecision(DecisionBuilder* const db,
|
||||
bool restore)
|
||||
: db_(db), restore_(restore), state_(DECISION_PENDING) {
|
||||
CHECK(NULL != db);
|
||||
}
|
||||
|
||||
void NestedSolveDecision::Apply(Solver* const solver) {
|
||||
CHECK(NULL != solver);
|
||||
if (solver->NestedSolve(db_, restore_,
|
||||
monitors_.data(), monitors_.size())) {
|
||||
solver->SaveAndSetValue(&state_, static_cast<int>(DECISION_FOUND));
|
||||
} else {
|
||||
solver->SaveAndSetValue(&state_, static_cast<int>(DECISION_FAILED));
|
||||
}
|
||||
}
|
||||
|
||||
void NestedSolveDecision::Refute(Solver* const solver) {}
|
||||
|
||||
// ----- Local search decision builder -----
|
||||
|
||||
// Given a first solution (resulting from either an initial assignment or the
|
||||
// result of a decision builder), it searches for neighbors using a local
|
||||
// search operator. The first solution corresponds to the first leaf of the
|
||||
// search.
|
||||
// The local search applies to the variables contained either in the assignment
|
||||
// or the vector of variables passed.
|
||||
|
||||
class LocalSearch : public DecisionBuilder {
|
||||
public:
|
||||
LocalSearch(Assignment* const assignment,
|
||||
SolutionPool* const pool,
|
||||
LocalSearchOperator* const ls_operator,
|
||||
DecisionBuilder* const sub_decision_builder,
|
||||
SearchLimit* const limit,
|
||||
const std::vector<LocalSearchFilter*>& filters);
|
||||
// TODO(user): find a way to not have to pass vars here: redundant with
|
||||
// variables in operators
|
||||
LocalSearch(IntVar* const* vars,
|
||||
int size,
|
||||
SolutionPool* const pool,
|
||||
DecisionBuilder* const first_solution,
|
||||
LocalSearchOperator* const ls_operator,
|
||||
DecisionBuilder* const sub_decision_builder,
|
||||
SearchLimit* const limit,
|
||||
const std::vector<LocalSearchFilter*>& filters);
|
||||
virtual ~LocalSearch();
|
||||
virtual Decision* Next(Solver* const solver);
|
||||
virtual string DebugString() const {
|
||||
return "LocalSearch";
|
||||
}
|
||||
virtual void Accept(ModelVisitor* const visitor) const;
|
||||
|
||||
protected:
|
||||
void PushFirstSolutionDecision(DecisionBuilder* first_solution);
|
||||
void PushLocalSearchDecision();
|
||||
|
||||
private:
|
||||
Assignment* assignment_;
|
||||
SolutionPool* const pool_;
|
||||
LocalSearchOperator* const ls_operator_;
|
||||
DecisionBuilder* const sub_decision_builder_;
|
||||
std::vector<NestedSolveDecision*> nested_decisions_;
|
||||
int nested_decision_index_;
|
||||
SearchLimit* const limit_;
|
||||
const std::vector<LocalSearchFilter*> filters_;
|
||||
bool has_started_;
|
||||
};
|
||||
|
||||
LocalSearch::LocalSearch(Assignment* const assignment,
|
||||
SolutionPool* const pool,
|
||||
LocalSearchOperator* const ls_operator,
|
||||
@@ -3010,7 +3060,6 @@ void LocalSearch::PushLocalSearchDecision() {
|
||||
solver->RevAlloc(new NestedSolveDecision(find_neighbors, false)));
|
||||
}
|
||||
|
||||
namespace {
|
||||
class DefaultSolutionPool : public SolutionPool {
|
||||
public:
|
||||
DefaultSolutionPool() : reference_assignment_(NULL) {}
|
||||
|
||||
@@ -157,11 +157,12 @@ template <class C> void Double(C*** array_ptr, int* size_ptr) {
|
||||
while (tmp != NULL) {
|
||||
C* const to_reinsert = tmp;
|
||||
tmp = tmp->next();
|
||||
const uint64 code = to_reinsert->Hash();
|
||||
to_reinsert->set_next((*array_ptr)[code]);
|
||||
(*array_ptr)[code] = to_reinsert;
|
||||
const uint64 position = to_reinsert->Hash() % (*size_ptr);
|
||||
to_reinsert->set_next((*array_ptr)[position]);
|
||||
(*array_ptr)[position] = to_reinsert;
|
||||
}
|
||||
}
|
||||
delete [] (old_cell_array);
|
||||
}
|
||||
|
||||
// ----- Cache objects built with 1 object -----
|
||||
@@ -177,7 +178,12 @@ template <class C, class A1> class Cache1 {
|
||||
|
||||
~Cache1() {
|
||||
for (int i = 0; i < size_; ++i) {
|
||||
delete array_[i];
|
||||
Cell* tmp = array_[i];
|
||||
while (tmp != NULL) {
|
||||
Cell* const to_delete = tmp;
|
||||
tmp = tmp->next();
|
||||
delete to_delete;
|
||||
}
|
||||
}
|
||||
delete [] array_;
|
||||
}
|
||||
@@ -249,7 +255,12 @@ template <class C, class A1, class A2> class Cache2 {
|
||||
|
||||
~Cache2() {
|
||||
for (int i = 0; i < size_; ++i) {
|
||||
delete array_[i];
|
||||
Cell* tmp = array_[i];
|
||||
while (tmp != NULL) {
|
||||
Cell* const to_delete = tmp;
|
||||
tmp = tmp->next();
|
||||
delete to_delete;
|
||||
}
|
||||
}
|
||||
delete [] array_;
|
||||
}
|
||||
@@ -322,7 +333,12 @@ template <class C, class A1, class A2, class A3> class Cache3 {
|
||||
|
||||
~Cache3() {
|
||||
for (int i = 0; i < size_; ++i) {
|
||||
delete array_[i];
|
||||
Cell* tmp = array_[i];
|
||||
while (tmp != NULL) {
|
||||
Cell* const to_delete = tmp;
|
||||
tmp = tmp->next();
|
||||
delete to_delete;
|
||||
}
|
||||
}
|
||||
delete [] array_;
|
||||
}
|
||||
@@ -491,7 +507,8 @@ class NonReversibleCache : public ModelCache {
|
||||
DCHECK(var != NULL);
|
||||
DCHECK_GE(type, 0);
|
||||
DCHECK_LT(type, VAR_CONSTANT_CONSTRAINT_MAX);
|
||||
if (solver()->state() != Solver::IN_SEARCH) {
|
||||
if (solver()->state() != Solver::IN_SEARCH &&
|
||||
var_constant_constraints_[type]->Find(var, value) == NULL) {
|
||||
var_constant_constraints_[type]->UnsafeInsert(var, value, ct);
|
||||
}
|
||||
}
|
||||
@@ -519,7 +536,10 @@ class NonReversibleCache : public ModelCache {
|
||||
DCHECK(var != NULL);
|
||||
DCHECK_GE(type, 0);
|
||||
DCHECK_LT(type, VAR_CONSTANT_CONSTANT_CONSTRAINT_MAX);
|
||||
if (solver()->state() != Solver::IN_SEARCH) {
|
||||
if (solver()->state() != Solver::IN_SEARCH &&
|
||||
var_constant_constant_constraints_[type]->Find(var,
|
||||
value1,
|
||||
value2) == NULL) {
|
||||
var_constant_constant_constraints_[type]->UnsafeInsert(var,
|
||||
value1,
|
||||
value2,
|
||||
@@ -549,7 +569,8 @@ class NonReversibleCache : public ModelCache {
|
||||
DCHECK(var2 != NULL);
|
||||
DCHECK_GE(type, 0);
|
||||
DCHECK_LT(type, VAR_VAR_CONSTRAINT_MAX);
|
||||
if (solver()->state() != Solver::IN_SEARCH) {
|
||||
if (solver()->state() != Solver::IN_SEARCH &&
|
||||
var_var_constraints_[type]->Find(var1, var2) == NULL) {
|
||||
var_var_constraints_[type]->UnsafeInsert(var1, var2, ct);
|
||||
}
|
||||
}
|
||||
@@ -571,7 +592,8 @@ class NonReversibleCache : public ModelCache {
|
||||
DCHECK(var != NULL);
|
||||
DCHECK_GE(type, 0);
|
||||
DCHECK_LT(type, VAR_EXPRESSION_MAX);
|
||||
if (solver()->state() != Solver::IN_SEARCH) {
|
||||
if (solver()->state() != Solver::IN_SEARCH &&
|
||||
var_expressions_[type]->Find(var) == NULL) {
|
||||
var_expressions_[type]->UnsafeInsert(var, expression);
|
||||
}
|
||||
}
|
||||
@@ -597,7 +619,8 @@ class NonReversibleCache : public ModelCache {
|
||||
DCHECK(var != NULL);
|
||||
DCHECK_GE(type, 0);
|
||||
DCHECK_LT(type, VAR_CONSTANT_EXPRESSION_MAX);
|
||||
if (solver()->state() != Solver::IN_SEARCH) {
|
||||
if (solver()->state() != Solver::IN_SEARCH &&
|
||||
var_constant_expressions_[type]->Find(var, value) == NULL) {
|
||||
var_constant_expressions_[type]->UnsafeInsert(var, value, expression);
|
||||
}
|
||||
}
|
||||
@@ -625,7 +648,8 @@ class NonReversibleCache : public ModelCache {
|
||||
DCHECK(var2 != NULL);
|
||||
DCHECK_GE(type, 0);
|
||||
DCHECK_LT(type, VAR_VAR_EXPRESSION_MAX);
|
||||
if (solver()->state() != Solver::IN_SEARCH) {
|
||||
if (solver()->state() != Solver::IN_SEARCH &&
|
||||
var_var_expressions_[type]->Find(var1, var2) == NULL) {
|
||||
var_var_expressions_[type]->UnsafeInsert(var1, var2, expression);
|
||||
}
|
||||
}
|
||||
@@ -653,7 +677,10 @@ class NonReversibleCache : public ModelCache {
|
||||
DCHECK(var != NULL);
|
||||
DCHECK_GE(type, 0);
|
||||
DCHECK_LT(type, VAR_CONSTANT_CONSTANT_EXPRESSION_MAX);
|
||||
if (solver()->state() != Solver::IN_SEARCH) {
|
||||
if (solver()->state() != Solver::IN_SEARCH &&
|
||||
var_constant_constant_expressions_[type]->Find(var,
|
||||
value1,
|
||||
value2) == NULL) {
|
||||
var_constant_constant_expressions_[type]->UnsafeInsert(var,
|
||||
value1,
|
||||
value2,
|
||||
@@ -682,7 +709,8 @@ class NonReversibleCache : public ModelCache {
|
||||
DCHECK(var != NULL);
|
||||
DCHECK_GE(type, 0);
|
||||
DCHECK_LT(type, VAR_CONSTANT_ARRAY_EXPRESSION_MAX);
|
||||
if (solver()->state() != Solver::IN_SEARCH) {
|
||||
if (solver()->state() != Solver::IN_SEARCH &&
|
||||
var_constant_array_expressions_[type]->Find(var, values) == NULL) {
|
||||
var_constant_array_expressions_[type]->UnsafeInsert(var,
|
||||
values,
|
||||
expression);
|
||||
@@ -706,7 +734,8 @@ class NonReversibleCache : public ModelCache {
|
||||
DCHECK(expression != NULL);
|
||||
DCHECK_GE(type, 0);
|
||||
DCHECK_LT(type, VAR_ARRAY_EXPRESSION_MAX);
|
||||
if (solver()->state() != Solver::IN_SEARCH) {
|
||||
if (solver()->state() != Solver::IN_SEARCH &&
|
||||
var_array_expressions_[type]->Find(vars) == NULL) {
|
||||
var_array_expressions_[type]->UnsafeInsert(vars, expression);
|
||||
}
|
||||
}
|
||||
@@ -729,4 +758,8 @@ class NonReversibleCache : public ModelCache {
|
||||
ModelCache* BuildModelCache(Solver* const solver) {
|
||||
return new NonReversibleCache(solver);
|
||||
}
|
||||
|
||||
ModelCache* Solver::Cache() const {
|
||||
return model_cache_.get();
|
||||
}
|
||||
} // namespace operations_research
|
||||
|
||||
Reference in New Issue
Block a user