Skip to content

Commit

Permalink
export constraint_solver form google3/
Browse files Browse the repository at this point in the history
  • Loading branch information
Mizux committed Jul 28, 2023
1 parent 45b5e1c commit ffd8ec0
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 47 deletions.
9 changes: 5 additions & 4 deletions ortools/constraint_solver/routing.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4866,20 +4866,21 @@ void RoutingModel::CreateFirstSolutionDecisionBuilders(
[FirstSolutionStrategy::BEST_INSERTION]));

// Local cheapest cost insertion
const RoutingSearchParameters::PairInsertionStrategy lcci_pair_strategy =
search_parameters
.local_cheapest_cost_insertion_pickup_delivery_strategy();
first_solution_filtered_decision_builders_
[FirstSolutionStrategy::LOCAL_CHEAPEST_COST_INSERTION] =
CreateIntVarFilteredDecisionBuilder<
LocalCheapestInsertionFilteredHeuristic>(
/*evaluator=*/nullptr,
RoutingSearchParameters::BEST_PICKUP_DELIVERY_PAIR,
/*evaluator=*/nullptr, lcci_pair_strategy,
GetOrCreateLocalSearchFilterManager(
search_parameters, {/*filter_objective=*/true,
/*filter_with_cp_solver=*/false}));
IntVarFilteredDecisionBuilder* const strong_lcci =
CreateIntVarFilteredDecisionBuilder<
LocalCheapestInsertionFilteredHeuristic>(
/*evaluator=*/nullptr,
RoutingSearchParameters::BEST_PICKUP_DELIVERY_PAIR,
/*evaluator=*/nullptr, lcci_pair_strategy,
GetOrCreateLocalSearchFilterManager(
search_parameters, {/*filter_objective=*/true,
/*filter_with_cp_solver=*/true}));
Expand Down
2 changes: 2 additions & 0 deletions ortools/constraint_solver/routing_parameters.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ RoutingSearchParameters CreateDefaultRoutingSearchParameters() {
p.set_cheapest_insertion_add_unperformed_entries(false);
p.set_local_cheapest_insertion_pickup_delivery_strategy(
RoutingSearchParameters::BEST_PICKUP_THEN_BEST_DELIVERY);
p.set_local_cheapest_cost_insertion_pickup_delivery_strategy(
RoutingSearchParameters::BEST_PICKUP_DELIVERY_PAIR);
RoutingSearchParameters::LocalSearchNeighborhoodOperators* o =
p.mutable_local_search_operators();
o->set_use_relocate(BOOL_TRUE);
Expand Down
10 changes: 7 additions & 3 deletions ortools/constraint_solver/routing_parameters.proto
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ package operations_research;
// then the routing library will pick its preferred value for that parameter
// automatically: this should be the case for most parameters.
// To see those "default" parameters, call GetDefaultRoutingSearchParameters().
// Next ID: 55
// Next ID: 56
message RoutingSearchParameters {
// First solution strategies, used as starting point of local search.
FirstSolutionStrategy.Value first_solution_strategy = 1;
Expand Down Expand Up @@ -123,9 +123,13 @@ message RoutingSearchParameters {
// Order by increasing by cost(pickup) + cost(delivery).
BEST_PICKUP_DELIVERY_PAIR_MULTITOUR = 3;
}
// Choice of insertion strategy for pickup/delivery pairs,
// used in local cheapest insertion, both first solution heuristic and LNS.
// Choice of insertion strategy for pickup/delivery pairs, used in local
// cheapest insertion, both first solution heuristic and LNS.
PairInsertionStrategy local_cheapest_insertion_pickup_delivery_strategy = 49;
// Choice of insertion strategy for pickup/delivery pairs, used in local
// cheapest cost insertion, both first solution heuristic and LNS.
PairInsertionStrategy local_cheapest_cost_insertion_pickup_delivery_strategy =
55;

// If true use minimum matching instead of minimal matching in the
// Christofides algorithm.
Expand Down
110 changes: 74 additions & 36 deletions ortools/constraint_solver/routing_search.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2225,16 +2225,13 @@ LocalCheapestInsertionFilteredHeuristic::
RoutingModel* model, std::function<bool()> stop_search,
std::function<int64_t(int64_t, int64_t, int64_t)> evaluator,
RoutingSearchParameters::PairInsertionStrategy pair_insertion_strategy,
LocalSearchFilterManager* filter_manager)
LocalSearchFilterManager* filter_manager, BinCapacities* bin_capacities)
: CheapestInsertionFilteredHeuristic(model, std::move(stop_search),
std::move(evaluator), nullptr,
filter_manager),
update_start_end_distances_per_node_(true),
pair_insertion_strategy_(pair_insertion_strategy) {
DCHECK(evaluator_ != nullptr ||
pair_insertion_strategy_ ==
RoutingSearchParameters::BEST_PICKUP_DELIVERY_PAIR);
}
pair_insertion_strategy_(pair_insertion_strategy),
bin_capacities_(bin_capacities) {}

