diff --git a/ortools/constraint_solver/constraint_solveri.h b/ortools/constraint_solver/constraint_solveri.h index 75c70ccfc8..53a1e64b35 100644 --- a/ortools/constraint_solver/constraint_solveri.h +++ b/ortools/constraint_solver/constraint_solveri.h @@ -1683,20 +1683,26 @@ class LocalSearchState { class Variable; // Adds a variable to this state, return a handler to the new variable. int AddVariable(int64_t initial_min, int64_t initial_max); - void ChangeInitialVariableBounds(int variable_index, int64_t min, + void ChangeRelaxedVariableBounds(int variable_index, int64_t min, int64_t max); // Makes an object with restricted operations on the variable identified by // variable_index: only Relax, Tighten and read operations are available. Variable MakeVariable(int variable_index); void Commit(); void Revert(); - bool StateIsValid() const { return state_is_valid_; } + bool StateIsFeasible() const { + return state_all_variable_bounds_are_correct_ && + num_committed_empty_domains_ == 0; + } private: struct Bounds { int64_t min; int64_t max; }; + bool BoundsIntersectionIsEmpty(const Bounds& b1, const Bounds& b2) const { + return b1.max < b2.min || b2.max < b1.min; + } void RelaxVariableBounds(int variable_index); bool TightenVariableMin(int variable_index, int64_t value); @@ -1705,11 +1711,17 @@ class LocalSearchState { int64_t VariableMax(int variable_index) const; // TODO(user): turn these into strong vectors. - std::vector initial_variable_bounds_; + std::vector relaxed_variable_bounds_; std::vector variable_bounds_; - std::vector> saved_variable_bounds_trail_; + std::vector> trailed_variable_bounds_; std::vector variable_is_relaxed_; - bool state_is_valid_ = true; + // True iff all variable have their variable_bounds_ min <= max. + bool state_all_variable_bounds_are_correct_ = true; + bool state_has_relaxed_variables_ = false; + // Number of variables v for which the intersection of + // variable_bounds_[v] and relaxed_variable_bounds_[v] is empty. + int num_committed_empty_domains_ = 0; + int trailed_num_committed_empty_domains_ = 0; }; // A LocalSearchVariable can only be created by a LocalSearchState, then it is diff --git a/ortools/constraint_solver/docs/routing_svg.py b/ortools/constraint_solver/docs/routing_svg.py index d918431d9a..81deb7e0d7 100755 --- a/ortools/constraint_solver/docs/routing_svg.py +++ b/ortools/constraint_solver/docs/routing_svg.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # Copyright 2010-2022 Google LLC # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/ortools/constraint_solver/local_search.cc b/ortools/constraint_solver/local_search.cc index d6ff79dc13..d12775d4df 100644 --- a/ortools/constraint_solver/local_search.cc +++ b/ortools/constraint_solver/local_search.cc @@ -12,35 +12,35 @@ // limitations under the License. #include +#include +#include #include #include -#include #include -#include #include #include #include #include -#include #include #include #include #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" -#include "absl/memory/memory.h" +#include "absl/flags/flag.h" +#include "absl/log/check.h" #include "absl/random/distributions.h" #include "absl/random/random.h" #include "absl/strings/str_cat.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/base/hash.h" +#include "absl/strings/str_format.h" #include "ortools/base/iterator_adaptors.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" -#include "ortools/base/types.h" +#include "ortools/base/timer.h" #include "ortools/constraint_solver/constraint_solver.h" #include "ortools/constraint_solver/constraint_solveri.h" #include "ortools/graph/hamiltonian_path.h" +#include "ortools/util/bitset.h" #include "ortools/util/saturated_arithmetic.h" ABSL_FLAG(int, cp_local_search_sync_frequency, 16, @@ -319,9 +319,7 @@ class IncrementValue : public ChangeValue { explicit IncrementValue(const std::vector& vars) : ChangeValue(vars) {} ~IncrementValue() override {} - int64_t ModifyValue(int64_t index, int64_t value) override { - return value + 1; - } + int64_t ModifyValue(int64_t, int64_t value) override { return value + 1; } std::string DebugString() const override { return "IncrementValue"; } }; @@ -333,9 +331,7 @@ class DecrementValue : public ChangeValue { explicit DecrementValue(const std::vector& vars) : ChangeValue(vars) {} ~DecrementValue() override {} - int64_t ModifyValue(int64_t index, int64_t value) override { - return value - 1; - } + int64_t ModifyValue(int64_t, int64_t value) override { return value - 1; } std::string DebugString() const override { return "DecrementValue"; } }; @@ -1437,7 +1433,7 @@ class MakeChainInactiveOperator : public PathOperator { } protected: - bool OnSamePathAsPreviousBase(int64_t base_index) override { + bool OnSamePathAsPreviousBase(int64_t) override { // Start and end of chain (defined by both base nodes) must be on the same // path. return true; @@ -2162,9 +2158,7 @@ int64_t CompoundOperatorNoRestart(int size, int active_index, : operator_index - active_index; } -int64_t CompoundOperatorRestart(int active_index, int operator_index) { - return 0; -} +int64_t CompoundOperatorRestart(int, int) { return 0; } } // namespace LocalSearchOperator* Solver::ConcatenateOperators( @@ -2633,12 +2627,10 @@ namespace { class AcceptFilter : public LocalSearchFilter { public: std::string DebugString() const override { return "AcceptFilter"; } - bool Accept(const Assignment* delta, const Assignment* deltadelta, - int64_t obj_min, int64_t obj_max) override { + bool Accept(const Assignment*, const Assignment*, int64_t, int64_t) override { return true; } - void Synchronize(const Assignment* assignment, - const Assignment* delta) override {} + void Synchronize(const Assignment*, const Assignment*) override {} }; } // namespace @@ -2651,12 +2643,10 @@ namespace { class RejectFilter : public LocalSearchFilter { public: std::string DebugString() const override { return "RejectFilter"; } - bool Accept(const Assignment* delta, const Assignment* deltadelta, - int64_t obj_min, int64_t obj_max) override { + bool Accept(const Assignment*, const Assignment*, int64_t, int64_t) override { return false; } - void Synchronize(const Assignment* assignment, - const Assignment* delta) override {} + void Synchronize(const Assignment*, const Assignment*) override {} }; } // namespace @@ -2829,12 +2819,10 @@ class PathStateFilter : public LocalSearchFilter { PathStateFilter(std::unique_ptr path_state, const std::vector& nexts); void Relax(const Assignment* delta, const Assignment* deltadelta) override; - bool Accept(const Assignment* delta, const Assignment* deltadelta, - int64_t objective_min, int64_t objective_max) override { + bool Accept(const Assignment*, const Assignment*, int64_t, int64_t) override { return true; } - void Synchronize(const Assignment* delta, - const Assignment* deltadelta) override{}; + void Synchronize(const Assignment*, const Assignment*) override{}; void Commit(const Assignment* assignment, const Assignment* delta) override; void Revert() override; void Reset() override; @@ -2902,8 +2890,7 @@ PathStateFilter::PathStateFilter(std::unique_ptr path_state, path_has_changed_.assign(path_state_->NumPaths(), false); } -void PathStateFilter::Relax(const Assignment* delta, - const Assignment* deltadelta) { +void PathStateFilter::Relax(const Assignment* delta, const Assignment*) { path_state_->Revert(); changed_arcs_.clear(); for (const IntVarElement& var_value : delta->IntVarContainer().elements()) { @@ -3452,13 +3439,11 @@ class DimensionFilter : public LocalSearchFilter { : checker_(std::move(checker)), name_(absl::StrCat("DimensionFilter(", dimension_name, ")")) {} - bool Accept(const Assignment* delta, const Assignment* deltadelta, - int64_t objective_min, int64_t objective_max) override { + bool Accept(const Assignment*, const Assignment*, int64_t, int64_t) override { return checker_->Check(); } - void Synchronize(const Assignment* assignment, - const Assignment* delta) override { + void Synchronize(const Assignment*, const Assignment*) override { checker_->Commit(); } @@ -3487,16 +3472,13 @@ class VariableDomainFilter : public LocalSearchFilter { ~VariableDomainFilter() override {} bool Accept(const Assignment* delta, const Assignment* deltadelta, int64_t objective_min, int64_t objective_max) override; - void Synchronize(const Assignment* assignment, - const Assignment* delta) override {} + void Synchronize(const Assignment*, const Assignment*) override {} std::string DebugString() const override { return "VariableDomainFilter"; } }; -bool VariableDomainFilter::Accept(const Assignment* delta, - const Assignment* deltadelta, - int64_t objective_min, - int64_t objective_max) { +bool VariableDomainFilter::Accept(const Assignment* delta, const Assignment*, + int64_t, int64_t) { const Assignment::IntContainer& container = delta->IntVarContainer(); const int size = container.Size(); for (int i = 0; i < size; ++i) { @@ -3642,7 +3624,7 @@ class SumObjectiveFilter : public IntVarLocalSearchFilter { bool incremental_; private: - void OnSynchronize(const Assignment* delta) override { + void OnSynchronize(const Assignment*) override { synchronized_sum_ = 0; for (int i = 0; i < primary_vars_size_; ++i) { const int64_t cost = CostOfSynchronizedVariable(i); @@ -3779,14 +3761,14 @@ IntVarLocalSearchFilter* Solver::MakeSumObjectiveFilter( Solver::LocalSearchFilterBound filter_enum) { switch (filter_enum) { case Solver::LE: { - auto filter = [](int64_t value, int64_t min_value, int64_t max_value) { + auto filter = [](int64_t value, int64_t, int64_t max_value) { return value <= max_value; }; return RevAlloc(new BinaryObjectiveFilter( vars, std::move(values), std::move(filter))); } case Solver::GE: { - auto filter = [](int64_t value, int64_t min_value, int64_t max_value) { + auto filter = [](int64_t value, int64_t min_value, int64_t) { return value >= min_value; }; return RevAlloc(new BinaryObjectiveFilter( @@ -3812,14 +3794,14 @@ IntVarLocalSearchFilter* Solver::MakeSumObjectiveFilter( Solver::LocalSearchFilterBound filter_enum) { switch (filter_enum) { case Solver::LE: { - auto filter = [](int64_t value, int64_t min_value, int64_t max_value) { + auto filter = [](int64_t value, int64_t, int64_t max_value) { return value <= max_value; }; return RevAlloc(new TernaryObjectiveFilter( vars, secondary_vars, std::move(values), std::move(filter))); } case Solver::GE: { - auto filter = [](int64_t value, int64_t min_value, int64_t max_value) { + auto filter = [](int64_t value, int64_t min_value, int64_t) { return value >= min_value; }; return RevAlloc(new TernaryObjectiveFilter( @@ -3840,9 +3822,9 @@ IntVarLocalSearchFilter* Solver::MakeSumObjectiveFilter( } int LocalSearchState::AddVariable(int64_t initial_min, int64_t initial_max) { - DCHECK(state_is_valid_); + DCHECK(state_all_variable_bounds_are_correct_); DCHECK_LE(initial_min, initial_max); - initial_variable_bounds_.push_back({initial_min, initial_max}); + relaxed_variable_bounds_.push_back({initial_min, initial_max}); variable_bounds_.push_back({initial_min, initial_max}); variable_is_relaxed_.push_back(false); return variable_bounds_.size() - 1; @@ -3853,80 +3835,103 @@ LocalSearchState::Variable LocalSearchState::MakeVariable(int variable_index) { } void LocalSearchState::RelaxVariableBounds(int variable_index) { - DCHECK(state_is_valid_); + DCHECK(state_all_variable_bounds_are_correct_); DCHECK(0 <= variable_index && variable_index < variable_is_relaxed_.size()); + if (!state_has_relaxed_variables_) { + trailed_num_committed_empty_domains_ = num_committed_empty_domains_; + } + state_has_relaxed_variables_ = true; if (!variable_is_relaxed_[variable_index]) { variable_is_relaxed_[variable_index] = true; - saved_variable_bounds_trail_.emplace_back(variable_bounds_[variable_index], - variable_index); - variable_bounds_[variable_index] = initial_variable_bounds_[variable_index]; + trailed_variable_bounds_.emplace_back(variable_bounds_[variable_index], + variable_index); + if (BoundsIntersectionIsEmpty(relaxed_variable_bounds_[variable_index], + variable_bounds_[variable_index])) { + DCHECK_GT(num_committed_empty_domains_, 0); + --num_committed_empty_domains_; + } + variable_bounds_[variable_index] = relaxed_variable_bounds_[variable_index]; } } int64_t LocalSearchState::VariableMin(int variable_index) const { - DCHECK(state_is_valid_); + DCHECK(state_all_variable_bounds_are_correct_); DCHECK(0 <= variable_index && variable_index < variable_bounds_.size()); return variable_bounds_[variable_index].min; } int64_t LocalSearchState::VariableMax(int variable_index) const { - DCHECK(state_is_valid_); + DCHECK(state_all_variable_bounds_are_correct_); DCHECK(0 <= variable_index && variable_index < variable_bounds_.size()); return variable_bounds_[variable_index].max; } bool LocalSearchState::TightenVariableMin(int variable_index, int64_t min_value) { - DCHECK(state_is_valid_); + DCHECK(state_all_variable_bounds_are_correct_); DCHECK(variable_is_relaxed_[variable_index]); DCHECK(0 <= variable_index && variable_index < variable_bounds_.size()); Bounds& bounds = variable_bounds_[variable_index]; if (bounds.max < min_value) { - state_is_valid_ = false; + state_all_variable_bounds_are_correct_ = false; } bounds.min = std::max(bounds.min, min_value); - return state_is_valid_; + return state_all_variable_bounds_are_correct_; } bool LocalSearchState::TightenVariableMax(int variable_index, int64_t max_value) { - DCHECK(state_is_valid_); + DCHECK(state_all_variable_bounds_are_correct_); DCHECK(variable_is_relaxed_[variable_index]); DCHECK(0 <= variable_index && variable_index < variable_bounds_.size()); Bounds& bounds = variable_bounds_[variable_index]; if (bounds.min > max_value) { - state_is_valid_ = false; + state_all_variable_bounds_are_correct_ = false; } bounds.max = std::min(bounds.max, max_value); - return state_is_valid_; + return state_all_variable_bounds_are_correct_; } -void LocalSearchState::ChangeInitialVariableBounds(int variable_index, +void LocalSearchState::ChangeRelaxedVariableBounds(int variable_index, int64_t min, int64_t max) { - DCHECK(state_is_valid_); + DCHECK(state_all_variable_bounds_are_correct_); DCHECK_GE(variable_index, 0); DCHECK_LT(variable_index, variable_bounds_.size()); DCHECK(!variable_is_relaxed_[variable_index]); - initial_variable_bounds_[variable_index] = {min, max}; + const bool domain_was_empty = + BoundsIntersectionIsEmpty(relaxed_variable_bounds_[variable_index], + variable_bounds_[variable_index]); + relaxed_variable_bounds_[variable_index] = {min, max}; + const bool domain_is_empty = + BoundsIntersectionIsEmpty({min, max}, variable_bounds_[variable_index]); + + if (!domain_was_empty && domain_is_empty) { + num_committed_empty_domains_++; + } else if (domain_was_empty && !domain_is_empty) { + num_committed_empty_domains_--; + } } // TODO(user): When the class has more users, find a threshold ratio of // saved/total variables under which a sparse clear would be more efficient // for both Commit() and Revert(). void LocalSearchState::Commit() { - DCHECK(state_is_valid_); - saved_variable_bounds_trail_.clear(); + DCHECK(StateIsFeasible()); + state_has_relaxed_variables_ = false; + trailed_variable_bounds_.clear(); variable_is_relaxed_.assign(variable_is_relaxed_.size(), false); } void LocalSearchState::Revert() { - for (const auto& bounds_index : saved_variable_bounds_trail_) { + for (const auto& bounds_index : trailed_variable_bounds_) { DCHECK(variable_is_relaxed_[bounds_index.second]); variable_bounds_[bounds_index.second] = bounds_index.first; } - saved_variable_bounds_trail_.clear(); + trailed_variable_bounds_.clear(); + state_has_relaxed_variables_ = false; variable_is_relaxed_.assign(variable_is_relaxed_.size(), false); - state_is_valid_ = true; + state_all_variable_bounds_are_correct_ = true; + num_committed_empty_domains_ = trailed_num_committed_empty_domains_; } // ----- LocalSearchProfiler ----- @@ -4047,7 +4052,7 @@ class LocalSearchProfiler : public LocalSearchMonitor { std::string overview; size_t max_name_size = 0; ParseFirstSolutionStatistics( - [&max_name_size](const std::string& name, double duration_seconds) { + [&max_name_size](const std::string& name, double) { max_name_size = std::max(max_name_size, name.length()); }); if (max_name_size > 0) { @@ -4062,13 +4067,11 @@ class LocalSearchProfiler : public LocalSearchMonitor { }); } max_name_size = 0; - ParseLocalSearchOperatorStatistics( - [&max_name_size](const std::string& name, int64_t num_neighbors, - int64_t num_filtered_neighbors, - int64_t num_accepted_neighbors, - double duration_seconds) { - max_name_size = std::max(max_name_size, name.length()); - }); + ParseLocalSearchOperatorStatistics([&max_name_size](const std::string& name, + int64_t, int64_t, + int64_t, double) { + max_name_size = std::max(max_name_size, name.length()); + }); if (max_name_size > 0) { absl::StrAppendFormat( &overview, @@ -4097,9 +4100,8 @@ class LocalSearchProfiler : public LocalSearchMonitor { } max_name_size = 0; ParseLocalSearchFilterStatistics( - [&max_name_size](const std::string& context, const std::string& name, - int64_t num_calls, int64_t num_rejects, - double duration_seconds) { + [&max_name_size](const std::string&, const std::string& name, int64_t, + int64_t, double) { max_name_size = std::max(max_name_size, name.length()); }); if (max_name_size > 0) { @@ -4152,20 +4154,19 @@ class LocalSearchProfiler : public LocalSearchMonitor { } } void EndMakeNextNeighbor(const LocalSearchOperator* op, bool neighbor_found, - const Assignment* delta, - const Assignment* deltadelta) override { + const Assignment*, const Assignment*) override { if (neighbor_found) { operator_stats_[op->Self()].neighbors++; } } - void BeginFilterNeighbor(const LocalSearchOperator* op) override {} + void BeginFilterNeighbor(const LocalSearchOperator*) override {} void EndFilterNeighbor(const LocalSearchOperator* op, bool neighbor_found) override { if (neighbor_found) { operator_stats_[op->Self()].filtered_neighbors++; } } - void BeginAcceptNeighbor(const LocalSearchOperator* op) override {} + void BeginAcceptNeighbor(const LocalSearchOperator*) override {} void EndAcceptNeighbor(const LocalSearchOperator* op, bool neighbor_found) override { if (neighbor_found) { @@ -4909,7 +4910,7 @@ void NestedSolveDecision::Apply(Solver* const solver) { } } -void NestedSolveDecision::Refute(Solver* const solver) {} +void NestedSolveDecision::Refute(Solver* const) {} } // namespace // ----- Local search decision builder ----- @@ -5202,7 +5203,7 @@ class DefaultSolutionPool : public SolutionPool { assignment->CopyIntersection(reference_assignment_.get()); } - bool SyncNeeded(Assignment* const local_assignment) override { return false; } + bool SyncNeeded(Assignment* const) override { return false; } std::string DebugString() const override { return "DefaultSolutionPool"; } diff --git a/ortools/constraint_solver/resource.cc b/ortools/constraint_solver/resource.cc index 23e22ed949..1ba2c80cbf 100644 --- a/ortools/constraint_solver/resource.cc +++ b/ortools/constraint_solver/resource.cc @@ -33,6 +33,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" #include "ortools/base/commandlineflags.h" #include "ortools/base/logging.h" #include "ortools/base/mathutil.h" @@ -2192,7 +2193,7 @@ class CumulativeConstraint : public Constraint { CumulativeConstraint(Solver* const s, const std::vector& intervals, const std::vector& demands, - IntVar* const capacity, const std::string& name) + IntVar* const capacity, absl::string_view name) : Constraint(s), capacity_(capacity), intervals_(intervals), @@ -2388,7 +2389,7 @@ class VariableDemandCumulativeConstraint : public Constraint { const std::vector& intervals, const std::vector& demands, IntVar* const capacity, - const std::string& name) + absl::string_view name) : Constraint(s), capacity_(capacity), intervals_(intervals), diff --git a/ortools/constraint_solver/routing_filters.cc b/ortools/constraint_solver/routing_filters.cc index 4c30324883..da729a34be 100644 --- a/ortools/constraint_solver/routing_filters.cc +++ b/ortools/constraint_solver/routing_filters.cc @@ -33,9 +33,11 @@ #include "absl/container/flat_hash_set.h" #include "absl/flags/flag.h" #include "absl/log/check.h" +#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "ortools/base/logging.h" +#include "ortools/base/map_util.h" #include "ortools/base/small_map.h" #include "ortools/base/strong_vector.h" #include "ortools/base/types.h" @@ -48,7 +50,6 @@ #include "ortools/util/bitset.h" #include "ortools/util/piecewise_linear_function.h" #include "ortools/util/saturated_arithmetic.h" -#include "ortools/util/sorted_interval_list.h" ABSL_FLAG(bool, routing_strong_debug_checks, false, "Run stronger checks in debug; these stronger tests might change " @@ -1089,18 +1090,6 @@ class PathCumulFilter : public BasePathFilter { (has_breaks || filter_objective_cost_); } - bool FilterDimensionForbiddenIntervals() const { - for (const SortedDisjointIntervalList& intervals : - dimension_.forbidden_intervals()) { - // TODO(user): Change the following test to check intervals within - // the domain of the corresponding variables. - if (intervals.NumIntervals() > 0) { - return true; - } - } - return false; - } - int64_t GetCumulPiecewiseLinearCost(int64_t node, int64_t cumul_value) const; bool FilterCumulSoftLowerBounds() const { @@ -2130,7 +2119,7 @@ void AppendLightWeightDimensionFilters( dimension->GetUnaryTransitEvaluator(vehicle); if (unary_evaluator != nullptr) { transits[vehicle_class] = [&unary_evaluator, dimension, num_slacks]( - int64_t node, int64_t next) -> Interval { + int64_t node, int64_t) -> Interval { if (node >= num_slacks) return {0, 0}; const int64_t min_transit = unary_evaluator(node); const int64_t max_transit = @@ -2476,13 +2465,15 @@ class VehicleVarFilter : public BasePathFilter { std::vector start_to_vehicle_; std::vector vehicle_vars_; const int64_t unconstrained_vehicle_var_domain_size_; + SparseBitset touched_; }; VehicleVarFilter::VehicleVarFilter(const RoutingModel& routing_model) : BasePathFilter(routing_model.Nexts(), routing_model.Size() + routing_model.vehicles()), vehicle_vars_(routing_model.VehicleVars()), - unconstrained_vehicle_var_domain_size_(routing_model.vehicles()) { + unconstrained_vehicle_var_domain_size_(routing_model.vehicles()), + touched_(routing_model.Nexts().size()) { start_to_vehicle_.resize(Size(), -1); for (int i = 0; i < routing_model.vehicles(); ++i) { start_to_vehicle_[routing_model.Start(i)] = i; @@ -2491,12 +2482,14 @@ VehicleVarFilter::VehicleVarFilter(const RoutingModel& routing_model) bool VehicleVarFilter::AcceptPath(int64_t path_start, int64_t chain_start, int64_t chain_end) { + touched_.SparseClearAll(); const int64_t vehicle = start_to_vehicle_[path_start]; int64_t node = chain_start; while (node != chain_end) { - if (!vehicle_vars_[node]->Contains(vehicle)) { + if (touched_[node] || !vehicle_vars_[node]->Contains(vehicle)) { return false; } + touched_.Set(node); node = GetNext(node); } return vehicle_vars_[node]->Contains(vehicle); @@ -3165,20 +3158,19 @@ class PathEnergyCostFilter : public LocalSearchFilter { public: std::string DebugString() const override { return name_; } PathEnergyCostFilter(std::unique_ptr checker, - const std::string& energy_name) + absl::string_view energy_name) : checker_(std::move(checker)), name_(absl::StrCat("PathEnergyCostFilter(", energy_name, ")")) {} - bool Accept(const Assignment* delta, const Assignment* deltadelta, - int64_t objective_min, int64_t objective_max) override { + bool Accept(const Assignment*, const Assignment*, int64_t objective_min, + int64_t objective_max) override { if (objective_max > kint64max / 2) return true; if (!checker_->Check()) return false; const int64_t cost = checker_->AcceptedCost(); return objective_min <= cost && cost <= objective_max; } - void Synchronize(const Assignment* assignment, - const Assignment* delta) override { + void Synchronize(const Assignment*, const Assignment*) override { checker_->Commit(); } diff --git a/ortools/constraint_solver/routing_filters.h b/ortools/constraint_solver/routing_filters.h index 7b86d1a601..6fcb40ea24 100644 --- a/ortools/constraint_solver/routing_filters.h +++ b/ortools/constraint_solver/routing_filters.h @@ -14,18 +14,19 @@ #ifndef OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_FILTERS_H_ #define OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_FILTERS_H_ +#include #include #include #include #include #include -#include "ortools/base/types.h" #include "ortools/constraint_solver/constraint_solver.h" #include "ortools/constraint_solver/constraint_solveri.h" #include "ortools/constraint_solver/routing.h" #include "ortools/constraint_solver/routing_lp_scheduling.h" #include "ortools/constraint_solver/routing_parameters.pb.h" +#include "ortools/constraint_solver/routing_types.h" #include "ortools/util/bitset.h" namespace operations_research { @@ -170,14 +171,11 @@ class BasePathFilter : public IntVarLocalSearchFilter { virtual bool DisableFiltering() const { return false; } virtual void OnBeforeSynchronizePaths() {} virtual void OnAfterSynchronizePaths() {} - virtual void OnSynchronizePathFromStart(int64_t start) {} + virtual void OnSynchronizePathFromStart(int64_t) {} virtual bool InitializeAcceptPath() { return true; } virtual bool AcceptPath(int64_t path_start, int64_t chain_start, int64_t chain_end) = 0; - virtual bool FinalizeAcceptPath(int64_t objective_min, - int64_t objective_max) { - return true; - } + virtual bool FinalizeAcceptPath(int64_t, int64_t) { return true; } /// Detects path starts, used to track which node belongs to which path. void ComputePathStarts(std::vector* path_starts, std::vector* index_to_path); diff --git a/ortools/constraint_solver/routing_index_manager.h b/ortools/constraint_solver/routing_index_manager.h index 30b39598e2..492b6a7b4c 100644 --- a/ortools/constraint_solver/routing_index_manager.h +++ b/ortools/constraint_solver/routing_index_manager.h @@ -101,9 +101,6 @@ class RoutingIndexManager { /// complete. int num_unique_depots() const { return num_unique_depots_; } std::vector GetIndexToNodeMap() const { return index_to_node_; } - absl::StrongVector GetNodeToIndexMap() const { - return node_to_index_; - } private: void Initialize( diff --git a/ortools/constraint_solver/routing_lp_scheduling.cc b/ortools/constraint_solver/routing_lp_scheduling.cc index b23862e711..5c8f8e1179 100644 --- a/ortools/constraint_solver/routing_lp_scheduling.cc +++ b/ortools/constraint_solver/routing_lp_scheduling.cc @@ -32,6 +32,7 @@ #include "absl/container/flat_hash_set.h" #include "absl/log/check.h" #include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" @@ -2873,7 +2874,7 @@ std::string VariablesToString( absl::flat_hash_map>& variable_instances, absl::flat_hash_map>& variable_childs, - const sat::CpSolverResponse& response_, const std::string& variable, + const sat::CpSolverResponse& response_, absl::string_view variable, std::string prefix = "") { if (variable.empty()) { std::string s = ""; @@ -2888,7 +2889,7 @@ std::string VariablesToString( } const auto& instances = variable_instances[variable]; - std::string variable_display = variable; + std::string variable_display(variable); std::size_t bracket_pos = variable.find_last_of(')'); if (bracket_pos != std::string::npos) { variable_display = variable.substr(bracket_pos + 1); diff --git a/ortools/constraint_solver/routing_neighborhoods.cc b/ortools/constraint_solver/routing_neighborhoods.cc index d2caa44fd8..e1fb01a9ec 100644 --- a/ortools/constraint_solver/routing_neighborhoods.cc +++ b/ortools/constraint_solver/routing_neighborhoods.cc @@ -19,11 +19,13 @@ #include #include +#include "absl/log/check.h" #include "ortools/base/types.h" #include "ortools/constraint_solver/constraint_solver.h" #include "ortools/constraint_solver/constraint_solveri.h" #include "ortools/constraint_solver/routing_types.h" #include "ortools/constraint_solver/routing_utils.h" +#include "ortools/util/saturated_arithmetic.h" namespace operations_research { @@ -1001,20 +1003,11 @@ bool RelocateExpensiveChain::FindMostExpensiveChainsOnRemainingPaths() { return false; } -RelocateSubtrip::RelocateSubtrip( - const std::vector& vars, - const std::vector& secondary_vars, - std::function start_empty_path_class, - std::function&(int, int)> get_neighbors, - const std::vector& pairs) - : PathOperator( - vars, secondary_vars, - /*number_of_base_nodes=*/get_neighbors == nullptr ? 2 : 1, - /*skip_locally_optimal_paths=*/true, /*accept_path_end_base=*/false, - std::move(start_empty_path_class), std::move(get_neighbors)) { - is_pickup_node_.resize(number_of_nexts_, false); - is_delivery_node_.resize(number_of_nexts_, false); - pair_of_node_.resize(number_of_nexts_, -1); +PickupAndDeliveryData::PickupAndDeliveryData( + int num_nodes, const std::vector& pairs) + : is_pickup_node_(num_nodes, false), + is_delivery_node_(num_nodes, false), + pair_of_node_(num_nodes, -1) { for (int pair_index = 0; pair_index < pairs.size(); ++pair_index) { for (const int node : pairs[pair_index].pickup_alternatives) { is_pickup_node_[node] = true; @@ -1025,7 +1018,27 @@ RelocateSubtrip::RelocateSubtrip( pair_of_node_[node] = pair_index; } } - opened_pairs_bitset_.resize(pairs.size(), false); +} + +RelocateSubtrip::RelocateSubtrip( + const std::vector& vars, + const std::vector& secondary_vars, + std::function start_empty_path_class, + std::function&(int, int)> get_neighbors, + const std::vector& pairs) + : PathOperator(vars, secondary_vars, + /*number_of_base_nodes=*/get_neighbors == nullptr ? 2 : 1, + /*skip_locally_optimal_paths=*/true, + /*accept_path_end_base=*/false, + std::move(start_empty_path_class), std::move(get_neighbors)), + pd_data_(number_of_nexts_, pairs) { + opened_pairs_set_.resize(pairs.size(), false); +} + +void RelocateSubtrip::SetPath(const std::vector& path, int path_id) { + for (int i = 1; i < path.size(); ++i) { + SetNext(path[i - 1], path[i], path_id); + } } bool RelocateSubtrip::RelocateSubTripFromPickup(const int64_t chain_first_node, @@ -1041,21 +1054,21 @@ bool RelocateSubtrip::RelocateSubTripFromPickup(const int64_t chain_first_node, int current = chain_first_node; do { if (current == insertion_node) { - // opened_pairs_bitset_ must be all false when we leave this function. - opened_pairs_bitset_.assign(opened_pairs_bitset_.size(), false); + // opened_pairs_set_ must be all false when we leave this function. + opened_pairs_set_.assign(opened_pairs_set_.size(), false); return false; } - const int pair = pair_of_node_[current]; - if (IsDeliveryNode(current) && !opened_pairs_bitset_[pair]) { + const int pair = pd_data_.GetPairOfNode(current); + if (pd_data_.IsDeliveryNode(current) && !opened_pairs_set_[pair]) { rejected_nodes_.push_back(current); } else { subtrip_nodes_.push_back(current); - if (IsPickupNode(current)) { + if (pd_data_.IsPickupNode(current)) { ++num_opened_pairs; - opened_pairs_bitset_[pair] = true; - } else if (IsDeliveryNode(current)) { + opened_pairs_set_[pair] = true; + } else if (pd_data_.IsDeliveryNode(current)) { --num_opened_pairs; - opened_pairs_bitset_[pair] = false; + opened_pairs_set_[pair] = false; } } current = Next(current); @@ -1065,14 +1078,8 @@ bool RelocateSubtrip::RelocateSubTripFromPickup(const int64_t chain_first_node, subtrip_nodes_.push_back(Next(insertion_node)); // Set new paths. - const int64_t rejected_path = Path(chain_first_node); - for (int i = 1; i < rejected_nodes_.size(); ++i) { - SetNext(rejected_nodes_[i - 1], rejected_nodes_[i], rejected_path); - } - const int64_t insertion_path = Path(insertion_node); - for (int i = 1; i < subtrip_nodes_.size(); ++i) { - SetNext(subtrip_nodes_[i - 1], subtrip_nodes_[i], insertion_path); - } + SetPath(rejected_nodes_, Path(chain_first_node)); + SetPath(subtrip_nodes_, Path(insertion_node)); return true; } @@ -1080,8 +1087,8 @@ bool RelocateSubtrip::RelocateSubTripFromDelivery( const int64_t chain_last_node, const int64_t insertion_node) { if (IsPathEnd(insertion_node)) return false; - // opened_pairs_bitset_ should be all false. - DCHECK(std::none_of(opened_pairs_bitset_.begin(), opened_pairs_bitset_.end(), + // opened_pairs_set_ should be all false. + DCHECK(std::none_of(opened_pairs_set_.begin(), opened_pairs_set_.end(), [](bool value) { return value; })); int num_opened_pairs = 0; // Split chain into subtrip and rejected nodes. Store nodes in reverse order. @@ -1090,20 +1097,20 @@ bool RelocateSubtrip::RelocateSubTripFromDelivery( int current = chain_last_node; do { if (current == insertion_node) { - opened_pairs_bitset_.assign(opened_pairs_bitset_.size(), false); + opened_pairs_set_.assign(opened_pairs_set_.size(), false); return false; } - const int pair = pair_of_node_[current]; - if (IsPickupNode(current) && !opened_pairs_bitset_[pair]) { + const int pair = pd_data_.GetPairOfNode(current); + if (pd_data_.IsPickupNode(current) && !opened_pairs_set_[pair]) { rejected_nodes_.push_back(current); } else { subtrip_nodes_.push_back(current); - if (IsDeliveryNode(current)) { + if (pd_data_.IsDeliveryNode(current)) { ++num_opened_pairs; - opened_pairs_bitset_[pair] = true; - } else if (IsPickupNode(current)) { + opened_pairs_set_[pair] = true; + } else if (pd_data_.IsPickupNode(current)) { --num_opened_pairs; - opened_pairs_bitset_[pair] = false; + opened_pairs_set_[pair] = false; } } current = Prev(current); @@ -1119,23 +1126,17 @@ bool RelocateSubtrip::RelocateSubTripFromDelivery( std::reverse(subtrip_nodes_.begin(), subtrip_nodes_.end()); // Set new paths. - const int64_t rejected_path = Path(chain_last_node); - for (int i = 1; i < rejected_nodes_.size(); ++i) { - SetNext(rejected_nodes_[i - 1], rejected_nodes_[i], rejected_path); - } - const int64_t insertion_path = Path(insertion_node); - for (int i = 1; i < subtrip_nodes_.size(); ++i) { - SetNext(subtrip_nodes_[i - 1], subtrip_nodes_[i], insertion_path); - } + SetPath(rejected_nodes_, Path(chain_last_node)); + SetPath(subtrip_nodes_, Path(insertion_node)); return true; } bool RelocateSubtrip::MakeNeighbor() { const auto do_move = [this](int64_t node, int64_t insertion_node) { if (IsInactive(node)) return false; - if (IsPickupNode(node)) { + if (pd_data_.IsPickupNode(node)) { return RelocateSubTripFromPickup(node, insertion_node); - } else if (IsDeliveryNode(node)) { + } else if (pd_data_.IsDeliveryNode(node)) { return RelocateSubTripFromDelivery(node, insertion_node); } else { return false; @@ -1153,24 +1154,12 @@ ExchangeSubtrip::ExchangeSubtrip( std::function start_empty_path_class, std::function&(int, int)> get_neighbors, const std::vector& pairs) - : PathOperator( - vars, secondary_vars, - /*number_of_base_nodes=*/get_neighbors == nullptr ? 2 : 1, - /*skip_locally_optimal_paths=*/true, /*accept_path_end_base=*/false, - std::move(start_empty_path_class), std::move(get_neighbors)) { - is_pickup_node_.resize(number_of_nexts_, false); - is_delivery_node_.resize(number_of_nexts_, false); - pair_of_node_.resize(number_of_nexts_, -1); - for (int pair_index = 0; pair_index < pairs.size(); ++pair_index) { - for (const int node : pairs[pair_index].pickup_alternatives) { - is_pickup_node_[node] = true; - pair_of_node_[node] = pair_index; - } - for (const int node : pairs[pair_index].delivery_alternatives) { - is_delivery_node_[node] = true; - pair_of_node_[node] = pair_index; - } - } + : PathOperator(vars, secondary_vars, + /*number_of_base_nodes=*/get_neighbors == nullptr ? 2 : 1, + /*skip_locally_optimal_paths=*/true, + /*accept_path_end_base=*/false, + std::move(start_empty_path_class), std::move(get_neighbors)), + pd_data_(number_of_nexts_, pairs) { opened_pairs_set_.resize(pairs.size(), false); } @@ -1193,11 +1182,12 @@ bool ExchangeSubtrip::MakeNeighbor() { const int64_t node = BaseNode(0); const int64_t neighbor = GetNeighborForBaseNode(0); if (IsInactive(neighbor)) return false; - if (IsDeliveryNode(node) && IsDeliveryNode(Prev(neighbor))) { + if (pd_data_.IsDeliveryNode(node) && + pd_data_.IsDeliveryNode(Prev(neighbor))) { node0 = node; node1 = Prev(neighbor); - } else if (IsPickupNode(neighbor) && !IsPathEnd(Next(node)) && - IsPickupNode(Next(node))) { + } else if (pd_data_.IsPickupNode(neighbor) && !IsPathEnd(Next(node)) && + pd_data_.IsPickupNode(Next(node))) { node0 = Next(node); node1 = neighbor; } else { @@ -1208,8 +1198,8 @@ bool ExchangeSubtrip::MakeNeighbor() { node1 = BaseNode(1); } - if (pair_of_node_[node0] == -1) return false; - if (pair_of_node_[node1] == -1) return false; + if (pd_data_.GetPairOfNode(node0) == -1) return false; + if (pd_data_.GetPairOfNode(node1) == -1) return false; // Break symmetry: a move generated from (node0, node1) is the // same as from (node1, node0): no need to do it twice. if (node0 >= node1) return false; @@ -1240,12 +1230,12 @@ bool ExchangeSubtrip::MakeNeighbor() { const bool concatenated01 = last0 == subtrip1_.front(); const bool concatenated10 = last1 == subtrip0_.front(); - if (IsDeliveryNode(node0)) std::swap(subtrip1_, rejects0_); + if (pd_data_.IsDeliveryNode(node0)) std::swap(subtrip1_, rejects0_); path0_.insert(path0_.end(), subtrip1_.begin(), subtrip1_.end()); path0_.insert(path0_.end(), rejects0_.begin(), rejects0_.end()); path0_.push_back(last0); - if (IsDeliveryNode(node1)) std::swap(subtrip0_, rejects1_); + if (pd_data_.IsDeliveryNode(node1)) std::swap(subtrip0_, rejects1_); path1_.insert(path1_.end(), subtrip0_.begin(), subtrip0_.end()); path1_.insert(path1_.end(), rejects1_.begin(), rejects1_.end()); path1_.push_back(last1); @@ -1272,20 +1262,21 @@ bool ExchangeSubtrip::ExtractChainsAndCheckCanonical( int64_t base_node, std::vector* rejects, std::vector* subtrip) { const bool extracted = - IsPickupNode(base_node) + pd_data_.IsPickupNode(base_node) ? ExtractChainsFromPickup(base_node, rejects, subtrip) : ExtractChainsFromDelivery(base_node, rejects, subtrip); if (!extracted) return false; // Check canonicality. - return !IsDeliveryNode(base_node) || - pair_of_node_[subtrip->front()] != pair_of_node_[subtrip->back()] || + return !pd_data_.IsDeliveryNode(base_node) || + pd_data_.GetPairOfNode(subtrip->front()) != + pd_data_.GetPairOfNode(subtrip->back()) || !rejects->empty(); } bool ExchangeSubtrip::ExtractChainsFromPickup(int64_t base_node, std::vector* rejects, std::vector* subtrip) { - DCHECK(IsPickupNode(base_node)); + DCHECK(pd_data_.IsPickupNode(base_node)); DCHECK(rejects->empty()); DCHECK(subtrip->empty()); // Iterate from base_node forwards while maintaining the set of opened pairs. @@ -1294,15 +1285,15 @@ bool ExchangeSubtrip::ExtractChainsFromPickup(int64_t base_node, int num_opened_pairs = 0; int current = base_node; do { - const int pair = pair_of_node_[current]; - if (IsDeliveryNode(current) && !opened_pairs_set_[pair]) { + const int pair = pd_data_.GetPairOfNode(current); + if (pd_data_.IsDeliveryNode(current) && !opened_pairs_set_[pair]) { rejects->push_back(current); } else { subtrip->push_back(current); - if (IsPickupNode(current)) { + if (pd_data_.IsPickupNode(current)) { ++num_opened_pairs; opened_pairs_set_[pair] = true; - } else if (IsDeliveryNode(current)) { + } else if (pd_data_.IsDeliveryNode(current)) { --num_opened_pairs; opened_pairs_set_[pair] = false; } @@ -1315,7 +1306,7 @@ bool ExchangeSubtrip::ExtractChainsFromPickup(int64_t base_node, bool ExchangeSubtrip::ExtractChainsFromDelivery(int64_t base_node, std::vector* rejects, std::vector* subtrip) { - DCHECK(IsDeliveryNode(base_node)); + DCHECK(pd_data_.IsDeliveryNode(base_node)); DCHECK(rejects->empty()); DCHECK(subtrip->empty()); // Iterate from base_node backwards while maintaining the set of opened pairs. @@ -1324,15 +1315,15 @@ bool ExchangeSubtrip::ExtractChainsFromDelivery(int64_t base_node, int num_opened_pairs = 0; int current = base_node; do { - const int pair = pair_of_node_[current]; - if (IsPickupNode(current) && !opened_pairs_set_[pair]) { + const int pair = pd_data_.GetPairOfNode(current); + if (pd_data_.IsPickupNode(current) && !opened_pairs_set_[pair]) { rejects->push_back(current); } else { subtrip->push_back(current); - if (IsDeliveryNode(current)) { + if (pd_data_.IsDeliveryNode(current)) { ++num_opened_pairs; opened_pairs_set_[pair] = true; - } else if (IsPickupNode(current)) { + } else if (pd_data_.IsPickupNode(current)) { --num_opened_pairs; opened_pairs_set_[pair] = false; } diff --git a/ortools/constraint_solver/routing_neighborhoods.h b/ortools/constraint_solver/routing_neighborhoods.h index 2ede3bf1b3..6955aed8ae 100644 --- a/ortools/constraint_solver/routing_neighborhoods.h +++ b/ortools/constraint_solver/routing_neighborhoods.h @@ -20,6 +20,7 @@ #include #include +#include "absl/log/check.h" #include "ortools/constraint_solver/constraint_solver.h" #include "ortools/constraint_solver/constraint_solveri.h" #include "ortools/constraint_solver/routing_types.h" @@ -613,6 +614,30 @@ bool PairNodeSwapActiveOperator::MakeNeighbor() { } } +/// A utility class to maintain pickup and delivery information of nodes. +class PickupAndDeliveryData { + public: + PickupAndDeliveryData(int num_nodes, + const std::vector& pairs); + bool IsPickupNode(int64_t node) const { + DCHECK_LT(node, is_pickup_node_.size()); + return is_pickup_node_[node]; + } + bool IsDeliveryNode(int64_t node) const { + DCHECK_LT(node, is_delivery_node_.size()); + return is_delivery_node_[node]; + } + int GetPairOfNode(int64_t node) const { + DCHECK_LT(node, pair_of_node_.size()); + return pair_of_node_[node]; + } + + private: + std::vector is_pickup_node_; + std::vector is_delivery_node_; + std::vector pair_of_node_; +}; + /// Tries to move subtrips after an insertion node. /// A subtrip is a subsequence that contains only matched pickup and delivery /// nodes, or pickup-only nodes, i.e. it cannot contain a pickup without a @@ -649,24 +674,13 @@ class RelocateSubtrip : public PathOperator { /// Relocates the subtrip ending at chain_first_node. It must be a delivery. bool RelocateSubTripFromDelivery(int64_t chain_last_node, int64_t insertion_node); - bool IsPickupNode(int64_t node) const { - DCHECK_LT(node, is_pickup_node_.size()); - DCHECK_GE(node, 0); - return is_pickup_node_[node]; - } - bool IsDeliveryNode(int64_t node) const { - DCHECK_LT(node, is_delivery_node_.size()); - DCHECK_GE(node, 0); - return is_delivery_node_[node]; - } + void SetPath(const std::vector& path, int path_id); - std::vector is_pickup_node_; - std::vector is_delivery_node_; - std::vector pair_of_node_; + const PickupAndDeliveryData pd_data_; // Represents the set of pairs that have been opened during a call to // MakeNeighbor(). This vector must be all false before and after calling // RelocateSubTripFromPickup() and RelocateSubTripFromDelivery(). - std::vector opened_pairs_bitset_; + std::vector opened_pairs_set_; std::vector rejected_nodes_; std::vector subtrip_nodes_; @@ -718,21 +732,8 @@ class ExchangeSubtrip : public PathOperator { std::vector* rejects, std::vector* subtrip); void SetPath(const std::vector& path, int path_id); - bool IsPickupNode(int64_t node) const { - DCHECK_LT(node, is_pickup_node_.size()); - DCHECK_GE(node, 0); - return is_pickup_node_[node]; - } - bool IsDeliveryNode(int64_t node) const { - DCHECK_LT(node, is_delivery_node_.size()); - DCHECK_GE(node, 0); - return is_delivery_node_[node]; - } - // Precompute some information about nodes. - std::vector is_pickup_node_; - std::vector is_delivery_node_; - std::vector pair_of_node_; + const PickupAndDeliveryData pd_data_; // Represents the set of opened pairs during ExtractChainsFromXXX(). std::vector opened_pairs_set_; // Keep internal structures under hand to avoid reallocation. diff --git a/ortools/constraint_solver/routing_sat.cc b/ortools/constraint_solver/routing_sat.cc index 9a5e0932df..414b0ef718 100644 --- a/ortools/constraint_solver/routing_sat.cc +++ b/ortools/constraint_solver/routing_sat.cc @@ -16,13 +16,14 @@ #include #include #include -#include #include #include #include #include +#include "absl/container/btree_map.h" #include "absl/container/flat_hash_map.h" +#include "absl/log/check.h" #include "absl/time/time.h" #include "ortools/base/map_util.h" #include "ortools/constraint_solver/constraint_solver.h" @@ -37,6 +38,7 @@ #include "ortools/util/bitset.h" #include "ortools/util/optional_boolean.pb.h" #include "ortools/util/saturated_arithmetic.h" +#include "ortools/util/time_limit.h" namespace operations_research { namespace sat { @@ -111,7 +113,8 @@ struct Arc { } }; -using ArcVarMap = std::map; // needs to be stable when iterating +using ArcVarMap = + absl::btree_map; // needs to be stable when iterating void AddSoftCumulBounds(const RoutingDimension* dimension, int index, int cumul, int64_t cumul_min, int64_t cumul_max, @@ -290,7 +293,7 @@ ArcVarMap PopulateMultiRouteModelFromRoutingModel(const RoutingModel& model, : model.UnperformedPenalty(tail); if (cost == std::numeric_limits::max()) continue; const Arc arc = {tail_index, head_index}; - if (gtl::ContainsKey(arc_vars, arc)) continue; + if (arc_vars.contains(arc)) continue; const int index = AddVariable(cp_model, 0, 1); gtl::InsertOrDie(&arc_vars, arc, index); cp_model->mutable_objective()->add_vars(index); @@ -619,7 +622,7 @@ void AddGeneralizedPickupDeliveryConstraints( for (int vehicle = 0; vehicle < model.vehicles(); vehicle++) { const Arc vehicle_start_delivery_arc = { static_cast(model.Start(vehicle) + 1), cp_delivery}; - if (gtl::ContainsKey(arc_vars, vehicle_start_delivery_arc)) { + if (arc_vars.contains(vehicle_start_delivery_arc)) { // Forbid vehicle_start -> delivery arc. AddLinearConstraint(cp_model, 0, 0, {{arc_vars.at(vehicle_start_delivery_arc), 1}}); @@ -629,7 +632,7 @@ void AddGeneralizedPickupDeliveryConstraints( for (const int pickup : pickups) { const int cp_pickup = pickup + 1; const Arc delivery_pickup_arc = {cp_delivery, cp_pickup}; - if (gtl::ContainsKey(arc_vars, delivery_pickup_arc)) { + if (arc_vars.contains(delivery_pickup_arc)) { // Forbid delivery -> pickup arc. AddLinearConstraint(cp_model, 0, 0, {{arc_vars.at(delivery_pickup_arc), 1}}); @@ -693,13 +696,13 @@ ArcVarMap PopulateGeneralizedRouteModelFromRoutingModel( const int cp_start = model.Start(vehicle) + 1; const Arc start_arc = {depot, cp_start}; const int start_arc_var = AddVariable(cp_model, 1, 1); - DCHECK(!gtl::ContainsKey(arc_vars, start_arc)); + DCHECK(!arc_vars.contains(start_arc)); arc_vars.insert({start_arc, start_arc_var}); const int cp_end = model.End(vehicle) + 1; const Arc end_arc = {cp_end, depot}; const int end_arc_var = AddVariable(cp_model, 1, 1); - DCHECK(!gtl::ContainsKey(arc_vars, end_arc)); + DCHECK(!arc_vars.contains(end_arc)); arc_vars.insert({end_arc, end_arc_var}); vehicle_performs_node[vehicle][cp_start] = start_arc_var; @@ -753,7 +756,7 @@ ArcVarMap PopulateGeneralizedRouteModelFromRoutingModel( is_unperformed[disjunction_indices[0] + 1] == -1) { const int cp_node = disjunction_indices[0] + 1; const Arc arc = {cp_node, cp_node}; - DCHECK(!gtl::ContainsKey(arc_vars, arc)); + DCHECK(!arc_vars.contains(arc)); is_unperformed[cp_node] = AddVariable(cp_model, 0, 1); arc_vars.insert({arc, is_unperformed[cp_node]}); cp_model->mutable_objective()->add_vars(is_unperformed[cp_node]); @@ -769,7 +772,7 @@ ArcVarMap PopulateGeneralizedRouteModelFromRoutingModel( // Node can be unperformed. if (is_unperformed[cp_node] == -1) { const Arc arc = {cp_node, cp_node}; - DCHECK(!gtl::ContainsKey(arc_vars, arc)); + DCHECK(!arc_vars.contains(arc)); is_unperformed[cp_node] = AddVariable(cp_model, 0, 1); arc_vars.insert({arc, is_unperformed[cp_node]}); } @@ -821,7 +824,7 @@ ArcVarMap PopulateGeneralizedRouteModelFromRoutingModel( if (!feasible) continue; const Arc arc = {cp_tail, cp_head}; - DCHECK(!gtl::ContainsKey(arc_vars, arc)); + DCHECK(!arc_vars.contains(arc)); const int arc_var = AddVariable(cp_model, 0, 1); arc_vars.insert({arc, arc_var}); } diff --git a/ortools/constraint_solver/routing_search.h b/ortools/constraint_solver/routing_search.h index 8230ef0e91..24f34eb877 100644 --- a/ortools/constraint_solver/routing_search.h +++ b/ortools/constraint_solver/routing_search.h @@ -386,9 +386,6 @@ class CheapestInsertionFilteredHeuristic : public RoutingFilteredHeuristic { SeedQueue* sq); // clang-format on - /// Creates and returns a Seed corresponding to the given node/pair_index. - Seed CreateSeed(int index, bool is_pair_index, StartEndValue start_end_value); - /// Adds a Seed corresponding to the given 'node' to sq.priority_queue, based /// on the last entry in its 'start_end_distances' (from which it's deleted). void AddSeedNodeToQueue(int node, diff --git a/ortools/constraint_solver/samples/vrp_initial_routes.py b/ortools/constraint_solver/samples/vrp_initial_routes.py index 9b6906f67a..9c19e7156d 100755 --- a/ortools/constraint_solver/samples/vrp_initial_routes.py +++ b/ortools/constraint_solver/samples/vrp_initial_routes.py @@ -83,6 +83,7 @@ def print_solution(data, manager, routing, solution): print(plan_output) max_route_distance = max(route_distance, max_route_distance) print(f"Maximum of the route distances: {max_route_distance}m") + # [END solution_printer] diff --git a/ortools/constraint_solver/samples/vrp_solution_callback.py b/ortools/constraint_solver/samples/vrp_solution_callback.py index c42274e74b..be8f198662 100755 --- a/ortools/constraint_solver/samples/vrp_solution_callback.py +++ b/ortools/constraint_solver/samples/vrp_solution_callback.py @@ -84,6 +84,7 @@ def print_solution( print(plan_output) total_distance += route_distance print(f"Total Distance of all routes: {total_distance}m") + # [END solution_callback_printer] @@ -111,6 +112,7 @@ class SolutionCallback: self._counter += 1 if self._counter > self._counter_limit: self._routing_model.solver().FinishCurrentSearch() + # [END solution_callback] diff --git a/ortools/constraint_solver/sched_constraints.cc b/ortools/constraint_solver/sched_constraints.cc index 8e4bf45d5e..6d154181c5 100644 --- a/ortools/constraint_solver/sched_constraints.cc +++ b/ortools/constraint_solver/sched_constraints.cc @@ -28,6 +28,7 @@ #include #include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" #include "ortools/base/types.h" @@ -63,7 +64,7 @@ class TreeArrayConstraint : public Constraint { root_node_ = &tree_[0][0]; } - std::string DebugStringInternal(const std::string& name) const { + std::string DebugStringInternal(absl::string_view name) const { return absl::StrFormat("Cover(%s) == %s", JoinDebugStringPtr(vars_, ", "), target_var_->DebugString()); } diff --git a/ortools/constraint_solver/utilities.cc b/ortools/constraint_solver/utilities.cc index ada2494f57..716a542af0 100644 --- a/ortools/constraint_solver/utilities.cc +++ b/ortools/constraint_solver/utilities.cc @@ -19,6 +19,7 @@ #include "absl/container/flat_hash_set.h" #include "absl/strings/str_format.h" #include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" #include "ortools/base/hash.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" @@ -513,7 +514,7 @@ class PrintModelVisitor : public ModelVisitor { return result; } - void set_prefix(const std::string& prefix) { prefix_ = prefix; } + void set_prefix(absl::string_view prefix) { prefix_ = prefix; } int indent_; std::string prefix_; @@ -685,15 +686,15 @@ class ModelStatisticsVisitor : public ModelVisitor { } } - void AddConstraintType(const std::string& constraint_type) { + void AddConstraintType(absl::string_view constraint_type) { constraint_types_[constraint_type]++; } - void AddExpressionType(const std::string& expression_type) { + void AddExpressionType(absl::string_view expression_type) { expression_types_[expression_type]++; } - void AddExtensionType(const std::string& extension_type) { + void AddExtensionType(absl::string_view extension_type) { extension_types_[extension_type]++; }