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}