Export Google dev in constraint_solver
This commit is contained in:
@@ -1311,23 +1311,39 @@ class ChangeValue : public IntVarLocalSearchOperator {
|
||||
/// the services above (no direct manipulation of assignments).
|
||||
class PathOperator : public IntVarLocalSearchOperator {
|
||||
public:
|
||||
/// Set of parameters used to configure how the neighnorhood is traversed.
|
||||
struct IterationParameters {
|
||||
/// Number of nodes needed to define a neighbor.
|
||||
int number_of_base_nodes;
|
||||
/// Skip paths which have been proven locally optimal. Note this might skip
|
||||
/// neighbors when paths are not independent.
|
||||
bool skip_locally_optimal_paths;
|
||||
/// True if path ends should be considered when iterating over neighbors.
|
||||
bool accept_path_end_base;
|
||||
/// Callback returning an index such that if
|
||||
/// c1 = start_empty_path_class(StartNode(p1)),
|
||||
/// c2 = start_empty_path_class(StartNode(p2)),
|
||||
/// p1 and p2 are path indices,
|
||||
/// then if c1 == c2, p1 and p2 are equivalent if they are empty.
|
||||
/// This is used to remove neighborhood symmetries on equivalent empty
|
||||
/// paths; for instance if a node cannot be moved to an empty path, then all
|
||||
/// moves moving the same node to equivalent empty paths will be skipped.
|
||||
/// 'start_empty_path_class' can be nullptr in which case no symmetries will
|
||||
/// be removed.
|
||||
std::function<int(int64_t)> start_empty_path_class;
|
||||
};
|
||||
/// Builds an instance of PathOperator from next and path variables.
|
||||
/// 'number_of_base_nodes' is the number of nodes needed to define a
|
||||
/// neighbor. 'start_empty_path_class' is a callback returning an index such
|
||||
/// that if
|
||||
/// c1 = start_empty_path_class(StartNode(p1)),
|
||||
/// c2 = start_empty_path_class(StartNode(p2)),
|
||||
/// p1 and p2 are path indices,
|
||||
/// then if c1 == c2, p1 and p2 are equivalent if they are empty.
|
||||
/// This is used to remove neighborhood symmetries on equivalent empty paths;
|
||||
/// for instance if a node cannot be moved to an empty path, then all moves
|
||||
/// moving the same node to equivalent empty paths will be skipped.
|
||||
/// 'start_empty_path_class' can be nullptr in which case no symmetries will
|
||||
/// be removed.
|
||||
PathOperator(const std::vector<IntVar*>& next_vars,
|
||||
const std::vector<IntVar*>& path_vars,
|
||||
IterationParameters iteration_parameters);
|
||||
PathOperator(const std::vector<IntVar*>& next_vars,
|
||||
const std::vector<IntVar*>& path_vars, int number_of_base_nodes,
|
||||
bool skip_locally_optimal_paths, bool accept_path_end_base,
|
||||
std::function<int(int64_t)> start_empty_path_class);
|
||||
std::function<int(int64_t)> start_empty_path_class)
|
||||
: PathOperator(
|
||||
next_vars, path_vars,
|
||||
{number_of_base_nodes, skip_locally_optimal_paths,
|
||||
accept_path_end_base, std::move(start_empty_path_class)}) {}
|
||||
~PathOperator() override {}
|
||||
virtual bool MakeNeighbor() = 0;
|
||||
void Reset() override;
|
||||
@@ -1397,8 +1413,8 @@ class PathOperator : public IntVarLocalSearchOperator {
|
||||
const std::vector<int64_t>& path_starts() const { return path_starts_; }
|
||||
/// Returns the class of the path of the ith base node.
|
||||
int PathClass(int i) const {
|
||||
return start_empty_path_class_ != nullptr
|
||||
? start_empty_path_class_(StartNode(i))
|
||||
return iteration_parameters_.start_empty_path_class != nullptr
|
||||
? iteration_parameters_.start_empty_path_class(StartNode(i))
|
||||
: StartNode(i);
|
||||
}
|
||||
|
||||
@@ -1588,9 +1604,7 @@ class PathOperator : public IntVarLocalSearchOperator {
|
||||
std::vector<bool> inactives_;
|
||||
bool just_started_;
|
||||
bool first_start_;
|
||||
const bool accept_path_end_base_;
|
||||
std::function<int(int64_t)> start_empty_path_class_;
|
||||
bool skip_locally_optimal_paths_;
|
||||
IterationParameters iteration_parameters_;
|
||||
bool optimal_paths_enabled_;
|
||||
std::vector<int> path_basis_;
|
||||
std::vector<bool> optimal_paths_;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Using the CP solver
|
||||
|
||||
https://developers.google.com/optimization/cp/
|
||||
|
||||
## Documentation structure
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Using the Vehicle Routing solver
|
||||
|
||||
https://developers.google.com/optimization/routing
|
||||
|
||||
## Documentation structure
|
||||
|
||||
|
||||
@@ -344,27 +344,22 @@ class DecrementValue : public ChangeValue {
|
||||
|
||||
PathOperator::PathOperator(const std::vector<IntVar*>& next_vars,
|
||||
const std::vector<IntVar*>& path_vars,
|
||||
int number_of_base_nodes,
|
||||
bool skip_locally_optimal_paths,
|
||||
bool accept_path_end_base,
|
||||
std::function<int(int64_t)> start_empty_path_class)
|
||||
IterationParameters iteration_parameters)
|
||||
: IntVarLocalSearchOperator(next_vars, true),
|
||||
number_of_nexts_(next_vars.size()),
|
||||
ignore_path_vars_(path_vars.empty()),
|
||||
next_base_to_increment_(number_of_base_nodes),
|
||||
base_nodes_(number_of_base_nodes),
|
||||
base_alternatives_(number_of_base_nodes),
|
||||
base_sibling_alternatives_(number_of_base_nodes),
|
||||
end_nodes_(number_of_base_nodes),
|
||||
base_paths_(number_of_base_nodes),
|
||||
next_base_to_increment_(iteration_parameters.number_of_base_nodes),
|
||||
base_nodes_(iteration_parameters.number_of_base_nodes),
|
||||
base_alternatives_(iteration_parameters.number_of_base_nodes),
|
||||
base_sibling_alternatives_(iteration_parameters.number_of_base_nodes),
|
||||
end_nodes_(iteration_parameters.number_of_base_nodes),
|
||||
base_paths_(iteration_parameters.number_of_base_nodes),
|
||||
just_started_(false),
|
||||
first_start_(true),
|
||||
accept_path_end_base_(accept_path_end_base),
|
||||
start_empty_path_class_(std::move(start_empty_path_class)),
|
||||
skip_locally_optimal_paths_(skip_locally_optimal_paths),
|
||||
iteration_parameters_(std::move(iteration_parameters)),
|
||||
optimal_paths_enabled_(false),
|
||||
alternative_index_(next_vars.size(), -1) {
|
||||
DCHECK_GT(number_of_base_nodes, 0);
|
||||
DCHECK_GT(iteration_parameters_.number_of_base_nodes, 0);
|
||||
if (!ignore_path_vars_) {
|
||||
AddVars(path_vars);
|
||||
}
|
||||
@@ -377,7 +372,7 @@ PathOperator::PathOperator(const std::vector<IntVar*>& next_vars,
|
||||
->solver()
|
||||
->parameters()
|
||||
.skip_locally_optimal_paths())) {
|
||||
skip_locally_optimal_paths_ = false;
|
||||
iteration_parameters_.skip_locally_optimal_paths = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,7 +489,7 @@ bool PathOperator::SwapActiveAndInactive(int64_t active, int64_t inactive) {
|
||||
}
|
||||
|
||||
bool PathOperator::IncrementPosition() {
|
||||
const int base_node_size = base_nodes_.size();
|
||||
const int base_node_size = iteration_parameters_.number_of_base_nodes;
|
||||
|
||||
if (!just_started_) {
|
||||
const int number_of_paths = path_starts_.size();
|
||||
@@ -533,7 +528,9 @@ bool PathOperator::IncrementPosition() {
|
||||
base_alternatives_[i] = 0;
|
||||
base_sibling_alternatives_[i] = 0;
|
||||
base_nodes_[i] = OldNext(base_nodes_[i]);
|
||||
if (accept_path_end_base_ || !IsPathEnd(base_nodes_[i])) break;
|
||||
if (iteration_parameters_.accept_path_end_base ||
|
||||
!IsPathEnd(base_nodes_[i]))
|
||||
break;
|
||||
}
|
||||
base_alternatives_[i] = 0;
|
||||
base_sibling_alternatives_[i] = 0;
|
||||
@@ -561,7 +558,8 @@ bool PathOperator::IncrementPosition() {
|
||||
// If all base nodes have been restarted, base nodes are moved to new paths.
|
||||
// First we mark the current paths as locally optimal if they have been
|
||||
// completely explored.
|
||||
if (optimal_paths_enabled_ && skip_locally_optimal_paths_) {
|
||||
if (optimal_paths_enabled_ &&
|
||||
iteration_parameters_.skip_locally_optimal_paths) {
|
||||
if (path_basis_.size() > 1) {
|
||||
for (int i = 1; i < path_basis_.size(); ++i) {
|
||||
optimal_paths_[num_paths_ *
|
||||
@@ -598,7 +596,7 @@ bool PathOperator::IncrementPosition() {
|
||||
base_nodes_[i] = path_starts_[0];
|
||||
}
|
||||
}
|
||||
if (!skip_locally_optimal_paths_) return CheckEnds();
|
||||
if (!iteration_parameters_.skip_locally_optimal_paths) return CheckEnds();
|
||||
// If the new paths have already been completely explored, we can
|
||||
// skip them from now on.
|
||||
if (path_basis_.size() > 1) {
|
||||
@@ -648,7 +646,8 @@ void PathOperator::InitializePathStarts() {
|
||||
max_next = std::max(max_next, next);
|
||||
}
|
||||
// Update locally optimal paths.
|
||||
if (optimal_paths_.empty() && skip_locally_optimal_paths_) {
|
||||
if (optimal_paths_.empty() &&
|
||||
iteration_parameters_.skip_locally_optimal_paths) {
|
||||
num_paths_ = 0;
|
||||
start_to_path_.clear();
|
||||
start_to_path_.resize(number_of_nexts_, -1);
|
||||
@@ -660,7 +659,7 @@ void PathOperator::InitializePathStarts() {
|
||||
}
|
||||
optimal_paths_.resize(num_paths_ * num_paths_, false);
|
||||
}
|
||||
if (skip_locally_optimal_paths_) {
|
||||
if (iteration_parameters_.skip_locally_optimal_paths) {
|
||||
for (int i = 0; i < number_of_nexts_; ++i) {
|
||||
if (!has_prevs[i]) {
|
||||
int current = i;
|
||||
@@ -686,9 +685,10 @@ void PathOperator::InitializePathStarts() {
|
||||
for (int i = 0; i < number_of_nexts_; ++i) {
|
||||
if (!has_prevs[i]) {
|
||||
if (use_empty_path_symmetry_breaker && IsPathEnd(OldNext(i))) {
|
||||
if (start_empty_path_class_ != nullptr) {
|
||||
if (empty_found[start_empty_path_class_(i)]) continue;
|
||||
empty_found[start_empty_path_class_(i)] = true;
|
||||
if (iteration_parameters_.start_empty_path_class != nullptr) {
|
||||
if (empty_found[iteration_parameters_.start_empty_path_class(i)])
|
||||
continue;
|
||||
empty_found[iteration_parameters_.start_empty_path_class(i)] = true;
|
||||
}
|
||||
}
|
||||
new_path_starts.push_back(i);
|
||||
@@ -708,7 +708,7 @@ void PathOperator::InitializePathStarts() {
|
||||
}
|
||||
node_paths[node] = i;
|
||||
}
|
||||
for (int j = 0; j < base_nodes_.size(); ++j) {
|
||||
for (int j = 0; j < iteration_parameters_.number_of_base_nodes; ++j) {
|
||||
// Always restart from first alternative.
|
||||
base_alternatives_[j] = 0;
|
||||
base_sibling_alternatives_[j] = 0;
|
||||
@@ -737,7 +737,7 @@ void PathOperator::InitializePathStarts() {
|
||||
if (found) {
|
||||
new_index = index;
|
||||
}
|
||||
for (int j = 0; j < base_nodes_.size(); ++j) {
|
||||
for (int j = 0; j < iteration_parameters_.number_of_base_nodes; ++j) {
|
||||
if (base_paths_[j] == i && !gtl::ContainsKey(found_bases, j)) {
|
||||
found_bases.insert(j);
|
||||
base_paths_[j] = new_index;
|
||||
@@ -767,13 +767,13 @@ void PathOperator::InitializeBaseNodes() {
|
||||
if (first_start_ || InitPosition()) {
|
||||
// Only do this once since the following starts will continue from the
|
||||
// preceding position
|
||||
for (int i = 0; i < base_nodes_.size(); ++i) {
|
||||
for (int i = 0; i < iteration_parameters_.number_of_base_nodes; ++i) {
|
||||
base_paths_[i] = 0;
|
||||
base_nodes_[i] = path_starts_[0];
|
||||
}
|
||||
first_start_ = false;
|
||||
}
|
||||
for (int i = 0; i < base_nodes_.size(); ++i) {
|
||||
for (int i = 0; i < iteration_parameters_.number_of_base_nodes; ++i) {
|
||||
// If base node has been made inactive, restart from path start.
|
||||
int64_t base_node = base_nodes_[i];
|
||||
if (RestartAtPathStartOnSynchronize() || IsInactive(base_node)) {
|
||||
@@ -784,7 +784,7 @@ void PathOperator::InitializeBaseNodes() {
|
||||
}
|
||||
// Repair end_nodes_ in case some must be on the same path and are not anymore
|
||||
// (due to other operators moving these nodes).
|
||||
for (int i = 1; i < base_nodes_.size(); ++i) {
|
||||
for (int i = 1; i < iteration_parameters_.number_of_base_nodes; ++i) {
|
||||
if (OnSamePathAsPreviousBase(i) &&
|
||||
!OnSamePath(base_nodes_[i - 1], base_nodes_[i])) {
|
||||
const int64_t base_node = base_nodes_[i - 1];
|
||||
@@ -793,7 +793,7 @@ void PathOperator::InitializeBaseNodes() {
|
||||
base_paths_[i] = base_paths_[i - 1];
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < base_nodes_.size(); ++i) {
|
||||
for (int i = 0; i < iteration_parameters_.number_of_base_nodes; ++i) {
|
||||
base_alternatives_[i] = 0;
|
||||
base_sibling_alternatives_[i] = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user