kotoba_core/graph/
algorithms.rs1use std::collections::{HashMap, HashSet, VecDeque};
6use crate::graph::Graph;
7use crate::types::VertexId;
8use crate::types::*;
9
10pub struct GraphTraversal<'a> {
12 graph: &'a Graph,
13 visited: HashSet<VertexId>,
14 queue: VecDeque<VertexId>,
15 stack: Vec<VertexId>,
16}
17
18impl<'a> GraphTraversal<'a> {
19 pub fn new(graph: &'a Graph) -> Self {
21 Self {
22 graph,
23 visited: HashSet::new(),
24 queue: VecDeque::new(),
25 stack: Vec::new(),
26 }
27 }
28
29 pub fn bfs(&mut self, start: VertexId) -> Vec<VertexId> {
31 self.visited.clear();
32 self.queue.clear();
33 let mut result = Vec::new();
34
35 self.visited.insert(start);
36 self.queue.push_back(start);
37
38 while let Some(current) = self.queue.pop_front() {
39 result.push(current);
40
41 if let Some(neighbors) = self.graph.adj_out.get(¤t) {
43 for &neighbor in neighbors {
44 if !self.visited.contains(&neighbor) {
45 self.visited.insert(neighbor);
46 self.queue.push_back(neighbor);
47 }
48 }
49 }
50 }
51
52 result
53 }
54
55 pub fn dfs(&mut self, start: VertexId) -> Vec<VertexId> {
57 self.visited.clear();
58 self.stack.clear();
59 let mut result = Vec::new();
60
61 self.stack.push(start);
62
63 while let Some(current) = self.stack.pop() {
64 if !self.visited.contains(¤t) {
65 self.visited.insert(current);
66 result.push(current);
67
68 if let Some(neighbors) = self.graph.adj_out.get(¤t) {
70 let neighbors_vec: Vec<_> = neighbors.iter().collect();
71 for &neighbor in neighbors_vec.iter().rev() {
72 if !self.visited.contains(&neighbor) {
73 self.stack.push(*neighbor);
74 }
75 }
76 }
77 }
78 }
79
80 result
81 }
82
83 pub fn connected_components(&mut self) -> Vec<Vec<VertexId>> {
85 self.visited.clear();
86 let mut components = Vec::new();
87
88 for &vertex_id in self.graph.vertices.keys() {
89 if !self.visited.contains(&vertex_id) {
90 let component = self.bfs(vertex_id);
91 components.push(component);
92 }
93 }
94
95 components
96 }
97}
98
99pub struct GraphAlgorithms;
101
102impl GraphAlgorithms {
103 pub fn shortest_path(graph: &Graph, start: VertexId, end: VertexId) -> Option<Vec<VertexId>> {
105 if start == end {
106 return Some(vec![start]);
107 }
108
109 let mut visited = HashSet::new();
110 let mut queue = VecDeque::new();
111 let mut parent = HashMap::new();
112
113 visited.insert(start);
114 queue.push_back(start);
115
116 while let Some(current) = queue.pop_front() {
117 if let Some(neighbors) = graph.adj_out.get(¤t) {
118 for &neighbor in neighbors {
119 if !visited.contains(&neighbor) {
120 visited.insert(neighbor);
121 parent.insert(neighbor, current);
122 queue.push_back(neighbor);
123
124 if neighbor == end {
125 let mut path = vec![end];
127 let mut current_vertex = end;
128 while let Some(&parent_vertex) = parent.get(¤t_vertex) {
129 path.push(parent_vertex);
130 current_vertex = parent_vertex;
131 if parent_vertex == start {
132 break;
133 }
134 }
135 path.reverse();
136 return Some(path);
137 }
138 }
139 }
140 }
141 }
142
143 None }
145
146 pub fn topological_sort(graph: &Graph) -> Result<Vec<VertexId>> {
148 let mut in_degree = HashMap::new();
149 let mut queue = VecDeque::new();
150 let mut result = Vec::new();
151
152 for &vertex_id in graph.vertices.keys() {
154 in_degree.insert(vertex_id, 0);
155 }
156
157 for neighbors in graph.adj_in.values() {
158 for &neighbor in neighbors {
159 if let Some(degree) = in_degree.get_mut(&neighbor) {
160 *degree += 1;
161 }
162 }
163 }
164
165 for (&vertex_id, °ree) in &in_degree {
167 if degree == 0 {
168 queue.push_back(vertex_id);
169 }
170 }
171
172 while let Some(current) = queue.pop_front() {
173 result.push(current);
174
175 if let Some(neighbors) = graph.adj_out.get(¤t) {
176 for &neighbor in neighbors {
177 if let Some(degree) = in_degree.get_mut(&neighbor) {
178 *degree -= 1;
179 if *degree == 0 {
180 queue.push_back(neighbor);
181 }
182 }
183 }
184 }
185 }
186
187 if result.len() != graph.vertices.len() {
189 return Err(kotoba_errors::KotobaError::Validation("Graph contains a cycle".to_string()));
190 }
191
192 Ok(result)
193 }
194
195 pub fn strongly_connected_components(graph: &Graph) -> Vec<Vec<VertexId>> {
197 let mut traversal = GraphTraversal::new(graph);
199 traversal.connected_components()
200 }
201
202 pub fn degrees(graph: &Graph) -> HashMap<VertexId, (usize, usize)> {
204 let mut degrees = HashMap::new();
205
206 for &vertex_id in graph.vertices.keys() {
207 let out_degree = graph.adj_out.get(&vertex_id).map(|s| s.len()).unwrap_or(0);
208 let in_degree = graph.adj_in.get(&vertex_id).map(|s| s.len()).unwrap_or(0);
209 degrees.insert(vertex_id, (in_degree, out_degree));
210 }
211
212 degrees
213 }
214
215 pub fn density(graph: &Graph) -> f64 {
217 let n = graph.vertices.len() as f64;
218 let m = graph.edges.len() as f64;
219
220 if n <= 1.0 {
221 0.0
222 } else {
223 2.0 * m / (n * (n - 1.0))
224 }
225 }
226
227 pub fn is_connected(graph: &Graph) -> bool {
229 if graph.vertices.is_empty() {
230 return true;
231 }
232
233 let start = *graph.vertices.keys().next().unwrap();
234 let mut traversal = GraphTraversal::new(graph);
235 let reachable = traversal.bfs(start);
236
237 reachable.len() == graph.vertices.len()
238 }
239
240 pub fn has_cycle(graph: &Graph) -> bool {
242 Self::topological_sort(graph).is_err()
243 }
244}