23 #include "absl/time/time.h"
46 return model.GetVehicleClassesCount() == 1;
50 int AddVariable(CpModelProto* cp_model, int64_t lb, int64_t ub) {
51 const int index = cp_model->variables_size();
52 IntegerVariableProto*
const var = cp_model->add_variables();
67 return a.tail ==
b.tail &&
a.head ==
b.head;
70 friend bool operator<(
const Arc&
a,
const Arc&
b) {
71 return a.tail ==
b.tail ?
a.head <
b.head :
a.tail <
b.tail;
73 friend std::ostream&
operator<<(std::ostream& strm,
const Arc& arc) {
74 return strm <<
"{" << arc.tail <<
", " << arc.head <<
"}";
78 return H::combine(std::move(h),
a.tail,
a.head);
82 using ArcVarMap = std::map<Arc, int>;
86 void AddDimensions(
const RoutingModel&
model,
const ArcVarMap& arc_vars,
87 CpModelProto* cp_model) {
88 for (
const RoutingDimension* dimension :
model.GetDimensions()) {
91 dimension->transit_evaluator(0);
92 std::vector<int> cumuls(dimension->cumuls().size(), -1);
93 const int64_t min_start = dimension->cumuls()[
model.Start(0)]->Min();
94 const int64_t max_end =
std::min(dimension->cumuls()[
model.End(0)]->Max(),
95 dimension->vehicle_capacities()[0]);
96 for (
int i = 0; i < cumuls.size(); ++i) {
97 if (
model.IsStart(i) ||
model.IsEnd(i))
continue;
99 const int64_t cumul_min =
101 std::max(dimension->cumuls()[i]->Min(),
103 const int64_t cumul_max =
105 std::min(dimension->cumuls()[i]->Max(),
107 cumuls[i] = AddVariable(cp_model, cumul_min, cumul_max);
109 for (
const auto arc_var : arc_vars) {
110 const int tail = arc_var.first.tail;
111 const int head = arc_var.first.head;
115 ConstraintProto*
ct = cp_model->add_constraints();
116 ct->add_enforcement_literal(arc_var.second);
117 LinearConstraintProto* arg =
ct->mutable_linear();
118 arg->add_domain(transit(
tail,
head));
120 arg->add_vars(cumuls[
tail]);
122 arg->add_vars(cumuls[
head]);
128 std::vector<int> CreateRanks(
const RoutingModel&
model,
129 const ArcVarMap& arc_vars,
130 CpModelProto* cp_model) {
131 const int depot = GetDepotFromModel(
model);
132 const int size =
model.Size() +
model.vehicles();
133 const int rank_size =
model.Size() -
model.vehicles();
134 std::vector<int> ranks(size, -1);
135 for (
int i = 0; i < size; ++i) {
136 if (
model.IsStart(i) ||
model.IsEnd(i))
continue;
137 ranks[i] = AddVariable(cp_model, 0, rank_size);
139 ranks[depot] = AddVariable(cp_model, 0, 0);
140 for (
const auto arc_var : arc_vars) {
141 const int tail = arc_var.first.tail;
142 const int head = arc_var.first.head;
145 ConstraintProto*
ct = cp_model->add_constraints();
146 ct->add_enforcement_literal(arc_var.second);
147 LinearConstraintProto* arg =
ct->mutable_linear();
150 arg->add_vars(ranks[
tail]);
152 arg->add_vars(ranks[
head]);
162 std::vector<int> CreateVehicleVars(
const RoutingModel&
model,
163 const ArcVarMap& arc_vars,
164 CpModelProto* cp_model) {
165 const int depot = GetDepotFromModel(
model);
166 const int size =
model.Size() +
model.vehicles();
167 std::vector<int> vehicles(size, -1);
168 for (
int i = 0; i < size; ++i) {
169 if (
model.IsStart(i) ||
model.IsEnd(i))
continue;
170 vehicles[i] = AddVariable(cp_model, 0, size - 1);
172 for (
const auto arc_var : arc_vars) {
173 const int tail = arc_var.first.tail;
174 const int head = arc_var.first.head;
178 ConstraintProto*
ct = cp_model->add_constraints();
179 ct->add_enforcement_literal(arc_var.second);
180 LinearConstraintProto* arg =
ct->mutable_linear();
181 arg->add_domain(
head);
182 arg->add_domain(
head);
183 arg->add_vars(vehicles[
head]);
188 ConstraintProto*
ct = cp_model->add_constraints();
189 ct->add_enforcement_literal(arc_var.second);
190 LinearConstraintProto* arg =
ct->mutable_linear();
193 arg->add_vars(vehicles[
tail]);
195 arg->add_vars(vehicles[
head]);
201 void AddPickupDeliveryConstraints(
const RoutingModel&
model,
202 const ArcVarMap& arc_vars,
203 CpModelProto* cp_model) {
204 if (
model.GetPickupAndDeliveryPairs().empty())
return;
205 const std::vector<int> ranks = CreateRanks(
model, arc_vars, cp_model);
206 const std::vector<int> vehicles =
207 CreateVehicleVars(
model, arc_vars, cp_model);
208 for (
const auto& pairs :
model.GetPickupAndDeliveryPairs()) {
209 const int64_t pickup = pairs.first[0];
210 const int64_t delivery = pairs.second[0];
213 ConstraintProto*
ct = cp_model->add_constraints();
214 LinearConstraintProto* arg =
ct->mutable_linear();
217 arg->add_vars(ranks[delivery]);
219 arg->add_vars(ranks[pickup]);
224 ConstraintProto*
ct = cp_model->add_constraints();
225 LinearConstraintProto* arg =
ct->mutable_linear();
228 arg->add_vars(vehicles[delivery]);
230 arg->add_vars(vehicles[pickup]);
242 ArcVarMap PopulateMultiRouteModelFromRoutingModel(
const RoutingModel&
model,
243 CpModelProto* cp_model) {
245 const int num_nodes =
model.Nexts().size();
246 const int depot = GetDepotFromModel(
model);
251 std::unique_ptr<IntVarIterator> iter(
252 model.NextVar(
tail)->MakeDomainIterator(
false));
253 for (
int head : InitAndGetValues(iter.get())) {
260 if (head_index == tail_index)
continue;
264 const Arc arc = {tail_index, head_index};
266 const int index = AddVariable(cp_model, 0, 1);
268 cp_model->mutable_objective()->add_vars(
index);
269 cp_model->mutable_objective()->add_coeffs(
cost);
279 LinearConstraintProto*
ct = cp_model->add_constraints()->mutable_linear();
282 for (
int node = 0; node < num_nodes; ++node) {
283 if (
model.IsStart(node) ||
model.IsEnd(node))
continue;
285 if (depot_node_var ==
nullptr)
continue;
286 ct->add_vars(*depot_node_var);
289 if (node_depot_var ==
nullptr)
continue;
290 ct->add_vars(*node_depot_var);
296 LinearConstraintProto*
ct = cp_model->add_constraints()->mutable_linear();
301 for (
int node = 0; node < num_nodes; ++node) {
302 if (
model.IsStart(node) ||
model.IsEnd(node))
continue;
304 if (
var ==
nullptr)
continue;
312 LinearConstraintProto*
ct = cp_model->add_constraints()->mutable_linear();
315 std::unique_ptr<IntVarIterator> iter(
316 model.NextVar(
tail)->MakeDomainIterator(
false));
317 bool depot_added =
false;
318 for (
int head : InitAndGetValues(iter.get())) {
322 if (depot_added)
continue;
327 if (
var ==
nullptr)
continue;
335 LinearConstraintProto*
ct = cp_model->add_constraints()->mutable_linear();
343 if (
var ==
nullptr)
continue;
349 AddPickupDeliveryConstraints(
model, arc_vars, cp_model);
351 AddDimensions(
model, arc_vars, cp_model);
356 RoutesConstraintProto* routes_ct =
357 cp_model->add_constraints()->mutable_routes();
358 for (
const auto arc_var : arc_vars) {
359 const int tail = arc_var.first.tail;
360 const int head = arc_var.first.head;
361 routes_ct->add_tails(
tail == 0 ? depot :
tail == depot ? 0 :
tail);
362 routes_ct->add_heads(
head == 0 ? depot :
head == depot ? 0 :
head);
363 routes_ct->add_literals(arc_var.second);
370 const RoutingDimension* master_dimension =
nullptr;
371 for (
const RoutingDimension* dimension :
model.GetDimensions()) {
373 if (dimension->GetUnaryTransitEvaluator(0) !=
nullptr) {
374 master_dimension = dimension;
378 if (master_dimension !=
nullptr) {
380 master_dimension->GetUnaryTransitEvaluator(0);
381 for (
int node = 0; node < num_nodes; ++node) {
384 if (!
model.IsEnd(node) && (!
model.IsStart(node) || node == depot)) {
385 routes_ct->add_demands(transit(node));
388 DCHECK_EQ(routes_ct->demands_size(), num_nodes + 1 -
model.vehicles());
389 routes_ct->set_capacity(master_dimension->vehicle_capacities()[0]);
397 ArcVarMap PopulateSingleRouteModelFromRoutingModel(
const RoutingModel&
model,
398 CpModelProto* cp_model) {
400 const int num_nodes =
model.Nexts().size();
401 CircuitConstraintProto* circuit =
402 cp_model->add_constraints()->mutable_circuit();
404 std::unique_ptr<IntVarIterator> iter(
405 model.NextVar(
tail)->MakeDomainIterator(
false));
406 for (
int head : InitAndGetValues(iter.get())) {
416 const int index = AddVariable(cp_model, 0, 1);
417 circuit->add_literals(
index);
418 circuit->add_tails(
tail);
419 circuit->add_heads(
head);
420 cp_model->mutable_objective()->add_vars(
index);
421 cp_model->mutable_objective()->add_coeffs(
cost);
425 AddPickupDeliveryConstraints(
model, arc_vars, cp_model);
426 AddDimensions(
model, arc_vars, cp_model);
433 ArcVarMap PopulateModelFromRoutingModel(
const RoutingModel&
model,
434 CpModelProto* cp_model) {
435 if (
model.vehicles() == 1) {
436 return PopulateSingleRouteModelFromRoutingModel(
model, cp_model);
438 return PopulateMultiRouteModelFromRoutingModel(
model, cp_model);
442 bool ConvertToSolution(
const CpSolverResponse&
response,
443 const RoutingModel&
model,
const ArcVarMap& arc_vars,
444 Assignment* solution) {
448 const int depot = GetDepotFromModel(
model);
450 for (
const auto& arc_var : arc_vars) {
451 if (
response.solution(arc_var.second) != 0) {
452 const int tail = arc_var.first.tail;
453 const int head = arc_var.first.head;
454 if (
head == depot)
continue;
458 solution->Add(
model.NextVar(
model.Start(vehicle)))->SetValue(
head);
464 for (
int v = 0; v <
model.vehicles(); ++v) {
465 int current =
model.Start(v);
466 while (solution->Contains(
model.NextVar(current))) {
467 current = solution->Value(
model.NextVar(current));
469 solution->Add(
model.NextVar(current))->SetValue(
model.End(v));
474 void AddSolutionAsHintToModel(
const Assignment* solution,
475 const RoutingModel&
model,
476 const ArcVarMap& arc_vars,
477 CpModelProto* cp_model) {
478 if (solution ==
nullptr)
return;
479 PartialVariableAssignment*
const hint = cp_model->mutable_solution_hint();
481 const int depot = GetDepotFromModel(
model);
482 const int num_nodes =
model.Nexts().size();
487 if (tail_index == depot && head_index == depot)
continue;
488 const int*
const var_index =
494 if (var_index ==
nullptr)
continue;
495 hint->add_vars(*var_index);
502 CpSolverResponse SolveRoutingModel(
503 const CpModelProto& cp_model, absl::Duration remaining_time,
504 const std::function<
void(
const CpSolverResponse&
response)>& observer) {
508 parameters.set_max_time_in_seconds(absl::ToDoubleSeconds(remaining_time));
512 if (observer !=
nullptr) {
526 const RoutingSearchParameters& search_parameters,
529 if (!sat::RoutingModelCanBeSolvedBySat(
model))
return false;
530 sat::CpModelProto cp_model;
531 cp_model.mutable_objective()->set_scaling_factor(
532 search_parameters.log_cost_scaling_factor());
533 cp_model.mutable_objective()->set_offset(search_parameters.log_cost_offset());
534 const sat::ArcVarMap arc_vars =
535 sat::PopulateModelFromRoutingModel(
model, &cp_model);
536 sat::AddSolutionAsHintToModel(initial_solution,
model, arc_vars, &cp_model);
537 return sat::ConvertToSolution(
538 sat::SolveRoutingModel(cp_model,
model.RemainingTime(),
nullptr),
model,
#define DCHECK_EQ(val1, val2)
An Assignment is a variable -> domains mapping, used to report solutions to the user.
RoutingTransitCallback1 TransitCallback1
RoutingTransitCallback2 TransitCallback2
SharedResponseManager * response
void InsertOrDie(Collection *const collection, const typename Collection::value_type &value)
bool ContainsKey(const Collection &collection, const Key &key)
const Collection::value_type::second_type * FindOrNull(const Collection &collection, const typename Collection::value_type::first_type &key)
bool operator!=(const STLCountingAllocator< T, A > &a, const STLCountingAllocator< T, A > &b)
H AbslHashValue(H h, const LinearConstraint &linear_constraint)
std::function< void(Model *)> NewFeasibleSolutionObserver(const std::function< void(const CpSolverResponse &response)> &observer)
Creates a solution observer with the model with model.Add(NewFeasibleSolutionObserver([](response){....
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::ostream & operator<<(std::ostream &os, const BoolVar &var)
std::function< SatParameters(Model *)> NewSatParameters(const std::string ¶ms)
Creates parameters for the solver, which you can add to the model with.
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue)
CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model)
Solves the given CpModelProto.
Collection of objects used to extend the Constraint Solver library.
bool SolveModelWithSat(const RoutingModel &model, const RoutingSearchParameters &search_parameters, const Assignment *initial_solution, Assignment *solution)
Attempts to solve the model using the cp-sat solver.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
std::pair< int64_t, int64_t > Arc
LinearRange operator==(const LinearExpr &lhs, const LinearExpr &rhs)