use std::iter::zip;
use bitvec::prelude::*;
pub type Index = u32;
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct Bipartite {
v: Vec<(Index, Index)>,
e: Vec<(Index, Index)>,
a: Vec<Index>,
v_enabled: BitVec,
num_disabled: usize,
c: Vec<f32>,
w: Vec<f32>,
}
#[derive(Clone, Copy)]
pub(crate) struct Memento {
pub(crate) u: Index,
pub(crate) v: Index,
u_idx: Index,
u_len: Index,
}
impl Bipartite {
pub(crate) fn new(capacities: &[f32], weights: &[f32], nets: &[&[Index]]) -> Self {
let num_v = capacities.len();
let num_e = weights.len();
assert_eq!(num_e, nets.len());
let mut bipartite = Bipartite {
v: vec![],
e: vec![],
a: vec![],
v_enabled: bitvec![usize, Lsb0; 1; num_v],
num_disabled: 0,
c: Vec::from(capacities),
w: Vec::from(weights),
};
for net in nets {
bipartite
.e
.push((bipartite.a.len() as Index, net.len() as Index));
bipartite.a.extend(*net);
}
for v_idx in 0..num_v {
let old_a = bipartite.a.len();
for (e_idx, net) in nets.into_iter().enumerate() {
if net.into_iter().any(|p| *p == v_idx as Index) {
bipartite.a.push(e_idx as Index);
}
}
let num_nets = bipartite.a.len() - old_a;
bipartite.v.push((old_a as Index, num_nets as Index));
}
bipartite
}
pub(crate) fn contract(&mut self, u: Index, v: Index) -> Memento {
assert_ne!(u, v);
let u_idx = self.v[u as usize].0;
let u_len = self.v[u as usize].1;
let memento = Memento { u, v, u_idx, u_len };
let c_v = self.c[v as usize];
self.c[u as usize] += c_v;
let mut copy = true;
let incident: Vec<_> = self.incident_nets(v).collect();
for e in incident {
let e_idx = self.e[e as usize].0;
let e_len = self.e[e as usize].1;
let l = e_idx + e_len - 1;
let mut tau = l;
for i in e_idx..=l {
if self.a[i as usize] == v {
let a_i = self.a[i as usize];
self.a[i as usize] = self.a[l as usize];
self.a[l as usize] = a_i;
}
if self.a[i as usize] == u {
tau = i;
}
}
if tau == l {
self.a[l as usize] = u;
if copy {
let incident_u: Vec<_> = self.incident_nets(u).collect();
self.a.extend(incident_u);
self.v[u as usize].0 = self.a.len() as Index - self.v[u as usize].1;
copy = false;
}
self.a.push(e);
self.v[u as usize].1 += 1;
} else {
self.e[e as usize].1 -= 1;
}
}
self.v_enabled.set(v as usize, false);
self.num_disabled += 1;
memento
}
pub(crate) fn uncontract(&mut self, m: Memento) {
self.v_enabled.set(m.v as usize, true);
self.num_disabled -= 1;
let mut b = bitvec![usize, Lsb0; 0; self.e.len()];
for e in self.incident_nets(m.v) {
b.set(e as usize, true);
}
for i in m.u_idx..m.u_idx + m.u_len {
b.set(self.a[i as usize] as usize, false);
}
if self.v[m.u as usize].1 > m.u_len {
let inc_u: Vec<_> = self.incident_nets(m.u).collect();
for e in inc_u {
if b[e as usize] {
let e_idx = self.e[e as usize].0;
let e_len = self.e[e as usize].1;
for p_idx in e_idx..e_idx + e_len {
if self.a[p_idx as usize] == m.u {
self.a[p_idx as usize] = m.v;
break;
}
}
}
}
}
self.v[m.u as usize].0 = m.u_idx;
self.v[m.u as usize].1 = m.u_len;
self.c[m.u as usize] -= self.c[m.v as usize];
let inc_v: Vec<_> = self.incident_nets(m.v).collect();
for e in inc_v {
if !b[e as usize] {
self.e[e as usize].1 += 1;
}
}
}
pub(crate) fn incident_nets(
&self,
v: Index,
) -> impl ExactSizeIterator<Item = Index> + Clone + '_ {
let v_idx = self.v[v as usize].0 as usize;
let v_len = self.v[v as usize].1 as usize;
self.a[v_idx..v_idx + v_len].iter().map(|x| *x)
}
pub(crate) fn pins_in_net(
&self,
e: Index,
) -> impl ExactSizeIterator<Item = Index> + Clone + '_ {
let e_idx = self.e[e as usize].0 as usize;
let e_len = self.e[e as usize].1 as usize;
self.a[e_idx..e_idx + e_len].iter().map(|x| *x)
}
pub(crate) fn incident_pins(&self, v: Index) -> impl Iterator<Item = Index> + Clone + '_ {
self.incident_nets(v)
.map(|e| self.pins_in_net(e))
.flatten()
.filter(move |u| *u != v)
}
pub(crate) fn total_capacity(&self) -> f32 {
self.c
.iter()
.enumerate()
.filter(|(idx, _)| self.v_enabled[*idx])
.map(|(_, c)| c)
.sum()
}
pub(crate) fn pins(&self) -> impl Iterator<Item = Index> + Clone + '_ {
(0..self.v.len())
.filter(|idx| self.v_enabled[*idx])
.map(|idx| idx as Index)
}
pub(crate) fn nets(&self) -> impl Iterator<Item = Index> + Clone {
(0..self.e.len()).map(|idx| idx as Index)
}
pub(crate) fn enabled(&self, v: Index) -> bool {
self.v_enabled[v as usize]
}
pub(crate) fn capacity(&self, v: Index) -> f32 {
assert!(self.v_enabled[v as usize]);
self.c[v as usize]
}
pub(crate) fn weight(&self, e: Index) -> f32 {
self.w[e as usize]
}
pub(crate) fn num_pins(&self) -> usize {
self.v.len() - self.num_disabled
}
pub(crate) fn pin_index_space_size(&self) -> usize {
self.v.len()
}
pub(crate) fn num_nets(&self) -> usize {
self.e.len()
}
pub(crate) fn evaluate_bipartition(&self, p: &Bipartition) -> (f32, f32) {
let mut cut_weight = 0.0;
for e in self.nets() {
let clusters = self.pins_in_net(e).map(|v| p[v as usize]);
if zip(clusters.clone(), clusters.skip(1)).any(|(l1, l2)| l1 != l2) {
cut_weight += self.w[e as usize];
}
}
let mut capacity1 = 0.0;
let mut capacity2 = 0.0;
for v in self.pins() {
let c = self.c[v as usize];
if p[v as usize] {
capacity1 += c;
} else {
capacity2 += c;
}
}
let imbalance = capacity1.max(capacity2);
(imbalance, cut_weight)
}
pub(crate) fn size_constraint(&self, epsilon: f32) -> f32 {
(1.0 + epsilon) * (self.total_capacity() as f32 / 2.0)
}
}
pub(crate) type Bipartition = Vec<bool>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_contract() {
let original = Bipartite {
v: vec![(0, 1), (1, 2), (3, 1), (4, 1), (5, 1), (6, 1)],
e: vec![(7, 4), (11, 3)],
a: vec![0, 0, 1, 0, 0, 1, 1, 0, 1, 2, 3, 1, 4, 5],
v_enabled: bitvec![usize, Lsb0; 1; 6],
num_disabled: 0,
c: vec![1.0; 6],
w: vec![1.0; 2],
};
let mut contract = original.clone();
let m = contract.contract(0, 1);
let correct = Bipartite {
v: vec![(14, 2), (1, 2), (3, 1), (4, 1), (5, 1), (6, 1)],
e: vec![(7, 3), (11, 3)],
a: vec![0, 0, 1, 0, 0, 1, 1, 0, 3, 2, 1, 5, 4, 0, 0, 1],
v_enabled: bitvec![1, 0, 1, 1, 1, 1],
num_disabled: 1,
c: vec![2.0, 1.0, 1.0, 1.0, 1.0, 1.0],
w: vec![1.0; 2],
};
assert_eq!(contract, correct);
contract.uncontract(m);
let correct = Bipartite {
v: vec![(0, 1), (1, 2), (3, 1), (4, 1), (5, 1), (6, 1)],
e: vec![(7, 4), (11, 3)],
a: vec![0, 0, 1, 0, 0, 1, 1, 0, 3, 2, 1, 5, 4, 1, 0, 1],
num_disabled: 0,
v_enabled: bitvec![usize, Lsb0; 1; 6],
c: vec![1.0; 6],
w: vec![1.0; 2],
};
assert_eq!(contract, correct);
}
}