rust_igraph/algorithms/properties/
is_self_complementary.rs1use crate::algorithms::isomorphism::vf2::isomorphic_vf2;
12use crate::algorithms::operators::complementer::complementer;
13use crate::core::{Graph, IgraphResult};
14
15pub fn is_self_complementary(graph: &Graph) -> IgraphResult<bool> {
46 if graph.is_directed() {
47 return Ok(false);
48 }
49
50 let n = graph.vcount();
51 if n <= 1 {
52 return Ok(true);
53 }
54
55 let n64 = u64::from(n);
56 let total_possible = n64.saturating_mul(n64.saturating_sub(1)) / 2;
57 let ecount = graph.ecount() as u64;
58 if total_possible % 2 != 0 || ecount != total_possible / 2 {
59 return Ok(false);
60 }
61
62 let comp = complementer(graph, false)?;
63 let result = isomorphic_vf2(graph, &comp, None, None, None, None)?;
64
65 Ok(result.iso)
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn empty_graph() {
74 let g = Graph::with_vertices(0);
75 assert!(is_self_complementary(&g).unwrap());
76 }
77
78 #[test]
79 fn single_vertex() {
80 let g = Graph::with_vertices(1);
81 assert!(is_self_complementary(&g).unwrap());
82 }
83
84 #[test]
85 fn k2_not_self_complementary() {
86 let mut g = Graph::with_vertices(2);
88 g.add_edge(0, 1).unwrap();
89 assert!(!is_self_complementary(&g).unwrap());
90 }
91
92 #[test]
93 fn k3_not_self_complementary() {
94 let mut g = Graph::with_vertices(3);
95 g.add_edge(0, 1).unwrap();
96 g.add_edge(1, 2).unwrap();
97 g.add_edge(2, 0).unwrap();
98 assert!(!is_self_complementary(&g).unwrap());
99 }
100
101 #[test]
102 fn path_4_is_self_complementary() {
103 let mut g = Graph::with_vertices(4);
105 g.add_edge(0, 1).unwrap();
106 g.add_edge(1, 2).unwrap();
107 g.add_edge(2, 3).unwrap();
108 assert!(is_self_complementary(&g).unwrap());
109 }
110
111 #[test]
112 fn cycle_5_is_self_complementary() {
113 let mut g = Graph::with_vertices(5);
115 g.add_edge(0, 1).unwrap();
116 g.add_edge(1, 2).unwrap();
117 g.add_edge(2, 3).unwrap();
118 g.add_edge(3, 4).unwrap();
119 g.add_edge(4, 0).unwrap();
120 assert!(is_self_complementary(&g).unwrap());
121 }
122
123 #[test]
124 fn cycle_4_not_self_complementary() {
125 let mut g = Graph::with_vertices(4);
127 g.add_edge(0, 1).unwrap();
128 g.add_edge(1, 2).unwrap();
129 g.add_edge(2, 3).unwrap();
130 g.add_edge(3, 0).unwrap();
131 assert!(!is_self_complementary(&g).unwrap());
132 }
133
134 #[test]
135 fn edgeless_2_not_self_complementary() {
136 let g = Graph::with_vertices(2);
138 assert!(!is_self_complementary(&g).unwrap());
139 }
140
141 #[test]
142 fn edgeless_4_not_self_complementary() {
143 let g = Graph::with_vertices(4);
145 assert!(!is_self_complementary(&g).unwrap());
146 }
147
148 #[test]
149 fn k4_not_self_complementary() {
150 let mut g = Graph::with_vertices(4);
152 for u in 0..4u32 {
153 for v in (u + 1)..4 {
154 g.add_edge(u, v).unwrap();
155 }
156 }
157 assert!(!is_self_complementary(&g).unwrap());
158 }
159
160 #[test]
161 fn star_k13_not_self_complementary() {
162 let mut g = Graph::with_vertices(4);
168 g.add_edge(0, 1).unwrap();
169 g.add_edge(0, 2).unwrap();
170 g.add_edge(0, 3).unwrap();
171 assert!(!is_self_complementary(&g).unwrap());
172 }
173
174 #[test]
175 fn directed_returns_false() {
176 let mut g = Graph::new(4, true).unwrap();
177 g.add_edge(0, 1).unwrap();
178 g.add_edge(1, 2).unwrap();
179 g.add_edge(2, 3).unwrap();
180 assert!(!is_self_complementary(&g).unwrap());
181 }
182
183 #[test]
184 fn three_vertices_not_possible() {
185 let mut g = Graph::with_vertices(3);
188 g.add_edge(0, 1).unwrap();
189 g.add_edge(1, 2).unwrap();
190 assert!(!is_self_complementary(&g).unwrap());
191 }
192
193 #[test]
194 fn bull_graph_is_self_complementary() {
195 let mut g = Graph::with_vertices(5);
197 g.add_edge(0, 1).unwrap();
198 g.add_edge(1, 2).unwrap();
199 g.add_edge(2, 0).unwrap();
200 g.add_edge(0, 3).unwrap();
201 g.add_edge(1, 4).unwrap();
202 assert!(is_self_complementary(&g).unwrap());
203 }
204}