rust_igraph/algorithms/properties/
is_strongly_chordal.rs1use crate::algorithms::chordality::{is_chordal, maximum_cardinality_search};
13use crate::core::{Graph, IgraphResult};
14
15pub fn is_strongly_chordal(graph: &Graph) -> IgraphResult<bool> {
53 let n = graph.vcount();
54 if n <= 3 {
55 let chordal = is_chordal(graph, None)?;
56 return Ok(chordal.chordal);
57 }
58
59 let chordal = is_chordal(graph, None)?;
60 if !chordal.chordal {
61 return Ok(false);
62 }
63
64 let n_usize = n as usize;
65 let mut adj = vec![vec![false; n_usize]; n_usize];
66 for v in 0..n {
67 let nbrs = graph.neighbors(v)?;
68 for &w in &nbrs {
69 adj[v as usize][w as usize] = true;
70 adj[w as usize][v as usize] = true;
71 }
72 }
73
74 let mcs = maximum_cardinality_search(graph)?;
76 let order = &mcs.alpham1;
78
79 let mut position = vec![0usize; n_usize];
81 for (i, &v) in order.iter().enumerate() {
82 position[v as usize] = i;
83 }
84
85 for (i, &vi) in order.iter().enumerate() {
90 let v = vi as usize;
91 let later_nbrs: Vec<usize> = (0..n_usize)
92 .filter(|&u| adj[v][u] && position[u] > i)
93 .collect();
94
95 if later_nbrs.len() <= 1 {
96 continue;
97 }
98
99 for (a_idx, &a) in later_nbrs.iter().enumerate() {
102 for &b in &later_nbrs[(a_idx + 1)..] {
103 let nbrs_a: Vec<usize> = (0..n_usize)
104 .filter(|&x| adj[a][x] && position[x] > i)
105 .collect();
106 let nbrs_b: Vec<usize> = (0..n_usize)
107 .filter(|&x| adj[b][x] && position[x] > i)
108 .collect();
109
110 let a_sub_b = nbrs_a.iter().all(|x| adj[b][*x] || *x == b);
112 let b_sub_a = nbrs_b.iter().all(|x| adj[a][*x] || *x == a);
113
114 if !a_sub_b && !b_sub_a {
115 return Ok(false);
116 }
117 }
118 }
119 }
120
121 Ok(true)
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn empty_graph() {
130 let g = Graph::with_vertices(0);
131 assert!(is_strongly_chordal(&g).unwrap());
132 }
133
134 #[test]
135 fn single_vertex() {
136 let g = Graph::with_vertices(1);
137 assert!(is_strongly_chordal(&g).unwrap());
138 }
139
140 #[test]
141 fn single_edge() {
142 let mut g = Graph::with_vertices(2);
143 g.add_edge(0, 1).unwrap();
144 assert!(is_strongly_chordal(&g).unwrap());
145 }
146
147 #[test]
148 fn triangle() {
149 let mut g = Graph::with_vertices(3);
150 g.add_edge(0, 1).unwrap();
151 g.add_edge(1, 2).unwrap();
152 g.add_edge(2, 0).unwrap();
153 assert!(is_strongly_chordal(&g).unwrap());
154 }
155
156 #[test]
157 fn complete_k4() {
158 let mut g = Graph::with_vertices(4);
159 for i in 0..4u32 {
160 for j in (i + 1)..4 {
161 g.add_edge(i, j).unwrap();
162 }
163 }
164 assert!(is_strongly_chordal(&g).unwrap());
165 }
166
167 #[test]
168 fn complete_k5() {
169 let mut g = Graph::with_vertices(5);
170 for i in 0..5u32 {
171 for j in (i + 1)..5 {
172 g.add_edge(i, j).unwrap();
173 }
174 }
175 assert!(is_strongly_chordal(&g).unwrap());
176 }
177
178 #[test]
179 fn tree() {
180 let mut g = Graph::with_vertices(5);
182 g.add_edge(0, 1).unwrap();
183 g.add_edge(1, 2).unwrap();
184 g.add_edge(1, 3).unwrap();
185 g.add_edge(3, 4).unwrap();
186 assert!(is_strongly_chordal(&g).unwrap());
187 }
188
189 #[test]
190 fn sun_3_not_strongly_chordal() {
191 let mut g = Graph::with_vertices(6);
195 g.add_edge(0, 1).unwrap();
196 g.add_edge(1, 2).unwrap();
197 g.add_edge(2, 0).unwrap();
198 g.add_edge(3, 0).unwrap();
199 g.add_edge(3, 1).unwrap();
200 g.add_edge(4, 1).unwrap();
201 g.add_edge(4, 2).unwrap();
202 g.add_edge(5, 2).unwrap();
203 g.add_edge(5, 0).unwrap();
204 assert!(!is_strongly_chordal(&g).unwrap());
205 }
206
207 #[test]
208 fn c4_not_chordal() {
209 let mut g = Graph::with_vertices(4);
211 g.add_edge(0, 1).unwrap();
212 g.add_edge(1, 2).unwrap();
213 g.add_edge(2, 3).unwrap();
214 g.add_edge(3, 0).unwrap();
215 assert!(!is_strongly_chordal(&g).unwrap());
216 }
217
218 #[test]
219 fn star() {
220 let mut g = Graph::with_vertices(5);
222 g.add_edge(0, 1).unwrap();
223 g.add_edge(0, 2).unwrap();
224 g.add_edge(0, 3).unwrap();
225 g.add_edge(0, 4).unwrap();
226 assert!(is_strongly_chordal(&g).unwrap());
227 }
228
229 #[test]
230 fn path() {
231 let mut g = Graph::with_vertices(5);
232 g.add_edge(0, 1).unwrap();
233 g.add_edge(1, 2).unwrap();
234 g.add_edge(2, 3).unwrap();
235 g.add_edge(3, 4).unwrap();
236 assert!(is_strongly_chordal(&g).unwrap());
237 }
238
239 #[test]
240 fn diamond_strongly_chordal() {
241 let mut g = Graph::with_vertices(4);
243 g.add_edge(0, 1).unwrap();
244 g.add_edge(0, 2).unwrap();
245 g.add_edge(0, 3).unwrap();
246 g.add_edge(1, 2).unwrap();
247 g.add_edge(1, 3).unwrap();
248 assert!(is_strongly_chordal(&g).unwrap());
250 }
251
252 #[test]
253 fn edgeless() {
254 let g = Graph::with_vertices(4);
255 assert!(is_strongly_chordal(&g).unwrap());
256 }
257
258 #[test]
259 fn directed_treated_as_undirected() {
260 let mut g = Graph::new(3, true).unwrap();
261 g.add_edge(0, 1).unwrap();
262 g.add_edge(1, 2).unwrap();
263 g.add_edge(2, 0).unwrap();
264 assert!(is_strongly_chordal(&g).unwrap());
265 }
266}