Skip to content

Commit ba08309

Browse files
committed
graph: export from google3
1 parent a620505 commit ba08309

5 files changed

Lines changed: 376 additions & 7 deletions

File tree

ortools/graph/README.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,129 @@ Flow algorithms:
7676
supplies/demands at nodes, based on the Goldberg-Tarjan push-relabel
7777
algorithm.
7878

79+
## Class design
80+
81+
`BaseGraph` is a generic graph interface on which most algorithms can be built
82+
and provides efficient implementations with a fast construction time. Its design
83+
is based on the experience acquired in various graph algorithm implementations.
84+
85+
The main ideas are:
86+
87+
- Graph nodes and arcs are represented by integers.
88+
89+
- Node or arc annotations (weight, cost, ...) are not part of the graph class,
90+
they can be stored outside in one or more arrays and can be easily retrieved
91+
using a node or arc as an index.
92+
93+
### Terminology
94+
95+
An *arc* (or *forward arc*) of a graph is directed and going from a *tail node*
96+
to a *head node*.
97+
98+
```mermaid
99+
graph TD;
100+
tail -->|arc| head;
101+
```
102+
103+
Node and arc indices are of type `NodeIndexType` and `ArcIndexType`
104+
respectively. Those default to `int32_t`, which allows representing most
105+
practical graphs, but applications that have smaller graphs can improve memory
106+
usage and locality by parameterizing the graph type (e.g. `BaseGraph<int16_t,
107+
int16_t>` allows representing graphs with up to 65k nodes and arcs).
108+
109+
A node or arc index is *valid* if it represents a node or arc of the graph. The
110+
validity ranges are always `[0, num_nodes())` for nodes and `[0, num_arcs())`
111+
for forward arcs. For example, the following graph has 4 nodes numbered 0
112+
through 3 and 5 forward arcs numbered 0 through 4:
113+
114+
```mermaid
115+
graph TD;
116+
0-->|0| 1;
117+
2-->|1| 1;
118+
0-->|2| 2;
119+
3-->|3| 3;
120+
1-->|4| 2;
121+
```
122+
123+
Some graph implementations also store *reverse arcs* and can be used for
124+
undirected graphs or flow-like algorithms. Reverse arcs are elements of
125+
`[-num_arcs(), 0)` and are also considered valid by the implementations that
126+
store them. In the following diagram, reverse arcs are represented with dashed
127+
lines. A reverse arc is created for each forward arc (the forward and
128+
reverse arc in this pair are called *opposite* of each other). This possibly
129+
results in multiarcs:
130+
131+
```mermaid
132+
graph TD;
133+
0-->|0| 1;
134+
1-.->|-1| 0;
135+
2-->|1| 1;
136+
1-.->|-2| 2;
137+
0-->|2| 2;
138+
2-.->|-3| 0;
139+
3-->|3| 3;
140+
3-.->|-4| 3;
141+
1-->|4| 2;
142+
2-.->|-5| 1;
143+
```
144+
145+
#### Graph traversal
146+
147+
- The *outgoing arcs* of a node `v` are the forward arcs whose tail is `v`.
148+
- The *incoming arcs* of `v` are the forward arcs whose head is `v`.
149+
- The *opposite incoming* arcs of `v` are the opposite arcs of the incoming
150+
arcs for `v`.
151+
152+
Forward graph classes allow iteration on outgoing arcs using accessor
153+
`OutgoingArcs()`. Graph classes with both forward and reverse arcs additionally
154+
provide `IncomingArcs` and `OppositeIncomingArcs()`, that return iterators for
155+
the two other categories. They also provide `OutgoingOrOppositeIncomingArcs()`,
156+
which allows iterating both outgoing and opposite incoming arcs at the same
157+
time, which corresponds to iterating forward and reverse arcs *leaving* the
158+
node.
159+
160+
`v` | `OutgoingArcs(v)` | `IncomingArcs(v)` | `OppositeIncomingArcs(v)` | `OutgoingOrOppositeIncoming(v)`
161+
--- | ----------------- | ----------------- | ------------------------- | -------------------------------
162+
0 | {0,2} | {} | {} | {0,2}
163+
1 | {4} | {0,1} | {-2,-1} | {-2,-1,4}
164+
2 | {1} | {2,4} | {-5,-3} | {-5,-3,1}
165+
3 | {3} | {3} | {-4} | {-4,3}
166+
167+
### Graph implementations
168+
169+
- `ListGraph<>`: Simplest API. Iterating outgoing arcs requires `2 + degree`
170+
memory loads.
171+
172+
- `StaticGraph<>`: More memory and speed efficient than `ListGraph<>`, but
173+
requires calling `Build()` once after adding all nodes and arcs. Iterating
174+
outgoing arcs requires only `2` memory loads.
175+
176+
- `ReverseArcListGraph<>` adds reverse arcs to `ListGraph<>`. Iterating
177+
neighboring arcs for a node requires `O(degree)` memory loads.
178+
179+
- `ReverseArcStaticGraph<>` adds reverse arcs to `StaticGraph<>`. Iterating
180+
neighboring arcs for a node requires `O(1)` memory loads.
181+
182+
- `CompleteGraph<>`: If you need a fully connected graph. O(1) memory usage
183+
and much faster than explicitly storing nodes and arcs using
184+
`StaticGraph<>`.
185+
186+
- `CompleteBipartiteGraph<>`: If you need a fully connected bipartite graph.
187+
O(1) memory usage and much faster than explicitly storing nodes and arcs
188+
using `StaticGraph<>`.
189+
190+
- `FlowGraph<>`: A graph specialized for max-flow/min-cost-flow algorithms.
191+
For max-flow or min-cost-flow we need a directed graph where each arc from
192+
tail to head has a reverse arc from head to tail. In practice many input
193+
graphs already have such reverse arc and it can make a big difference just
194+
to reuse them. This is similar to `ReverseArcStaticGraph` but handles
195+
reverse arcs in a different way. Instead of always creating a *new* reverse
196+
arc for each arc of the input graph, this detects if a reverse arc is
197+
already present in the input, and does not create a new one when this is the
198+
case. In the best case, this can gain a factor 2 in the final graph size,
199+
note however that the graph construction is slightly slower because of this
200+
detection.
201+
79202
## Wrappers
80203

