rust_igraph/algorithms/properties/
is_path.rs1use crate::algorithms::paths::dijkstra::DijkstraMode;
10use crate::algorithms::properties::is_tree::is_tree;
11use crate::core::{Graph, IgraphResult};
12
13pub fn is_path(graph: &Graph) -> IgraphResult<bool> {
42 if graph.is_directed() {
43 return Ok(false);
44 }
45
46 let n = graph.vcount();
47 if n == 0 {
48 return Ok(true);
49 }
50
51 if is_tree(graph, DijkstraMode::All)?.is_none() {
52 return Ok(false);
53 }
54
55 for v in 0..n {
56 if graph.degree(v)? > 2 {
57 return Ok(false);
58 }
59 }
60
61 Ok(true)
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn empty_graph() {
70 let g = Graph::with_vertices(0);
71 assert!(is_path(&g).unwrap());
72 }
73
74 #[test]
75 fn single_vertex() {
76 let g = Graph::with_vertices(1);
77 assert!(is_path(&g).unwrap());
78 }
79
80 #[test]
81 fn single_edge() {
82 let mut g = Graph::with_vertices(2);
83 g.add_edge(0, 1).unwrap();
84 assert!(is_path(&g).unwrap());
85 }
86
87 #[test]
88 fn p3() {
89 let mut g = Graph::with_vertices(3);
90 g.add_edge(0, 1).unwrap();
91 g.add_edge(1, 2).unwrap();
92 assert!(is_path(&g).unwrap());
93 }
94
95 #[test]
96 fn p5() {
97 let mut g = Graph::with_vertices(5);
98 g.add_edge(0, 1).unwrap();
99 g.add_edge(1, 2).unwrap();
100 g.add_edge(2, 3).unwrap();
101 g.add_edge(3, 4).unwrap();
102 assert!(is_path(&g).unwrap());
103 }
104
105 #[test]
106 fn star_not_path() {
107 let mut g = Graph::with_vertices(4);
108 g.add_edge(0, 1).unwrap();
109 g.add_edge(0, 2).unwrap();
110 g.add_edge(0, 3).unwrap();
111 assert!(!is_path(&g).unwrap());
112 }
113
114 #[test]
115 fn cycle_not_path() {
116 let mut g = Graph::with_vertices(4);
117 g.add_edge(0, 1).unwrap();
118 g.add_edge(1, 2).unwrap();
119 g.add_edge(2, 3).unwrap();
120 g.add_edge(3, 0).unwrap();
121 assert!(!is_path(&g).unwrap());
122 }
123
124 #[test]
125 fn triangle_not_path() {
126 let mut g = Graph::with_vertices(3);
127 g.add_edge(0, 1).unwrap();
128 g.add_edge(1, 2).unwrap();
129 g.add_edge(2, 0).unwrap();
130 assert!(!is_path(&g).unwrap());
131 }
132
133 #[test]
134 fn caterpillar_not_path() {
135 let mut g = Graph::with_vertices(5);
136 g.add_edge(0, 1).unwrap();
137 g.add_edge(1, 2).unwrap();
138 g.add_edge(2, 3).unwrap();
139 g.add_edge(1, 4).unwrap();
140 assert!(!is_path(&g).unwrap());
141 }
142
143 #[test]
144 fn disconnected_not_path() {
145 let mut g = Graph::with_vertices(4);
146 g.add_edge(0, 1).unwrap();
147 g.add_edge(2, 3).unwrap();
148 assert!(!is_path(&g).unwrap());
149 }
150
151 #[test]
152 fn directed_returns_false() {
153 let mut g = Graph::new(3, true).unwrap();
154 g.add_edge(0, 1).unwrap();
155 g.add_edge(1, 2).unwrap();
156 assert!(!is_path(&g).unwrap());
157 }
158
159 #[test]
160 fn two_isolated_vertices_not_path() {
161 let g = Graph::with_vertices(2);
162 assert!(!is_path(&g).unwrap());
163 }
164
165 #[test]
166 fn path_non_sequential_edges() {
167 let mut g = Graph::with_vertices(4);
169 g.add_edge(3, 1).unwrap();
170 g.add_edge(1, 0).unwrap();
171 g.add_edge(0, 2).unwrap();
172 assert!(is_path(&g).unwrap());
173 }
174}