void LocalCheapestInsertionFilteredHeuristic::Initialize() {
// Avoid recomputing if used in a local search operator.
Expand Down Expand Up @@ -2263,19 +2260,27 @@ bool LocalCheapestInsertionFilteredHeuristic::InsertPair(

void LocalCheapestInsertionFilteredHeuristic::InsertBestPickupThenDelivery(
const RoutingModel::IndexPair& index_pair) {
for (int64_t pickup : index_pair.first) {
for (int pickup : index_pair.first) {
std::vector<NodeInsertion> pickup_insertions =
ComputeEvaluatorSortedPositions(pickup);
for (int64_t delivery : index_pair.second) {
for (int delivery : index_pair.second) {
if (StopSearch()) return;
for (const NodeInsertion& pickup_insertion : pickup_insertions) {
const int vehicle = pickup_insertion.vehicle;
if (bin_capacities_ && !bin_capacities_->CheckAdditionsFeasibility(
{pickup, delivery}, vehicle)) {
continue;
}
for (const NodeInsertion& delivery_insertion :
ComputeEvaluatorSortedPositionsOnRouteAfter(
delivery, pickup, Value(pickup_insertion.insert_after),
vehicle)) {
if (InsertPair(pickup, pickup_insertion.insert_after, delivery,
delivery_insertion.insert_after, vehicle)) {
if (bin_capacities_) {
bin_capacities_->AddItemToBin(pickup, vehicle);
bin_capacities_->AddItemToBin(delivery, vehicle);
}
return;
}
}
Expand All @@ -2287,17 +2292,20 @@ void LocalCheapestInsertionFilteredHeuristic::InsertBestPickupThenDelivery(

void LocalCheapestInsertionFilteredHeuristic::InsertBestPair(
const RoutingModel::IndexPair& index_pair) {
for (int64_t pickup : index_pair.first) {
for (int64_t delivery : index_pair.second) {
for (int pickup : index_pair.first) {
for (int delivery : index_pair.second) {
if (StopSearch()) return;
std::optional<std::vector<PickupDeliveryInsertion>>
sorted_pair_positions =
ComputeEvaluatorSortedPairPositions(pickup, delivery);
if (!sorted_pair_positions.has_value()) return;
std::vector<PickupDeliveryInsertion> sorted_pair_positions =
ComputeEvaluatorSortedPairPositions(pickup, delivery);
if (sorted_pair_positions.empty()) continue;
for (const auto [insert_pickup_after, insert_delivery_after, unused_value,
vehicle] : *sorted_pair_positions) {
vehicle] : sorted_pair_positions) {
if (InsertPair(pickup, insert_pickup_after, delivery,
insert_delivery_after, vehicle)) {
if (bin_capacities_) {
bin_capacities_->AddItemToBin(pickup, vehicle);
bin_capacities_->AddItemToBin(delivery, vehicle);
}
return;
}
if (StopSearch()) return;
Expand Down Expand Up @@ -2361,11 +2369,15 @@ void LocalCheapestInsertionFilteredHeuristic::InsertBestPairMultitour(
}
};

for (int64_t pickup : index_pair.first) {
for (int pickup : index_pair.first) {
if (StopSearch()) return;
for (int64_t delivery : index_pair.second) {
for (int delivery : index_pair.second) {
insertion_container_.Clear();
for (int vehicle = 0; vehicle < model()->vehicles(); ++vehicle) {
if (bin_capacities_ && !bin_capacities_->CheckAdditionsFeasibility(
{pickup, delivery}, vehicle)) {
continue;
}
fill_path(vehicle);
insertion_generator_.AppendPickupDeliveryMultitourInsertions(
pickup, delivery, vehicle, path, node_is_pickup, node_is_delivery,
Expand Down Expand Up @@ -2396,7 +2408,14 @@ void LocalCheapestInsertionFilteredHeuristic::InsertBestPairMultitour(
previous_node = insertion.node;
previous_succ = succ;
}
if (Evaluate(/*commit=*/true).has_value()) return;
if (Evaluate(/*commit=*/true).has_value()) {
// Insertion succeeded.
if (bin_capacities_) {
bin_capacities_->AddItemToBin(pickup, vehicle);
bin_capacities_->AddItemToBin(delivery, vehicle);
}
return;
}
}
}
}
Expand Down Expand Up @@ -2450,6 +2469,7 @@ bool LocalCheapestInsertionFilteredHeuristic::BuildSolutionInternal() {
}
}
std::sort(pair_domain_sizes.begin(), pair_domain_sizes.end());
// Multitour needs to know if a node is a pickup, delivery, or single.
std::vector<bool> node_is_pickup, node_is_delivery;
if (pair_insertion_strategy_ ==
RoutingSearchParameters::BEST_PICKUP_DELIVERY_PAIR_MULTITOUR) {
Expand All @@ -2465,6 +2485,16 @@ bool LocalCheapestInsertionFilteredHeuristic::BuildSolutionInternal() {
}
}
}
// Fill vehicle bins with nodes that are already inserted.
if (bin_capacities_) {
bin_capacities_->ClearItems();
for (int vehicle = 0; vehicle < model()->vehicles(); ++vehicle) {
const int start = Value(model()->Start(vehicle));
for (int node = start; !model()->IsEnd(node); node = Value(node)) {
bin_capacities_->AddItemToBin(node, vehicle);
}
}
}

// Try to insert each pair by increasing amount of its possible vehicles.
for (const PairDomainSize& pair_domain_size : pair_domain_sizes) {
Expand Down Expand Up @@ -2506,6 +2536,9 @@ bool LocalCheapestInsertionFilteredHeuristic::BuildSolutionInternal() {
InsertBetween(node, insertion.insert_after, Value(insertion.insert_after),
insertion.vehicle);
if (Evaluate(/*commit=*/true).has_value()) {
if (bin_capacities_) {
bin_capacities_->AddItemToBin(node, insertion.vehicle);
}
break;
}
}
Expand All @@ -2517,16 +2550,19 @@ std::vector<LocalCheapestInsertionFilteredHeuristic::NodeInsertion>
LocalCheapestInsertionFilteredHeuristic::ComputeEvaluatorSortedPositions(
int64_t node) {
DCHECK(!Contains(node));
std::vector<NodeInsertion> sorted_insertions;
const int size = model()->Size();
if (node < size) {
for (int vehicle = 0; vehicle < model()->vehicles(); ++vehicle) {
const int64_t start = model()->Start(vehicle);
AppendInsertionPositionsAfter(node, start, Value(start), vehicle,
/*ignore_cost=*/false, &sorted_insertions);
if (node >= size) return {};
std::vector<NodeInsertion> sorted_insertions;
for (int vehicle = 0; vehicle < model()->vehicles(); ++vehicle) {
if (bin_capacities_ &&
!bin_capacities_->CheckAdditionFeasibility(node, vehicle)) {
continue;
}
std::sort(sorted_insertions.begin(), sorted_insertions.end());
const int64_t start = model()->Start(vehicle);
AppendInsertionPositionsAfter(node, start, Value(start), vehicle,
/*ignore_cost=*/false, &sorted_insertions);
}
std::sort(sorted_insertions.begin(), sorted_insertions.end());
return sorted_insertions;
}

Expand All @@ -2536,30 +2572,33 @@ LocalCheapestInsertionFilteredHeuristic::
int64_t next_after_start,
int vehicle) {
DCHECK(!Contains(node));
std::vector<NodeInsertion> sorted_insertions;
const int size = model()->Size();
if (node < size) {
AppendInsertionPositionsAfter(node, start, next_after_start, vehicle,
/*ignore_cost=*/false, &sorted_insertions);
std::sort(sorted_insertions.begin(), sorted_insertions.end());
}
if (node >= size) return {};
std::vector<NodeInsertion> sorted_insertions;
AppendInsertionPositionsAfter(node, start, next_after_start, vehicle,
/*ignore_cost=*/false, &sorted_insertions);
std::sort(sorted_insertions.begin(), sorted_insertions.end());
return sorted_insertions;
}

std::optional<std::vector<PickupDeliveryInsertion>>
std::vector<PickupDeliveryInsertion>
LocalCheapestInsertionFilteredHeuristic::ComputeEvaluatorSortedPairPositions(
int64_t pickup, int64_t delivery) {
int pickup, int delivery) {
std::vector<PickupDeliveryInsertion> sorted_pickup_delivery_insertions;
const int size = model()->Size();
DCHECK_LT(pickup, size);
DCHECK_LT(delivery, size);
for (int vehicle = 0; vehicle < model()->vehicles(); ++vehicle) {
if (bin_capacities_ && !bin_capacities_->CheckAdditionsFeasibility(
{pickup, delivery}, vehicle)) {
continue;
}
int64_t insert_pickup_after = model()->Start(vehicle);
while (!model()->IsEnd(insert_pickup_after)) {
const int64_t insert_pickup_before = Value(insert_pickup_after);
int64_t insert_delivery_after = pickup;
while (!model()->IsEnd(insert_delivery_after)) {
if (StopSearch()) return std::nullopt;
if (StopSearch()) return {};
const int64_t insert_delivery_before =
insert_delivery_after == pickup ? insert_pickup_before
: Value(insert_delivery_after);
Expand Down Expand Up @@ -2592,8 +2631,7 @@ LocalCheapestInsertionFilteredHeuristic::ComputeEvaluatorSortedPairPositions(
}
std::sort(sorted_pickup_delivery_insertions.begin(),
sorted_pickup_delivery_insertions.end());
return std::optional<std::vector<PickupDeliveryInsertion>>{
sorted_pickup_delivery_insertions};
return sorted_pickup_delivery_insertions;
}

// CheapestAdditionFilteredHeuristic
Expand Down
11 changes: 7 additions & 4 deletions ortools/constraint_solver/routing_search.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "ortools/constraint_solver/constraint_solveri.h"
#include "ortools/constraint_solver/routing.h"
#include "ortools/constraint_solver/routing_index_manager.h"
#include "ortools/constraint_solver/routing_utils.h"
#include "ortools/util/bitset.h"

namespace operations_research {
Expand Down Expand Up @@ -1032,7 +1033,8 @@ class LocalCheapestInsertionFilteredHeuristic
RoutingModel* model, std::function<bool()> stop_search,
std::function<int64_t(int64_t, int64_t, int64_t)> evaluator,
RoutingSearchParameters::PairInsertionStrategy pair_insertion_strategy,
LocalSearchFilterManager* filter_manager);
LocalSearchFilterManager* filter_manager,
BinCapacities* bin_capacities = nullptr);
~LocalCheapestInsertionFilteredHeuristic() override {}
bool BuildSolutionInternal() override;
std::string DebugString() const override {
Expand All @@ -1056,9 +1058,9 @@ class LocalCheapestInsertionFilteredHeuristic

/// Computes the possible simultaneous insertion positions of the pair
/// 'pickup' and 'delivery'. Sorts them according to the current cost
/// evaluator. If a timeout is detected returns std::nullopt.
std::optional<std::vector<PickupDeliveryInsertion>>
ComputeEvaluatorSortedPairPositions(int64_t pickup, int64_t delivery);
/// evaluator.
std::vector<PickupDeliveryInsertion> ComputeEvaluatorSortedPairPositions(
int pickup, int delivery);

// Tries to insert any alternative of the given pair,
// ordered by cost of pickup insertion, then by cost of delivery insertion.
Expand Down Expand Up @@ -1086,6 +1088,7 @@ class LocalCheapestInsertionFilteredHeuristic

// Marks whether a node has already been tried for insertion.
std::vector<bool> visited_;
BinCapacities* const bin_capacities_;
};

/// Filtered-base decision builder based on the addition heuristic, extending
Expand Down

0 comments on commit ffd8ec0

Please sign in to comment.