constraint_solver: fixup
This commit is contained in:
@@ -3359,35 +3359,29 @@ class PathState::NodeRange {
|
||||
const CommittedNode* const first_node_;
|
||||
};
|
||||
|
||||
// This checker enforces unary dimension requirements.
|
||||
// A unary dimension requires that there is some valuation of
|
||||
// node_capacity and demand such that for all paths,
|
||||
// if arc A -> B is on a path of path_class p,
|
||||
// then node_capacity[A] + demand[p][A] = node_capacity[B].
|
||||
// Moreover, all node_capacities of a path must be inside interval
|
||||
// path_capacity[path].
|
||||
// Note that Intervals have two meanings:
|
||||
// - for demand and node_capacity, those are values allowed for each associated
|
||||
// decision variable.
|
||||
// - for path_capacity, those are set of values that node_capacities of the path
|
||||
// must respect.
|
||||
// If the path capacity of a path is [kint64min, kint64max],
|
||||
// then the unary dimension requirements are not enforced on this path.
|
||||
class UnaryDimensionChecker {
|
||||
// This checker enforces dimension requirements.
|
||||
// A dimension requires that there is some valuation of
|
||||
// cumul and demand such that for all paths:
|
||||
// - cumul[A] is in interval node_capacity[A]
|
||||
// - if arc A -> B is on a path of path_class p,
|
||||
// then cumul[A] + demand[p](A, B) = cumul[B].
|
||||
// - if A is on a path of class p, then
|
||||
// cumul[A] must be inside interval path_capacity[path].
|
||||
class DimensionChecker {
|
||||
public:
|
||||
struct Interval {
|
||||
int64_t min;
|
||||
int64_t max;
|
||||
};
|
||||
|
||||
UnaryDimensionChecker(const PathState* path_state,
|
||||
std::vector<Interval> path_capacity,
|
||||
std::vector<int> path_class,
|
||||
std::vector<std::function<Interval(int64_t)>>
|
||||
min_max_demand_per_path_class,
|
||||
std::vector<Interval> node_capacity);
|
||||
DimensionChecker(const PathState* path_state,
|
||||
std::vector<Interval> path_capacity,
|
||||
std::vector<int> path_class,
|
||||
std::vector<std::function<Interval(int64_t)>>
|
||||
min_max_demand_per_path_class,
|
||||
std::vector<Interval> node_capacity);
|
||||
|
||||
// Given the change made in PathState, checks that the unary dimension
|
||||
// Given the change made in PathState, checks that the dimension
|
||||
// constraint is still feasible.
|
||||
bool Check() const;
|
||||
|
||||
@@ -3469,14 +3463,14 @@ LocalSearchFilter* MakePathStateFilter(Solver* solver,
|
||||
const std::vector<IntVar*>& nexts);
|
||||
|
||||
// Make a filter that translates solver events to the input checker's interface.
|
||||
// Since UnaryDimensionChecker has a PathState, the filter returned by this
|
||||
// Since DimensionChecker has a PathState, the filter returned by this
|
||||
// must be synchronized to the corresponding PathStateFilter:
|
||||
// - Relax() must be called after the PathStateFilter's.
|
||||
// - Accept() must be called after.
|
||||
// - Synchronize() must be called before.
|
||||
// - Revert() must be called before.
|
||||
LocalSearchFilter* MakeUnaryDimensionFilter(
|
||||
Solver* solver, std::unique_ptr<UnaryDimensionChecker> checker,
|
||||
LocalSearchFilter* MakeDimensionFilter(
|
||||
Solver* solver, std::unique_ptr<DimensionChecker> checker,
|
||||
const std::string& dimension_name);
|
||||
|
||||
#endif // !defined(SWIG)
|
||||
|
||||
@@ -2760,7 +2760,7 @@ class PathStateFilter : public LocalSearchFilter {
|
||||
// Selection-based algorithm in O(n^2), to use for small change sets.
|
||||
void MakeChainsFromChangedPathsAndArcsWithSelectionAlgorithm();
|
||||
// From changed_paths_ and changed_arcs_, fill chains_ and paths_.
|
||||
// Generic algorithm in O(sort(n)+n), to use for larger change sets.
|
||||
// Generic algorithm in O(std::sort(n)+n), to use for larger change sets.
|
||||
void MakeChainsFromChangedPathsAndArcsWithGenericAlgorithm();
|
||||
|
||||
const std::unique_ptr<PathState> path_state_;
|
||||
@@ -3007,7 +3007,7 @@ LocalSearchFilter* MakePathStateFilter(Solver* solver,
|
||||
}
|
||||
|
||||
namespace {
|
||||
using Interval = UnaryDimensionChecker::Interval;
|
||||
using Interval = DimensionChecker::Interval;
|
||||
|
||||
Interval Intersect(const Interval& i1, const Interval& i2) {
|
||||
return {std::max(i1.min, i2.min), std::min(i1.max, i2.max)};
|
||||
@@ -3032,7 +3032,7 @@ Interval Delta(const Interval& from, const Interval& to) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UnaryDimensionChecker::UnaryDimensionChecker(
|
||||
DimensionChecker::DimensionChecker(
|
||||
const PathState* path_state, std::vector<Interval> path_capacity,
|
||||
std::vector<int> path_class,
|
||||
std::vector<std::function<Interval(int64_t)>> min_max_demand_per_path_class,
|
||||
@@ -3057,7 +3057,7 @@ UnaryDimensionChecker::UnaryDimensionChecker(
|
||||
FullCommit();
|
||||
}
|
||||
|
||||
bool UnaryDimensionChecker::Check() const {
|
||||
bool DimensionChecker::Check() const {
|
||||
if (path_state_->IsInvalid()) return true;
|
||||
for (const int path : path_state_->ChangedPaths()) {
|
||||
const Interval path_capacity = path_capacity_[path];
|
||||
@@ -3079,7 +3079,7 @@ bool UnaryDimensionChecker::Check() const {
|
||||
chain_path == -1 ? -1 : path_class_[chain_path];
|
||||
// Call the RIQ if the chain size is large enough;
|
||||
// the optimal value was found with the associated benchmark in tests,
|
||||
// in particular BM_UnaryDimensionChecker<ChangeSparsity::kSparse, *>.
|
||||
// in particular BM_DimensionChecker<ChangeSparsity::kSparse, *>.
|
||||
constexpr int kMinRangeSizeForRIQ = 4;
|
||||
const bool chain_is_cached = chain_path_class == path_class;
|
||||
if (last_index - first_index > kMinRangeSizeForRIQ && chain_is_cached &&
|
||||
@@ -3116,7 +3116,7 @@ bool UnaryDimensionChecker::Check() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnaryDimensionChecker::Commit() {
|
||||
void DimensionChecker::Commit() {
|
||||
const int current_layer_size = backwards_demand_sums_riq_[0].size();
|
||||
int change_size = path_state_->ChangedPaths().size();
|
||||
for (const int path : path_state_->ChangedPaths()) {
|
||||
@@ -3131,7 +3131,7 @@ void UnaryDimensionChecker::Commit() {
|
||||
}
|
||||
}
|
||||
|
||||
void UnaryDimensionChecker::IncrementalCommit() {
|
||||
void DimensionChecker::IncrementalCommit() {
|
||||
for (const int path : path_state_->ChangedPaths()) {
|
||||
const int begin_index = backwards_demand_sums_riq_[0].size();
|
||||
AppendPathDemandsToSums(path);
|
||||
@@ -3139,7 +3139,7 @@ void UnaryDimensionChecker::IncrementalCommit() {
|
||||
}
|
||||
}
|
||||
|
||||
void UnaryDimensionChecker::FullCommit() {
|
||||
void DimensionChecker::FullCommit() {
|
||||
// Clear all structures.
|
||||
previous_nontrivial_index_.clear();
|
||||
for (auto& sums : backwards_demand_sums_riq_) sums.clear();
|
||||
@@ -3152,7 +3152,7 @@ void UnaryDimensionChecker::FullCommit() {
|
||||
}
|
||||
}
|
||||
|
||||
void UnaryDimensionChecker::AppendPathDemandsToSums(int path) {
|
||||
void DimensionChecker::AppendPathDemandsToSums(int path) {
|
||||
const int path_class = path_class_[path];
|
||||
// Compute sum of all demands for this path.
|
||||
// TODO(user): backwards Nodes() iterator, to compute sum directly.
|
||||
@@ -3183,7 +3183,7 @@ void UnaryDimensionChecker::AppendPathDemandsToSums(int path) {
|
||||
}
|
||||
}
|
||||
|
||||
void UnaryDimensionChecker::UpdateRIQStructure(int begin_index, int end_index) {
|
||||
void DimensionChecker::UpdateRIQStructure(int begin_index, int end_index) {
|
||||
// The max layer is the one used by
|
||||
// GetMinMaxPartialDemandSum(begin_index, end_index - 1).
|
||||
const int maximum_riq_exponent =
|
||||
@@ -3210,8 +3210,7 @@ void UnaryDimensionChecker::UpdateRIQStructure(int begin_index, int end_index) {
|
||||
// For instance, if this is only called when the range size is > 4
|
||||
// and paths are <= 32 nodes long, then we only need layers 0, 2, 3, and 4.
|
||||
// To compare, on a 512 < #nodes <= 1024 problem, this uses layers in [0, 10].
|
||||
UnaryDimensionChecker::Interval
|
||||
UnaryDimensionChecker::GetTightestBackwardsDemandSum(
|
||||
DimensionChecker::Interval DimensionChecker::GetTightestBackwardsDemandSum(
|
||||
int first_node_index, int last_node_index) const {
|
||||
DCHECK_LE(0, first_node_index);
|
||||
DCHECK_LT(first_node_index, last_node_index);
|
||||
@@ -3228,8 +3227,8 @@ UnaryDimensionChecker::GetTightestBackwardsDemandSum(
|
||||
return Intersect(i1, i2);
|
||||
}
|
||||
|
||||
bool UnaryDimensionChecker::SubpathOnlyHasTrivialNodes(
|
||||
int first_node_index, int last_node_index) const {
|
||||
bool DimensionChecker::SubpathOnlyHasTrivialNodes(int first_node_index,
|
||||
int last_node_index) const {
|
||||
DCHECK_LE(0, first_node_index);
|
||||
DCHECK_LT(first_node_index, last_node_index);
|
||||
DCHECK_LT(last_node_index, previous_nontrivial_index_.size());
|
||||
@@ -3238,13 +3237,13 @@ bool UnaryDimensionChecker::SubpathOnlyHasTrivialNodes(
|
||||
|
||||
namespace {
|
||||
|
||||
class UnaryDimensionFilter : public LocalSearchFilter {
|
||||
class DimensionFilter : public LocalSearchFilter {
|
||||
public:
|
||||
std::string DebugString() const override { return name_; }
|
||||
UnaryDimensionFilter(std::unique_ptr<UnaryDimensionChecker> checker,
|
||||
const std::string& dimension_name)
|
||||
DimensionFilter(std::unique_ptr<DimensionChecker> checker,
|
||||
const std::string& dimension_name)
|
||||
: checker_(std::move(checker)),
|
||||
name_(absl::StrCat("UnaryDimensionFilter(", dimension_name, ")")) {}
|
||||
name_(absl::StrCat("DimensionFilter(", dimension_name, ")")) {}
|
||||
|
||||
bool Accept(const Assignment* delta, const Assignment* deltadelta,
|
||||
int64_t objective_min, int64_t objective_max) override {
|
||||
@@ -3257,17 +3256,17 @@ class UnaryDimensionFilter : public LocalSearchFilter {
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<UnaryDimensionChecker> checker_;
|
||||
std::unique_ptr<DimensionChecker> checker_;
|
||||
const std::string name_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
LocalSearchFilter* MakeUnaryDimensionFilter(
|
||||
Solver* solver, std::unique_ptr<UnaryDimensionChecker> checker,
|
||||
LocalSearchFilter* MakeDimensionFilter(
|
||||
Solver* solver, std::unique_ptr<DimensionChecker> checker,
|
||||
const std::string& dimension_name) {
|
||||
UnaryDimensionFilter* filter =
|
||||
new UnaryDimensionFilter(std::move(checker), dimension_name);
|
||||
DimensionFilter* filter =
|
||||
new DimensionFilter(std::move(checker), dimension_name);
|
||||
return solver->RevAlloc(filter);
|
||||
}
|
||||
|
||||
|
||||
@@ -976,7 +976,7 @@ class ResourceAssignmentConstraint : public Constraint {
|
||||
ResourceAssignmentOptimizer resource_assignment_optimizer(
|
||||
&resource_group_, optimizer, mp_optimizer);
|
||||
|
||||
const auto transit = [&dimension](int64_t node, int64_t next) {
|
||||
const auto transit = [&dimension](int64_t node, int64_t /*next*/) {
|
||||
// TODO(user): Get rid of this max() by only allowing resources on
|
||||
// dimensions with positive transits (model.AreVehicleTransitsPositive()).
|
||||
// TODO(user): The transit lower bounds have not necessarily been
|
||||
@@ -1103,7 +1103,7 @@ Constraint* MakeResourceConstraint(
|
||||
|
||||
// Evaluators
|
||||
template <class A, class B>
|
||||
static int64_t ReturnZero(A a, B b) {
|
||||
static int64_t ReturnZero(A, B) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1271,7 +1271,7 @@ int RoutingModel::RegisterUnaryTransitVector(std::vector<int64_t> values) {
|
||||
int RoutingModel::RegisterUnaryTransitCallback(TransitCallback1 callback) {
|
||||
const int index = unary_transit_evaluators_.size();
|
||||
unary_transit_evaluators_.push_back(std::move(callback));
|
||||
return RegisterTransitCallback([this, index](int i, int j) {
|
||||
return RegisterTransitCallback([this, index](int i, int /*j*/) {
|
||||
return unary_transit_evaluators_[index](i);
|
||||
});
|
||||
}
|
||||
@@ -1422,7 +1422,6 @@ bool RoutingModel::InitializeDimensionInternal(
|
||||
const DimensionIndex dimension_index(dimensions_.size());
|
||||
dimension_name_to_index_[dimension->name()] = dimension_index;
|
||||
dimensions_.push_back(dimension);
|
||||
dimension_cumuls_optimized_with_cumul_dependent_transits_.push_back(false);
|
||||
dimension->Initialize(evaluator_indices, state_dependent_evaluator_indices,
|
||||
slack_max);
|
||||
solver_->AddConstraint(solver_->MakeDelayedPathCumul(
|
||||
@@ -1851,7 +1850,7 @@ const RoutingModel::CostClassIndex RoutingModel::kCostClassIndexOfZeroCost =
|
||||
CostClassIndex(0);
|
||||
|
||||
void RoutingModel::ComputeCostClasses(
|
||||
const RoutingSearchParameters& parameters) {
|
||||
const RoutingSearchParameters& /*parameters*/) {
|
||||
// Create and reduce the cost classes.
|
||||
cost_classes_.reserve(vehicles_);
|
||||
cost_classes_.clear();
|
||||
@@ -2525,7 +2524,7 @@ class RoutingModelInspector : public ModelVisitor {
|
||||
RegisterInspectors();
|
||||
}
|
||||
~RoutingModelInspector() override {}
|
||||
void EndVisitModel(const std::string& solver_name) override {
|
||||
void EndVisitModel(const std::string& /*solver_name*/) override {
|
||||
const std::vector<int> node_to_same_vehicle_component_id =
|
||||
same_vehicle_components_.GetComponentIds();
|
||||
model_->InitSameVehicleGroups(
|
||||
@@ -2538,18 +2537,18 @@ class RoutingModelInspector : public ModelVisitor {
|
||||
// TODO(user): Have a single annotated precedence graph.
|
||||
}
|
||||
void EndVisitConstraint(const std::string& type_name,
|
||||
const Constraint* const constraint) override {
|
||||
const Constraint* const /*constraint*/) override {
|
||||
gtl::FindWithDefault(constraint_inspectors_, type_name, []() {})();
|
||||
}
|
||||
void VisitIntegerExpressionArgument(const std::string& type_name,
|
||||
IntExpr* const expr) override {
|
||||
gtl::FindWithDefault(expr_inspectors_, type_name,
|
||||
[](const IntExpr* expr) {})(expr);
|
||||
[](const IntExpr*) {})(expr);
|
||||
}
|
||||
void VisitIntegerArrayArgument(const std::string& arg_name,
|
||||
const std::vector<int64_t>& values) override {
|
||||
gtl::FindWithDefault(array_inspectors_, arg_name,
|
||||
[](const std::vector<int64_t>& int_array) {})(values);
|
||||
[](const std::vector<int64_t>&) {})(values);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -5113,8 +5112,6 @@ void RoutingModel::StoreDimensionCumulOptimizers(
|
||||
const int num_dimensions = dimensions_.size();
|
||||
local_optimizer_index_.resize(num_dimensions, -1);
|
||||
global_optimizer_index_.resize(num_dimensions, -1);
|
||||
dimension_local_optimizer_for_cumul_dependent_transits_.resize(
|
||||
num_dimensions);
|
||||
if (parameters.disable_scheduling_beware_this_may_degrade_performance()) {
|
||||
return;
|
||||
}
|
||||
@@ -5191,12 +5188,6 @@ void RoutingModel::StoreDimensionCumulOptimizers(
|
||||
dimension, parameters.continuous_scheduling_solver()),
|
||||
std::make_unique<LocalDimensionCumulOptimizer>(
|
||||
dimension, parameters.mixed_integer_scheduling_solver())});
|
||||
} else if (dimension_cumuls_optimized_with_cumul_dependent_transits_[dim]) {
|
||||
needs_optimizer = true;
|
||||
dimension->SetVehicleOffsetsForLocalOptimizer(std::move(vehicle_offsets));
|
||||
dimension_local_optimizer_for_cumul_dependent_transits_[dim] =
|
||||
std::make_unique<LocalDimensionCumulOptimizer>(
|
||||
dimension, parameters.mixed_integer_scheduling_solver());
|
||||
}
|
||||
if (needs_optimizer) {
|
||||
optimized_dimensions_collector_assignment->Add(dimension->cumuls());
|
||||
@@ -6663,7 +6654,6 @@ void RoutingDimension::InitializeTransits(
|
||||
InitializeTransitVariables(slack_max);
|
||||
}
|
||||
|
||||
// TODO(user): Apply -pointer-following.
|
||||
void FillPathEvaluation(const std::vector<int64_t>& path,
|
||||
const RoutingModel::TransitCallback2& evaluator,
|
||||
std::vector<int64_t>* values) {
|
||||
@@ -7288,7 +7278,7 @@ void RoutingDimension::SetBreakIntervalsOfVehicle(
|
||||
std::vector<int64_t> node_visit_transits) {
|
||||
if (breaks.empty()) return;
|
||||
const int visit_evaluator = model()->RegisterTransitCallback(
|
||||
[node_visit_transits](int64_t from, int64_t to) {
|
||||
[node_visit_transits](int64_t from, int64_t /*to*/) {
|
||||
return node_visit_transits[from];
|
||||
});
|
||||
SetBreakIntervalsOfVehicle(std::move(breaks), vehicle, visit_evaluator, -1);
|
||||
@@ -7300,7 +7290,7 @@ void RoutingDimension::SetBreakIntervalsOfVehicle(
|
||||
std::function<int64_t(int64_t, int64_t)> delays) {
|
||||
if (breaks.empty()) return;
|
||||
const int visit_evaluator = model()->RegisterTransitCallback(
|
||||
[node_visit_transits](int64_t from, int64_t to) {
|
||||
[node_visit_transits](int64_t from, int64_t /*to*/) {
|
||||
return node_visit_transits[from];
|
||||
});
|
||||
const int delay_evaluator =
|
||||
|
||||
@@ -73,8 +73,8 @@ class MaxActiveVehiclesFilter : public IntVarLocalSearchFilter {
|
||||
routing_model_(routing_model),
|
||||
is_active_(routing_model.vehicles(), false),
|
||||
active_vehicles_(0) {}
|
||||
bool Accept(const Assignment* delta, const Assignment* deltadelta,
|
||||
int64_t objective_min, int64_t objective_max) override {
|
||||
bool Accept(const Assignment* delta, const Assignment* /*deltadelta*/,
|
||||
int64_t /*objective_min*/, int64_t /*objective_max*/) override {
|
||||
const int64_t kUnassigned = -1;
|
||||
const Assignment::IntContainer& container = delta->IntVarContainer();
|
||||
const int delta_size = container.Size();
|
||||
@@ -103,7 +103,7 @@ class MaxActiveVehiclesFilter : public IntVarLocalSearchFilter {
|
||||
}
|
||||
|
||||
private:
|
||||
void OnSynchronize(const Assignment* delta) override {
|
||||
void OnSynchronize(const Assignment* /*delta*/) override {
|
||||
active_vehicles_ = 0;
|
||||
for (int i = 0; i < routing_model_.vehicles(); ++i) {
|
||||
const int index = routing_model_.Start(i);
|
||||
@@ -144,8 +144,8 @@ class NodeDisjunctionFilter : public IntVarLocalSearchFilter {
|
||||
filter_cost_(filter_cost),
|
||||
has_mandatory_disjunctions_(routing_model.HasMandatoryDisjunctions()) {}
|
||||
|
||||
bool Accept(const Assignment* delta, const Assignment* deltadelta,
|
||||
int64_t objective_min, int64_t objective_max) override {
|
||||
bool Accept(const Assignment* delta, const Assignment* /*deltadelta*/,
|
||||
int64_t /*objective_min*/, int64_t objective_max) override {
|
||||
const int64_t kUnassigned = -1;
|
||||
const Assignment::IntContainer& container = delta->IntVarContainer();
|
||||
const int delta_size = container.Size();
|
||||
@@ -236,7 +236,7 @@ class NodeDisjunctionFilter : public IntVarLocalSearchFilter {
|
||||
}
|
||||
|
||||
private:
|
||||
void OnSynchronize(const Assignment* delta) override {
|
||||
void OnSynchronize(const Assignment* /*delta*/) override {
|
||||
synchronized_objective_value_ = 0;
|
||||
for (RoutingModel::DisjunctionIndex i(0);
|
||||
i < active_per_disjunction_.size(); ++i) {
|
||||
@@ -301,8 +301,8 @@ BasePathFilter::BasePathFilter(const std::vector<IntVar*>& nexts,
|
||||
lns_detected_(false) {}
|
||||
|
||||
bool BasePathFilter::Accept(const Assignment* delta,
|
||||
const Assignment* deltadelta, int64_t objective_min,
|
||||
int64_t objective_max) {
|
||||
const Assignment* /*deltadelta*/,
|
||||
int64_t objective_min, int64_t objective_max) {
|
||||
if (IsDisabled()) return true;
|
||||
lns_detected_ = false;
|
||||
for (const int touched : delta_touched_) {
|
||||
@@ -660,7 +660,7 @@ bool VehicleAmortizedCostFilter::AcceptPath(int64_t path_start,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VehicleAmortizedCostFilter::FinalizeAcceptPath(int64_t objective_min,
|
||||
bool VehicleAmortizedCostFilter::FinalizeAcceptPath(int64_t /*objective_min*/,
|
||||
int64_t objective_max) {
|
||||
return delta_vehicle_cost_ <= objective_max;
|
||||
}
|
||||
@@ -1078,12 +1078,11 @@ class PathCumulFilter : public BasePathFilter {
|
||||
|
||||
// The DimensionCumulOptimizer is used to compute a more precise value of
|
||||
// the cost related to the cumul values (soft bounds and span costs).
|
||||
// It is also used to garantee feasibility with complex mixes of constraints
|
||||
// and in particular in the presence of break requests along other
|
||||
// constraints.
|
||||
// Therefore, without breaks, we only use the optimizer when the costs are
|
||||
// actually used to filter the solutions, i.e. when filter_objective_cost_
|
||||
// is true.
|
||||
// It is also used to guarantee feasibility with complex mixes of
|
||||
// constraints and in particular in the presence of break requests along
|
||||
// other constraints. Therefore, without breaks, we only use the optimizer
|
||||
// when the costs are actually used to filter the solutions, i.e. when
|
||||
// filter_objective_cost_ is true.
|
||||
return num_linear_constraints >= 2 &&
|
||||
(has_breaks || filter_objective_cost_);
|
||||
}
|
||||
@@ -1580,8 +1579,8 @@ void PathCumulFilter::OnBeforeSynchronizePaths() {
|
||||
current_min_start_.cumul_value)));
|
||||
}
|
||||
|
||||
bool PathCumulFilter::AcceptPath(int64_t path_start, int64_t chain_start,
|
||||
int64_t chain_end) {
|
||||
bool PathCumulFilter::AcceptPath(int64_t path_start, int64_t /*chain_start*/,
|
||||
int64_t /*chain_end*/) {
|
||||
int64_t node = path_start;
|
||||
int64_t cumul = cumuls_[node]->Min();
|
||||
int64_t cumul_cost_delta = 0;
|
||||
@@ -1722,7 +1721,7 @@ bool PathCumulFilter::AcceptPath(int64_t path_start, int64_t chain_start,
|
||||
StoreMinMaxCumulOfNodesOnPath(path, min_path_cumuls, /*is_delta=*/true);
|
||||
}
|
||||
if (!filter_vehicle_costs) {
|
||||
// If this route's costs should't be taken into account, reset the
|
||||
// If this route's costs shouldn't be taken into account, reset the
|
||||
// cumul_cost_delta and delta_path_transits_ for this path.
|
||||
cumul_cost_delta = 0;
|
||||
delta_path_transits_.ClearPath(path);
|
||||
@@ -1742,7 +1741,7 @@ bool PathCumulFilter::AcceptPath(int64_t path_start, int64_t chain_start,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PathCumulFilter::FinalizeAcceptPath(int64_t objective_min,
|
||||
bool PathCumulFilter::FinalizeAcceptPath(int64_t /*objective_min*/,
|
||||
int64_t objective_max) {
|
||||
DCHECK(!lns_detected());
|
||||
if (!FilterSpanCost() && !FilterCumulSoftBounds() && !FilterSlackCost() &&
|
||||
@@ -2100,12 +2099,12 @@ void AppendLightWeightDimensionFilters(
|
||||
const PathState* path_state,
|
||||
const std::vector<RoutingDimension*>& dimensions,
|
||||
std::vector<LocalSearchFilterManager::FilterEvent>* filters) {
|
||||
// For every dimension that fits, add a UnaryDimensionChecker.
|
||||
// For every dimension that fits, add a DimensionChecker.
|
||||
for (const RoutingDimension* dimension : dimensions) {
|
||||
// Skip dimension if not unary.
|
||||
if (dimension->GetUnaryTransitEvaluator(0) == nullptr) continue;
|
||||
|
||||
using Intervals = std::vector<UnaryDimensionChecker::Interval>;
|
||||
using Intervals = std::vector<DimensionChecker::Interval>;
|
||||
// Fill path capacities and classes.
|
||||
const int num_vehicles = dimension->model()->vehicles();
|
||||
Intervals path_capacity(num_vehicles);
|
||||
@@ -2118,13 +2117,13 @@ void AppendLightWeightDimensionFilters(
|
||||
// For each class, retrieve the demands of each node.
|
||||
// Dimension store evaluators with a double indirection for compacity:
|
||||
// vehicle -> vehicle_class -> evaluator_index.
|
||||
// We replicate this in UnaryDimensionChecker,
|
||||
// We replicate this in DimensionChecker,
|
||||
// except we expand evaluator_index to an array of values for all nodes.
|
||||
const int num_vehicle_classes =
|
||||
1 + *std::max_element(path_class.begin(), path_class.end());
|
||||
const int num_cumuls = dimension->cumuls().size();
|
||||
const int num_slacks = dimension->slacks().size();
|
||||
using Interval = UnaryDimensionChecker::Interval;
|
||||
using Interval = DimensionChecker::Interval;
|
||||
std::vector<std::function<Interval(int64_t)>> transits(num_vehicle_classes,
|
||||
nullptr);
|
||||
for (int vehicle = 0; vehicle < num_vehicles; ++vehicle) {
|
||||
@@ -2147,11 +2146,11 @@ void AppendLightWeightDimensionFilters(
|
||||
node_capacity[node] = {cumul->Min(), cumul->Max()};
|
||||
}
|
||||
// Make the dimension checker and pass ownership to the filter.
|
||||
auto checker = std::make_unique<UnaryDimensionChecker>(
|
||||
auto checker = std::make_unique<DimensionChecker>(
|
||||
path_state, std::move(path_capacity), std::move(path_class),
|
||||
std::move(transits), std::move(node_capacity));
|
||||
const auto kAccept = LocalSearchFilterManager::FilterEventType::kAccept;
|
||||
LocalSearchFilter* filter = MakeUnaryDimensionFilter(
|
||||
LocalSearchFilter* filter = MakeDimensionFilter(
|
||||
dimension->model()->solver(), std::move(checker), dimension->name());
|
||||
filters->push_back({filter, kAccept});
|
||||
}
|
||||
@@ -2312,8 +2311,9 @@ PickupDeliveryFilter::PickupDeliveryFilter(
|
||||
}
|
||||
}
|
||||
|
||||
bool PickupDeliveryFilter::AcceptPath(int64_t path_start, int64_t chain_start,
|
||||
int64_t chain_end) {
|
||||
bool PickupDeliveryFilter::AcceptPath(int64_t path_start,
|
||||
int64_t /*chain_start*/,
|
||||
int64_t /*chain_end*/) {
|
||||
switch (vehicle_policies_[GetPath(path_start)]) {
|
||||
case RoutingModel::PICKUP_AND_DELIVERY_NO_ORDER:
|
||||
return AcceptPathDefault(path_start);
|
||||
@@ -2553,9 +2553,9 @@ CumulBoundsPropagatorFilter::CumulBoundsPropagatorFilter(
|
||||
delta_nexts_(Size()) {}
|
||||
|
||||
bool CumulBoundsPropagatorFilter::Accept(const Assignment* delta,
|
||||
const Assignment* deltadelta,
|
||||
int64_t objective_min,
|
||||
int64_t objective_max) {
|
||||
const Assignment* /*deltadelta*/,
|
||||
int64_t /*objective_min*/,
|
||||
int64_t /*objective_max*/) {
|
||||
delta_touched_.ClearAll();
|
||||
for (const IntVarElement& delta_element :
|
||||
delta->IntVarContainer().elements()) {
|
||||
@@ -2625,8 +2625,8 @@ LPCumulFilter::LPCumulFilter(const std::vector<IntVar*>& nexts,
|
||||
delta_nexts_(Size()) {}
|
||||
|
||||
bool LPCumulFilter::Accept(const Assignment* delta,
|
||||
const Assignment* deltadelta, int64_t objective_min,
|
||||
int64_t objective_max) {
|
||||
const Assignment* /*deltadelta*/,
|
||||
int64_t /*objective_min*/, int64_t objective_max) {
|
||||
delta_touched_.ClearAll();
|
||||
for (const IntVarElement& delta_element :
|
||||
delta->IntVarContainer().elements()) {
|
||||
@@ -2648,11 +2648,10 @@ bool LPCumulFilter::Accept(const Assignment* delta,
|
||||
// No need to compute the cost of the LP, only verify its feasibility.
|
||||
delta_cost_without_transit_ = 0;
|
||||
const DimensionSchedulingStatus status =
|
||||
optimizer_.ComputeCumuls(next_accessor, {}, nullptr, nullptr, nullptr);
|
||||
optimizer_.ComputeCumuls(next_accessor, nullptr, nullptr, nullptr);
|
||||
if (status == DimensionSchedulingStatus::OPTIMAL) return true;
|
||||
if (status == DimensionSchedulingStatus::RELAXED_OPTIMAL_ONLY &&
|
||||
mp_optimizer_.ComputeCumuls(next_accessor, {}, nullptr, nullptr,
|
||||
nullptr) ==
|
||||
mp_optimizer_.ComputeCumuls(next_accessor, nullptr, nullptr, nullptr) ==
|
||||
DimensionSchedulingStatus::OPTIMAL) {
|
||||
return true;
|
||||
}
|
||||
@@ -2682,7 +2681,7 @@ int64_t LPCumulFilter::GetAcceptedObjectiveValue() const {
|
||||
return delta_cost_without_transit_;
|
||||
}
|
||||
|
||||
void LPCumulFilter::OnSynchronize(const Assignment* delta) {
|
||||
void LPCumulFilter::OnSynchronize(const Assignment* /*delta*/) {
|
||||
// TODO(user): Try to optimize this so the LP is not called when the last
|
||||
// computed delta cost corresponds to the solution being synchronized.
|
||||
const RoutingModel& model = *optimizer_.dimension()->model();
|
||||
@@ -2805,8 +2804,8 @@ bool ResourceGroupAssignmentFilter::InitializeAcceptPath() {
|
||||
}
|
||||
|
||||
bool ResourceGroupAssignmentFilter::AcceptPath(int64_t path_start,
|
||||
int64_t chain_start,
|
||||
int64_t chain_end) {
|
||||
int64_t /*chain_start*/,
|
||||
int64_t /*chain_end*/) {
|
||||
const int vehicle = model_.VehicleIndex(path_start);
|
||||
return resource_assignment_optimizer_.ComputeAssignmentCostsForVehicle(
|
||||
vehicle, [this](int64_t index) { return GetNext(index); },
|
||||
@@ -2814,8 +2813,8 @@ bool ResourceGroupAssignmentFilter::AcceptPath(int64_t path_start,
|
||||
&delta_vehicle_to_resource_assignment_costs_[vehicle], nullptr, nullptr);
|
||||
}
|
||||
|
||||
bool ResourceGroupAssignmentFilter::FinalizeAcceptPath(int64_t objective_min,
|
||||
int64_t objective_max) {
|
||||
bool ResourceGroupAssignmentFilter::FinalizeAcceptPath(
|
||||
int64_t /*objective_min*/, int64_t objective_max) {
|
||||
delta_cost_without_transit_ =
|
||||
resource_assignment_optimizer_.ComputeBestAssignmentCost(
|
||||
delta_vehicle_to_resource_assignment_costs_,
|
||||
@@ -3000,8 +2999,9 @@ CPFeasibilityFilter::CPFeasibilityFilter(RoutingModel* routing_model)
|
||||
}
|
||||
|
||||
bool CPFeasibilityFilter::Accept(const Assignment* delta,
|
||||
const Assignment* deltadelta,
|
||||
int64_t objective_min, int64_t objective_max) {
|
||||
const Assignment* /*deltadelta*/,
|
||||
int64_t /*objective_min*/,
|
||||
int64_t /*objective_max*/) {
|
||||
temp_assignment_->Copy(assignment_);
|
||||
AddDeltaToAssignment(delta, temp_assignment_);
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ LocalDimensionCumulOptimizer::LocalDimensionCumulOptimizer(
|
||||
DimensionSchedulingStatus LocalDimensionCumulOptimizer::ComputeRouteCumulCost(
|
||||
int vehicle, const std::function<int64_t(int64_t)>& next_accessor,
|
||||
int64_t* optimal_cost) {
|
||||
return optimizer_core_.OptimizeSingleRoute(vehicle, next_accessor, {},
|
||||
return optimizer_core_.OptimizeSingleRoute(vehicle, next_accessor,
|
||||
solver_[vehicle].get(), nullptr,
|
||||
nullptr, optimal_cost, nullptr);
|
||||
}
|
||||
@@ -209,8 +209,8 @@ LocalDimensionCumulOptimizer::ComputeRouteCumulCostWithoutFixedTransits(
|
||||
int64_t cost = 0;
|
||||
int64_t transit_cost = 0;
|
||||
const DimensionSchedulingStatus status = optimizer_core_.OptimizeSingleRoute(
|
||||
vehicle, next_accessor, {}, solver_[vehicle].get(), nullptr, nullptr,
|
||||
&cost, &transit_cost);
|
||||
vehicle, next_accessor, solver_[vehicle].get(), nullptr, nullptr, &cost,
|
||||
&transit_cost);
|
||||
if (status != DimensionSchedulingStatus::INFEASIBLE &&
|
||||
optimal_cost_without_transits != nullptr) {
|
||||
*optimal_cost_without_transits = CapSub(cost, transit_cost);
|
||||
@@ -228,7 +228,7 @@ std::vector<DimensionSchedulingStatus> LocalDimensionCumulOptimizer::
|
||||
std::vector<std::vector<int64_t>>* optimal_cumuls,
|
||||
std::vector<std::vector<int64_t>>* optimal_breaks) {
|
||||
return optimizer_core_.OptimizeSingleRouteWithResources(
|
||||
vehicle, next_accessor, transit_accessor, {}, resources, resource_indices,
|
||||
vehicle, next_accessor, transit_accessor, resources, resource_indices,
|
||||
optimize_vehicle_costs, solver_[vehicle].get(),
|
||||
optimal_costs_without_transits, optimal_cumuls, optimal_breaks);
|
||||
}
|
||||
@@ -863,9 +863,11 @@ DimensionCumulOptimizerCore::OptimizeAndPackSingleRoute(
|
||||
{*resource}, {0}, /*optimize_vehicle_costs=*/true, solver,
|
||||
&costs_without_transits, /*cumul_values=*/nullptr,
|
||||
/*break_values=*/nullptr, /*clear_lp=*/false);
|
||||
DCHECK_EQ(statuses.size(), 1);
|
||||
if (statuses[0] == DimensionSchedulingStatus::INFEASIBLE) {
|
||||
if (dimension_->model()->CheckLimit()) {
|
||||
status = DimensionSchedulingStatus::INFEASIBLE;
|
||||
} else {
|
||||
DCHECK_EQ(statuses.size(), 1);
|
||||
status = statuses[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1839,8 +1841,8 @@ GlobalDimensionCumulOptimizer::ComputeCumulCostWithoutFixedTransits(
|
||||
int64_t cost = 0;
|
||||
int64_t transit_cost = 0;
|
||||
DimensionSchedulingStatus status =
|
||||
optimizer_core_.Optimize(next_accessor, {}, solver_.get(), nullptr,
|
||||
nullptr, nullptr, &cost, &transit_cost);
|
||||
optimizer_core_.Optimize(next_accessor, solver_.get(), nullptr, nullptr,
|
||||
nullptr, &cost, &transit_cost);
|
||||
if (status != DimensionSchedulingStatus::INFEASIBLE &&
|
||||
optimal_cost_without_transits != nullptr) {
|
||||
*optimal_cost_without_transits = CapSub(cost, transit_cost);
|
||||
|
||||
@@ -360,9 +360,11 @@ class RoutingGlopWrapper : public RoutingLinearSolverWrapper {
|
||||
linear_program_.SetConstraintBounds(ct, -glop::kInfinity,
|
||||
normalized_objective_value);
|
||||
}
|
||||
void AddMaximumConstraint(int max_var, std::vector<int> vars) override {}
|
||||
void AddProductConstraint(int product_var, std::vector<int> vars) override {}
|
||||
void SetEnforcementLiteral(int ct, int condition) override{};
|
||||
void AddMaximumConstraint(int /*max_var*/,
|
||||
std::vector<int> /*vars*/) override {}
|
||||
void AddProductConstraint(int /*product_var*/,
|
||||
std::vector<int> /*vars*/) override {}
|
||||
void SetEnforcementLiteral(int /*ct*/, int /*condition*/) override{};
|
||||
DimensionSchedulingStatus Solve(absl::Duration duration_limit) override {
|
||||
lp_solver_.GetMutableParameters()->set_max_time_in_seconds(
|
||||
absl::ToDoubleSeconds(duration_limit));
|
||||
@@ -449,7 +451,7 @@ class RoutingCPSatWrapper : public RoutingLinearSolverWrapper {
|
||||
return index;
|
||||
}
|
||||
void SetVariableName(int index, absl::string_view name) override {
|
||||
model_.mutable_variables(index)->set_name(name);
|
||||
model_.mutable_variables(index)->set_name(name.data());
|
||||
}
|
||||
bool SetVariableBounds(int index, int64_t lower_bound,
|
||||
int64_t upper_bound) override {
|
||||
@@ -590,7 +592,9 @@ class RoutingCPSatWrapper : public RoutingLinearSolverWrapper {
|
||||
bool SolutionIsInteger() const override { return true; }
|
||||
|
||||
// NOTE: This function is not implemented for the CP-SAT solver.
|
||||
void SetParameters(const std::string& parameters) override { DCHECK(false); }
|
||||
void SetParameters(const std::string& /*parameters*/) override {
|
||||
DCHECK(false);
|
||||
}
|
||||
|
||||
private:
|
||||
sat::CpModelProto model_;
|
||||
@@ -650,7 +654,7 @@ class DimensionCumulOptimizerCore {
|
||||
|
||||
private:
|
||||
// Initializes the containers and given solver. Must be called prior to
|
||||
// setting any contraints and solving.
|
||||
// setting any constraints and solving.
|
||||
void InitOptimizer(RoutingLinearSolverWrapper* solver);
|
||||
|
||||
// Computes the minimum/maximum of cumuls for nodes on "route", and sets them
|
||||
|
||||
Reference in New Issue
Block a user