use std::time::Instant;
use super::deterministic::{AfterElim, ElimPolicy, Seeded, eliminate_greedy};
use super::*;
use crate::deadline::expired;
#[derive(Eq, PartialEq)]
pub(super) struct HeapEntry {
pub key: (Reverse<u64>, Reverse<usize>, Reverse<u32>, Reverse<u32>),
pub vertex: u32,
pub fill: u64,
}
impl HeapEntry {
pub(super) fn new(fill: u64, degree: usize, salt: u32, v: u32) -> Self {
HeapEntry {
key: (Reverse(fill), Reverse(degree), Reverse(salt), Reverse(v)),
vertex: v,
fill,
}
}
}
ord_by_key!(HeapEntry);
impl ElimEntry for HeapEntry {
fn vertex(&self) -> u32 {
self.vertex
}
fn snapshot(&self) -> u64 {
self.fill
}
}
fn scan_fill(
scratch: &mut FillScratch,
graph: &EliminationGraph,
fill_count: &mut [u64],
deadline: Option<Instant>,
hard_deadline: Option<Instant>,
) -> Seeded {
let mut init_check = 0u32;
for (v, slot) in fill_count.iter_mut().enumerate() {
if !graph.active[v] {
continue;
}
init_check += 1;
if init_check >= DEADLINE_CHECK_STRIDE {
init_check = 0;
if expired(hard_deadline) {
return Seeded::Bailed;
}
if expired(deadline) {
return Seeded::CheapMode;
}
}
*slot = scratch.fill_count_of(graph, v as u32);
}
Seeded::Ready
}
struct MinFill<'a> {
heap: BinaryHeap<HeapEntry>,
scratch: FillScratch,
dirty: Vec<bool>,
salt: &'a [u32],
}
impl ElimPolicy for MinFill<'_> {
type Entry = HeapEntry;
const CHEAP_MODE: bool = true;
const MAINTAIN_BITSET: bool = true;
const ZERO_SCORE_IS_SIMPLICIAL: bool = true;
fn heap(&mut self) -> &mut BinaryHeap<HeapEntry> {
&mut self.heap
}
fn push(&mut self, graph: &EliminationGraph, v: u32, score: u64) {
self.heap.push(HeapEntry::new(
score,
graph.degree(v),
self.salt[v as usize],
v,
));
}
fn live_score(&mut self, graph: &EliminationGraph, v: u32) -> u64 {
self.scratch.fill_count_of(graph, v)
}
fn seed(
&mut self,
graph: &mut EliminationGraph,
deadline: Option<Instant>,
hard_deadline: Option<Instant>,
) -> Seeded {
let mut fill_count: Vec<u64> = vec![0; graph.len()];
let outcome = scan_fill(
&mut self.scratch,
graph,
&mut fill_count,
deadline,
hard_deadline,
);
if matches!(outcome, Seeded::Bailed) {
return outcome;
}
for (v, &fill) in fill_count.iter().enumerate() {
if graph.active[v] {
self.push(graph, v as u32, fill);
}
}
outcome
}
fn rescore_on_pop(&mut self, graph: &EliminationGraph, v: u32) -> Option<u64> {
std::mem::replace(&mut self.dirty[v as usize], false)
.then(|| self.scratch.fill_count_of(graph, v))
}
fn after_eliminate(
&mut self,
graph: &EliminationGraph,
nbrs: &[u32],
cheap_mode: bool,
deadline: Option<Instant>,
) -> AfterElim {
if cheap_mode {
for &u in nbrs {
if graph.active[u as usize] {
self.heap
.push(HeapEntry::new(0, graph.degree(u), self.salt[u as usize], u));
}
}
return AfterElim::Continue;
}
for &u in nbrs {
let ui = u as usize;
if !graph.active[ui] {
continue;
}
if expired(deadline) {
if graph.num_active > CHEAP_MODE_MAX_ACTIVE {
return AfterElim::Bail;
}
return AfterElim::EnterCheapMode;
}
let live = self.scratch.fill_count_of(graph, u);
self.push(graph, u, live);
self.dirty[ui] = true;
}
AfterElim::Continue
}
}
pub(crate) fn eliminate_min_fill(
graph: &mut EliminationGraph,
salt: &[u32],
sink: ElimSink<'_>,
stop: ElimStop,
) -> ElimExit {
let n = graph.len();
assert_eq!(salt.len(), n);
let mut policy = MinFill {
heap: BinaryHeap::with_capacity(n),
scratch: FillScratch::new(n),
dirty: vec![false; n],
salt,
};
eliminate_greedy(&mut policy, graph, sink, stop)
}