use super::*;
use crate::deadline::expired;
use crate::rng::{SEED_OFFSET, Xorshift64};
fn rescore_neighbours(
scratch: &mut FillScratch,
graph: &EliminationGraph,
nbrs: &[u32],
buckets: &mut BucketMap,
) {
for &u in nbrs {
if graph.active[u as usize] {
let new_fill = scratch.fill_count_of(graph, u);
buckets.update(u, new_fill);
}
}
}
pub(crate) fn eliminate_sampled_min_fill(
graph: &mut EliminationGraph,
weights: &[u32],
seed: u64,
mut sink: ElimSink<'_>,
stop: ElimStop,
initial_fill: Option<&[u64]>,
) -> ElimExit {
let ElimStop {
hard_deadline,
width_bound,
..
} = stop;
let n = graph.len();
assert_eq!(weights.len(), n);
if graph.should_promote_bitset() {
graph.promote_bitset();
}
let mut scratch = FillScratch::new(n);
let mut live_nbrs = Vec::new();
let mut buckets = BucketMap::with_capacity(n);
for v in 0..n {
if graph.active[v] {
let f = match initial_fill {
Some(f) => f[v],
None => scratch.fill_count_of(graph, v as u32),
};
buckets.insert(v as u32, f);
}
}
let mut rng = Xorshift64::from_state(seed.wrapping_add(SEED_OFFSET));
let mut check_counter = 0u32;
while let Some((min_fill, tie_set)) = buckets.min_bucket() {
check_counter += 1;
if check_counter >= DEADLINE_CHECK_STRIDE {
check_counter = 0;
if expired(hard_deadline) {
return ElimExit::DeadlineReached;
}
if graph.should_promote_bitset() {
graph.promote_bitset();
}
}
let v = sample_tie_set(tie_set, weights, &mut rng);
buckets.remove_vertex(v);
let bag = take_bag(graph, v, &mut live_nbrs);
if min_fill == 0 {
if graph.bitset_words > 0 {
let w = graph.bitset_words;
let vb = v as usize * w;
for &u in &live_nbrs {
let ui = u as usize;
let ub = ui * w;
let mut o_count = 0u64;
for j in 0..w {
o_count +=
(graph.bitset[ub + j] & !graph.bitset[vb + j]).count_ones() as u64;
}
o_count = o_count.saturating_sub(1); if let Some(old_key) = buckets.key_of(u) {
buckets.update(u, old_key.saturating_sub(o_count));
}
}
graph.remove_without_fill_nbrs(v, &live_nbrs);
} else {
graph.remove_without_fill_nbrs(v, &live_nbrs);
rescore_neighbours(&mut scratch, graph, &live_nbrs, &mut buckets);
}
} else {
graph.eliminate_with_nbrs(v, &live_nbrs);
rescore_neighbours(&mut scratch, graph, &live_nbrs, &mut buckets);
}
let bag_len = bag.len();
sink.record(v, bag);
if exceeds_width_bound(bag_len, width_bound) {
return ElimExit::WidthLimitExceeded;
}
}
ElimExit::Complete
}
pub(crate) fn eliminate_sampled_min_degree(
graph: &mut EliminationGraph,
weights: &[u32],
seed: u64,
mut sink: ElimSink<'_>,
stop: ElimStop,
) -> ElimExit {
let ElimStop {
hard_deadline,
width_bound,
..
} = stop;
let n = graph.len();
assert_eq!(weights.len(), n);
let mut buckets = BucketMap::with_capacity(n);
for v in 0..n {
if graph.active[v] {
buckets.insert(v as u32, graph.degree(v as u32) as u64);
}
}
let mut rng = Xorshift64::from_state(seed.wrapping_add(SEED_OFFSET));
let mut nbrs_buf = Vec::new();
let mut check_counter = 0u32;
let mut clique_residual = false;
let mut degree_stale: Vec<bool> = vec![false; n];
while let Some((min_deg, tie_set)) = buckets.min_bucket() {
check_counter += 1;
if check_counter >= DEADLINE_CHECK_STRIDE {
check_counter = 0;
if expired(hard_deadline) {
return ElimExit::DeadlineReached;
}
}
let v = sample_tie_set(tie_set, weights, &mut rng);
let vi = v as usize;
if degree_stale[vi] {
let live_degree = graph.degree(v) as u64;
degree_stale[vi] = false;
if live_degree != min_deg {
buckets.update(v, live_degree);
continue;
}
}
buckets.remove_vertex(v);
let bag = take_bag(graph, v, &mut nbrs_buf);
let bag_len = bag.len();
if !clique_residual && graph.is_residual_clique() {
clique_residual = true;
}
if clique_residual {
graph.remove_without_fill_nbrs(v, &nbrs_buf);
} else {
graph.eliminate_with_nbrs(v, &nbrs_buf);
}
sink.record(v, bag);
if exceeds_width_bound(bag_len, width_bound) {
return ElimExit::WidthLimitExceeded;
}
for &u in &nbrs_buf {
degree_stale[u as usize] = true;
}
}
ElimExit::Complete
}