oxihuman_core/
dep_graph_simple.rs1#![allow(dead_code)]
4
5pub struct DepGraph {
7 pub nodes: Vec<String>,
8 pub edges: Vec<(usize, usize)>,
9}
10
11impl DepGraph {
12 pub fn new() -> Self {
13 DepGraph {
14 nodes: Vec::new(),
15 edges: Vec::new(),
16 }
17 }
18}
19
20impl Default for DepGraph {
21 fn default() -> Self {
22 Self::new()
23 }
24}
25
26pub fn new_dep_graph() -> DepGraph {
27 DepGraph::new()
28}
29
30pub fn dep_add_node(g: &mut DepGraph, name: &str) -> usize {
31 let idx = g.nodes.len();
32 g.nodes.push(name.to_string());
33 idx
34}
35
36pub fn dep_add_edge(g: &mut DepGraph, from: usize, to: usize) {
37 g.edges.push((from, to));
38}
39
40pub fn dep_node_count(g: &DepGraph) -> usize {
41 g.nodes.len()
42}
43
44pub fn dep_topo_sort(g: &DepGraph) -> Option<Vec<usize>> {
46 let n = g.nodes.len();
47 let mut in_degree = vec![0usize; n];
48 for &(_, to) in &g.edges {
49 in_degree[to] += 1;
50 }
51
52 let mut queue: std::collections::VecDeque<usize> =
53 (0..n).filter(|&i| in_degree[i] == 0).collect();
54
55 let mut order = Vec::with_capacity(n);
56 while let Some(node) = queue.pop_front() {
57 order.push(node);
58 for &(from, to) in &g.edges {
59 if from == node {
60 in_degree[to] -= 1;
61 if in_degree[to] == 0 {
62 queue.push_back(to);
63 }
64 }
65 }
66 }
67
68 if order.len() == n {
69 Some(order)
70 } else {
71 None
72 }
73}
74
75pub fn dep_has_cycle(g: &DepGraph) -> bool {
76 dep_topo_sort(g).is_none()
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn test_new_empty() {
85 let g = new_dep_graph();
87 assert_eq!(dep_node_count(&g), 0);
88 }
89
90 #[test]
91 fn test_add_nodes() {
92 let mut g = new_dep_graph();
94 let a = dep_add_node(&mut g, "a");
95 let b = dep_add_node(&mut g, "b");
96 assert_eq!(a, 0);
97 assert_eq!(b, 1);
98 assert_eq!(dep_node_count(&g), 2);
99 }
100
101 #[test]
102 fn test_topo_sort_linear() {
103 let mut g = new_dep_graph();
105 let a = dep_add_node(&mut g, "a");
106 let b = dep_add_node(&mut g, "b");
107 let c = dep_add_node(&mut g, "c");
108 dep_add_edge(&mut g, a, b);
109 dep_add_edge(&mut g, b, c);
110 let order = dep_topo_sort(&g).expect("should succeed");
111 assert_eq!(order, vec![a, b, c]);
112 }
113
114 #[test]
115 fn test_no_cycle() {
116 let mut g = new_dep_graph();
118 let a = dep_add_node(&mut g, "a");
119 let b = dep_add_node(&mut g, "b");
120 dep_add_edge(&mut g, a, b);
121 assert!(!dep_has_cycle(&g));
122 }
123
124 #[test]
125 fn test_cycle_detected() {
126 let mut g = new_dep_graph();
128 let a = dep_add_node(&mut g, "a");
129 let b = dep_add_node(&mut g, "b");
130 dep_add_edge(&mut g, a, b);
131 dep_add_edge(&mut g, b, a);
132 assert!(dep_has_cycle(&g));
133 assert!(dep_topo_sort(&g).is_none());
134 }
135
136 #[test]
137 fn test_no_edges() {
138 let mut g = new_dep_graph();
140 dep_add_node(&mut g, "x");
141 dep_add_node(&mut g, "y");
142 let order = dep_topo_sort(&g).expect("should succeed");
143 assert_eq!(order.len(), 2);
144 }
145
146 #[test]
147 fn test_default() {
148 let g = DepGraph::default();
150 assert_eq!(g.nodes.len(), 0);
151 }
152
153 #[test]
154 fn test_diamond() {
155 let mut g = new_dep_graph();
157 let a = dep_add_node(&mut g, "a");
158 let b = dep_add_node(&mut g, "b");
159 let c = dep_add_node(&mut g, "c");
160 let d = dep_add_node(&mut g, "d");
161 dep_add_edge(&mut g, a, b);
162 dep_add_edge(&mut g, a, c);
163 dep_add_edge(&mut g, b, d);
164 dep_add_edge(&mut g, c, d);
165 let order = dep_topo_sort(&g).expect("should succeed");
166 assert_eq!(order.len(), 4);
167 let pos_a = order.iter().position(|&x| x == a).expect("should succeed");
169 let pos_d = order.iter().position(|&x| x == d).expect("should succeed");
170 assert!(pos_a < pos_d);
171 }
172}