Skip to main content

rust_igraph/algorithms/properties/
satisfies_dirac.rs

1//! Dirac's condition for Hamiltonicity (ALGO-PR-118).
2//!
3//! A simple undirected graph on n ≥ 3 vertices satisfies Dirac's
4//! condition if every vertex has degree ≥ n/2. By Dirac's theorem
5//! (1952), such a graph is Hamiltonian (contains a Hamiltonian cycle).
6//!
7//! Returns `false` for directed graphs, graphs with n < 3, or
8//! graphs failing the degree condition.
9
10use crate::core::{Graph, IgraphResult};
11
12/// Check whether a graph satisfies Dirac's condition.
13///
14/// Dirac's condition: every vertex has degree ≥ ⌈n/2⌉ (equivalently
15/// ≥ n/2 for integer arithmetic). A graph satisfying this on n ≥ 3
16/// vertices is guaranteed to be Hamiltonian.
17///
18/// Returns `false` for directed graphs or n < 3.
19///
20/// # Examples
21///
22/// ```
23/// use rust_igraph::{Graph, satisfies_dirac};
24///
25/// // `K_4`: every vertex has degree 3 ≥ 4/2 = 2
26/// let mut g = Graph::with_vertices(4);
27/// for i in 0..4u32 {
28///     for j in (i+1)..4 {
29///         g.add_edge(i, j).unwrap();
30///     }
31/// }
32/// assert!(satisfies_dirac(&g).unwrap());
33///
34/// // `C_5`: each vertex has degree 2 < 5/2 = 2.5 → fails
35/// let mut g = Graph::with_vertices(5);
36/// g.add_edge(0, 1).unwrap();
37/// g.add_edge(1, 2).unwrap();
38/// g.add_edge(2, 3).unwrap();
39/// g.add_edge(3, 4).unwrap();
40/// g.add_edge(4, 0).unwrap();
41/// assert!(!satisfies_dirac(&g).unwrap());
42/// ```
43pub fn satisfies_dirac(graph: &Graph) -> IgraphResult<bool> {
44    if graph.is_directed() {
45        return Ok(false);
46    }
47
48    let n = graph.vcount();
49    if n < 3 {
50        return Ok(false);
51    }
52
53    let threshold = (n as usize).div_ceil(2);
54
55    for v in 0..n {
56        let deg = graph.degree(v)?;
57        if deg < threshold {
58            return Ok(false);
59        }
60    }
61
62    Ok(true)
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn empty_graph() {
71        let g = Graph::with_vertices(0);
72        assert!(!satisfies_dirac(&g).unwrap());
73    }
74
75    #[test]
76    fn single_vertex() {
77        let g = Graph::with_vertices(1);
78        assert!(!satisfies_dirac(&g).unwrap());
79    }
80
81    #[test]
82    fn two_vertices() {
83        let mut g = Graph::with_vertices(2);
84        g.add_edge(0, 1).unwrap();
85        assert!(!satisfies_dirac(&g).unwrap());
86    }
87
88    #[test]
89    fn triangle() {
90        // K_3: deg=2 ≥ 3/2=1 ✓
91        let mut g = Graph::with_vertices(3);
92        g.add_edge(0, 1).unwrap();
93        g.add_edge(1, 2).unwrap();
94        g.add_edge(2, 0).unwrap();
95        assert!(satisfies_dirac(&g).unwrap());
96    }
97
98    #[test]
99    fn complete_k4() {
100        // K_4: deg=3 ≥ 4/2=2 ✓
101        let mut g = Graph::with_vertices(4);
102        for i in 0..4u32 {
103            for j in (i + 1)..4 {
104                g.add_edge(i, j).unwrap();
105            }
106        }
107        assert!(satisfies_dirac(&g).unwrap());
108    }
109
110    #[test]
111    fn complete_k5() {
112        let mut g = Graph::with_vertices(5);
113        for i in 0..5u32 {
114            for j in (i + 1)..5 {
115                g.add_edge(i, j).unwrap();
116            }
117        }
118        assert!(satisfies_dirac(&g).unwrap());
119    }
120
121    #[test]
122    fn c4() {
123        // C_4: deg=2 ≥ 4/2=2 ✓
124        let mut g = Graph::with_vertices(4);
125        g.add_edge(0, 1).unwrap();
126        g.add_edge(1, 2).unwrap();
127        g.add_edge(2, 3).unwrap();
128        g.add_edge(3, 0).unwrap();
129        assert!(satisfies_dirac(&g).unwrap());
130    }
131
132    #[test]
133    fn c5_fails() {
134        // C_5: deg=2 < 5/2=2 (integer: 2 < 2 is false, but 2 < 2.5)
135        // threshold = 5/2 = 2 (integer division). deg=2 ≥ 2 ✓
136        // Actually with integer div, 5/2 = 2, and deg=2 ≥ 2 is true.
137        // Dirac's condition is deg ≥ n/2 where n/2 is real 2.5.
138        // So C_5 does NOT satisfy Dirac (deg 2 < 2.5).
139        // With integer: threshold should be ceil(n/2) = 3.
140        // Wait, Dirac's theorem states δ(G) ≥ n/2 (real division).
141        // For n=5, need deg ≥ 2.5, so min deg must be ≥ 3.
142        // C_5 has deg 2 < 3. So does NOT satisfy.
143        let mut g = Graph::with_vertices(5);
144        g.add_edge(0, 1).unwrap();
145        g.add_edge(1, 2).unwrap();
146        g.add_edge(2, 3).unwrap();
147        g.add_edge(3, 4).unwrap();
148        g.add_edge(4, 0).unwrap();
149        assert!(!satisfies_dirac(&g).unwrap());
150    }
151
152    #[test]
153    fn path_p4_fails() {
154        // P_4: endpoint deg=1 < 4/2=2 → fails
155        let mut g = Graph::with_vertices(4);
156        g.add_edge(0, 1).unwrap();
157        g.add_edge(1, 2).unwrap();
158        g.add_edge(2, 3).unwrap();
159        assert!(!satisfies_dirac(&g).unwrap());
160    }
161
162    #[test]
163    fn star_fails() {
164        // Star: leaves have deg 1 → fails
165        let mut g = Graph::with_vertices(5);
166        g.add_edge(0, 1).unwrap();
167        g.add_edge(0, 2).unwrap();
168        g.add_edge(0, 3).unwrap();
169        g.add_edge(0, 4).unwrap();
170        assert!(!satisfies_dirac(&g).unwrap());
171    }
172
173    #[test]
174    fn directed_returns_false() {
175        let mut g = Graph::new(3, true).unwrap();
176        g.add_edge(0, 1).unwrap();
177        g.add_edge(1, 2).unwrap();
178        g.add_edge(2, 0).unwrap();
179        assert!(!satisfies_dirac(&g).unwrap());
180    }
181
182    #[test]
183    fn complete_bipartite_k33() {
184        // K_{3,3}: deg=3 ≥ 6/2=3 ✓
185        let mut g = Graph::with_vertices(6);
186        for i in 0..3u32 {
187            for j in 3..6u32 {
188                g.add_edge(i, j).unwrap();
189            }
190        }
191        assert!(satisfies_dirac(&g).unwrap());
192    }
193
194    #[test]
195    fn k22_satisfies() {
196        // K_{2,2} = C_4: deg=2 ≥ 4/2=2 ✓
197        let mut g = Graph::with_vertices(4);
198        g.add_edge(0, 2).unwrap();
199        g.add_edge(0, 3).unwrap();
200        g.add_edge(1, 2).unwrap();
201        g.add_edge(1, 3).unwrap();
202        assert!(satisfies_dirac(&g).unwrap());
203    }
204}