add ability to inject decision builder inside the default search; adapt flatzinc interface

This commit is contained in:
laurent.perron@gmail.com
2013-07-06 19:43:21 +00:00
parent 68c8fb487f
commit 7221cc0b36
6 changed files with 272 additions and 321 deletions

View File

@@ -242,21 +242,12 @@ struct DefaultPhaseParameters {
VERBOSE = 2
};
enum SearchStrategy {
CHOOSE_FIRST_UNBOUND_ASSIGN_MIN,
CHOOSE_MIN_SIZE_ASSIGN_MIN,
IMPACT_BASED_SEARCH,
CHOOSE_RANDOM_ASSIGN_MIN,
CHOOSE_RANDOM_ASSIGN_MAX,
};
static const int kDefaultNumberOfSplits;
static const int kDefaultHeuristicPeriod;
static const int kDefaultHeuristicNumFailuresLimit;
static const int kDefaultSeed;
static const double kDefaultRestartLogSize;
static const bool kDefaultUseNoGoods;
static const DefaultPhaseParameters::SearchStrategy kDefaultSearchStrategy;
DefaultPhaseParameters()
: var_selection_schema(CHOOSE_MAX_SUM_IMPACT),
@@ -270,7 +261,7 @@ struct DefaultPhaseParameters {
restart_log_size(kDefaultRestartLogSize),
display_level(NORMAL),
use_no_goods(kDefaultUseNoGoods),
search_strategy(kDefaultSearchStrategy) {}
decision_builder(NULL) {}
// This parameter describes how the next variable to instantiate
// will be chosen.
@@ -321,8 +312,8 @@ struct DefaultPhaseParameters {
// Should we use Nogoods when restarting. The default is false.
bool use_no_goods;
// Used in tests. Disable impacts and run choose first unbound, assign min.
SearchStrategy search_strategy;
// When defined, this override the default impact based decision builder.
DecisionBuilder* decision_builder;
};

View File

@@ -43,9 +43,6 @@ const int DefaultPhaseParameters::kDefaultHeuristicNumFailuresLimit = 30;
const int DefaultPhaseParameters::kDefaultSeed = 0;
const double DefaultPhaseParameters::kDefaultRestartLogSize = -1.0;
const bool DefaultPhaseParameters::kDefaultUseNoGoods = true;
const DefaultPhaseParameters::SearchStrategy
DefaultPhaseParameters::kDefaultSearchStrategy =
DefaultPhaseParameters::IMPACT_BASED_SEARCH;
class NoGoodManager;
@@ -1005,13 +1002,16 @@ class RunHeuristicsAsDives : public Decision {
bool RunAllHeuristics(Solver* const solver) {
if (run_all_heuristics_) {
LOG(INFO) << "Start";
for (int index = 0; index < heuristics_.size(); ++index) {
for (int run = 0; run < heuristics_[index]->runs; ++run) {
if (RunOneHeuristic(solver, index)) {
LOG(INFO) << "Success";
return true;
}
}
}
LOG(INFO) << "No Success";
return false;
} else {
const int index = random_.Uniform(heuristics_.size());
@@ -1162,21 +1162,16 @@ class DefaultIntegerSearch : public DecisionBuilder {
return &heuristics_;
}
IntVar* var = NULL;
int64 value = 0;
if (FindVarValue(&var, &value)) {
return solver->MakeAssignVariableValue(var, value);
} else {
return NULL;
}
return parameters_.decision_builder != NULL ?
parameters_.decision_builder->Next(solver) :
ImpactNext(solver);
}
virtual void AppendMonitors(Solver* const solver,
std::vector<SearchMonitor*>* const extras) {
CHECK_NOTNULL(solver);
CHECK_NOTNULL(extras);
if (parameters_.search_strategy ==
DefaultPhaseParameters::IMPACT_BASED_SEARCH) {
if (parameters_.decision_builder == NULL) {
extras->push_back(&impact_recorder_);
}
if (parameters_.restart_log_size >= 0) {
@@ -1195,11 +1190,11 @@ class DefaultIntegerSearch : public DecisionBuilder {
virtual string DebugString() const {
string out = "DefaultIntegerSearch(";
if (parameters_.search_strategy ==
DefaultPhaseParameters::IMPACT_BASED_SEARCH) {
if (parameters_.decision_builder == NULL) {
out.append("Impact Based Search, ");
} else {
out.append("Choose First Unbound Assing Min, ");
out.append(parameters_.decision_builder->DebugString());
out.append(", ");
}
out.append(DebugStringVector(vars_, ", "));
out.append(")");
@@ -1211,8 +1206,7 @@ class DefaultIntegerSearch : public DecisionBuilder {
if (init_done_) {
return;
}
if (parameters_.search_strategy ==
DefaultPhaseParameters::IMPACT_BASED_SEARCH) {
if (parameters_.decision_builder == NULL) {
// Decide if we are doing impacts, no if one variable is too big.
for (int i = 0; i < vars_.size(); ++i) {
if (vars_[i]->Max() - vars_[i]->Min() > 0xFFFFFF) {
@@ -1220,8 +1214,9 @@ class DefaultIntegerSearch : public DecisionBuilder {
LOG(INFO) << "Domains are too large, switching to simple "
<< "heuristics";
}
parameters_.search_strategy =
DefaultPhaseParameters::CHOOSE_FIRST_UNBOUND_ASSIGN_MIN;
parameters_.decision_builder =
solver->MakePhase(vars_, Solver::CHOOSE_MIN_SIZE_LOWEST_MIN,
Solver::ASSIGN_MIN_VALUE);
init_done_ = true;
return;
}
@@ -1232,8 +1227,9 @@ class DefaultIntegerSearch : public DecisionBuilder {
LOG(INFO) << "Search space is too small, switching to simple "
<< "heuristics";
}
parameters_.search_strategy =
DefaultPhaseParameters::CHOOSE_FIRST_UNBOUND_ASSIGN_MIN;
parameters_.decision_builder =
solver->MakePhase(vars_, Solver::CHOOSE_FIRST_UNBOUND,
Solver::ASSIGN_MIN_VALUE);
init_done_ = true;
return;
}
@@ -1257,31 +1253,13 @@ class DefaultIntegerSearch : public DecisionBuilder {
}
}
bool FindVarValue(IntVar** const var, int64* const value) {
switch (parameters_.search_strategy) {
case DefaultPhaseParameters::IMPACT_BASED_SEARCH:
return FindUnboundVarValueWithImpact(var, value);
case DefaultPhaseParameters::CHOOSE_FIRST_UNBOUND_ASSIGN_MIN:
return FindUnboundVarValueNoImpact(var, value);
case DefaultPhaseParameters::CHOOSE_MIN_SIZE_ASSIGN_MIN:
return FindUnboundVarValueMinSize(var, value);
case DefaultPhaseParameters::CHOOSE_RANDOM_ASSIGN_MIN:
return FindUnboundVarValueRandom(var, value, true);
case DefaultPhaseParameters::CHOOSE_RANDOM_ASSIGN_MAX:
return FindUnboundVarValueRandom(var, value, false);
}
return false;
}
// This method will do an exhaustive scan of all domains of all
// variables to select the variable with the maximal sum of impacts
// per value in its domain, and then select the value with the
// minimal impact.
bool FindUnboundVarValueWithImpact(IntVar** const var, int64* const value) {
CHECK_NOTNULL(var);
CHECK_NOTNULL(value);
*var = NULL;
*value = 0;
Decision* ImpactNext(Solver* const solver) {
IntVar* var = NULL;
int64 value = 0;
double best_var_impact = -std::numeric_limits<double>::max();
for (int i = 0; i < vars_.size(); ++i) {
if (!vars_[i]->Bound()) {
@@ -1293,72 +1271,17 @@ class DefaultIntegerSearch : public DecisionBuilder {
parameters_.var_selection_schema,
parameters_.value_selection_schema);
if (current_var_impact > best_var_impact) {
*var = vars_[i];
*value = current_value;
var = vars_[i];
value = current_value;
best_var_impact = current_var_impact;
}
}
}
return (*var != NULL);
}
bool FindUnboundVarValueNoImpact(IntVar** const var, int64* const value) {
CHECK_NOTNULL(var);
CHECK_NOTNULL(value);
*var = NULL;
*value = 0;
for (int i = 0; i < vars_.size(); ++i) {
if (!vars_[i]->Bound()) {
*var = vars_[i];;
*value = vars_[i]->Min();
return true;
}
if (var == NULL) {
return NULL;
} else {
return solver->MakeAssignVariableValue(var, value);
}
return false;
}
bool FindUnboundVarValueMinSize(IntVar** const found_var,
int64* const value) {
CHECK_NOTNULL(found_var);
CHECK_NOTNULL(value);
*found_var = NULL;
*value = 0;
uint64 best_size = kint64max;
int64 best_min = kint64max;
for (int i = 0; i < vars_.size(); ++i) {
IntVar* const var = vars_[i];
if (!var->Bound()) {
if (var->Size() < best_size ||
(var->Size() == best_size && var->Min() < best_min)) {
best_size = var->Size();
best_min = var->Min();
*value = var->Min();
*found_var = var;
}
}
}
return *found_var != NULL;
}
bool FindUnboundVarValueRandom(IntVar** const found_var,
int64* const value,
bool assign_min) {
CHECK_NOTNULL(found_var);
CHECK_NOTNULL(value);
*found_var = NULL;
*value = 0;
const int size = vars_.size();
const int shift = heuristics_.Rand32(size);
for (int i = 0; i < size; ++i) {
const int index = (i + shift) < size ? i + shift : i + shift - size;
IntVar* const var = vars_[index];
if (!var->Bound()) {
*found_var = var;
*value = assign_min ? var->Min() : var->Max();
return true;
}
}
return false;
}
// ----- data members -----

View File

@@ -507,6 +507,9 @@ DecisionBuilder* Solver::Compose(DecisionBuilder* const db1,
}
DecisionBuilder* Solver::Compose(const std::vector<DecisionBuilder*>& dbs) {
if (dbs.size() == 1) {
return dbs[0];
}
return RevAlloc(new ComposeDecisionBuilder(dbs));
}

View File

@@ -73,6 +73,7 @@ struct FlatZincSearchParameters {
search_type(MIN_SIZE) {}
enum SearchType {
DEFAULT,
IBS,
FIRST_UNBOUND,
MIN_SIZE,
@@ -225,9 +226,15 @@ class FlatZincModel {
bool HasSolveAnnotations() const;
void CreateDecisionBuilders(const FlatZincSearchParameters& parameters);
DecisionBuilder* CreateDecisionBuilders(
const FlatZincSearchParameters& parameters);
void ParseSearchAnnotations(bool ignore_unknown,
std::vector<DecisionBuilder*>* const defined,
std::vector<IntVar*>* const defined_vars);
void AddCompletionDecisionBuilders(
std::vector<DecisionBuilder*>* const builders);
const std::vector<DecisionBuilder*>& DecisionBuilders() const;
const std::vector<IntVar*>& PrimaryVariables() const;
const std::vector<IntVar*>& SecondaryVariables() const;
@@ -242,7 +249,6 @@ class FlatZincModel {
int set_var_count;
scoped_ptr<Solver> solver_;
std::vector<DecisionBuilder*> builders_;
OptimizeVar* objective_;
// Index of the integer variable to optimize

View File

@@ -106,6 +106,8 @@ void ParallelRun(char* const file, int worker_id,
switch (worker_id) {
case 0: {
parameters.free_search = false;
parameters.search_type =
operations_research::FlatZincSearchParameters::DEFAULT;
parameters.restart_log_size = -1.0;
break;
}
@@ -144,64 +146,70 @@ void ParallelRun(char* const file, int worker_id,
Run(file, parameters, parallel_support);
}
} // namespace operations_research
void SequentialRun(char* const file) {
FlatZincSearchParameters parameters;
parameters.all_solutions = FLAGS_all;
parameters.free_search = FLAGS_free;
parameters.heuristic_period = FLAGS_heuristic_period;
parameters.ignore_unknown = false;
parameters.log_period = FLAGS_log_period;
parameters.luby_restart = FLAGS_luby_restart;
parameters.num_solutions = FLAGS_num_solutions;
parameters.restart_log_size = FLAGS_restart_log_size;
parameters.simplex_frequency = FLAGS_simplex_frequency;
parameters.threads = FLAGS_workers;
parameters.time_limit_in_ms = FLAGS_time_limit;
parameters.use_log = FLAGS_logging;
parameters.verbose_impact = FLAGS_verbose_impact;
parameters.worker_id = -1;
parameters.search_type =
FLAGS_use_impact ? FlatZincSearchParameters::IBS
: FlatZincSearchParameters::DEFAULT;
int main(int argc, char** argv) {
scoped_ptr<FzParallelSupport> parallel_support(
operations_research::MakeSequentialSupport(parameters.all_solutions,
parameters.num_solutions,
FLAGS_verbose_mt));
Run(file, parameters, parallel_support.get());
}
void FixAndParseParameters(int* argc, char*** argv) {
FLAGS_log_prefix = false;
char all_param[] = "--all";
char free_param[] = "--free";
char workers_param[] = "--workers";
char solutions_param[] = "--num_solutions";
char logging_param[] = "--logging";
for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-a") == 0) {
argv[i] = all_param;
for (int i = 1; i < *argc; ++i) {
if (strcmp((*argv)[i], "-a") == 0) {
(*argv)[i] = all_param;
}
if (strcmp(argv[i], "-f") == 0) {
argv[i] = free_param;
if (strcmp((*argv)[i], "-f") == 0) {
(*argv)[i] = free_param;
}
if (strcmp(argv[i], "-p") == 0) {
argv[i] = workers_param;
if (strcmp((*argv)[i], "-p") == 0) {
(*argv)[i] = workers_param;
}
if (strcmp(argv[i], "-n") == 0) {
argv[i] = solutions_param;
if (strcmp((*argv)[i], "-n") == 0) {
(*argv)[i] = solutions_param;
}
if (strcmp(argv[i], "-l") == 0) {
argv[i] = logging_param;
if (strcmp((*argv)[i], "-l") == 0) {
(*argv)[i] = logging_param;
}
}
google::ParseCommandLineFlags( &argc, &argv, true);
google::ParseCommandLineFlags(argc, argv, true);
}
} // namespace operations_research
int main(int argc, char** argv) {
operations_research::FixAndParseParameters(&argc, &argv);
if (argc <= 1) {
LOG(ERROR) << "Usage: " << argv[0] << " <file>";
exit(EXIT_FAILURE);
}
if (FLAGS_workers == 0) {
operations_research::FlatZincSearchParameters parameters;
parameters.all_solutions = FLAGS_all;
parameters.free_search = FLAGS_free;
parameters.heuristic_period = FLAGS_heuristic_period;
parameters.ignore_unknown = false;
parameters.log_period = FLAGS_log_period;
parameters.luby_restart = FLAGS_luby_restart;
parameters.num_solutions = FLAGS_num_solutions;
parameters.restart_log_size = FLAGS_restart_log_size;
parameters.simplex_frequency = FLAGS_simplex_frequency;
parameters.threads = FLAGS_workers;
parameters.time_limit_in_ms = FLAGS_time_limit;
parameters.use_log = FLAGS_logging;
parameters.verbose_impact = FLAGS_verbose_impact;
parameters.worker_id = -1;
parameters.search_type =
FLAGS_use_impact
? operations_research::FlatZincSearchParameters::IBS
: operations_research::FlatZincSearchParameters::FIRST_UNBOUND;
scoped_ptr<operations_research::FzParallelSupport> parallel_support(
operations_research::MakeSequentialSupport(parameters.all_solutions,
parameters.num_solutions,
FLAGS_verbose_mt));
operations_research::Run(argv[1], parameters, parallel_support.get());
operations_research::SequentialRun(argv[1]);
} else {
scoped_ptr<operations_research::FzParallelSupport> parallel_support(
operations_research::MakeMtSupport(FLAGS_all, FLAGS_verbose_mt));

View File

@@ -459,11 +459,11 @@ bool FlatZincModel::HasSolveAnnotations() const {
return has_annotations;
}
void FlatZincModel::CreateDecisionBuilders(const FlatZincSearchParameters& p) {
void FlatZincModel::ParseSearchAnnotations(
bool ignore_unknown,
std::vector<DecisionBuilder*>* const defined,
std::vector<IntVar*>* const active_variables) {
const bool has_solve_annotations = HasSolveAnnotations();
hash_set<IntVar*> added;
VLOG(1) << "Create decision builders";
std::vector<AstNode*> flat_annotations;
if (has_solve_annotations) {
CHECK_NOTNULL(solve_annotations_);
@@ -473,21 +473,82 @@ void FlatZincModel::CreateDecisionBuilders(const FlatZincSearchParameters& p) {
flat_annotations.push_back(solve_annotations_);
}
}
search_name_ = p.free_search ? "free" : "defined";
if (!p.free_search) {
for (unsigned int i = 0; i < flat_annotations.size(); i++) {
VLOG(1) << "Create decision builders from search annotations";
hash_set<IntVar*> added;
for (unsigned int i = 0; i < flat_annotations.size(); i++) {
try {
AstCall* call = flat_annotations[i]->getCall("int_search");
AstArray* args = call->getArgs(4);
AstArray* vars = args->a[0]->getArray();
std::vector<IntVar*> int_vars;
for (int i = 0; i < vars->a.size(); ++i) {
if (vars->a[i]->isIntVar()) {
IntVar* const to_add =
integer_variables_[vars->a[i]->getIntVar()]->Var();
if (!ContainsKey(added, to_add)) {
int_vars.push_back(to_add);
active_variables->push_back(to_add);
added.insert(to_add);
}
}
}
Solver::IntVarStrategy str = Solver::CHOOSE_MIN_SIZE_LOWEST_MIN;
if (args->hasAtom("input_order")) {
str = Solver::CHOOSE_FIRST_UNBOUND;
}
if (args->hasAtom("first_fail")) {
str = Solver::CHOOSE_MIN_SIZE;
}
if (args->hasAtom("anti_first_fail")) {
str = Solver::CHOOSE_MAX_SIZE;
}
if (args->hasAtom("smallest")) {
str = Solver::CHOOSE_LOWEST_MIN;
}
if (args->hasAtom("largest")) {
str = Solver::CHOOSE_HIGHEST_MAX;
}
if (args->hasAtom("max_regret")) {
str = Solver::CHOOSE_MAX_REGRET_ON_MIN;
}
if (args->hasAtom("occurrence")) {
SortVariableByDegree(solver_.get(), &int_vars);
str = Solver::CHOOSE_FIRST_UNBOUND;
}
Solver::IntValueStrategy vstr = Solver::ASSIGN_MIN_VALUE;
if (args->hasAtom("indomain_max")) {
vstr = Solver::ASSIGN_MAX_VALUE;
}
if (args->hasAtom("indomain_median") ||
args->hasAtom("indomain_middle")) {
vstr = Solver::ASSIGN_CENTER_VALUE;
}
if (args->hasAtom("indomain_random")) {
vstr = Solver::ASSIGN_RANDOM_VALUE;
}
if (args->hasAtom("indomain_split")) {
vstr = Solver::SPLIT_LOWER_HALF;
}
if (args->hasAtom("indomain_reverse_split")) {
vstr = Solver::SPLIT_UPPER_HALF;
}
defined->push_back(solver_->MakePhase(int_vars, str, vstr));
}
catch (AstTypeError & e) {
(void) e;
try {
AstCall* call = flat_annotations[i]->getCall("int_search");
AstCall* call = flat_annotations[i]->getCall("bool_search");
AstArray* args = call->getArgs(4);
AstArray* vars = args->a[0]->getArray();
std::vector<IntVar*> int_vars;
std::vector<IntVar*> bool_vars;
for (int i = 0; i < vars->a.size(); ++i) {
if (vars->a[i]->isIntVar()) {
if (vars->a[i]->isBoolVar()) {
IntVar* const to_add =
integer_variables_[vars->a[i]->getIntVar()]->Var();
boolean_variables_[vars->a[i]->getBoolVar()]->Var();
if (!ContainsKey(added, to_add)) {
int_vars.push_back(to_add);
bool_vars.push_back(to_add);
active_variables->push_back(to_add);
added.insert(to_add);
}
}
@@ -496,162 +557,140 @@ void FlatZincModel::CreateDecisionBuilders(const FlatZincSearchParameters& p) {
if (args->hasAtom("input_order")) {
str = Solver::CHOOSE_FIRST_UNBOUND;
}
if (args->hasAtom("first_fail")) {
str = Solver::CHOOSE_MIN_SIZE;
}
if (args->hasAtom("anti_first_fail")) {
str = Solver::CHOOSE_MAX_SIZE;
}
if (args->hasAtom("smallest")) {
str = Solver::CHOOSE_LOWEST_MIN;
}
if (args->hasAtom("largest")) {
str = Solver::CHOOSE_HIGHEST_MAX;
}
if (args->hasAtom("max_regret")) {
str = Solver::CHOOSE_MAX_REGRET_ON_MIN;
}
if (args->hasAtom("occurrence")) {
SortVariableByDegree(solver_.get(), &int_vars);
SortVariableByDegree(solver_.get(), &bool_vars);
str = Solver::CHOOSE_FIRST_UNBOUND;
}
Solver::IntValueStrategy vstr = Solver::ASSIGN_MIN_VALUE;
if (args->hasAtom("indomain_max")) {
vstr = Solver::ASSIGN_MAX_VALUE;
}
if (args->hasAtom("indomain_median") ||
args->hasAtom("indomain_middle")) {
vstr = Solver::ASSIGN_CENTER_VALUE;
Solver::IntValueStrategy vstr = Solver::ASSIGN_MAX_VALUE;
if (args->hasAtom("indomain_min")) {
vstr = Solver::ASSIGN_MIN_VALUE;
}
if (args->hasAtom("indomain_random")) {
vstr = Solver::ASSIGN_RANDOM_VALUE;
}
if (args->hasAtom("indomain_split")) {
vstr = Solver::SPLIT_LOWER_HALF;
}
if (args->hasAtom("indomain_reverse_split")) {
vstr = Solver::SPLIT_UPPER_HALF;
}
builders_.push_back(solver_->MakePhase(int_vars, str, vstr));
defined->push_back(solver_->MakePhase(bool_vars, str, vstr));
}
catch (AstTypeError & e) {
(void) e;
try {
AstCall* call = flat_annotations[i]->getCall("bool_search");
AstCall* call = flat_annotations[i]->getCall("set_search");
AstArray* args = call->getArgs(4);
AstArray* vars = args->a[0]->getArray();
std::vector<IntVar*> bool_vars;
for (int i = 0; i < vars->a.size(); ++i) {
if (vars->a[i]->isBoolVar()) {
IntVar* const to_add =
boolean_variables_[vars->a[i]->getBoolVar()]->Var();
if (!ContainsKey(added, to_add)) {
bool_vars.push_back(to_add);
added.insert(to_add);
}
}
}
Solver::IntVarStrategy str = Solver::CHOOSE_MIN_SIZE_LOWEST_MIN;
if (args->hasAtom("input_order")) {
str = Solver::CHOOSE_FIRST_UNBOUND;
}
if (args->hasAtom("occurrence")) {
SortVariableByDegree(solver_.get(), &bool_vars);
str = Solver::CHOOSE_FIRST_UNBOUND;
}
Solver::IntValueStrategy vstr = Solver::ASSIGN_MAX_VALUE;
if (args->hasAtom("indomain_min")) {
vstr = Solver::ASSIGN_MIN_VALUE;
}
if (args->hasAtom("indomain_random")) {
vstr = Solver::ASSIGN_RANDOM_VALUE;
}
builders_.push_back(solver_->MakePhase(bool_vars, str, vstr));
args->a[0]->getArray();
LOG(FATAL) << "Search on set variables not supported";
}
catch (AstTypeError & e) {
(void) e;
try {
AstCall* call = flat_annotations[i]->getCall("set_search");
AstArray* args = call->getArgs(4);
args->a[0]->getArray();
LOG(FATAL) << "Search on set variables not supported";
}
catch (AstTypeError & e) {
(void) e;
if (!p.ignore_unknown) {
LOG(WARNING) << "Warning, ignored search annotation: "
<< flat_annotations[i]->DebugString();
}
if (!ignore_unknown) {
LOG(WARNING) << "Warning, ignored search annotation: "
<< flat_annotations[i]->DebugString();
}
}
}
}
}
// Add completion goals to be robust to incomplete search.
// First on active varialbes, create the variable array, push
// smaller variable first.
std::vector<IntVar*> vars;
if (defined->empty() || (defined->size() == 1 && method_ != SAT)) {
active_variables->clear();
// Create the variable array, push smaller variable first.
for (int i = 0; i < active_variables_.size(); ++i) {
IntVar* const var = active_variables_[i];
if (var->Size() < 0xFFFF) {
vars.push_back(var);
active_variables->push_back(var);
}
}
for (int i = 0; i < active_variables_.size(); ++i) {
IntVar* const var = active_variables_[i];
if (var->Size() >= 0xFFFF) {
vars.push_back(var);
active_variables->push_back(var);
}
}
}
}
// Then introduced variables.
builders_.push_back(solver_->MakePhase(vars, Solver::CHOOSE_FIRST_UNBOUND,
// Add completion goals to be robust to incomplete search specifications.
void FlatZincModel::AddCompletionDecisionBuilders(
std::vector<DecisionBuilder*>* const builders) {
const bool has_solve_annotations = HasSolveAnnotations();
// Add introduced variables.
// builders->push_back(solver_->MakePhase(vars, Solver::CHOOSE_FIRST_UNBOUND,
// Solver::ASSIGN_MIN_VALUE));
// Then fixed variables.
if (!introduced_variables_.empty() && !has_solve_annotations) {
// Better safe than sorry.
builders->push_back(solver_->MakePhase(introduced_variables_,
Solver::CHOOSE_FIRST_UNBOUND,
Solver::ASSIGN_MIN_VALUE));
// Then fixed variables.
if (!introduced_variables_.empty() && !has_solve_annotations) {
// Better safe than sorry.
builders_.push_back(solver_->MakePhase(introduced_variables_,
Solver::CHOOSE_FIRST_UNBOUND,
Solver::ASSIGN_MIN_VALUE));
}
if (!one_constraint_variables_.empty()) {
// Better safe than sorry.
builders_.push_back(
solver_->RevAlloc(new AssignToBounds(one_constraint_variables_)));
}
if (!one_constraint_variables_.empty()) {
// Better safe than sorry.
builders->push_back(
solver_->RevAlloc(new AssignToBounds(one_constraint_variables_)));
}
}
DecisionBuilder* FlatZincModel::CreateDecisionBuilders(
const FlatZincSearchParameters& p) {
VLOG(1) << "Create decision builders";
// Fill builders_ with predefined search.
std::vector<DecisionBuilder*> defined;
std::vector<IntVar*> active_variables;
ParseSearchAnnotations(p.ignore_unknown, &defined, &active_variables);
// We collect the decision builder linked to the objective.
DecisionBuilder* obj_db = NULL;
if (defined.size() > 0 && method_ != SAT) {
obj_db = defined.back();
defined.pop_back();
if (defined.size() > 0) {
// We need to remove the objective variables from the list of
// defined_vars.
active_variables.pop_back();
}
}
search_name_ =
defined.empty() ? "automatic" : (p.free_search ? "free" : "defined");
if (p.free_search || builders_.size() == 0 ||
(builders_.size() == 1 && method_ != SAT)) {
search_name_ = "automatic";
// We collect the objective linked decision builder.
DecisionBuilder* const obj_db =
builders_.size() == 1 ? builders_.back() : NULL;
builders_.clear();
// We fill builders with information from search (flags, annotations).
std::vector<DecisionBuilder*> builders;
if (!p.free_search && !defined.empty()) {
builders = defined;
} else {
DefaultPhaseParameters parameters;
DecisionBuilder* inner_builder = NULL;
switch (p.search_type) {
case FlatZincSearchParameters::IBS:
parameters.search_strategy =
DefaultPhaseParameters::IMPACT_BASED_SEARCH;
case FlatZincSearchParameters::DEFAULT: {
if (defined.empty()) {
inner_builder = solver_->MakePhase(active_variables,
Solver::CHOOSE_MIN_SIZE,
Solver::ASSIGN_MIN_VALUE);
} else {
inner_builder = solver_->Compose(defined);
}
break;
case FlatZincSearchParameters::FIRST_UNBOUND:
parameters.search_strategy =
DefaultPhaseParameters::CHOOSE_FIRST_UNBOUND_ASSIGN_MIN;
}
case FlatZincSearchParameters::IBS: {
break;
case FlatZincSearchParameters::MIN_SIZE:
parameters.search_strategy =
DefaultPhaseParameters::CHOOSE_MIN_SIZE_ASSIGN_MIN;
}
case FlatZincSearchParameters::FIRST_UNBOUND: {
inner_builder = solver_->MakePhase(
active_variables, Solver::CHOOSE_FIRST_UNBOUND,
Solver::ASSIGN_MIN_VALUE);
break;
case FlatZincSearchParameters::RANDOM_MIN:
parameters.search_strategy =
DefaultPhaseParameters::CHOOSE_RANDOM_ASSIGN_MIN;
break;
case FlatZincSearchParameters::RANDOM_MAX:
parameters.search_strategy =
DefaultPhaseParameters::CHOOSE_RANDOM_ASSIGN_MAX;
}
case FlatZincSearchParameters::MIN_SIZE: {
inner_builder = solver_->MakePhase(
active_variables, Solver::CHOOSE_MIN_SIZE_LOWEST_MIN,
Solver::ASSIGN_MIN_VALUE);
break;
}
case FlatZincSearchParameters::RANDOM_MIN: {
inner_builder = solver_->MakePhase(
active_variables, Solver::CHOOSE_RANDOM, Solver::ASSIGN_MIN_VALUE);
}
case FlatZincSearchParameters::RANDOM_MAX: {
inner_builder = solver_->MakePhase(
active_variables, Solver::CHOOSE_RANDOM, Solver::ASSIGN_MAX_VALUE);
}
}
parameters.run_all_heuristics = true;
parameters.heuristic_period =
@@ -663,50 +702,31 @@ void FlatZincModel::CreateDecisionBuilders(const FlatZincSearchParameters& p) {
p.use_log ? (p.verbose_impact ? DefaultPhaseParameters::VERBOSE
: DefaultPhaseParameters::NORMAL)
: DefaultPhaseParameters::NONE;
parameters.use_no_goods = true;
parameters.use_no_goods = (p.restart_log_size > 0);
parameters.var_selection_schema =
DefaultPhaseParameters::CHOOSE_MAX_SUM_IMPACT;
parameters.value_selection_schema =
DefaultPhaseParameters::SELECT_MIN_IMPACT;
parameters.random_seed = p.random_seed;
// Create the variable array, push smaller variable first.
std::vector<IntVar*> vars;
for (int i = 0; i < active_variables_.size(); ++i) {
IntVar* const var = active_variables_[i];
if (var->Size() < 0xFFFF) {
vars.push_back(var);
}
}
for (int i = 0; i < active_variables_.size(); ++i) {
IntVar* const var = active_variables_[i];
if (var->Size() >= 0xFFFF) {
vars.push_back(var);
}
}
builders_.push_back(solver_->MakeDefaultPhase(vars, parameters));
if (!introduced_variables_.empty() && !has_solve_annotations) {
// Better safe than sorry.
builders_.push_back(solver_->MakePhase(introduced_variables_,
Solver::CHOOSE_FIRST_UNBOUND,
Solver::ASSIGN_MIN_VALUE));
}
if (!one_constraint_variables_.empty()) {
// Better safe than sorry.
builders_.push_back(
solver_->RevAlloc(new AssignToBounds(one_constraint_variables_)));
}
if (obj_db != NULL) {
builders_.push_back(obj_db);
if (inner_builder == NULL) {
CHECK_EQ(FlatZincSearchParameters::IBS, p.search_type);
parameters.decision_builder = NULL;
} else {
parameters.decision_builder = inner_builder;
}
builders.push_back(solver_->MakeDefaultPhase(active_variables, parameters));
}
// Add completion decision builders to be more robust.
AddCompletionDecisionBuilders(&builders);
// Add finally the objective decision builder.
if (obj_db != NULL) {
builders.push_back(obj_db);
}
// Reporting
for (int i = 0; i < builders_.size(); ++i) {
VLOG(1) << " - adding decision builder = " << builders_[i]->DebugString();
for (int i = 0; i < builders.size(); ++i) {
VLOG(1) << " - adding decision builder = " << builders[i]->DebugString();
}
}
const std::vector<DecisionBuilder*>& FlatZincModel::DecisionBuilders() const {
return builders_;
return solver_->Compose(builders);
}
const std::vector<IntVar*>& FlatZincModel::PrimaryVariables() const {
@@ -723,7 +743,7 @@ void FlatZincModel::Solve(FlatZincSearchParameters p,
return;
}
CreateDecisionBuilders(p);
DecisionBuilder* const db = CreateDecisionBuilders(p);
bool print_last = false;
if (p.all_solutions && p.num_solutions == 0) {
p.num_solutions = kint32max;
@@ -779,7 +799,7 @@ void FlatZincModel::Solve(FlatZincSearchParameters p,
bool breaked = false;
string solution_string;
const int64 build_time = solver_->wall_time();
solver_->NewSearch(solver_->Compose(builders_), monitors);
solver_->NewSearch(db, monitors);
while (solver_->NextSolution()) {
if (output_ != NULL && !parallel_support->ShouldFinish()) {
solution_string.clear();