add ability to inject decision builder inside the default search; adapt flatzinc interface
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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 -----
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user