diff --git a/ortools/constraint_solver/routing.h b/ortools/constraint_solver/routing.h index b3fa632fe9..2b9be85dc1 100644 --- a/ortools/constraint_solver/routing.h +++ b/ortools/constraint_solver/routing.h @@ -2810,9 +2810,9 @@ class GlobalCheapestInsertionFilteredDecisionBuilder AdjustablePriorityQueue* priority_queue, std::vector* node_entries); - /// Inserts neighbor_index in - /// node_index_to_[pickup|delivery|single]_neighbors_per_cost_class_ - /// [node_index][cost_class] according to whether neighbor is a pickup, + /// Marks neighbor_index as visited in + /// node_index_to_[pickup|delivery|single]_neighbors_by_cost_class_ + /// [node_index][cost_class] according to whether the neighbor is a pickup, /// a delivery, or neither. void AddNeighborForCostClass(int cost_class, int64 node_index, int64 neighbor_index, bool neighbor_is_pickup, @@ -2824,23 +2824,24 @@ class GlobalCheapestInsertionFilteredDecisionBuilder int64 neighbor_index) const; /// Returns a reference to the set of pickup neighbors of node_index. - const absl::flat_hash_set& GetPickupNeighborsOfNodeForCostClass( + const std::vector& GetPickupNeighborsOfNodeForCostClass( int cost_class, int64 node_index) { if (neighbors_ratio_ == 1) { return pickup_nodes_; } - return node_index_to_pickup_neighbors_by_cost_class_[node_index] - [cost_class]; + return node_index_to_pickup_neighbors_by_cost_class_[node_index][cost_class] + ->PositionsSetAtLeastOnce(); } /// Same as above for delivery neighbors. - const absl::flat_hash_set& GetDeliveryNeighborsOfNodeForCostClass( + const std::vector& GetDeliveryNeighborsOfNodeForCostClass( int cost_class, int64 node_index) { if (neighbors_ratio_ == 1) { return delivery_nodes_; } - return node_index_to_delivery_neighbors_by_cost_class_[node_index] - [cost_class]; + return node_index_to_delivery_neighbors_by_cost_class_ + [node_index][cost_class] + ->PositionsSetAtLeastOnce(); } const bool is_sequential_; @@ -2848,19 +2849,19 @@ class GlobalCheapestInsertionFilteredDecisionBuilder const double neighbors_ratio_; // clang-format off - std::vector > > + std::vector > > > node_index_to_single_neighbors_by_cost_class_; - std::vector > > + std::vector > > > node_index_to_pickup_neighbors_by_cost_class_; - std::vector > > + std::vector > > > node_index_to_delivery_neighbors_by_cost_class_; // clang-format on /// When neighbors_ratio is 1, we don't compute the neighborhood members /// above, and use the following sets in the code to avoid unnecessary /// computations and decrease the time and space complexities. - absl::flat_hash_set pickup_nodes_; - absl::flat_hash_set delivery_nodes_; + std::vector pickup_nodes_; + std::vector delivery_nodes_; }; /// Filter-base decision builder which builds a solution by inserting diff --git a/ortools/constraint_solver/routing_search.cc b/ortools/constraint_solver/routing_search.cc index 0c21f909fc..4fbd111a37 100644 --- a/ortools/constraint_solver/routing_search.cc +++ b/ortools/constraint_solver/routing_search.cc @@ -2854,10 +2854,10 @@ GlobalCheapestInsertionFilteredDecisionBuilder:: if (neighbors_ratio == 1) { for (int64 node = 0; node < size; node++) { if (!model->GetPickupIndexPairs(node).empty()) { - pickup_nodes_.insert(node); + pickup_nodes_.push_back(node); } if (!model->GetDeliveryIndexPairs(node).empty()) { - delivery_nodes_.insert(node); + delivery_nodes_.push_back(node); } } return; @@ -2875,6 +2875,14 @@ GlobalCheapestInsertionFilteredDecisionBuilder:: num_cost_classes); node_index_to_delivery_neighbors_by_cost_class_[node_index].resize( num_cost_classes); + for (int cc = 0; cc < num_cost_classes; cc++) { + node_index_to_single_neighbors_by_cost_class_[node_index][cc] = + absl::make_unique>(size); + node_index_to_pickup_neighbors_by_cost_class_[node_index][cc] = + absl::make_unique>(size); + node_index_to_delivery_neighbors_by_cost_class_[node_index][cc] = + absl::make_unique>(size); + } } const int64 num_neighbors = std::max(1.0, neighbors_ratio * size); @@ -2929,16 +2937,16 @@ void GlobalCheapestInsertionFilteredDecisionBuilder::AddNeighborForCostClass( int cost_class, int64 node_index, int64 neighbor_index, bool neighbor_is_pickup, bool neighbor_is_delivery) { if (neighbor_is_pickup) { - node_index_to_pickup_neighbors_by_cost_class_[node_index][cost_class] - .insert(neighbor_index); + node_index_to_pickup_neighbors_by_cost_class_[node_index][cost_class]->Set( + neighbor_index); } if (neighbor_is_delivery) { node_index_to_delivery_neighbors_by_cost_class_[node_index][cost_class] - .insert(neighbor_index); + ->Set(neighbor_index); } if (!neighbor_is_pickup && !neighbor_is_delivery) { - node_index_to_single_neighbors_by_cost_class_[node_index][cost_class] - .insert(neighbor_index); + node_index_to_single_neighbors_by_cost_class_[node_index][cost_class]->Set( + neighbor_index); } } @@ -2947,19 +2955,21 @@ bool GlobalCheapestInsertionFilteredDecisionBuilder::IsNeighborForCostClass( if (neighbors_ratio_ == 1) { return true; } + const SparseBitset* neighbors; if (!model()->GetPickupIndexPairs(neighbor_index).empty()) { - return gtl::ContainsKey( - node_index_to_pickup_neighbors_by_cost_class_[node_index][cost_class], - neighbor_index); + neighbors = + node_index_to_pickup_neighbors_by_cost_class_[node_index][cost_class] + .get(); + } else if (!model()->GetDeliveryIndexPairs(neighbor_index).empty()) { + neighbors = + node_index_to_delivery_neighbors_by_cost_class_[node_index][cost_class] + .get(); + } else { + neighbors = + node_index_to_single_neighbors_by_cost_class_[node_index][cost_class] + .get(); } - if (!model()->GetDeliveryIndexPairs(neighbor_index).empty()) { - return gtl::ContainsKey( - node_index_to_delivery_neighbors_by_cost_class_[node_index][cost_class], - neighbor_index); - } - return gtl::ContainsKey( - node_index_to_single_neighbors_by_cost_class_[node_index][cost_class], - neighbor_index); + return (*neighbors)[neighbor_index]; } bool GlobalCheapestInsertionFilteredDecisionBuilder::BuildSolution() { @@ -3390,12 +3400,8 @@ void GlobalCheapestInsertionFilteredDecisionBuilder::UpdatePickupPositions( // pickup_insert_after. const int cost_class = model()->GetCostClassIndexOfVehicle(vehicle).value(); const int64 pickup_insert_before = Value(pickup_insert_after); - const absl::flat_hash_set& pickup_neighbors = - GetPickupNeighborsOfNodeForCostClass(cost_class, pickup_insert_after); - std::vector sorted_pickup_neighbors(pickup_neighbors.begin(), - pickup_neighbors.end()); - std::sort(sorted_pickup_neighbors.begin(), sorted_pickup_neighbors.end()); - for (int64 pickup : sorted_pickup_neighbors) { + for (int64 pickup : + GetPickupNeighborsOfNodeForCostClass(cost_class, pickup_insert_after)) { if (Contains(pickup)) { continue; } @@ -3502,12 +3508,8 @@ void GlobalCheapestInsertionFilteredDecisionBuilder::UpdateDeliveryPositions( // delivery_insert_after. const int cost_class = model()->GetCostClassIndexOfVehicle(vehicle).value(); const int64 delivery_insert_before = Value(delivery_insert_after); - const absl::flat_hash_set& delivery_neighbors = - GetDeliveryNeighborsOfNodeForCostClass(cost_class, delivery_insert_after); - std::vector sorted_delivery_neighbors(delivery_neighbors.begin(), - delivery_neighbors.end()); - std::sort(sorted_delivery_neighbors.begin(), sorted_delivery_neighbors.end()); - for (int64 delivery : sorted_delivery_neighbors) { + for (int64 delivery : GetDeliveryNeighborsOfNodeForCostClass( + cost_class, delivery_insert_after)) { if (Contains(delivery)) { continue; }