fixes in the default search, added a verbosity level to DefaultPhaseParameters
This commit is contained in:
@@ -200,6 +200,12 @@ struct DefaultPhaseParameters {
|
||||
SELECT_MAX_IMPACT = 1,
|
||||
};
|
||||
|
||||
enum DisplayLevel {
|
||||
NONE = 0,
|
||||
NORMAL = 1,
|
||||
VERBOSE = 2
|
||||
};
|
||||
|
||||
DefaultPhaseParameters()
|
||||
: var_selection_schema(CHOOSE_MAX_SUM_IMPACT),
|
||||
value_selection_schema(SELECT_MIN_IMPACT),
|
||||
@@ -207,8 +213,10 @@ struct DefaultPhaseParameters {
|
||||
run_all_heuristics(true),
|
||||
heuristic_period(kDefaultHeuristicPeriod),
|
||||
heuristic_num_failures_limit(kDefaultHeuristicNumFailuresLimit),
|
||||
persistent_impact(true),
|
||||
random_seed(kDefaultSeed),
|
||||
restart_log_size(kDefaultRestartLogSize) {}
|
||||
restart_log_size(kDefaultRestartLogSize),
|
||||
display_level(NORMAL) {}
|
||||
|
||||
// This parameter describes how the next variable to instantiate
|
||||
// will be chosen.
|
||||
@@ -226,6 +234,9 @@ struct DefaultPhaseParameters {
|
||||
int heuristic_period;
|
||||
// The failure limit for each heuristic that we run.
|
||||
int heuristic_num_failures_limit;
|
||||
// Whether to keep the impact from the first search for other searches
|
||||
// or to recompute the impact for each new search.
|
||||
bool persistent_impact;
|
||||
// Seed used to initialize the random part in some heuristics.
|
||||
int random_seed;
|
||||
// Automatic Restart Size. When diving down, the size of the search
|
||||
@@ -239,6 +250,9 @@ struct DefaultPhaseParameters {
|
||||
// parameter < 0 means no restart. A parameter of 0 indicates that
|
||||
// we restart after each failure.
|
||||
double restart_log_size;
|
||||
// This represents the amount of information displayed by the default search.
|
||||
// None means no display, verbose means extra information.
|
||||
DisplayLevel display_level;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1458,10 +1458,15 @@ namespace operations_research {
|
||||
%typemap(javain) const vector<type*>& "$javainput"
|
||||
%typemap(in) const vector<type*>& (vector<type*> result) {
|
||||
jclass object_class =
|
||||
jenv->FindClass("com/google/ortools/constraintsolver/type");
|
||||
jenv->FindClass("com/google/ortools/"
|
||||
"constraintsolver/type");
|
||||
if (NULL == object_class)
|
||||
return $null;
|
||||
jmethodID method_id = jenv->GetStaticMethodID(object_class, "getCPtr", "(Lcom/google/ortools/constraintsolver/type;)J");
|
||||
jmethodID method_id =
|
||||
jenv->GetStaticMethodID(object_class,
|
||||
"getCPtr",
|
||||
"(Lcom/google/ortools/"
|
||||
"constraintsolver/type;)J");
|
||||
assert(method_id != NULL);
|
||||
for (int i = 0; i < jenv->GetArrayLength($input); i++) {
|
||||
jobject elem = jenv->GetObjectArrayElement($input, i);
|
||||
|
||||
@@ -94,6 +94,7 @@ class InitVarImpacts : public DecisionBuilder {
|
||||
virtual ~InitVarImpacts() {}
|
||||
|
||||
void UpdateImpacts() {
|
||||
// the Min is always the value we just set.
|
||||
update_impact_callback_->Run(var_index_, var_->Min());
|
||||
}
|
||||
|
||||
@@ -291,13 +292,16 @@ class ImpactRecorder {
|
||||
static const double kFailureImpact;
|
||||
static const double kInitFailureImpact;
|
||||
|
||||
ImpactRecorder(const IntVar* const * vars, int size)
|
||||
ImpactRecorder(const IntVar* const * vars,
|
||||
int size,
|
||||
DefaultPhaseParameters::DisplayLevel display_level)
|
||||
: domain_watcher_(vars, size, kLogCacheSize),
|
||||
size_(size),
|
||||
current_log_space_(0.0),
|
||||
impacts_(size_),
|
||||
original_min_(size_, 0LL),
|
||||
domain_iterators_(new IntVarIterator*[size_]) {
|
||||
domain_iterators_(new IntVarIterator*[size_]),
|
||||
display_level_(display_level) {
|
||||
CHECK_GE(size_, 0);
|
||||
if (size_ > 0) {
|
||||
vars_.reset(new IntVar*[size_]);
|
||||
@@ -306,11 +310,20 @@ class ImpactRecorder {
|
||||
for (int i = 0; i < size_; ++i) {
|
||||
domain_iterators_[i] = vars_[i]->MakeDomainIterator(true);
|
||||
original_min_[i] = vars_[i]->Min();
|
||||
// By default, we init impacts to 1.0 -> equivalent to failure.
|
||||
// By default, we init impacts to 2.0 -> equivalent to failure.
|
||||
// This will be overwritten to real impact values on valid domain
|
||||
// values during the FirstRun() method.
|
||||
impacts_[i].resize(vars_[i]->Max() - vars_[i]->Min() + 1,
|
||||
kInitFailureImpact);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ResetImpacts() {
|
||||
for (int i = 0; i < size_; ++i) {
|
||||
for (int j = 0; j < impacts_[i].size(); ++j) {
|
||||
impacts_[i][j] = kInitFailureImpact;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,13 +348,17 @@ class ImpactRecorder {
|
||||
const double log_space = domain_watcher_.LogSearchSpaceSize();
|
||||
const double impact = kPerfectImpact - log_space / current_log_space_;
|
||||
const int64 value_index = value - original_min_[var_index];
|
||||
DCHECK_LT(var_index, size_);
|
||||
DCHECK_LT(value_index, impacts_[var_index].size());
|
||||
impacts_[var_index][value_index] = impact;
|
||||
init_count_++;
|
||||
}
|
||||
|
||||
void FirstRun(Solver* const solver, int64 splits) {
|
||||
current_log_space_ = domain_watcher_.LogSearchSpaceSize();
|
||||
VLOG(1) << " - initial log2(SearchSpace) = " << current_log_space_;
|
||||
if (display_level_ != DefaultPhaseParameters::NONE) {
|
||||
LOG(INFO) << " - initial log2(SearchSpace) = " << current_log_space_;
|
||||
}
|
||||
const int64 init_time = solver->wall_time();
|
||||
int64 removed_counter = 0;
|
||||
FirstRunVariableContainers* container = solver->RevAlloc(
|
||||
@@ -385,22 +402,23 @@ class ImpactRecorder {
|
||||
container->PushBackRemovedValue(value);
|
||||
}
|
||||
}
|
||||
CHECK(container->HasRemovedValues());
|
||||
CHECK(container->HasRemovedValues()) << var->DebugString();
|
||||
removed_counter += container->NumRemovedValues();
|
||||
const double old_log = domain_watcher_.Log2(var->Size());
|
||||
var->RemoveValues(container->removed_values());
|
||||
current_log_space_ += domain_watcher_.Log2(var->Size()) - old_log;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed_counter) {
|
||||
LOG(INFO) << " - init done, time = " << solver->wall_time() - init_time
|
||||
<< " ms, " << removed_counter
|
||||
<< " values removed, log2(SearchSpace) = "
|
||||
<< current_log_space_;
|
||||
} else {
|
||||
LOG(INFO) << " - init done, time = " << solver->wall_time() - init_time
|
||||
<< " ms";
|
||||
if (display_level_ != DefaultPhaseParameters::NONE) {
|
||||
if (removed_counter) {
|
||||
LOG(INFO) << " - init done, time = " << solver->wall_time() - init_time
|
||||
<< " ms, " << removed_counter
|
||||
<< " values removed, log2(SearchSpace) = "
|
||||
<< current_log_space_;
|
||||
} else {
|
||||
LOG(INFO) << " - init done, time = " << solver->wall_time() - init_time
|
||||
<< " ms";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,6 +454,8 @@ class ImpactRecorder {
|
||||
for (it->Init(); it->Ok(); it->Next()) {
|
||||
const int64 value = it->Value();
|
||||
const int64 value_index = value - original_min_[var_index];
|
||||
DCHECK_LT(var_index, size_);
|
||||
DCHECK_LT(value_index, impacts_[var_index].size());
|
||||
const double current_impact = impacts_[var_index][value_index];
|
||||
sum_var_impact += current_impact;
|
||||
if (current_impact > max_impact) {
|
||||
@@ -514,6 +534,7 @@ class ImpactRecorder {
|
||||
vector<int64> original_min_;
|
||||
scoped_array<IntVarIterator*> domain_iterators_;
|
||||
int64 init_count_;
|
||||
const DefaultPhaseParameters::DisplayLevel display_level_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ImpactRecorder);
|
||||
};
|
||||
@@ -533,7 +554,7 @@ class ImpactDecisionBuilder : public DecisionBuilder {
|
||||
const IntVar* const* vars,
|
||||
int size,
|
||||
const DefaultPhaseParameters& parameters)
|
||||
: impact_recorder_(vars, size),
|
||||
: impact_recorder_(vars, size, parameters.display_level),
|
||||
size_(size),
|
||||
parameters_(parameters),
|
||||
init_done_(false),
|
||||
@@ -668,7 +689,7 @@ class ImpactDecisionBuilder : public DecisionBuilder {
|
||||
|
||||
const bool result =
|
||||
solver->NestedSolve(wrapper->phase, false, heuristic_limit_);
|
||||
if (result) {
|
||||
if (result && parameters_.display_level != DefaultPhaseParameters::NONE) {
|
||||
LOG(INFO) << "Solution found by heuristic " << wrapper->name;
|
||||
}
|
||||
return result;
|
||||
@@ -692,14 +713,23 @@ class ImpactDecisionBuilder : public DecisionBuilder {
|
||||
|
||||
virtual Decision* Next(Solver* const solver) {
|
||||
if (!init_done_) {
|
||||
LOG(INFO) << "Init impact based search phase on " << size_
|
||||
<< " variables, initialization splits = "
|
||||
<< parameters_.initialization_splits
|
||||
<< ", heuristic_period = " << parameters_.heuristic_period
|
||||
<< ", run_all_heuristics = " << parameters_.run_all_heuristics
|
||||
<< ", restart_log_size = " << parameters_.restart_log_size;
|
||||
if (parameters_.display_level != DefaultPhaseParameters::NONE) {
|
||||
LOG(INFO) << "Init impact based search phase on " << size_
|
||||
<< " variables, initialization splits = "
|
||||
<< parameters_.initialization_splits
|
||||
<< ", heuristic_period = " << parameters_.heuristic_period
|
||||
<< ", run_all_heuristics = " << parameters_.run_all_heuristics
|
||||
<< ", restart_log_size = " << parameters_.restart_log_size;
|
||||
}
|
||||
// We need to reset the impacts because FirstRun calls RemoveValues
|
||||
// which can result in a Fail() therefore calling this method again.
|
||||
impact_recorder_.ResetImpacts();
|
||||
impact_recorder_.FirstRun(solver, parameters_.initialization_splits);
|
||||
init_done_ = true;
|
||||
if (parameters_.persistent_impact) {
|
||||
init_done_ = true;
|
||||
} else {
|
||||
solver->SaveAndSetValue(&init_done_, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (current_var_index_ == -1 && fail_stamp_ != 0) {
|
||||
@@ -722,14 +752,18 @@ class ImpactDecisionBuilder : public DecisionBuilder {
|
||||
const double log_search_space_size =
|
||||
impact_recorder_.LogSearchSpaceSize();
|
||||
const int search_depth = solver->SearchDepth();
|
||||
VLOG(2) << "search_depth = " << search_depth
|
||||
<< ", log_search_space_size = " << log_search_space_size
|
||||
<< ", min_log_search_space = " << min_log_search_space_;
|
||||
if (parameters_.display_level == DefaultPhaseParameters::VERBOSE) {
|
||||
LOG(INFO) << "search_depth = " << search_depth
|
||||
<< ", log_search_space_size = " << log_search_space_size
|
||||
<< ", min_log_search_space = " << min_log_search_space_;
|
||||
}
|
||||
if (min_log_search_space_ > log_search_space_size) {
|
||||
min_log_search_space_ = log_search_space_size;
|
||||
} else if (min_log_search_space_ + parameters_.restart_log_size
|
||||
< log_search_space_size) {
|
||||
VLOG(2) << "Restarting ";
|
||||
if (parameters_.display_level == DefaultPhaseParameters::VERBOSE) {
|
||||
LOG(INFO) << "Restarting ";
|
||||
}
|
||||
min_log_search_space_ = std::numeric_limits<double>::infinity();
|
||||
solver->RestartSearch();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user