14 #ifndef OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_LP_SCHEDULING_H_
15 #define OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_LP_SCHEDULING_H_
28 #include "absl/container/flat_hash_map.h"
29 #include "absl/memory/memory.h"
30 #include "absl/time/time.h"
64 const std::function<int64_t(int64_t)>& next_accessor,
65 int64_t cumul_offset);
68 return propagated_bounds_[PositiveNode(
index)];
72 const int64_t negated_upper_bound = propagated_bounds_[NegativeNode(
index)];
75 : -negated_upper_bound;
88 static const int kNoParent;
89 static const int kParentToBePropagated;
93 int PositiveNode(
int index)
const {
return 2 *
index; }
94 int NegativeNode(
int index)
const {
return 2 *
index + 1; }
96 void AddNodeToQueue(
int node) {
97 if (!node_in_queue_[node]) {
98 bf_queue_.push_back(node);
99 node_in_queue_[node] =
true;
106 void AddArcs(
int first_index,
int second_index, int64_t offset);
108 bool InitializeArcsAndBounds(
109 const std::function<int64_t(int64_t)>& next_accessor,
110 int64_t cumul_offset);
112 bool UpdateCurrentLowerBoundOfNode(
int node, int64_t new_lb, int64_t offset);
114 bool DisassembleSubtree(
int source,
int target);
116 bool CleanupAndReturnFalse() {
118 for (
int node_to_cleanup : bf_queue_) {
119 node_in_queue_[node_to_cleanup] =
false;
125 const RoutingDimension& dimension_;
126 const int64_t num_nodes_;
131 std::vector<std::vector<ArcInfo>> outgoing_arcs_;
133 std::deque<int> bf_queue_;
134 std::vector<bool> node_in_queue_;
135 std::vector<int> tree_parent_node_of_;
139 std::vector<int64_t> propagated_bounds_;
142 std::vector<int> tmp_dfs_stack_;
145 std::vector<std::pair<int64_t, int64_t>>
146 visited_pickup_delivery_indices_for_pair_;
167 const std::vector<int64_t>& starts,
168 const std::vector<int64_t>& ends) = 0;
197 const std::vector<std::pair<int, double>>& variable_coeffs) {
200 for (
const auto& variable_coeff : variable_coeffs) {
210 const std::vector<std::pair<int, double>>& weighted_variables) {
215 const int under_lower_bound_ct =
230 const int within_bounds_ct =
233 return within_bounds;
244 linear_program_.
Clear();
246 allowed_intervals_.clear();
257 const int64_t kMaxValue = 1e10;
259 const double lp_max =
261 if (lp_min <= lp_max) {
270 const std::vector<int64_t>& ends)
override {
275 allowed_intervals_[
index] =
276 absl::make_unique<SortedDisjointIntervalList>(starts, ends);
288 for (glop::ColIndex i(0); i < linear_program_.
num_variables(); ++i) {
315 absl::ToDoubleSeconds(duration_limit));
327 linear_program_.
Clear();
330 for (
const auto& allowed_interval : allowed_intervals_) {
331 const double value_double =
GetValue(allowed_interval.first);
332 const int64_t
value =
337 allowed_interval.second.get();
339 if (it == interval_list->
end() || value < it->start) {
359 absl::flat_hash_map<int, std::unique_ptr<SortedDisjointIntervalList>>
366 parameters_.set_num_search_workers(1);
369 parameters_.set_cp_model_presolve(
true);
370 parameters_.set_max_presolve_iterations(0);
371 parameters_.set_catch_sigint_signal(
false);
372 parameters_.set_mip_max_bound(1e8);
373 parameters_.set_search_branching(sat::SatParameters::LP_SEARCH);
379 objective_coefficients_.clear();
380 objective_offset_ = 0;
381 variable_offset_.clear();
382 constraint_offset_.clear();
383 first_constraint_to_offset_ = 0;
386 const int index = model_.variables_size();
387 if (
index >= variable_offset_.size()) {
388 variable_offset_.resize(
index + 1, 0);
390 sat::IntegerVariableProto*
const variable = model_.add_variables();
391 variable->add_domain(0);
392 variable->add_domain(
static_cast<int64_t
>(parameters_.mip_max_bound()));
401 variable_offset_[
index] = 0;
402 const int64_t offset_upper_bound =
404 parameters_.mip_max_bound());
405 const int64_t offset_lower_bound =
407 if (offset_lower_bound > offset_upper_bound)
return false;
408 sat::IntegerVariableProto*
const variable = model_.mutable_variables(
index);
409 variable->set_domain(0, offset_lower_bound);
410 variable->set_domain(1, offset_upper_bound);
414 const std::vector<int64_t>& ends)
override {
417 for (
int i = 0; i < starts.size(); ++i) {
423 model_.mutable_constraints(window_ct)->add_enforcement_literal(variable);
432 if (
index >= objective_coefficients_.size()) {
433 objective_coefficients_.resize(
index + 1, 0);
436 sat::CpObjectiveProto*
const objective = model_.mutable_objective();
437 objective->add_vars(
index);
442 return (
index < objective_coefficients_.size())
443 ? objective_coefficients_[
index]
447 model_.mutable_objective()->Clear();
448 objective_offset_ = 0;
452 const int ct_index = model_.constraints_size();
453 if (ct_index >= constraint_offset_.size()) {
454 constraint_offset_.resize(ct_index + 1, 0);
456 sat::LinearConstraintProto*
const ct =
457 model_.add_constraints()->mutable_linear();
465 sat::LinearConstraintProto*
const ct =
466 model_.mutable_constraints(ct_index)->mutable_linear();
469 constraint_offset_[ct_index] =
470 CapAdd(constraint_offset_[ct_index],
475 sat::LinearArgumentProto*
const ct =
476 model_.add_constraints()->mutable_lin_max();
477 ct->mutable_target()->add_vars(max_var);
478 ct->mutable_target()->add_coeffs(1);
479 for (
const int var : vars) {
480 sat::LinearExpressionProto*
const expr =
ct->add_exprs();
486 sat::IntegerArgumentProto*
const ct =
487 model_.add_constraints()->mutable_int_prod();
488 ct->set_target(product_var);
489 for (
const int var : vars) {
495 model_.mutable_constraints(
ct)->add_enforcement_literal(condition);
499 for (
int ct_index = first_constraint_to_offset_;
500 ct_index < constraint_offset_.size(); ++ct_index) {
501 if (!model_.mutable_constraints(ct_index)->has_linear())
continue;
502 sat::LinearConstraintProto*
const ct =
503 model_.mutable_constraints(ct_index)->mutable_linear();
504 ct->set_domain(0,
CapSub(
ct->domain(0), constraint_offset_[ct_index]));
505 ct->set_domain(1,
CapSub(
ct->domain(1), constraint_offset_[ct_index]));
507 first_constraint_to_offset_ = constraint_offset_.size();
508 parameters_.set_max_time_in_seconds(absl::ToDoubleSeconds(duration_limit));
509 VLOG(2) << model_.DebugString();
510 if (hint_.vars_size() == model_.variables_size()) {
511 *model_.mutable_solution_hint() = hint_;
516 VLOG(2) << response_.DebugString();
519 !model_.has_objective())) {
521 for (
int i = 0; i < response_.solution_size(); ++i) {
523 hint_.add_values(response_.solution(i));
534 return response_.solution(
index) + variable_offset_[
index];
539 sat::CpModelProto model_;
540 sat::CpSolverResponse response_;
541 sat::SatParameters parameters_;
542 std::vector<double> objective_coefficients_;
543 double objective_offset_;
544 std::vector<int64_t> variable_offset_;
545 std::vector<int64_t> constraint_offset_;
546 int first_constraint_to_offset_;
547 sat::PartialVariableAssignment hint_;
555 bool use_precedence_propagator);
562 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
564 std::vector<int64_t>* break_values, int64_t*
cost, int64_t* transit_cost,
565 bool clear_lp =
true);
567 bool Optimize(
const std::function<int64_t(int64_t)>& next_accessor,
569 std::vector<int64_t>* cumul_values,
570 std::vector<int64_t>* break_values, int64_t*
cost,
571 int64_t* transit_cost,
bool clear_lp =
true);
573 bool OptimizeAndPack(
const std::function<int64_t(int64_t)>& next_accessor,
575 std::vector<int64_t>* cumul_values,
576 std::vector<int64_t>* break_values);
579 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
581 std::vector<int64_t>* break_values);
596 bool ComputeRouteCumulBounds(
const std::vector<int64_t>& route,
597 const std::vector<int64_t>& fixed_transits,
598 int64_t cumul_offset);
604 bool SetRouteCumulConstraints(
605 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
606 int64_t cumul_offset,
bool optimize_costs,
608 int64_t* route_cost_offset);
616 void SetGlobalConstraints(
bool optimize_costs,
619 void SetValuesFromLP(
const std::vector<int>& lp_variables, int64_t offset,
621 std::vector<int64_t>* lp_values);
632 std::unique_ptr<CumulBoundsPropagator> propagator_;
633 std::vector<int64_t> current_route_min_cumuls_;
634 std::vector<int64_t> current_route_max_cumuls_;
637 std::vector<int> current_route_cumul_variables_;
638 std::vector<int> index_to_cumul_variable_;
643 std::vector<int> current_route_break_variables_;
647 std::vector<int> all_break_variables_;
651 std::vector<int> vehicle_to_all_break_variables_offset_;
654 int min_start_cumul_;
655 std::vector<std::pair<int64_t, int64_t>>
656 visited_pickup_delivery_indices_for_pair_;
668 RoutingSearchParameters::SchedulingSolver solver_type);
675 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
676 int64_t* optimal_cost);
681 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
682 int64_t* optimal_cost_without_transits);
690 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
691 std::vector<int64_t>* optimal_cumuls,
692 std::vector<int64_t>* optimal_breaks);
698 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
699 std::vector<int64_t>* packed_cumuls, std::vector<int64_t>* packed_breaks);
706 std::vector<std::unique_ptr<RoutingLinearSolverWrapper>> solver_;
719 const std::function<int64_t(int64_t)>& next_accessor,
720 int64_t* optimal_cost_without_transits);
726 bool ComputeCumuls(
const std::function<int64_t(int64_t)>& next_accessor,
727 std::vector<int64_t>* optimal_cumuls,
728 std::vector<int64_t>* optimal_breaks);
732 bool IsFeasible(
const std::function<int64_t(int64_t)>& next_accessor);
738 std::vector<int64_t>* packed_cumuls,
739 std::vector<int64_t>* packed_breaks);
746 std::unique_ptr<RoutingLinearSolverWrapper> solver_;
#define DCHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define CHECK_LE(val1, val2)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
const RoutingDimension & dimension() const
int64_t CumulMax(int index) const
bool PropagateCumulBounds(const std::function< int64_t(int64_t)> &next_accessor, int64_t cumul_offset)
int64_t CumulMin(int index) const
CumulBoundsPropagator(const RoutingDimension *dimension)
DimensionCumulOptimizerCore(const RoutingDimension *dimension, bool use_precedence_propagator)
const RoutingDimension * dimension() const
bool OptimizeAndPack(const std::function< int64_t(int64_t)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values)
DimensionSchedulingStatus OptimizeAndPackSingleRoute(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values)
bool Optimize(const std::function< int64_t(int64_t)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values, int64_t *cost, int64_t *transit_cost, bool clear_lp=true)
DimensionSchedulingStatus OptimizeSingleRoute(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values, int64_t *cost, int64_t *transit_cost, bool clear_lp=true)
bool ComputeCumulCostWithoutFixedTransits(const std::function< int64_t(int64_t)> &next_accessor, int64_t *optimal_cost_without_transits)
const RoutingDimension * dimension() const
GlobalDimensionCumulOptimizer(const RoutingDimension *dimension)
bool IsFeasible(const std::function< int64_t(int64_t)> &next_accessor)
bool ComputeCumuls(const std::function< int64_t(int64_t)> &next_accessor, std::vector< int64_t > *optimal_cumuls, std::vector< int64_t > *optimal_breaks)
bool ComputePackedCumuls(const std::function< int64_t(int64_t)> &next_accessor, std::vector< int64_t > *packed_cumuls, std::vector< int64_t > *packed_breaks)
DimensionSchedulingStatus ComputeRouteCumulCost(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, int64_t *optimal_cost)
DimensionSchedulingStatus ComputeRouteCumuls(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, std::vector< int64_t > *optimal_cumuls, std::vector< int64_t > *optimal_breaks)
DimensionSchedulingStatus ComputeRouteCumulCostWithoutFixedTransits(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, int64_t *optimal_cost_without_transits)
LocalDimensionCumulOptimizer(const RoutingDimension *dimension, RoutingSearchParameters::SchedulingSolver solver_type)
const RoutingDimension * dimension() const
DimensionSchedulingStatus ComputePackedRouteCumuls(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, std::vector< int64_t > *packed_cumuls, std::vector< int64_t > *packed_breaks)
static int64_t FastInt64Round(double x)
void SetCoefficient(int ct_index, int index, double coefficient) override
int NumVariables() const override
bool IsCPSATSolver() override
int CreateNewPositiveVariable() override
bool SetVariableBounds(int index, int64_t lower_bound, int64_t upper_bound) override
double GetValue(int index) const override
int64_t GetObjectiveValue() const override
DimensionSchedulingStatus Solve(absl::Duration duration_limit) override
~RoutingCPSatWrapper() 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
double GetObjectiveCoefficient(int index) const override
void SetVariableDisjointBounds(int index, const std::vector< int64_t > &starts, const std::vector< int64_t > &ends) override
bool SolutionIsInteger() const override
int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound) override
void SetObjectiveCoefficient(int index, double coefficient) override
int64_t GetVariableLowerBound(int index) const override
void ClearObjective() override
Dimensions represent quantities accumulated at nodes along the routes.
int NumVariables() const override
bool IsCPSATSolver() override
int CreateNewPositiveVariable() override
bool SetVariableBounds(int index, int64_t lower_bound, int64_t upper_bound) override
double GetValue(int index) const override
int64_t GetObjectiveValue() const override
DimensionSchedulingStatus Solve(absl::Duration duration_limit) override
void SetCoefficient(int ct, int index, double coefficient) 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
double GetObjectiveCoefficient(int index) const override
RoutingGlopWrapper(const glop::GlopParameters ¶meters)
void SetVariableDisjointBounds(int index, const std::vector< int64_t > &starts, const std::vector< int64_t > &ends) override
bool SolutionIsInteger() const override
int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound) override
void SetObjectiveCoefficient(int index, double coefficient) override
int64_t GetVariableLowerBound(int index) const override
void ClearObjective() override
virtual void SetCoefficient(int ct, int index, double coefficient)=0
virtual int NumVariables() const =0
virtual double GetObjectiveCoefficient(int index) const =0
virtual void AddProductConstraint(int product_var, std::vector< int > vars)=0
virtual int CreateNewPositiveVariable()=0
int AddLinearConstraint(int64_t lower_bound, int64_t upper_bound, const std::vector< std::pair< int, double >> &variable_coeffs)
int AddVariable(int64_t lower_bound, int64_t upper_bound)
virtual bool IsCPSATSolver()=0
virtual int64_t GetObjectiveValue() const =0
int AddReifiedLinearConstraint(int64_t lower_bound, int64_t upper_bound, const std::vector< std::pair< int, double >> &weighted_variables)
virtual void ClearObjective()=0
virtual int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound)=0
virtual double GetValue(int index) const =0
virtual DimensionSchedulingStatus Solve(absl::Duration duration_limit)=0
virtual void SetVariableDisjointBounds(int index, const std::vector< int64_t > &starts, const std::vector< int64_t > &ends)=0
virtual bool SetVariableBounds(int index, int64_t lower_bound, int64_t upper_bound)=0
virtual void SetObjectiveCoefficient(int index, double coefficient)=0
virtual void SetEnforcementLiteral(int ct, int condition)=0
virtual bool SolutionIsInteger() const =0
virtual ~RoutingLinearSolverWrapper()
virtual int64_t GetVariableLowerBound(int index) const =0
virtual void AddMaximumConstraint(int max_var, std::vector< int > vars)=0
This class represents a sorted list of disjoint, closed intervals.
ConstIterator end() const
Iterator FirstIntervalGreaterOrEqual(int64_t value) const
Returns an iterator to either:
GlopParameters * GetMutableParameters()
const DenseRow & variable_values() const
Fractional GetObjectiveValue() const
ABSL_MUST_USE_RESULT ProblemStatus Solve(const LinearProgram &lp)
void SetParameters(const GlopParameters ¶meters)
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
const DenseRow & variable_lower_bounds() const
const DenseRow & objective_coefficients() const
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
ColIndex CreateNewVariable()
bool SolutionIsInteger(const DenseRow &solution, Fractional absolute_tolerance) const
void NotifyThatColumnsAreClean()
void SetObjectiveCoefficient(ColIndex col, Fractional value)
ColIndex num_variables() const
RowIndex CreateNewConstraint()
void SetMaximizationProblem(bool maximize)
Class that owns everything related to a particular optimization model.
std::function< SatParameters(Model *)> NewSatParameters(const std::string ¶ms)
Creates parameters for the solver, which you can add to the model with.
CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model)
Solves the given CpModelProto.
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
DimensionSchedulingStatus
int64_t CapProd(int64_t x, int64_t y)