Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
routing_cuts.h
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#ifndef OR_TOOLS_SAT_ROUTING_CUTS_H_
15#define OR_TOOLS_SAT_ROUTING_CUTS_H_
16
17#include <stdint.h>
18
19#include <functional>
20#include <limits>
21#include <optional>
22#include <utility>
23#include <vector>
24
25#include "absl/types/span.h"
26#include "ortools/sat/cp_model.pb.h"
27#include "ortools/sat/cuts.h"
28#include "ortools/sat/integer.h"
29#include "ortools/sat/model.h"
31
32namespace operations_research {
33namespace sat {
34
35// Given a graph with nodes in [0, num_nodes) and a set of arcs (the order is
36// important), this will:
37// - Start with each nodes in separate "subsets".
38// - Consider the arc in order, and each time one connects two separate
39// subsets, merge the two subsets into a new one.
40// - Stops when there is only 2 subset left.
41// - Output all subsets generated this way (at most 2 * num_nodes). The
42// subsets spans will point in the subset_data vector (which will be of size
43// exactly num_nodes).
44//
45// This is an heuristic to generate interesting cuts for TSP or other graph
46// based constraints. We roughly follow the algorithm described in section 6 of
47// "The Traveling Salesman Problem, A computational Study", David L. Applegate,
48// Robert E. Bixby, Vasek Chvatal, William J. Cook.
49//
50// Note that this is mainly a "symmetric" case algo, but it does still work for
51// the asymmetric case.
52void GenerateInterestingSubsets(int num_nodes,
53 const std::vector<std::pair<int, int>>& arcs,
54 int stop_at_num_components,
55 std::vector<int>* subset_data,
56 std::vector<absl::Span<const int>>* subsets);
57
58// Given a set of rooted tree on n nodes represented by the parent vector,
59// returns the n sets of nodes corresponding to all the possible subtree. Note
60// that the output memory is just n as all subset will point into the same
61// vector.
62//
63// This assumes no cycles, otherwise it will not crash but the result will not
64// be correct.
65//
66// In the TSP context, if the tree is a Gomory-Hu cut tree, this will returns
67// a set of "min-cut" that contains a min-cut for all node pairs.
68//
69// TODO(user): This also allocate O(n) memory internally, we could reuse it from
70// call to call if needed.
72 const std::vector<int>& parent, std::vector<int>* subset_data,
73 std::vector<absl::Span<const int>>* subsets,
74 int node_limit = std::numeric_limits<int>::max());
75
76// In the routing context, we usually always have lp_value in [0, 1] and only
77// looks at arcs with a lp_value that is not too close to zero.
79 int tail;
80 int head;
81 double lp_value;
82
83 bool operator==(const ArcWithLpValue& o) const {
84 return tail == o.tail && head == o.head && lp_value == o.lp_value;
85 }
86};
87
88// Regroups and sum the lp values on duplicate arcs or reversed arcs
89// (tail->head) and (head->tail). As a side effect, we will always
90// have tail <= head.
91void SymmetrizeArcs(std::vector<ArcWithLpValue>* arcs);
92
93// Given a set of arcs on a directed graph with n nodes (in [0, num_nodes)),
94// returns a "parent" vector of size n encoding a rooted Gomory-Hu tree.
95//
96// Note that usually each edge in the tree is attached a max-flow value (its
97// weight), but we don't need it here. It can be added if needed. This tree as
98// the property that for all (s, t) pair of nodes, if you take the minimum
99// weight edge on the path from s to t and split the tree in two, then this is a
100// min-cut for that pair.
101//
102// IMPORTANT: This algorithm currently "symmetrize" the graph, so we will
103// actually have all the min-cuts that minimize sum incoming + sum outgoing lp
104// values. The algo do not work as is on an asymmetric graph. Note however that
105// because of flow conservation, our outgoing lp values should be the same as
106// our incoming one on a circuit/route constraint.
107//
108// We use a simple implementation described in "Very Simple Methods for All
109// Pairs Network Flow Analysis", Dan Gusfield, 1990,
110// https://ranger.uta.edu/~weems/NOTES5311/LAB/LAB2SPR21/gusfield.huGomory.pdf
111std::vector<int> ComputeGomoryHuTree(
112 int num_nodes, const std::vector<ArcWithLpValue>& relevant_arcs);
113
114// Cut generator for the circuit constraint, where in any feasible solution, the
115// arcs that are present (variable at 1) must form a circuit through all the
116// nodes of the graph. Self arc are forbidden in this case.
117//
118// In more generality, this currently enforce the resulting graph to be strongly
119// connected. Note that we already assume basic constraint to be in the lp, so
120// we do not add any cuts for components of size 1.
122 int num_nodes, std::vector<int> tails, std::vector<int> heads,
123 std::vector<Literal> literals, Model* model);
124
125// Almost the same as CreateStronglyConnectedGraphCutGenerator() but for each
126// components, computes the demand needed to serves it, and depending on whether
127// it contains the depot (node zero) or not, compute the minimum number of
128// vehicle that needs to cross the component border.
129CutGenerator CreateCVRPCutGenerator(int num_nodes, std::vector<int> tails,
130 std::vector<int> heads,
131 std::vector<Literal> literals,
132 std::vector<int64_t> demands,
133 int64_t capacity, Model* model);
134
135// Try to find a subset where the current LP capacity of the outgoing or
136// incoming arc is not enough to satisfy the demands.
137//
138// We support the special value -1 for tail or head that means that the arc
139// comes from (or is going to) outside the nodes in [0, num_nodes). Such arc
140// must still have a capacity assigned to it.
141//
142// TODO(user): Support general linear expression for capacities.
143// TODO(user): Some model applies the same capacity to both an arc and its
144// reverse. Also support this case.
145CutGenerator CreateFlowCutGenerator(
146 int num_nodes, const std::vector<int>& tails, const std::vector<int>& heads,
147 const std::vector<AffineExpression>& arc_capacities,
148 std::function<void(const std::vector<bool>& in_subset,
149 IntegerValue* min_incoming_flow,
150 IntegerValue* min_outgoing_flow)>
151 get_flows,
152 Model* model);
153
154} // namespace sat
155} // namespace operations_research
156
157#endif // OR_TOOLS_SAT_ROUTING_CUTS_H_
GRBmodel * model
std::vector< int > ComputeGomoryHuTree(int num_nodes, const std::vector< ArcWithLpValue > &relevant_arcs)
CutGenerator CreateCVRPCutGenerator(int num_nodes, std::vector< int > tails, std::vector< int > heads, std::vector< Literal > literals, std::vector< int64_t > demands, int64_t capacity, Model *model)
CutGenerator CreateStronglyConnectedGraphCutGenerator(int num_nodes, std::vector< int > tails, std::vector< int > heads, std::vector< Literal > literals, Model *model)
CutGenerator CreateFlowCutGenerator(int num_nodes, const std::vector< int > &tails, const std::vector< int > &heads, const std::vector< AffineExpression > &arc_capacities, std::function< void(const std::vector< bool > &in_subset, IntegerValue *min_incoming_flow, IntegerValue *min_outgoing_flow)> get_flows, Model *model)
void ExtractAllSubsetsFromForest(const std::vector< int > &parent, std::vector< int > *subset_data, std::vector< absl::Span< const int > > *subsets, int node_limit)
void GenerateInterestingSubsets(int num_nodes, const std::vector< std::pair< int, int > > &arcs, int stop_at_num_components, std::vector< int > *subset_data, std::vector< absl::Span< const int > > *subsets)
void SymmetrizeArcs(std::vector< ArcWithLpValue > *arcs)
In SWIG mode, we don't want anything besides these top-level includes.
bool operator==(const ArcWithLpValue &o) const