diff --git a/ortools/constraint_solver/constraint_solveri.h b/ortools/constraint_solver/constraint_solveri.h index 21661af488..e35dc69fe2 100644 --- a/ortools/constraint_solver/constraint_solveri.h +++ b/ortools/constraint_solver/constraint_solveri.h @@ -3416,9 +3416,7 @@ class PathState { // State-dependent accessors. // Returns the committed path of a given node, -1 if it is a loop. - int Path(int node) const { - return committed_nodes_[committed_index_[node]].path; - } + int Path(int node) const { return committed_paths_[node]; } // Returns the set of paths that actually changed, // i.e. that have more than one chain. const std::vector& ChangedPaths() const { return changed_paths_; } @@ -3476,14 +3474,6 @@ class PathState { int begin_index; int end_index; }; - struct CommittedNode { - CommittedNode(int node, int path) : node(node), path(path) {} - int node; - // Path of node in the committed state, -1 for loop nodes. - // TODO(user): check if path would be better stored - // with committed_index_, or in its own vector, or just recomputed. - int path; - }; // Copies nodes in chains of path at the end of nodes, // and sets those nodes' path member to value path. @@ -3526,7 +3516,10 @@ class PathState { // Those chains do not overlap with one another or with committed chains. // - committed_nodes_ are not modified, and still represent the committed // paths. committed_index_ is not modified either. - std::vector committed_nodes_; + std::vector committed_nodes_; + // Maps nodes to their path in the latest committed state. + std::vector committed_paths_; + // Maps nodes to their index in the latest committed state. std::vector committed_index_; const int num_nodes_threshold_; std::vector chains_; @@ -3549,7 +3542,7 @@ class PathState::Chain { ++current_node_; return *this; } - int operator*() const { return current_node_->node; } + int operator*() const { return *current_node_; } bool operator!=(Iterator other) const { return current_node_ != other.current_node_; } @@ -3557,26 +3550,26 @@ class PathState::Chain { private: // Only a Chain can construct its iterator. friend class PathState::Chain; - explicit Iterator(const CommittedNode* node) : current_node_(node) {} - const CommittedNode* current_node_; + explicit Iterator(const int* node) : current_node_(node) {} + const int* current_node_; }; // Chains hold CommittedNode* values, a Chain may be invalidated // if the underlying vector is modified. - Chain(const CommittedNode* begin_node, const CommittedNode* end_node) + Chain(const int* begin_node, const int* end_node) : begin_(begin_node), end_(end_node) {} int NumNodes() const { return end_ - begin_; } - int First() const { return begin_->node; } - int Last() const { return (end_ - 1)->node; } + int First() const { return *begin_; } + int Last() const { return *(end_ - 1); } Iterator begin() const { return Iterator(begin_); } Iterator end() const { return Iterator(end_); } Chain WithoutFirstNode() const { return Chain(begin_ + 1, end_); } private: - const CommittedNode* const begin_; - const CommittedNode* const end_; + const int* const begin_; + const int* const end_; }; // A ChainRange is a range of Chains, committed or not. @@ -3599,17 +3592,16 @@ class PathState::ChainRange { private: // Only a ChainRange can construct its Iterator. friend class ChainRange; - Iterator(const ChainBounds* chain, const CommittedNode* const first_node) + Iterator(const ChainBounds* chain, const int* const first_node) : current_chain_(chain), first_node_(first_node) {} const ChainBounds* current_chain_; - const CommittedNode* const first_node_; + const int* const first_node_; }; // ChainRanges hold ChainBounds* and CommittedNode*, // a ChainRange may be invalidated if on of the underlying vector is modified. ChainRange(const ChainBounds* const begin_chain, - const ChainBounds* const end_chain, - const CommittedNode* const first_node) + const ChainBounds* const end_chain, const int* const first_node) : begin_(begin_chain), end_(end_chain), first_node_(first_node) {} Iterator begin() const { return {begin_, first_node_}; } @@ -3618,7 +3610,7 @@ class PathState::ChainRange { private: const ChainBounds* const begin_; const ChainBounds* const end_; - const CommittedNode* const first_node_; + const int* const first_node_; }; // A NodeRange allows to iterate on all nodes of a path, @@ -3639,7 +3631,7 @@ class PathState::NodeRange { } return *this; } - int operator*() const { return current_node_->node; } + int operator*() const { return *current_node_; } bool operator!=(Iterator other) const { return current_chain_ != other.current_chain_; } @@ -3647,22 +3639,21 @@ class PathState::NodeRange { private: // Only a NodeRange can construct its Iterator. friend class NodeRange; - Iterator(const ChainBounds* current_chain, - const CommittedNode* const first_node) + Iterator(const ChainBounds* current_chain, const int* const first_node) : current_node_(first_node + current_chain->begin_index), end_node_(first_node + current_chain->end_index), current_chain_(current_chain), first_node_(first_node) {} - const CommittedNode* current_node_; - const CommittedNode* end_node_; + const int* current_node_; + const int* end_node_; const ChainBounds* current_chain_; - const CommittedNode* const first_node_; + const int* const first_node_; }; - // NodeRanges hold ChainBounds* and CommittedNode*, + // NodeRanges hold ChainBounds* and int* (first committed node), // a NodeRange may be invalidated if on of the underlying vector is modified. NodeRange(const ChainBounds* begin_chain, const ChainBounds* end_chain, - const CommittedNode* first_node) + const int* first_node) : begin_chain_(begin_chain), end_chain_(end_chain), first_node_(first_node) {} @@ -3674,7 +3665,7 @@ class PathState::NodeRange { private: const ChainBounds* begin_chain_; const ChainBounds* end_chain_; - const CommittedNode* const first_node_; + const int* const first_node_; }; // This checker enforces dimension requirements. diff --git a/ortools/constraint_solver/local_search.cc b/ortools/constraint_solver/local_search.cc index 4c193d8657..3fdd0398ff 100644 --- a/ortools/constraint_solver/local_search.cc +++ b/ortools/constraint_solver/local_search.cc @@ -2663,17 +2663,21 @@ PathState::PathState(int num_nodes, std::vector path_start, } // Initial state is all unperformed: paths go from start to end directly. committed_index_.assign(num_nodes_, -1); - committed_nodes_.assign(2 * num_paths_, {-1, -1}); + committed_paths_.assign(num_nodes_, -1); + committed_nodes_.assign(2 * num_paths_, -1); chains_.assign(num_paths_ + 1, {-1, -1}); // Reserve 1 more for sentinel. paths_.assign(num_paths_, {-1, -1}); for (int path = 0; path < num_paths_; ++path) { const int index = 2 * path; - const PathStartEnd start_end = path_start_end_[path]; - committed_index_[start_end.start] = index; - committed_index_[start_end.end] = index + 1; + const auto& [start, end] = path_start_end_[path]; + committed_index_[start] = index; + committed_index_[end] = index + 1; - committed_nodes_[index] = {start_end.start, path}; - committed_nodes_[index + 1] = {start_end.end, path}; + committed_nodes_[index] = start; + committed_nodes_[index + 1] = end; + + committed_paths_[start] = path; + committed_paths_[end] = path; chains_[path] = {index, index + 2}; paths_[path] = {path, path + 1}; @@ -2683,7 +2687,7 @@ PathState::PathState(int num_nodes, std::vector path_start, for (int node = 0; node < num_nodes_; ++node) { if (committed_index_[node] != -1) continue; // node is start or end. committed_index_[node] = committed_nodes_.size(); - committed_nodes_.push_back({node, -1}); + committed_nodes_.push_back(node); } } @@ -2738,18 +2742,17 @@ void PathState::Revert() { void PathState::CopyNewPathAtEndOfNodes(int path) { // Copy path's nodes, chain by chain. - const int new_path_begin_index = committed_nodes_.size(); const PathBounds path_bounds = paths_[path]; for (int i = path_bounds.begin_index; i < path_bounds.end_index; ++i) { const ChainBounds chain_bounds = chains_[i]; committed_nodes_.insert(committed_nodes_.end(), committed_nodes_.data() + chain_bounds.begin_index, committed_nodes_.data() + chain_bounds.end_index); + if (committed_paths_[committed_nodes_.back()] == path) continue; + for (int i = chain_bounds.begin_index; i < chain_bounds.end_index; ++i) { + const int node = committed_nodes_[i]; + committed_paths_[node] = path; } - const int new_path_end_index = committed_nodes_.size(); - // Set new nodes' path member to path. - for (int i = new_path_begin_index; i < new_path_end_index; ++i) { - committed_nodes_[i].path = path; } } @@ -2766,13 +2769,13 @@ void PathState::IncrementalCommit() { // Re-index all copied nodes. const int new_nodes_end = committed_nodes_.size(); for (int i = new_nodes_begin; i < new_nodes_end; ++i) { - committed_index_[committed_nodes_[i].node] = i; + const int node = committed_nodes_[i]; + committed_index_[node] = i; } // New loops stay in place: only change their path to -1, // committed_index_ does not change. for (const int loop : ChangedLoops()) { - const int index = committed_index_[loop]; - committed_nodes_[index].path = -1; + committed_paths_[loop] = -1; } // Committed part of the state is set up, erase incremental changes. Revert(); @@ -2795,13 +2798,14 @@ void PathState::FullCommit() { constexpr int kUnindexed = -1; committed_index_.assign(num_nodes_, kUnindexed); int index = 0; - for (const CommittedNode committed_node : committed_nodes_) { - committed_index_[committed_node.node] = index++; + for (const int node : committed_nodes_) { + committed_index_[node] = index++; } for (int node = 0; node < num_nodes_; ++node) { if (committed_index_[node] != kUnindexed) continue; committed_index_[node] = index++; - committed_nodes_.push_back({node, -1}); + committed_nodes_.push_back(node); + committed_paths_[node] = -1; } // Committed part of the state is set up, erase incremental changes. Revert(); diff --git a/ortools/constraint_solver/samples/cp_is_fun_cp.cc b/ortools/constraint_solver/samples/cp_is_fun_cp.cc index 34fef46e5e..ca90e12be8 100644 --- a/ortools/constraint_solver/samples/cp_is_fun_cp.cc +++ b/ortools/constraint_solver/samples/cp_is_fun_cp.cc @@ -119,16 +119,11 @@ void CPIsFunCp() { letters, Solver::CHOOSE_FIRST_UNBOUND, Solver::ASSIGN_MIN_VALUE); solver.NewSearch(db); while (solver.NextSolution()) { - LOG(INFO) << "C=" << c->Value() << " " - << "P=" << p->Value() << " " - << "I=" << i->Value() << " " - << "S=" << s->Value() << " " - << "F=" << f->Value() << " " - << "U=" << u->Value() << " " - << "N=" << n->Value() << " " - << "T=" << t->Value() << " " - << "R=" << r->Value() << " " - << "E=" << e->Value(); + LOG(INFO) << "C=" << c->Value() << " " << "P=" << p->Value() << " " + << "I=" << i->Value() << " " << "S=" << s->Value() << " " + << "F=" << f->Value() << " " << "U=" << u->Value() << " " + << "N=" << n->Value() << " " << "T=" << t->Value() << " " + << "R=" << r->Value() << " " << "E=" << e->Value(); // Is CP + IS + FUN = TRUE? CHECK_EQ(p->Value() + s->Value() + n->Value() + diff --git a/ortools/constraint_solver/samples/nurses_cp.cc b/ortools/constraint_solver/samples/nurses_cp.cc index 23edff8626..7af24d3dd2 100644 --- a/ortools/constraint_solver/samples/nurses_cp.cc +++ b/ortools/constraint_solver/samples/nurses_cp.cc @@ -191,8 +191,7 @@ void SolveNursesExample() { for (const auto day : days) { LOG(INFO) << "Day " << day << ":"; for (const auto nurse : nurses) { - LOG(INFO) << "Nurse " << nurse << " assigned to " - << "Task " + LOG(INFO) << "Nurse " << nurse << " assigned to Task " << collector->Value(solution, shifts_flat[nurse * days.size() + day]); }