1use super::ir::VarId;
30use core::fmt;
31
32#[derive(Clone, Debug, PartialEq, Eq)]
34pub enum OrderError {
35 Cycle {
40 vars: Vec<VarId>,
42 },
43 UnknownVar {
45 var: VarId,
47 },
48}
49
50impl fmt::Display for OrderError {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 match self {
53 OrderError::Cycle { vars } => write!(
54 f,
55 "the `solve ... before` constraints are circular through random variables {vars:?} \
56 (IEEE 1800-2023 18.5.9)"
57 ),
58 OrderError::UnknownVar { var } => write!(
59 f,
60 "a `solve ... before` edge names random variable #{var} which does not exist"
61 ),
62 }
63 }
64}
65
66impl std::error::Error for OrderError {}
67
68pub fn levels(n: usize, edges: &[(VarId, VarId)]) -> Result<Vec<usize>, OrderError> {
72 let mut succ: Vec<Vec<usize>> = vec![Vec::new(); n];
73 for &(a, b) in edges {
74 for v in [a, b] {
75 if v as usize >= n {
76 return Err(OrderError::UnknownVar { var: v });
77 }
78 }
79 if !succ[a as usize].contains(&(b as usize)) {
80 succ[a as usize].push(b as usize);
81 }
82 }
83 let mut pred: Vec<Vec<usize>> = vec![Vec::new(); n];
86 for (a, ss) in succ.iter().enumerate() {
87 for &b in ss {
88 pred[b].push(a);
89 }
90 }
91 let mut pending: Vec<usize> = succ.iter().map(Vec::len).collect();
92 let mut height = vec![0usize; n];
93 let mut ready: Vec<usize> = (0..n).filter(|&v| pending[v] == 0).collect();
94 let mut done = 0usize;
95 while let Some(v) = ready.pop() {
96 done += 1;
97 for &p in &pred[v] {
98 height[p] = height[p].max(height[v] + 1);
99 pending[p] -= 1;
100 if pending[p] == 0 {
101 ready.push(p);
102 }
103 }
104 }
105 if done < n {
106 let unfinished: Vec<bool> = pending.iter().map(|&p| p > 0).collect();
109 let start = (0..n).find(|&v| unfinished[v]).expect("done < n");
110 let mut seen_at = vec![usize::MAX; n];
111 let mut path: Vec<usize> = Vec::new();
112 let mut cur = start;
113 loop {
114 if seen_at[cur] != usize::MAX {
115 let vars = path[seen_at[cur]..].iter().map(|&v| v as VarId).collect();
116 return Err(OrderError::Cycle { vars });
117 }
118 seen_at[cur] = path.len();
119 path.push(cur);
120 cur = *succ[cur]
121 .iter()
122 .find(|&&s| unfinished[s])
123 .expect("an unfinished variable has an unfinished successor");
124 }
125 }
126 let top = height.iter().copied().max().unwrap_or(0);
127 Ok(height.into_iter().map(|h| top - h).collect())
128}
129
130pub fn groups(n: usize, edges: &[(VarId, VarId)]) -> Result<Vec<Vec<VarId>>, OrderError> {
133 let lv = levels(n, edges)?;
134 let count = lv.iter().copied().max().map_or(0, |m| m + 1);
135 let mut out: Vec<Vec<VarId>> = vec![Vec::new(); count];
136 for (v, l) in lv.into_iter().enumerate() {
137 out[l].push(v as VarId);
138 }
139 debug_assert!(out.iter().all(|g| !g.is_empty()));
140 Ok(out)
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn no_edges_is_one_set() {
149 assert_eq!(levels(3, &[]).unwrap(), vec![0, 0, 0]);
150 assert_eq!(groups(3, &[]).unwrap(), vec![vec![0, 1, 2]]);
151 assert_eq!(groups(0, &[]).unwrap(), Vec::<Vec<VarId>>::new());
152 }
153
154 #[test]
155 fn a_before_b_leaves_unordered_variables_with_the_last_set() {
156 assert_eq!(levels(3, &[(0, 1)]).unwrap(), vec![0, 1, 1]);
159 assert_eq!(groups(3, &[(0, 1)]).unwrap(), vec![vec![0], vec![1, 2]]);
160 }
161
162 #[test]
163 fn a_partially_ordered_variable_is_solved_as_late_as_the_edges_allow() {
164 let e = [(0, 1), (1, 2), (3, 2)];
167 assert_eq!(levels(4, &e).unwrap(), vec![0, 1, 2, 1]);
168 assert_eq!(groups(4, &e).unwrap(), vec![vec![0], vec![1, 3], vec![2]]);
169 }
170
171 #[test]
172 fn several_names_on_one_side_fan_in_and_out() {
173 let e = [(0, 2), (0, 3), (1, 2), (1, 3)];
175 assert_eq!(groups(4, &e).unwrap(), vec![vec![0, 1], vec![2, 3]]);
176 }
177
178 #[test]
179 fn duplicate_edges_are_harmless() {
180 assert_eq!(levels(2, &[(0, 1), (0, 1), (0, 1)]).unwrap(), vec![0, 1]);
181 }
182
183 #[test]
184 fn cycles_are_rejected_and_named() {
185 assert_eq!(
186 levels(2, &[(0, 0)]).unwrap_err(),
187 OrderError::Cycle { vars: vec![0] }
188 );
189 let e = levels(3, &[(0, 1), (1, 2), (2, 1)]).unwrap_err();
190 let OrderError::Cycle { vars } = e else {
191 panic!("{e:?}")
192 };
193 let mut sorted = vars.clone();
194 sorted.sort_unstable();
195 assert_eq!(
196 sorted,
197 vec![1, 2],
198 "the cycle, not variable 0 upstream of it"
199 );
200 assert!(vars == vec![1, 2] || vars == vec![2, 1]);
202 }
203
204 #[test]
205 fn an_unknown_variable_is_an_error() {
206 assert_eq!(
207 levels(2, &[(0, 5)]).unwrap_err(),
208 OrderError::UnknownVar { var: 5 }
209 );
210 }
211
212 #[test]
213 fn errors_have_messages() {
214 assert!(
215 OrderError::Cycle { vars: vec![1, 2] }
216 .to_string()
217 .contains("circular")
218 );
219 assert!(OrderError::UnknownVar { var: 9 }.to_string().contains("#9"));
220 }
221}