heapless_graphs/algorithms/
kahns.rs1use super::ContainerResultExt;
5
6use super::AlgorithmError;
7use crate::containers::{maps::MapTrait, queues::Deque};
8use crate::graph::{Graph, NodeIndex};
9
10pub fn kahns<'a, G, NI, D, M>(
33 graph: &G,
34 mut queue: D,
35 mut in_degree_map: M,
36 sorted_nodes: &'a mut [NI],
37) -> Result<&'a [NI], AlgorithmError<NI>>
38where
39 G: Graph<NI>,
40 NI: NodeIndex,
41 D: Deque<NI>,
42 M: MapTrait<NI, isize>,
43 AlgorithmError<NI>: From<G::Error>,
44{
45 queue.clear();
46
47 let mut sort_index = 0;
48 let mut append_to_list = |node: NI| -> Result<(), AlgorithmError<NI>> {
49 if sort_index >= sorted_nodes.len() {
50 return Err(AlgorithmError::ResultCapacityExceeded);
51 }
52 sorted_nodes[sort_index] = node;
53 sort_index += 1;
54 Ok(())
55 };
56
57 for node in graph.iter_nodes()? {
59 let in_degree = graph.incoming_edges(node)?.count() as isize;
60 in_degree_map.insert(node, in_degree).capacity_error()?;
61 }
62
63 for (node, °ree) in in_degree_map.iter() {
65 if degree == 0 {
66 queue
67 .push_back(*node)
68 .map_err(|_| AlgorithmError::QueueCapacityExceeded)?;
69 }
70 }
71
72 while let Some(node) = queue.pop_front() {
74 append_to_list(node)?;
75
76 for target in graph.outgoing_edges(node)? {
78 if let Some(degree) = in_degree_map.get_mut(&target) {
79 *degree -= 1;
80 if *degree == 0 {
81 queue
82 .push_back(target)
83 .map_err(|_| AlgorithmError::QueueCapacityExceeded)?;
84 }
85 }
86 }
87 }
88
89 for (_, °ree) in in_degree_map.iter() {
91 if degree > 0 {
92 return Err(AlgorithmError::CycleDetected);
93 }
94 }
95
96 Ok(&sorted_nodes[..sort_index])
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::containers::{maps::staticdict::Dictionary, queues::CircularQueue};
103 use crate::edgelist::edge_list::EdgeList;
104
105 #[test]
106 fn test_kahns_simple() {
107 let graph = EdgeList::<8, _, _>::new([(0usize, 1usize), (1, 2)]);
109 let queue = CircularQueue::<usize, 8>::new();
110 let in_degree_map = Dictionary::<usize, isize, 8>::new();
111 let mut sorted_nodes = [0usize; 8];
112
113 let result = kahns(&graph, queue, in_degree_map, &mut sorted_nodes).unwrap();
114
115 assert_eq!(result, &[0, 1, 2]);
116 }
117
118 #[test]
119 fn test_kahns_complex() {
120 let graph = EdgeList::<8, _, _>::new([(0usize, 1usize), (0, 2), (1, 3), (2, 3)]);
122 let queue = CircularQueue::<usize, 8>::new();
123 let in_degree_map = Dictionary::<usize, isize, 8>::new();
124 let mut sorted_nodes = [0usize; 8];
125
126 let result = kahns(&graph, queue, in_degree_map, &mut sorted_nodes).unwrap();
127
128 assert_eq!(result.len(), 4);
129
130 assert_eq!(result[0], 0);
134 assert_eq!(result[result.len() - 1], 3);
135
136 assert!(result.contains(&1));
138 assert!(result.contains(&2));
139 }
140
141 #[test]
142 fn test_kahns_cycle_detection() {
143 let graph = EdgeList::<8, _, _>::new([(0usize, 1usize), (1, 2), (2, 0)]);
145 let queue = CircularQueue::<usize, 8>::new();
146 let in_degree_map = Dictionary::<usize, isize, 8>::new();
147 let mut sorted_nodes = [0usize; 8];
148
149 let error = kahns(&graph, queue, in_degree_map, &mut sorted_nodes);
150
151 assert_eq!(error, Err(AlgorithmError::CycleDetected));
152 }
153
154 #[test]
155 fn test_kahns_disconnected() {
156 let graph = EdgeList::<8, _, _>::new([(0usize, 1usize), (2, 3)]);
158 let queue = CircularQueue::<usize, 8>::new();
159 let in_degree_map = Dictionary::<usize, isize, 8>::new();
160 let mut sorted_nodes = [0usize; 8];
161
162 let result = kahns(&graph, queue, in_degree_map, &mut sorted_nodes).unwrap();
163
164 assert_eq!(result.len(), 4);
165
166 let pos_0 = result.iter().position(|&x| x == 0).unwrap();
168 let pos_1 = result.iter().position(|&x| x == 1).unwrap();
169 let pos_2 = result.iter().position(|&x| x == 2).unwrap();
170 let pos_3 = result.iter().position(|&x| x == 3).unwrap();
171
172 assert!(pos_0 < pos_1); assert!(pos_2 < pos_3); }
175
176 #[test]
177 fn test_kahns_self_loop() {
178 let graph = EdgeList::<8, _, _>::new([(0usize, 0usize)]);
180 let queue = CircularQueue::<usize, 8>::new();
181 let in_degree_map = Dictionary::<usize, isize, 8>::new();
182 let mut sorted_nodes = [0usize; 8];
183
184 let error = kahns(&graph, queue, in_degree_map, &mut sorted_nodes);
185
186 assert_eq!(error, Err(AlgorithmError::CycleDetected));
187 }
188}