use crate::graph::{node_map::NodeMap, postorder::postorder_all, GraphPred, GraphSucc};
struct NodeInfo {
last_use_count: u32,
priority: u32,
num_incomplete_deps: u32,
outstanding_users: u32,
max_height: u32,
peer_max_height: u32,
issued: bool,
}
pub fn dag_schedule<G: GraphPred + GraphSucc>(graph: G) -> Vec<G::Node> {
let mut nodes = NodeMap::new_with(graph, |_| NodeInfo {
last_use_count: 0,
priority: 0,
num_incomplete_deps: 0,
outstanding_users: 0,
max_height: u32::MAX,
peer_max_height: u32::MAX,
issued: false,
});
for id in graph.nodes() {
for depid in graph.pred_of(id) {
nodes[depid].outstanding_users += 1;
nodes[id].num_incomplete_deps += 1;
}
}
let order = postorder_all(graph);
for &id in &order {
let mut prio = 0;
let mut extra = 0;
for succ in graph.succ_of(id) {
let pprio = nodes[succ].priority;
if prio == pprio {
extra += 1;
} else if prio < pprio {
extra = 0;
prio = pprio;
}
}
nodes[id].priority = prio + extra + 1;
}
let mut ready = vec![];
for id in graph.nodes() {
if nodes[id].num_incomplete_deps == 0 {
ready.push(id);
}
}
let mut schedule = vec![];
while ready.len() != 0 {
for id in graph.nodes() {
let mut height = 0;
if !nodes[id].issued {
for dep in graph.pred_of(id) {
let node = &mut nodes[dep];
if node.issued {
height = height.max(node.max_height);
}
}
}
nodes[id].max_height = height + 1;
}
for id in graph.nodes() {
let mut peer_max_height = 0;
if !nodes[id].issued {
for s in graph.succ_of(id) {
if nodes[s].max_height > peer_max_height {
peer_max_height = nodes[s].max_height;
}
}
}
nodes[id].peer_max_height = peer_max_height + 1;
}
ready.sort_by_cached_key(|&id| {
let last_use_count = nodes[id].last_use_count;
let priority = nodes[id].priority;
let max_height = nodes[id].peer_max_height;
(last_use_count, priority, !max_height)
});
let id = ready.pop().unwrap();
schedule.push(id);
nodes[id].issued = true;
for succ in graph.succ_of(id) {
nodes[succ].num_incomplete_deps -= 1;
if nodes[succ].num_incomplete_deps == 0 {
ready.push(succ);
}
}
for dep in graph.pred_of(id) {
nodes[dep].outstanding_users -= 1;
if nodes[dep].outstanding_users == 1 {
for ns in graph.succ_of(dep) {
nodes[ns].last_use_count += 1;
}
}
}
if nodes[id].outstanding_users == 1 {
for ns in graph.succ_of(id) {
nodes[ns].last_use_count += 1;
}
}
}
schedule
}