81204
* [`python`](python): the SWIG code that makes the wrapper available in Python

ortools/graph/generic_max_flow_test.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,9 @@ void AddSourceAndSink(const typename Graph::NodeIndex num_tails,
352352
}
353353

354354
template <typename Graph>
355-
void GenerateCompleteGraph(const typename Graph::NodeIndex num_tails,
356-
const typename Graph::NodeIndex num_heads,
357-
Graph* graph) {
355+
void GenerateCompleteGraphWithSourceAndSink(
356+
const typename Graph::NodeIndex num_tails,
357+
const typename Graph::NodeIndex num_heads, Graph* graph) {
358358
const typename Graph::NodeIndex num_nodes = num_tails + num_heads + 2;
359359
const typename Graph::ArcIndex num_arcs =
360360
num_tails * num_heads + num_tails + num_heads;
@@ -470,7 +470,7 @@ void FullAssignment(std::optional<FlowQuantity> unused,
470470
typename Graph::NodeIndex num_tails,
471471
typename Graph::NodeIndex num_heads) {
472472
Graph graph;
473-
GenerateCompleteGraph(num_tails, num_heads, &graph);
473+
GenerateCompleteGraphWithSourceAndSink(num_tails, num_heads, &graph);
474474
graph.Build();
475475
std::vector<int64_t> arc_capacity(graph.num_arcs(), 1);
476476
std::unique_ptr<GenericMaxFlow<Graph>> max_flow(new GenericMaxFlow<Graph>(
@@ -590,7 +590,7 @@ void FullRandomFlow(std::optional<FlowQuantity> expected_flow,
590590
const FlowQuantity kCapacityRange = 10000;
591591
const FlowQuantity kCapacityDelta = 1000;
592592
Graph graph;
593-
GenerateCompleteGraph(num_tails, num_heads, &graph);
593+
GenerateCompleteGraphWithSourceAndSink(num_tails, num_heads, &graph);
594594
std::vector<int64_t> arc_capacity(graph.num_arcs());
595595
GenerateRandomArcValuations(random, graph, kCapacityRange, &arc_capacity);
596596

ortools/graph/graph_generator.h

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2010-2025 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 UTIL_GRAPH_GRAPH_GENERATOR_H_
15+
#define UTIL_GRAPH_GRAPH_GENERATOR_H_
16+
17+
// Generates a complete undirected graph with `num_nodes` nodes.
18+
//
19+
// A complete graph is a graph in which all pairs of distinct nodes are
20+
// connected by an edge.
21+
// The graph is represented using the provided `Graph` template.
22+
// If the chosen graph type requires a call to `Build()`, the user is expected
23+
// to perform this call, possibly after tweaking the graph.
24+
//
25+
// Consider using `CompleteGraph` (util/graph/graph.h) instead of this function
26+
// in production code, as it uses constant memory to store the graph. Instead,
27+
// this function explicitly creates the graph using the template type, which is
28+
// mostly useful for tests or when you have to tweak the graph after creation
29+
// (i.e. a complete graph is just the core of your final graph).
30+
//
31+
// Args:
32+
// num_nodes: The number of nodes in the graph.
33+
//
34+
// Returns:
35+
// A complete undirected graph.
36+
template <typename Graph>
37+
Graph GenerateCompleteUndirectedGraph(
38+
const typename Graph::NodeIndex num_nodes) {
39+
Graph graph;
40+
graph.Reserve(num_nodes, num_nodes * (num_nodes - 1));
41+
graph.AddNode(num_nodes - 1); // Only for degenerate cases with no arcs.
42+
for (typename Graph::NodeIndex src = 0; src < num_nodes; ++src) {
43+
for (typename Graph::NodeIndex dst = src + 1; dst < num_nodes; ++dst) {
44+
graph.AddArc(src, dst);
45+
graph.AddArc(dst, src);
46+
}
47+
}
48+
return graph;
49+
}
50+
51+
// Generates a complete undirected bipartite graph with `num_nodes_1` and
52+
// `num_nodes_2` nodes in each part.
53+
//
54+
// A complete bipartite graph is a graph in which all pairs of distinct nodes,
55+
// one in each part, are connected by an edge.
56+
// The graph is represented using the provided `Graph` template.
57+
// If the chosen graph type requires a call to `Build()`, the user is expected
58+
// to perform this call, possibly after tweaking the graph.
59+
//
60+
// Args:
61+
// num_nodes_1: The number of nodes in the first part of the graph.
62+
// num_nodes_2: The number of nodes in the second part of the graph.
63+
//
64+
// Returns:
65+
// A complete undirected bipartite graph.
66+
template <typename Graph>
67+
Graph GenerateCompleteUndirectedBipartiteGraph(
68+
const typename Graph::NodeIndex num_nodes_1,
69+
const typename Graph::NodeIndex num_nodes_2) {
70+
Graph graph;
71+
graph.Reserve(num_nodes_1 + num_nodes_2, 2 * num_nodes_1 * num_nodes_2);
72+
graph.AddNode(num_nodes_1 + num_nodes_2 - 1); // Only for degenerate cases.
73+
for (typename Graph::NodeIndex src = 0; src < num_nodes_1; ++src) {
74+
for (typename Graph::NodeIndex dst = 0; dst < num_nodes_2; ++dst) {
75+
graph.AddArc(src, num_nodes_1 + dst);
76+
graph.AddArc(num_nodes_1 + dst, src);
77+
}
78+
}
79+
return graph;
80+
}
81+
82+
// Generates a complete directed bipartite graph with `num_nodes_1` and
83+
// `num_nodes_2` nodes in each part.
84+
//
85+
// A complete bipartite graph is a graph in which all pairs of distinct nodes,
86+
// one in each part, are connected by an edge. Edges are directed from the first
87+
// part towards the second part.
88+
// The graph is represented using the provided `Graph` template.
89+
// If the chosen graph type requires a call to `Build()`, the user is expected
90+
// to perform this call, possibly after tweaking the graph.
91+
//
92+
// Consider using `CompleteBipartiteGraph` (util/graph/graph.h) instead of this
93+
// function in production code, as it uses constant memory to store the graph.
94+
// Instead, this function explicitly creates the graph using the template type,
95+
// which is mostly useful for tests or when you have to tweak the graph after
96+
// creation (i.e. a complete graph is just the core of your final graph).
97+
//
98+
// Args:
99+
// num_nodes_1: The number of nodes in the first part of the graph.
100+
// num_nodes_2: The number of nodes in the second part of the graph.
101+
//
102+
// Returns:
103+
// A complete directed bipartite graph.
104+
template <typename Graph>
105+
Graph GenerateCompleteDirectedBipartiteGraph(
106+
const typename Graph::NodeIndex num_nodes_1,
107+
const typename Graph::NodeIndex num_nodes_2) {
108+
Graph graph;
109+
graph.Reserve(num_nodes_1 + num_nodes_2, num_nodes_1 * num_nodes_2);
110+
graph.AddNode(num_nodes_1 + num_nodes_2 - 1); // Only for degenerate cases.
111+
for (typename Graph::NodeIndex src = 0; src < num_nodes_1; ++src) {
112+
for (typename Graph::NodeIndex dst = 0; dst < num_nodes_2; ++dst) {
113+
graph.AddArc(src, num_nodes_1 + dst);
114+
}
115+
}
116+
return graph;
117+
}
118+
119+
#endif // UTIL_GRAPH_GRAPH_GENERATOR_H_

0 commit comments

Comments
 (0)