change interferrence graph impl

This commit is contained in:
janis 2026-10-25 01:47:10 +02:00
parent 51a2e69f74
commit 88512b37ac
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8

View file

@ -1,6 +1,6 @@
use std::{
cmp::Reverse,
collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, VecDeque},
collections::{BTreeSet, BinaryHeap, HashMap, VecDeque},
sync::Arc,
};
@ -64,41 +64,60 @@ impl ResourceLifetime {
/// An edge means the two resources are live at the same command index.
#[derive(Debug, Clone, Default)]
pub struct ResourceInterference {
adj: BTreeMap<ResourceId, BTreeSet<ResourceId>>,
edges: Vec<BTreeSet<ResourceId>>,
}
impl ResourceInterference {
/// Build a symmetric interference graph from inclusive resource lifetimes.
pub fn from_lifetimes(lifetimes: &HashMap<ResourceId, ResourceLifetime>) -> Self {
let mut graph = Self::default();
let resources: Vec<_> = lifetimes
let mut max_id = ResourceId(0);
let mut resources: Vec<_> = lifetimes
.iter()
.inspect(|(id, _)| {
if **id > max_id {
max_id = **id;
}
})
.map(|(&id, lifetime)| (id, *lifetime))
.collect();
for (index, &(id, lifetime)) in resources.iter().enumerate() {
graph.adj.entry(id).or_default();
for &(other_id, other) in &resources[index + 1..] {
if lifetime.overlaps(&other) {
graph.adj.entry(id).or_default().insert(other_id);
graph.adj.entry(other_id).or_default().insert(id);
let mut edges = vec![BTreeSet::new(); max_id.index() + 1];
resources.sort_unstable_by_key(|&(_, lifetime)| lifetime.first_command);
let mut resources = VecDeque::from(resources);
let mut index = 0;
while index < resources.len() {
let (id, lifetime) = resources[index];
let mut j = 0;
while j < index {
if resources[j].1.last_command < lifetime.first_command {
resources.swap_remove_front(j);
index -= 1;
} else {
j += 1;
}
}
index += 1;
// resources is no longer sorted in the interval ..index, but because of the invariant `last_command >= first_command`, it is still partitioned by `a.last_command <= b.first_command`.
let active = resources
.partition_point(|&(_, other)| other.first_command <= lifetime.last_command);
for &(other_id, _) in resources.range(..active) {
edges[id.index()].insert(other_id);
edges[other_id.index()].insert(id);
}
}
graph
Self { edges }
}
/// Returns whether both resources are live at any common command index.
pub fn interferes(&self, a: ResourceId, b: ResourceId) -> bool {
self.adj
.get(&a)
.is_some_and(|neighbors| neighbors.contains(&b))
}
/// Returns the resources that overlap `id`'s inclusive lifetime interval.
pub fn neighbors(&self, id: ResourceId) -> Option<&BTreeSet<ResourceId>> {
self.adj.get(&id)
self.edges[a.index()].contains(&b)
}
}