use super::graph::SparseGraph;
use super::tracker::{RadixHeap, Tracker};
pub(crate) const NONE: u32 = u32::MAX;
pub(crate) const BOUNDARY: u32 = u32::MAX - 1;
pub(crate) const NO_TIME: i64 = i64::MAX;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct CEdge {
pub a: u32,
pub b: u32,
pub obs: u64,
}
impl CEdge {
pub fn rev(self) -> CEdge {
CEdge { a: self.b, b: self.a, obs: self.obs }
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Radius {
pub y0: i64,
pub slope: i64,
}
impl Radius {
pub fn at(&self, t: i64) -> i64 {
self.y0 + self.slope * t
}
}
pub(crate) const NOBODY: usize = 0;
pub(crate) const NO_TOP: u32 = NOBODY as u32;
pub(crate) struct Region {
pub radius: Radius,
pub blossom_parent: u32,
pub children: Vec<(u32, CEdge)>,
pub shell: Vec<u32>,
pub tree: u32,
pub matched: Option<(u32, CEdge)>,
pub queued: i64,
pub dead: bool,
}
pub(crate) struct AltNode {
pub inner: u32,
pub outer: u32,
pub inner_to_outer: CEdge,
pub parent: u32,
pub parent_edge: CEdge,
pub children: Vec<u32>,
pub alive: bool,
pub mark: u64,
}
#[derive(Clone, Copy)]
pub(crate) struct NodeState {
pub region: u32,
pub top: u32,
pub source: u32,
pub obs: u64,
pub wrapped: i64,
pub own: u32,
}
const _: () = assert!(std::mem::size_of::<NodeState>() == 32);
impl NodeState {
pub const EMPTY: NodeState = NodeState {
region: NONE,
top: NO_TOP,
source: NONE,
obs: 0,
wrapped: 0,
own: NONE,
};
}
pub struct Scratch {
pub(crate) nodes: Vec<NodeState>,
pub(crate) queued: Vec<i64>,
pub(crate) dirty: Vec<bool>,
pub(crate) touched: Vec<u32>,
pub(crate) regions: Vec<Region>,
pub(crate) growing: u32,
pub(crate) creates: u64,
pub(crate) quiet: Vec<u64>,
pub(crate) alt: Vec<AltNode>,
pub(crate) queue: Tracker,
pub(crate) now: i64,
pub(crate) events: u64,
pub(crate) scan: Vec<(u32, i32)>,
pub(crate) undo: Vec<(u32, i64)>,
pub(crate) pairs: Vec<(u32, u32)>,
pub(crate) dist: Vec<i64>,
pub(crate) pred: Vec<(u32, u32)>,
pub(crate) seen: Vec<u32>,
pub(crate) heap: RadixHeap<u32>,
pub(crate) flipped: Vec<bool>,
pub(crate) edge_set: Vec<u32>,
pub(crate) stamp: u64,
pub(crate) path_a: Vec<u32>,
pub(crate) path_b: Vec<u32>,
pub(crate) stack: Vec<u32>,
pub(crate) touched_regions: Vec<u32>,
pub(crate) under: Vec<u32>,
pub(crate) under_stack: Vec<u32>,
pub(crate) spare_u32: Vec<Vec<u32>>,
pub(crate) spare_cycles: Vec<Vec<(u32, CEdge)>>,
}
impl Scratch {
pub(crate) fn weight(&self, e: usize) -> i64 {
i64::from(self.scan[e].1)
}
pub(crate) fn set_weight(&mut self, e: usize, w: i64) {
self.scan[e].1 = i32::try_from(w).expect("an edge weight fits 32 bits");
}
pub fn new(graph: &SparseGraph) -> Scratch {
Scratch {
nodes: vec![NodeState::EMPTY; graph.num_nodes + 1],
queued: vec![NO_TIME; graph.num_nodes],
dirty: vec![false; graph.num_nodes],
touched: Vec::new(),
regions: vec![Region {
radius: Radius { y0: 0, slope: 0 },
blossom_parent: NONE,
children: Vec::new(),
shell: Vec::new(),
tree: NONE,
matched: None,
queued: NO_TIME,
dead: true,
}],
growing: 0,
creates: 0,
quiet: vec![u64::MAX; graph.num_nodes],
alt: Vec::new(),
queue: Tracker::default(),
now: 0,
events: 0,
scan: graph.scan.clone(),
undo: Vec::new(),
pairs: Vec::new(),
dist: Vec::new(),
pred: Vec::new(),
seen: Vec::new(),
heap: RadixHeap::default(),
flipped: Vec::new(),
edge_set: Vec::new(),
stamp: 0,
path_a: Vec::new(),
path_b: Vec::new(),
stack: Vec::new(),
touched_regions: Vec::new(),
under: Vec::new(),
under_stack: Vec::new(),
spare_u32: Vec::new(),
spare_cycles: Vec::new(),
}
}
pub(crate) fn ensure_paths(&mut self, graph: &SparseGraph) {
if self.dist.len() != graph.num_nodes {
self.dist = vec![NO_TIME; graph.num_nodes];
self.pred = vec![(NONE, NONE); graph.num_nodes];
}
if self.flipped.len() != graph.num_edges() {
self.flipped = vec![false; graph.num_edges()];
}
}
pub(crate) fn next_stamp(&mut self) -> u64 {
self.stamp += 1;
self.stamp
}
pub(crate) fn spare_u32(&mut self) -> Vec<u32> {
self.spare_u32.pop().unwrap_or_default()
}
pub(crate) fn keep_u32(&mut self, mut v: Vec<u32>) {
if v.capacity() > 0 {
v.clear();
self.spare_u32.push(v);
}
}
}