hpart 0.1.1

A hypergraph partitioning library.
Documentation
use std::collections::BinaryHeap;

use bitvec::prelude::*;
use ordered_float::OrderedFloat;

use crate::bipartite::*;

const C: usize = 20;

pub(crate) fn uncoarsen(
    h: &mut Bipartite,
    size_constraint: f32,
    mementos: Vec<Memento>,
    partition: &mut Bipartition,
) {
    let mut gain_pq = BinaryHeap::new();
    let mut gain_vec = vec![0.0; h.pin_index_space_size()];

    for memento in mementos.into_iter().rev() {
        let u = memento.u;
        let v = memento.v;
        h.uncontract(memento);
        partition[v as usize] = partition[u as usize];
        let mut b1_capacity = h
            .pins()
            .filter(|v| partition[*v as usize])
            .map(|v| h.capacity(v))
            .sum::<f32>();
        let mut b2_capacity = h
            .pins()
            .filter(|v| !partition[*v as usize])
            .map(|v| h.capacity(v))
            .sum::<f32>();

        let border_u = h
            .incident_pins(u)
            .any(|p| partition[p as usize] != partition[u as usize]);
        if border_u {
            let gain = gain(h, u, partition);
            gain_pq.push((OrderedFloat(gain), u));
            gain_vec[u as usize] = gain;
        }
        let border_v = h
            .incident_pins(v)
            .any(|p| partition[p as usize] != partition[v as usize]);
        if border_v {
            let gain = gain(h, v, partition);
            gain_pq.push((OrderedFloat(gain), v));
            gain_vec[v as usize] = gain;
        }
        if !border_u && !border_v {
            continue;
        }

        let mut steps = vec![];
        let mut best_step = 0;
        let mut best_gain = 0.0;
        let mut current_gain = 0.0;
        let mut non_increase_count = 0;
        while let Some((OrderedFloat(g), v)) = gain_pq.pop() {
            if g != gain_vec[v as usize] {
                gain_pq.push((OrderedFloat(gain_vec[v as usize]), v));
                continue;
            }
            if g <= 0.0 {
                non_increase_count += 1;
            } else {
                non_increase_count = 0;
            }
            if non_increase_count >= C {
                break;
            }

            current_gain += g;
            partition[v as usize] = !partition[v as usize];
            steps.push(v);
            if partition[v as usize] {
                b1_capacity += h.capacity(v);
                b2_capacity += h.capacity(v);
            } else {
                b1_capacity -= h.capacity(v);
                b2_capacity += h.capacity(v);
            }
            if current_gain >= best_gain
                && b1_capacity <= size_constraint
                && b2_capacity <= size_constraint
            {
                best_step = steps.len();
                best_gain = current_gain;
            }
            for p in h.incident_pins(v) {
                gain_vec[p as usize] = gain(h, p, partition);
            }
        }
        for idx in (best_step..steps.len()).rev() {
            let step = steps[idx];
            partition[step as usize] = !partition[step as usize];
        }
    }
}

fn gain(h: &Bipartite, v: Index, partition: &Bipartition) -> f32 {
    let b_v = partition[v as usize];
    let upside: f32 = h
        .incident_nets(v)
        .filter(|e| {
            h.pins_in_net(*e)
                .filter(|n| partition[*n as usize] == !b_v)
                .count()
                == h.pins_in_net(*e).len() - 1
        })
        .map(|e| h.weight(e))
        .sum();
    let downside: f32 = h
        .incident_nets(v)
        .filter(|e| {
            h.pins_in_net(*e)
                .filter(|n| partition[*n as usize] == b_v)
                .count()
                == h.pins_in_net(*e).len()
        })
        .map(|e| h.weight(e))
        .sum();
    upside - downside
}