rs_graph/algorithms.rs
1// Copyright (c) 2016-2022 Frank Fischer <frank-fischer@shadow-soft.de>
2//
3// This program is free software: you can redistribute it and/or
4// modify it under the terms of the GNU General Public License as
5// published by the Free Software Foundation, either version 3 of the
6// License, or (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful, but
9// WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11// General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program. If not, see <http://www.gnu.org/licenses/>
15//
16
17//! General algorithms working on graphs.
18
19use crate::builder::{Buildable, Builder};
20use crate::traits::{Digraph, Graph, GraphType, IndexDigraph, IndexGraph};
21
22use std::cmp::{max, min};
23use std::collections::HashSet;
24use std::usize;
25
26/// Returns the complement of `g`.
27///
28/// # Example
29///
30/// ```
31/// use rs_graph::LinkedListGraph;
32/// use rs_graph::traits::{Undirected, IndexGraph, FiniteGraph};
33/// use rs_graph::algorithms::complement;
34/// use rs_graph::classes::cycle;
35/// use std::cmp::{min, max};
36///
37/// let g: LinkedListGraph = cycle(5);
38/// let h: LinkedListGraph = complement(&g);
39///
40/// assert_eq!(h.num_nodes(), 5);
41/// assert_eq!(h.num_edges(), 5);
42///
43/// let mut edges: Vec<_> = h.edges().map(|e| {
44/// let (u, v) = h.enodes(e);
45/// let (u, v) = (h.node_id(u), h.node_id(v));
46/// (min(u,v), max(u,v))
47/// }).collect();
48/// edges.sort();
49/// assert_eq!(edges, vec![(0,2), (0,3), (1,3), (1,4), (2,4)]);
50/// ```
51///
52/// Note that this function assumes that `g` is a simple graph (no
53/// loops or double edges). It will work on multi-graphs, too, but
54/// only adjacencies are respected, no multiplicities.
55pub fn complement<G, H>(g: G) -> H
56where
57 G: IndexGraph,
58 H: Graph + Buildable,
59{
60 let mut edges = HashSet::new();
61 for e in g.edges() {
62 let (u, v) = g.enodes(e);
63 edges.insert((min(g.node_id(u), g.node_id(v)), max(g.node_id(u), g.node_id(v))));
64 }
65
66 let n = g.num_nodes();
67 let mut h = H::Builder::with_capacities(n, n * (n - 1) / 2 - g.num_edges());
68 let nodes = h.add_nodes(n);
69 for i in 0..n {
70 for j in i..n {
71 if i < j && !edges.contains(&(i, j)) {
72 h.add_edge(nodes[i], nodes[j]);
73 }
74 }
75 }
76 h.into_graph()
77}
78
79/// Returns the inverse directed graph of `g`.
80///
81/// For $G=(V,A)$ the returned graph is $G=(V,A')$ with
82/// $A' := \{(v,u) \colon (u,v) \in A\}$.
83///
84/// # Example
85///
86/// ```
87/// use rs_graph::{LinkedListGraph, Buildable, Builder};
88/// use rs_graph::algorithms::inverse;
89/// use rs_graph::traits::*;
90///
91/// let g = LinkedListGraph::<usize>::new_with(|b| {
92/// let nodes = b.add_nodes(18);
93/// for &u in &nodes {
94/// for &v in &nodes {
95/// if b.node2id(v) > 0 && b.node2id(u) % b.node2id(v) == 0 {
96/// b.add_edge(u, v);
97/// }
98/// }
99/// }
100/// });
101///
102/// let h: LinkedListGraph = inverse(&g);
103/// assert_eq!(g.num_nodes(), h.num_nodes());
104/// assert_eq!(g.num_edges(), h.num_edges());
105/// for e in h.edges() {
106/// let (u,v) = (h.node_id(h.src(e)), h.node_id(h.snk(e)));
107/// assert!(u > 0 && v % u == 0);
108/// }
109/// ```
110///
111/// Another example to create a star with all edges directed to the center.
112///
113/// ```
114/// use rs_graph::LinkedListGraph;
115/// use rs_graph::traits::*;
116/// use rs_graph::classes::star;
117/// use rs_graph::algorithms::inverse;
118///
119/// type G = LinkedListGraph<usize>;
120/// let g: G = inverse(&star::<G>(42));
121/// assert_eq!(g.num_nodes(), 43);
122/// for e in g.edges() {
123/// let (u,v) = (g.node_id(g.src(e)), g.node_id(g.snk(e)));
124/// assert!(u > 0 && v == 0);
125/// }
126/// ```
127pub fn inverse<G, H>(g: G) -> H
128where
129 G: IndexDigraph,
130 H: Digraph + Buildable,
131{
132 let mut h = H::Builder::with_capacities(g.num_nodes(), g.num_edges());
133 let nodes = h.add_nodes(g.num_nodes());
134 for e in g.edges() {
135 h.add_edge(nodes[g.node_id(g.snk(e))], nodes[g.node_id(g.src(e))]);
136 }
137 h.into_graph()
138}
139
140/// Determines if a graph is connected.
141///
142/// The empty graph is connected.
143///
144/// # Example
145///
146/// ```
147/// use rs_graph::{LinkedListGraph, Graph, Buildable, Builder, classes, algorithms};
148///
149/// let mut g: LinkedListGraph = classes::cycle(5);
150/// assert!(algorithms::is_connected(&g));
151///
152/// let g = LinkedListGraph::<usize>::new_with(|b| {
153/// let nodes = b.add_nodes(5);
154/// for i in 0..5 {
155/// b.add_edge(nodes[i], nodes[(i + 1) % 5]);
156/// }
157/// b.add_node();
158/// });
159///
160/// assert!(!algorithms::is_connected(&g));
161///
162/// ```
163pub fn is_connected<G>(g: &G) -> bool
164where
165 G: IndexGraph,
166{
167 if g.num_nodes() == 0 {
168 return true;
169 }
170
171 let mut seen = vec![false; g.num_nodes()];
172 let mut q = vec![g.id2node(0)];
173
174 while let Some(u) = q.pop() {
175 for (_, v) in g.neighs(u) {
176 let vid = g.node_id(v);
177 if !seen[vid] {
178 seen[vid] = true;
179 q.push(v);
180 }
181 }
182 }
183
184 seen.iter().all(|&u| u)
185}
186
187/// Determines all components of a graph.
188///
189/// The function numbers all components and assigns each node the
190/// number its containing component. The number of components is
191/// returned.
192///
193/// The empty graph has 0 components.
194///
195/// # Example
196///
197/// ```
198/// use rs_graph::LinkedListGraph;
199/// use rs_graph::builder::{Buildable, Builder};
200/// use rs_graph::traits::*;
201/// use rs_graph::{algorithms, classes};
202///
203/// let mut g: LinkedListGraph = classes::cycle(5);
204/// {
205/// let (ncomps, comps) = algorithms::components(&g);
206/// assert_eq!(ncomps, 1);
207/// for u in g.nodes() { assert_eq!(comps[g.node_id(u)], 0); }
208/// }
209///
210/// let mut v = None;
211/// let g = LinkedListGraph::<usize>::new_with(|b| {
212/// let nodes = b.add_nodes(5);
213/// for i in 0..5 {
214/// b.add_edge(nodes[i], nodes[(i + 1) % 5]);
215/// }
216/// v = Some(b.add_node());
217/// });
218///
219/// {
220/// let v = v.unwrap();
221/// let (ncomps, comps) = algorithms::components(&g);
222/// assert_eq!(ncomps, 2);
223/// for u in g.nodes() { assert_eq!(comps[g.node_id(u)], if u == v { 1 } else { 0 }); }
224/// }
225/// ```
226pub fn components<G>(g: &G) -> (usize, Vec<usize>)
227where
228 G: IndexGraph,
229{
230 if g.num_nodes() == 0 {
231 return (0, vec![0; g.num_nodes()]);
232 }
233
234 let mut components = vec![usize::max_value(); g.num_nodes()];
235 let mut q = vec![];
236 let mut nodes = g.nodes();
237 let mut ncomponents = 0;
238
239 loop {
240 // find next node that has not been seen, yet
241 for u in nodes.by_ref() {
242 let uid = g.node_id(u);
243 if components[uid] == usize::MAX {
244 // found a node, start new component
245 components[uid] = ncomponents;
246 q.push(u);
247 ncomponents += 1;
248 break;
249 }
250 }
251
252 // no unseen node found -> stop
253 if q.is_empty() {
254 return (ncomponents, components);
255 }
256
257 // do dfs from this node
258 while let Some(u) = q.pop() {
259 let uid = g.node_id(u);
260 for (_, v) in g.neighs(u) {
261 let vid = g.node_id(v);
262 if components[vid] != components[uid] {
263 components[vid] = components[uid];
264 q.push(v);
265 }
266 }
267 }
268 }
269}
270
271/// Either a node or an edge.
272pub enum Item<'a, G>
273where
274 G: GraphType,
275{
276 Node(G::Node<'a>),
277 Edge(G::Edge<'a>),
278}
279
280/// Return a subgraph.
281///
282/// The resulting graph contains all nodes and edges for which the predicate
283/// returns *true*.
284///
285/// # Example
286/// ```
287/// // Extract a bipartite subgraph.
288/// use rs_graph::LinkedListGraph;
289/// use rs_graph::traits::*;
290/// use rs_graph::classes;
291/// use rs_graph::algorithms::*;
292///
293/// let g: LinkedListGraph = classes::complete_graph(7);
294/// let h: LinkedListGraph = subgraph(&g, |i| match i {
295/// Item::Node(u) => g.node_id(u) < 6,
296/// Item::Edge(e) => {
297/// let (u,v) = g.enodes(e);
298/// g.node_id(u) % 2 != g.node_id(v) % 2
299/// }
300/// });
301///
302/// assert_eq!(h.num_nodes(), 6);
303/// assert_eq!(h.num_edges(), 3*3);
304/// for u in h.nodes() {
305/// let mut neighs = h.neighs(u).map(|(_,v)| h.node_id(v)).collect::<Vec<_>>();
306/// neighs.sort();
307/// assert_eq!(neighs, if h.node_id(u) % 2 == 0 { vec![1,3,5] } else { vec![0,2,4] });
308/// }
309/// ```
310pub fn subgraph<G, H, P>(g: G, predicate: P) -> H
311where
312 G: IndexDigraph,
313 H: Digraph + Buildable,
314 P: Fn(Item<G>) -> bool,
315{
316 let mut h = H::Builder::with_capacities(g.num_nodes(), g.num_edges());
317
318 let mut nodes = Vec::with_capacity(g.num_nodes());
319 for u in g.nodes() {
320 nodes.push(if predicate(Item::Node(u)) {
321 Some(h.add_node())
322 } else {
323 None
324 });
325 }
326
327 for e in g.edges() {
328 let (u, v) = g.enodes(e);
329 if let (Some(u), Some(v)) = (nodes[g.node_id(u)], nodes[g.node_id(v)]) {
330 if predicate(Item::Edge(e)) {
331 h.add_edge(u, v);
332 }
333 }
334 }
335 h.into_graph()
336}
337
338#[cfg(test)]
339mod tests {
340 use crate::algorithms::complement;
341 use crate::classes::*;
342 use crate::linkedlistgraph::{Edge, LinkedListGraph};
343 use crate::traits::*;
344 use std::cmp::{max, min};
345
346 #[test]
347 fn test_complement() {
348 let g: LinkedListGraph = cycle(5);
349 let h: LinkedListGraph = complement(&g);
350 let l: LinkedListGraph = complement(&h);
351
352 fn to_id(g: &LinkedListGraph, e: Edge) -> (usize, usize) {
353 let (u, v) = g.enodes(e);
354 let (u, v) = (g.node_id(u), g.node_id(v));
355 (min(u, v), max(u, v))
356 }
357
358 let mut gedges: Vec<_> = g.edges().map(|e| to_id(&g, e)).collect();
359 gedges.sort();
360
361 let mut hedges: Vec<_> = h.edges().map(|e| to_id(&h, e)).collect();
362 hedges.sort();
363
364 let mut ledges: Vec<_> = g.edges().map(|e| to_id(&l, e)).collect();
365 ledges.sort();
366
367 assert_eq!(hedges, vec![(0, 2), (0, 3), (1, 3), (1, 4), (2, 4)]);
368 assert_eq!(gedges, ledges);
369 }
370}