use super::model::Hypergraph;
use super::refine_fm::refine_level;
use crate::partition::common::random_bisection;
use crate::rng::Xorshift64;
pub(super) fn greedy_growing(hg: &Hypergraph, seed: usize) -> Vec<u8> {
let n = hg.num_vertices;
let total_weight: u32 = hg.vertex_weights.iter().sum();
let target = total_weight / 2;
let mut part = vec![1u8; n];
let mut in_set = vec![false; n];
let mut pins_on_zero: Vec<u32> = vec![0; hg.num_hyperedges()];
part[seed] = 0;
in_set[seed] = true;
let mut set_weight = hg.vertex_weights[seed];
for &hyperedge in hg.vertex_hyperedges(seed) {
pins_on_zero[hyperedge as usize] += 1;
}
while set_weight < target {
let mut best_v = None;
let mut best_gain = i64::MIN;
for (v, &grown) in in_set.iter().enumerate() {
if grown {
continue;
}
let mut gain = 0i64;
for &hyperedge in hg.vertex_hyperedges(v) {
let hyperedge = hyperedge as usize;
let weight = i64::from(hg.hyperedge_weights[hyperedge]);
let total_pins =
hg.hyperedge_offsets[hyperedge + 1] - hg.hyperedge_offsets[hyperedge];
let count0 = pins_on_zero[hyperedge];
if count0 == 0 {
gain -= weight;
}
if count0 + 1 == total_pins {
gain += weight;
}
}
if best_v.is_none() || gain > best_gain {
best_gain = gain;
best_v = Some(v);
}
}
let Some(v) = best_v else {
break;
};
part[v] = 0;
in_set[v] = true;
set_weight += hg.vertex_weights[v];
for &hyperedge in hg.vertex_hyperedges(v) {
pins_on_zero[hyperedge as usize] += 1;
}
}
part
}
pub(super) fn hyperedge_cut(hg: &Hypergraph, part: &[u8]) -> u32 {
let mut cut_weight = 0u32;
for hyperedge in 0..hg.num_hyperedges() {
let pins = hg.charged_hyperedge_pins(hyperedge);
let first = part[pins[0] as usize];
if pins.iter().any(|&v| part[v as usize] != first) {
cut_weight += hg.hyperedge_weights[hyperedge];
}
}
cut_weight
}
pub(super) fn initial_partition(hg: &Hypergraph, rng: &mut Xorshift64, imbalance: f64) -> Vec<u8> {
let n = hg.num_vertices;
if n == 0 {
return Vec::new();
}
if n == 1 {
return vec![0];
}
let mut best_part = Vec::new();
let mut best_cut = u32::MAX;
let num_ggg = if n >= 30 { 6 } else { 4 };
let num_rand = if n >= 30 { 6 } else { 4 };
for _ in 0..num_ggg.min(n) {
let seed = (rng.next_u64() as usize) % n;
let part = greedy_growing(hg, seed);
let candidate_cut = hyperedge_cut(hg, &part);
if candidate_cut < best_cut {
best_cut = candidate_cut;
best_part = part;
}
}
for _ in 0..num_rand.min(n) {
let mut part = random_bisection(&hg.vertex_weights, rng);
refine_level(hg, &mut part, imbalance);
let candidate_cut = hyperedge_cut(hg, &part);
if candidate_cut < best_cut {
best_cut = candidate_cut;
best_part = part;
}
}
best_part
}