flow_rs_core/graph/
traversal.rs1use std::collections::{HashMap, HashSet, VecDeque};
4
5use crate::error::{FlowError, Result};
6use crate::types::NodeId;
7
8use super::Graph;
9
10impl<N, E> Graph<N, E>
11where
12 N: Clone,
13 E: Clone,
14{
15 pub fn has_cycle(&self) -> bool {
20 let mut visited = HashSet::new();
21 let mut rec_stack = HashSet::new();
22
23 for node_id in self.node_ids() {
25 if !visited.contains(node_id)
26 && self.has_cycle_dfs(node_id, &mut visited, &mut rec_stack)
27 {
28 return true;
29 }
30 }
31
32 false
33 }
34
35 fn has_cycle_dfs(
37 &self,
38 node_id: &NodeId,
39 visited: &mut HashSet<NodeId>,
40 rec_stack: &mut HashSet<NodeId>,
41 ) -> bool {
42 visited.insert(node_id.clone());
43 rec_stack.insert(node_id.clone());
44
45 for edge in self.get_outgoing_edges(node_id) {
48 let neighbor = &edge.target;
49
50 if !visited.contains(neighbor) {
52 if self.has_cycle_dfs(neighbor, visited, rec_stack) {
53 return true;
54 }
55 }
56 else if rec_stack.contains(neighbor) {
58 return true;
59 }
60 }
61
62 rec_stack.remove(node_id);
63 false
64 }
65
66 pub fn creates_cycle(&self, source: &NodeId, target: &NodeId) -> bool {
71 if !self.nodes.contains_key(source) || !self.nodes.contains_key(target) {
73 return false;
74 }
75
76 self.can_reach(target, source)
78 }
79
80 fn can_reach(&self, from: &NodeId, to: &NodeId) -> bool {
82 if from == to {
83 return true;
84 }
85
86 let mut visited = HashSet::new();
87 let mut queue = VecDeque::new();
88
89 queue.push_back(from.clone());
90 visited.insert(from.clone());
91
92 while let Some(current) = queue.pop_front() {
93 for edge in self.get_outgoing_edges(¤t) {
96 let neighbor = &edge.target;
97
98 if neighbor == to {
99 return true;
100 }
101
102 if !visited.contains(neighbor) {
103 visited.insert(neighbor.clone());
104 queue.push_back(neighbor.clone());
105 }
106 }
107 }
108
109 false
110 }
111
112 pub fn find_cycle(&self) -> Option<Vec<NodeId>> {
118 let mut visited = HashSet::new();
119 let mut rec_stack = HashSet::new();
120 let mut parent = HashMap::new();
121
122 for node_id in self.node_ids() {
124 if !visited.contains(node_id) {
125 if let Some(cycle) =
126 self.find_cycle_dfs(node_id, &mut visited, &mut rec_stack, &mut parent)
127 {
128 return Some(cycle);
129 }
130 }
131 }
132
133 None
134 }
135
136 fn find_cycle_dfs(
138 &self,
139 node_id: &NodeId,
140 visited: &mut HashSet<NodeId>,
141 rec_stack: &mut HashSet<NodeId>,
142 parent: &mut HashMap<NodeId, NodeId>,
143 ) -> Option<Vec<NodeId>> {
144 visited.insert(node_id.clone());
145 rec_stack.insert(node_id.clone());
146
147 for edge in self.get_outgoing_edges(node_id) {
150 let neighbor = &edge.target;
151
152 if !visited.contains(neighbor) {
154 parent.insert(neighbor.clone(), node_id.clone());
155 if let Some(cycle) = self.find_cycle_dfs(neighbor, visited, rec_stack, parent) {
156 return Some(cycle);
157 }
158 }
159 else if rec_stack.contains(neighbor) {
161 let mut cycle = vec![neighbor.clone()];
163 let mut current = node_id.clone();
164
165 while current != *neighbor {
167 cycle.push(current.clone());
168 current = parent.get(¤t).unwrap_or(¤t).clone();
169 }
170
171 cycle.reverse();
172 return Some(cycle);
173 }
174 }
175
176 rec_stack.remove(node_id);
177 None
178 }
179
180 pub fn topological_sort(&self) -> Result<Vec<NodeId>> {
187 let mut in_degree: HashMap<NodeId, usize> = HashMap::new();
189
190 for node_id in self.node_ids() {
192 in_degree.insert(node_id.clone(), 0);
193 }
194
195 for edge in self.edges() {
197 *in_degree.entry(edge.target.clone()).or_insert(0) += 1;
198 }
199
200 let mut queue = VecDeque::new();
202 for (node_id, °ree) in &in_degree {
203 if degree == 0 {
204 queue.push_back(node_id.clone());
205 }
206 }
207
208 let mut result = Vec::new();
209
210 while let Some(node_id) = queue.pop_front() {
211 result.push(node_id.clone());
212
213 for edge in self.edges() {
215 if edge.source == node_id {
216 let neighbor = &edge.target;
217 if let Some(degree) = in_degree.get_mut(neighbor) {
218 *degree -= 1;
219 if *degree == 0 {
220 queue.push_back(neighbor.clone());
221 }
222 }
223 }
224 }
225 }
226
227 if result.len() != self.node_count() {
229 return Err(FlowError::invalid_operation(
230 "Graph contains cycles - topological sort not possible",
231 ));
232 }
233
234 Ok(result)
235 }
236}