1use rand::Rng;
5use std::collections::HashSet;
6use std::hash::Hash;
7
8use crate::traits::EdgeCount;
9use petgraph::visit::{EdgeRef, IntoEdgeReferences, IntoNodeIdentifiers, NodeCount};
10
11pub fn is_tournament<G>(graph: G) -> bool
37where
38 G: IntoEdgeReferences + NodeCount + EdgeCount,
39 G::NodeId: Eq + Hash,
40{
41 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
65pub 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
99pub 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 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}