rust_igraph/algorithms/properties/
is_tournament.rs1use crate::algorithms::properties::is_simple::is_simple;
11use crate::algorithms::properties::mutual::has_mutual;
12use crate::core::{Graph, IgraphResult};
13
14pub fn is_tournament(graph: &Graph) -> IgraphResult<bool> {
42 if !graph.is_directed() {
43 return Ok(false);
44 }
45
46 let n = graph.vcount();
47 if n <= 1 {
48 return Ok(true);
49 }
50
51 let n_u64 = u64::from(n);
53 let expected = n_u64.saturating_mul(n_u64.saturating_sub(1)) / 2;
54 if graph.ecount() as u64 != expected {
55 return Ok(false);
56 }
57
58 if !is_simple(graph)? {
59 return Ok(false);
60 }
61
62 if has_mutual(graph, false)? {
64 return Ok(false);
65 }
66
67 Ok(true)
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn empty_graph() {
76 let g = Graph::new(0, true).unwrap();
77 assert!(is_tournament(&g).unwrap());
78 }
79
80 #[test]
81 fn single_vertex() {
82 let g = Graph::new(1, true).unwrap();
83 assert!(is_tournament(&g).unwrap());
84 }
85
86 #[test]
87 fn single_arc() {
88 let mut g = Graph::new(2, true).unwrap();
90 g.add_edge(0, 1).unwrap();
91 assert!(is_tournament(&g).unwrap());
92 }
93
94 #[test]
95 fn directed_3cycle() {
96 let mut g = Graph::new(3, true).unwrap();
98 g.add_edge(0, 1).unwrap();
99 g.add_edge(1, 2).unwrap();
100 g.add_edge(2, 0).unwrap();
101 assert!(is_tournament(&g).unwrap());
102 }
103
104 #[test]
105 fn transitive_tournament_3() {
106 let mut g = Graph::new(3, true).unwrap();
108 g.add_edge(0, 1).unwrap();
109 g.add_edge(0, 2).unwrap();
110 g.add_edge(1, 2).unwrap();
111 assert!(is_tournament(&g).unwrap());
112 }
113
114 #[test]
115 fn transitive_tournament_4() {
116 let mut g = Graph::new(4, true).unwrap();
118 g.add_edge(0, 1).unwrap();
119 g.add_edge(0, 2).unwrap();
120 g.add_edge(0, 3).unwrap();
121 g.add_edge(1, 2).unwrap();
122 g.add_edge(1, 3).unwrap();
123 g.add_edge(2, 3).unwrap();
124 assert!(is_tournament(&g).unwrap());
125 }
126
127 #[test]
128 fn undirected_returns_false() {
129 let mut g = Graph::with_vertices(3);
130 g.add_edge(0, 1).unwrap();
131 g.add_edge(1, 2).unwrap();
132 g.add_edge(2, 0).unwrap();
133 assert!(!is_tournament(&g).unwrap());
134 }
135
136 #[test]
137 fn mutual_edge_not_tournament() {
138 let mut g = Graph::new(3, true).unwrap();
140 g.add_edge(0, 1).unwrap();
141 g.add_edge(1, 0).unwrap();
142 g.add_edge(0, 2).unwrap();
143 g.add_edge(1, 2).unwrap();
144 assert!(!is_tournament(&g).unwrap());
146 }
147
148 #[test]
149 fn missing_edge_not_tournament() {
150 let mut g = Graph::new(3, true).unwrap();
152 g.add_edge(0, 1).unwrap();
153 g.add_edge(1, 2).unwrap();
154 assert!(!is_tournament(&g).unwrap());
155 }
156
157 #[test]
158 fn self_loop_not_tournament() {
159 let mut g = Graph::new(2, true).unwrap();
161 g.add_edge(0, 1).unwrap();
162 g.add_edge(0, 0).unwrap();
163 assert!(!is_tournament(&g).unwrap());
165 }
166
167 #[test]
168 fn complete_directed_not_tournament() {
169 let mut g = Graph::new(3, true).unwrap();
171 g.add_edge(0, 1).unwrap();
172 g.add_edge(1, 0).unwrap();
173 g.add_edge(0, 2).unwrap();
174 g.add_edge(2, 0).unwrap();
175 g.add_edge(1, 2).unwrap();
176 g.add_edge(2, 1).unwrap();
177 assert!(!is_tournament(&g).unwrap());
178 }
179
180 #[test]
181 fn two_vertices_no_edge() {
182 let g = Graph::new(2, true).unwrap();
183 assert!(!is_tournament(&g).unwrap());
184 }
185
186 #[test]
187 fn tournament_5_vertices() {
188 let mut g = Graph::new(5, true).unwrap();
190 g.add_edge(0, 1).unwrap();
191 g.add_edge(0, 2).unwrap();
192 g.add_edge(0, 3).unwrap();
193 g.add_edge(0, 4).unwrap();
194 g.add_edge(1, 2).unwrap();
195 g.add_edge(2, 3).unwrap();
196 g.add_edge(3, 4).unwrap();
197 g.add_edge(4, 1).unwrap();
198 g.add_edge(1, 3).unwrap();
199 g.add_edge(4, 2).unwrap();
200 assert!(is_tournament(&g).unwrap());
201 }
202}