graphalgs/
tournament.rs

1//! Algorithms that simplify work with such type of graphs as a
2//! [tournament](https://en.wikipedia.org/wiki/Tournament_(graph_theory)).
3
4use rand::Rng;
5use std::collections::HashSet;
6use std::hash::Hash;
7
8use crate::traits::EdgeCount;
9use petgraph::visit::{EdgeRef, IntoEdgeReferences, IntoNodeIdentifiers, NodeCount};
10
11/// Is the graph a [tournament](https://en.wikipedia.org/wiki/Tournament_(graph_theory))?
12///
13/// This function checks if the given graph is a tournament and returns the corresponding boolean value.
14///
15/// # Examples
16///
17/// ```
18/// use graphalgs::tournament::is_tournament;
19/// use petgraph::Graph;
20///
21/// let graph = Graph::<(), ()>::from_edges(&[
22///     (0, 2), (1, 0), (1, 2),
23///     (3, 0), (3, 1), (3, 2),
24/// ]);
25///
26/// assert!(is_tournament(&graph));
27///
28/// let graph = Graph::<(), ()>::from_edges(&[
29///     (0, 2), (1, 0), (1, 2),
30///     (3, 0), (3, 1), (1, 3),
31/// ]);
32///
33/// // The graph is not a tournament, because it contains a pair of opposite edges.
34/// assert!(!is_tournament(&graph));
35/// ```
36pub fn is_tournament<G>(graph: G) -> bool
37where
38    G: IntoEdgeReferences + NodeCount + EdgeCount,
39    G::NodeId: Eq + Hash,
40{
41    // Tournament has |V|*(|V|-1)/2 edges.
42    if 2 * graph.number_of_edges() != graph.node_count() * (graph.node_count() - 1) {
43        return false;
44    }
45
46    let mut edges: HashSet<(G::NodeId, G::NodeId)> = HashSet::new();
47
48    for edge in graph.edge_references() {
49        let source = edge.source();
50        let target = edge.target();
51
52        if source == target
53            || edges.contains(&(target, source))
54            || edges.contains(&(source, target))
55        {
56            return false;
57        }
58
59        edges.insert((source, target));
60    }
61
62    true
63}
64
65/// Random tournament on n vertices.
66///
67/// Returns a vector of edges `Vec<(usize, usize)>`.
68///
69/// # Examples
70///
71/// ```
72/// use graphalgs::tournament::{ random_tournament, is_tournament };
73/// use petgraph::{ Graph, Directed };
74///
75/// let graph: Graph::<(), (), Directed, usize> = Graph::from_edges(random_tournament(4));
76/// assert!(is_tournament(&graph));
77/// ```
78pub fn random_tournament(n: usize) -> Vec<(usize, usize)> {
79    if n == 0 {
80        return vec![];
81    }
82
83    let mut rng = rand::thread_rng();
84    let mut edges = Vec::with_capacity(n * (n - 1) / 2);
85
86    for i in 0..n - 1 {
87        for j in i + 1..n {
88            if rng.gen::<bool>() {
89                edges.push((i, j));
90            } else {
91                edges.push((j, i));
92            }
93        }
94    }
95
96    edges
97}
98
99/// Is the tournament transitive?
100///
101/// Check if the tournament is transitive and return the corresponding boolean value.
102///
103/// # Examples
104///
105/// ```
106/// use graphalgs::tournament::is_tournament_transitive;
107/// use petgraph::Graph;
108///
109/// let graph = Graph::<(), ()>::from_edges(&[
110///     (0, 1), (0, 2), (0, 3),
111///     (1, 2), (1, 3), (2, 3),
112/// ]);
113/// assert!(is_tournament_transitive(&graph));
114///
115/// let graph = Graph::<(), ()>::from_edges(&[
116///     (0, 2), (1, 0), (1, 2),
117///     (3, 0), (3, 1), (2, 3),
118/// ]);
119/// assert!(!is_tournament_transitive(&graph));
120/// ```
121pub fn is_tournament_transitive<G>(graph: G) -> bool
122where
123    G: IntoEdgeReferences + NodeCount + EdgeCount + IntoNodeIdentifiers,
124    G::NodeId: Eq + Hash,
125{
126    let mut edges: HashSet<(G::NodeId, G::NodeId)> =
127        HashSet::with_capacity(graph.number_of_edges());
128    edges.extend(
129        graph
130            .edge_references()
131            .map(|edge| (edge.source(), edge.target())),
132    );
133
134    for x in graph.node_identifiers() {
135        for y in graph.node_identifiers() {
136            if x != y {
137                for z in graph.node_identifiers() {
138                    if z != y
139                        && z != x
140                        && edges.contains(&(x, y))
141                        && edges.contains(&(y, z))
142                        && edges.contains(&(z, x))
143                    {
144                        return false;
145                    }
146                }
147            }
148        }
149    }
150
151    true
152}
153
154#[cfg(test)]
155mod tests {
156    use super::*;
157    use petgraph::csr::Csr;
158    use petgraph::graphmap::GraphMap;
159    use petgraph::matrix_graph::MatrixGraph;
160    use petgraph::matrix_graph::UnMatrix;
161    use petgraph::stable_graph::StableGraph;
162    use petgraph::Directed;
163    use petgraph::Graph;
164
165    fn graph1() -> Graph<(), ()> {
166        let mut graph = Graph::new();
167        let n0 = graph.add_node(());
168        let n1 = graph.add_node(());
169        graph.add_node(());
170        graph.add_edge(n0, n1, ());
171        graph
172    }
173
174    fn graph2() -> Graph<(), ()> {
175        let mut graph = Graph::new();
176        let n0 = graph.add_node(());
177        let n1 = graph.add_node(());
178        let n2 = graph.add_node(());
179        graph.add_edge(n0, n1, ());
180        graph.add_edge(n1, n2, ());
181        graph.add_edge(n2, n0, ());
182        graph.add_edge(n2, n1, ());
183        graph
184    }
185
186    fn graph3() -> Graph<(), ()> {
187        Graph::<(), ()>::from_edges([(0, 2), (1, 0), (1, 2), (3, 0), (3, 1), (1, 2)])
188    }
189
190    fn graph4() -> Graph<(), ()> {
191        Graph::<(), ()>::from_edges([(0, 2), (1, 0), (1, 2), (3, 0), (3, 1), (1, 1)])
192    }
193
194    fn graph_tour() -> Graph<(), i32> {
195        let mut graph = Graph::new();
196        let n0 = graph.add_node(());
197        let n1 = graph.add_node(());
198        let n2 = graph.add_node(());
199        graph.add_edge(n0, n1, 0);
200        graph.add_edge(n1, n2, 1);
201        graph.add_edge(n2, n0, 2);
202        graph
203    }
204
205    fn stable_graph_tour() -> StableGraph<(), i32> {
206        let mut graph = StableGraph::new();
207        let n0 = graph.add_node(());
208        let n1 = graph.add_node(());
209        let n2 = graph.add_node(());
210        graph.add_edge(n0, n1, 0);
211        graph.add_edge(n1, n2, 1);
212        graph.add_edge(n2, n0, 2);
213        graph
214    }
215
216    fn graphmap_tour() -> GraphMap<i8, i32, Directed> {
217        let mut graph = GraphMap::new();
218        let n0 = graph.add_node(0);
219        let n1 = graph.add_node(1);
220        let n2 = graph.add_node(2);
221        graph.add_edge(n0, n1, 1);
222        graph.add_edge(n1, n2, 3);
223        graph.add_edge(n0, n2, 2);
224        graph
225    }
226
227    fn matrix_graph_tour() -> UnMatrix<(), i32> {
228        let mut graph = MatrixGraph::new_undirected();
229        let n0 = graph.add_node(());
230        let n1 = graph.add_node(());
231        let n2 = graph.add_node(());
232        graph.add_edge(n0, n1, 0);
233        graph.add_edge(n1, n2, 1);
234        graph.add_edge(n0, n2, 2);
235        graph
236    }
237
238    fn csr_tour() -> Csr<(), i32> {
239        let mut graph = Csr::new();
240        let n0 = graph.add_node(());
241        let n1 = graph.add_node(());
242        let n2 = graph.add_node(());
243        let n3 = graph.add_node(());
244        graph.add_edge(n0, n1, 0);
245        graph.add_edge(n0, n2, 2);
246        graph.add_edge(n0, n3, 3);
247        graph.add_edge(n1, n2, 3);
248        graph.add_edge(n1, n3, 4);
249        graph.add_edge(n2, n3, 5);
250        graph
251    }
252
253    #[test]
254    fn test_is_tournament() {
255        // At the same time testing EdgeCount trait.
256        assert!(!is_tournament(&graph1()));
257        assert!(!is_tournament(&graph2()));
258        assert!(!is_tournament(&graph3()));
259        assert!(!is_tournament(&graph4()));
260        assert!(is_tournament(&graph_tour()));
261        assert!(is_tournament(&stable_graph_tour()));
262        assert!(is_tournament(&graphmap_tour()));
263        assert!(is_tournament(&matrix_graph_tour()));
264        assert!(is_tournament(&csr_tour()));
265    }
266
267    #[test]
268    fn test_random_tournament() {
269        assert_eq!(random_tournament(0), vec![]);
270        assert_eq!(random_tournament(1), vec![]);
271        for i in 2..100 {
272            assert!(is_tournament(
273                &Graph::<(), (), Directed, usize>::from_edges(random_tournament(i))
274            ));
275        }
276    }
277
278    #[test]
279    fn test_is_tournament_transitive() {
280        assert!(!is_tournament_transitive(&graph_tour()));
281        assert!(!is_tournament_transitive(&stable_graph_tour()));
282        assert!(is_tournament_transitive(&graphmap_tour()));
283        assert!(is_tournament_transitive(&matrix_graph_tour()));
284        assert!(is_tournament_transitive(&csr_tour()));
285        assert!(is_tournament_transitive(
286            &Graph::<(), (), Directed, usize>::from_edges(random_tournament(2))
287        ));
288
289        let mut graph = Graph::<(), ()>::new();
290        assert!(is_tournament_transitive(&graph));
291        graph.add_node(());
292        assert!(is_tournament_transitive(&graph));
293    }
294}