use alloc::vec::Vec;
use num_traits::AsPrimitive;
use crate::traits::SparseSquareMatrix;
pub(super) struct BlossomState<'a, M: SparseSquareMatrix + ?Sized> {
matrix: &'a M,
mate: Vec<Option<M::Index>>,
parent: Vec<Option<M::Index>>,
base: Vec<M::Index>,
in_queue: Vec<bool>,
used: Vec<bool>,
queue: Vec<M::Index>,
}
impl<'a, M: SparseSquareMatrix + ?Sized> BlossomState<'a, M> {
pub(super) fn new(matrix: &'a M) -> Self {
let n: usize = matrix.order().as_();
Self {
matrix,
mate: vec![None; n],
parent: vec![None; n],
base: matrix.row_indices().collect(),
in_queue: vec![false; n],
used: vec![false; n],
queue: Vec::new(),
}
}
pub(super) fn solve(mut self) -> Vec<(M::Index, M::Index)> {
for v in self.matrix.row_indices() {
if self.mate[v.as_()].is_none() {
self.find_augmenting_path(v);
}
}
self.into_pairs()
}
fn into_pairs(self) -> Vec<(M::Index, M::Index)> {
let indices: Vec<M::Index> = self.matrix.row_indices().collect();
let usize_mate: Vec<Option<usize>> =
self.mate.iter().map(|opt| opt.map(AsPrimitive::as_)).collect();
crate::traits::algorithms::matching_utils::mate_to_pairs(&usize_mate, &indices)
}
fn find_augmenting_path(&mut self, root: M::Index) -> bool {
for i in self.matrix.row_indices() {
let idx = i.as_();
self.parent[idx] = None;
self.base[idx] = i;
self.in_queue[idx] = false;
}
self.in_queue[root.as_()] = true;
self.queue.clear();
self.queue.push(root);
let mut head = 0;
while head < self.queue.len() {
let v = self.queue[head];
head += 1;
for w in self.matrix.sparse_row(v) {
if self.base[v.as_()] == self.base[w.as_()] || w == v {
continue;
}
if self.mate[w.as_()].is_none() && w != root {
self.parent[w.as_()] = Some(v);
self.augment_path(w);
return true;
}
if self.in_queue[self.base[w.as_()].as_()] {
let lca = self.find_lca(v, w);
self.contract_blossom(v, w, lca);
} else if self.parent[w.as_()].is_none() {
self.parent[w.as_()] = Some(v);
let m = self.mate[w.as_()].unwrap();
self.in_queue[m.as_()] = true;
self.queue.push(m);
}
}
}
false
}
fn find_lca(&mut self, a: M::Index, b: M::Index) -> M::Index {
self.used.fill(false);
let mut a = self.base[a.as_()];
let mut b = self.base[b.as_()];
loop {
self.used[a.as_()] = true;
match self.mate[a.as_()] {
None => break,
Some(ma) => {
a = self.base[self.parent[ma.as_()].unwrap().as_()];
}
}
}
loop {
if self.used[b.as_()] {
return b;
}
let mb = self.mate[b.as_()].unwrap();
b = self.base[self.parent[mb.as_()].unwrap().as_()];
}
}
fn contract_blossom(&mut self, v: M::Index, w: M::Index, lca: M::Index) {
self.used.fill(false);
self.mark_path(v, lca, w);
self.mark_path(w, lca, v);
for i in self.matrix.row_indices() {
if self.used[self.base[i.as_()].as_()] {
self.base[i.as_()] = lca;
if !self.in_queue[i.as_()] {
self.in_queue[i.as_()] = true;
self.queue.push(i);
}
}
}
}
fn mark_path(&mut self, mut v: M::Index, b: M::Index, mut child: M::Index) {
while self.base[v.as_()] != b {
self.used[self.base[v.as_()].as_()] = true;
let mv = self.mate[v.as_()].unwrap();
self.used[self.base[mv.as_()].as_()] = true;
self.parent[v.as_()] = Some(child);
child = mv;
v = self.parent[mv.as_()].unwrap();
}
}
fn augment_path(&mut self, mut u: M::Index) {
loop {
let pv = self.parent[u.as_()].unwrap();
let ppv = self.mate[pv.as_()];
self.mate[u.as_()] = Some(pv);
self.mate[pv.as_()] = Some(u);
match ppv {
Some(ppv) => u = ppv,
None => return,
}
}
}
}