vj_sim/constraints/
func_order.rs1use super::dist::SELECTOR_BASE;
27use super::ir::{ArrayNode, Expr, VarId};
28use std::collections::BTreeSet;
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq)]
32pub struct Cycle;
33
34fn split(e: &Expr, others: &mut BTreeSet<VarId>, args: &mut BTreeSet<VarId>) {
37 match e {
38 Expr::Array(ArrayNode::Call { args: a, .. }) => {
39 for x in a {
40 x.for_each_var(&mut |v, _| {
41 args.insert(v);
42 });
43 }
44 }
45 Expr::Var(v, _) => {
46 others.insert(*v);
47 }
48 other => {
49 let _ = other.try_map_children::<()>(&mut |c| {
50 split(c, others, args);
51 Ok(c.clone())
52 });
53 }
54 }
55}
56
57pub fn stages(n_vars: usize, conjuncts: &[Expr]) -> Result<Vec<u32>, Cycle> {
60 let mut edges: BTreeSet<(usize, usize)> = BTreeSet::new();
61 for c in conjuncts {
62 let (mut others, mut args) = (BTreeSet::new(), BTreeSet::new());
63 split(c, &mut others, &mut args);
64 let real =
65 |v: &VarId| (*v < SELECTOR_BASE && (*v as usize) < n_vars).then_some(*v as usize);
66 let args: Vec<usize> = args.iter().filter_map(real).collect();
67 for o in others.iter().filter_map(real) {
68 if args.contains(&o) {
69 continue;
70 }
71 for &a in &args {
72 edges.insert((a, o));
73 }
74 }
75 }
76 let mut indeg = vec![0usize; n_vars];
78 let mut succ: Vec<Vec<usize>> = vec![Vec::new(); n_vars];
79 for &(a, b) in &edges {
80 indeg[b] += 1;
81 succ[a].push(b);
82 }
83 let mut stage = vec![0u32; n_vars];
84 let mut ready: Vec<usize> = (0..n_vars).filter(|&v| indeg[v] == 0).collect();
85 let mut done = 0;
86 while let Some(v) = ready.pop() {
87 done += 1;
88 for &w in &succ[v] {
89 stage[w] = stage[w].max(stage[v] + 1);
90 indeg[w] -= 1;
91 if indeg[w] == 0 {
92 ready.push(w);
93 }
94 }
95 }
96 if done != n_vars {
97 return Err(Cycle);
98 }
99 Ok(stage)
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::constraints::ir::{BinOp, Ty};
106
107 fn s32() -> Ty {
108 Ty::signed(32)
109 }
110 fn var(i: u32) -> Expr {
111 Expr::Var(i, s32())
112 }
113 fn call(args: Vec<Expr>) -> Expr {
114 Expr::Array(ArrayNode::Call {
115 func: 0,
116 args,
117 ty: s32(),
118 })
119 }
120 fn eq(a: Expr, b: Expr) -> Expr {
121 Expr::Binary(BinOp::Eq, Box::new(a), Box::new(b), Ty::BIT)
122 }
123
124 #[test]
125 fn no_call_means_one_stage() {
126 assert_eq!(stages(3, &[eq(var(0), var(1))]), Ok(vec![0, 0, 0]));
127 }
128
129 #[test]
130 fn an_argument_is_solved_before_the_other_variables_of_its_constraint() {
131 let c = eq(var(0), call(vec![var(1)]));
133 assert_eq!(stages(2, &[c]), Ok(vec![1, 0]));
134 }
135
136 #[test]
137 fn chains_take_the_longest_path() {
138 let cs = [
140 eq(var(0), call(vec![var(1)])),
141 eq(var(1), call(vec![var(2)])),
142 ];
143 assert_eq!(stages(3, &cs), Ok(vec![2, 1, 0]));
144 }
145
146 #[test]
147 fn two_arguments_of_one_constraint_share_a_stage() {
148 let c = eq(call(vec![var(0)]), call(vec![var(1)]));
150 assert_eq!(stages(2, &[c]), Ok(vec![0, 0]));
151 assert_eq!(stages(1, &[eq(var(0), call(vec![var(0)]))]), Ok(vec![0]));
153 }
154
155 #[test]
156 fn nested_calls_put_every_inner_variable_before_the_rest() {
157 let c = eq(var(0), call(vec![call(vec![var(1), var(2)])]));
159 assert_eq!(stages(3, &[c]), Ok(vec![1, 0, 0]));
160 }
161
162 #[test]
163 fn a_circular_order_is_an_error() {
164 let cs = [
166 eq(var(0), call(vec![var(1)])),
167 eq(var(1), call(vec![var(0)])),
168 ];
169 assert_eq!(stages(2, &cs), Err(Cycle));
170 }
171
172 #[test]
173 fn selector_variables_take_no_part() {
174 let c = eq(var(SELECTOR_BASE), call(vec![var(0)]));
175 assert_eq!(stages(1, &[c]), Ok(vec![0]));
176 }
177}