use crate::graph::Graph;
use crate::id::{EdgeId, PortId};
use std::collections::HashMap;
#[derive(Debug, Clone, Default)]
pub struct Net {
pub ports: Vec<PortId>,
pub edges: Vec<EdgeId>,
}
impl<N, P, E> Graph<N, P, E> {
pub fn nets(&self) -> Vec<Net> {
let port_ids: Vec<PortId> = self.all_ports().map(|(id, _)| id).collect();
let index: HashMap<PortId, usize> =
port_ids.iter().enumerate().map(|(i, &p)| (p, i)).collect();
let mut uf = UnionFind::new(port_ids.len());
for (edge, _) in self.all_edges() {
let (a, b) = self.edge_endpoints(edge).expect("live edge");
uf.union(index[&a], index[&b]);
}
let mut by_root: HashMap<usize, Net> = HashMap::new();
for (i, &port) in port_ids.iter().enumerate() {
by_root.entry(uf.find(i)).or_default().ports.push(port);
}
for (edge, _) in self.all_edges() {
let (a, _) = self.edge_endpoints(edge).expect("live edge");
by_root
.entry(uf.find(index[&a]))
.or_default()
.edges
.push(edge);
}
by_root.into_values().collect()
}
}
struct UnionFind {
parent: Vec<usize>,
size: Vec<usize>,
}
impl UnionFind {
fn new(n: usize) -> Self {
UnionFind {
parent: (0..n).collect(),
size: vec![1; n],
}
}
fn find(&mut self, mut x: usize) -> usize {
while self.parent[x] != x {
self.parent[x] = self.parent[self.parent[x]]; x = self.parent[x];
}
x
}
fn union(&mut self, a: usize, b: usize) {
let (mut ra, mut rb) = (self.find(a), self.find(b));
if ra == rb {
return;
}
if self.size[ra] < self.size[rb] {
core::mem::swap(&mut ra, &mut rb);
}
self.parent[rb] = ra;
self.size[ra] += self.size[rb];
}
}