use crate::graph::{DynamicGraph, Edge, EdgeId, VertexId, Weight};
use crate::linkcut::LinkCutTree;
use crate::{MinCutError, Result};
use parking_lot::RwLock;
use std::collections::{HashMap, HashSet, VecDeque};
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct EdgeWitness {
pub tree_edge: (VertexId, VertexId),
pub cut_value: Weight,
pub cut_side: HashSet<VertexId>,
}
impl EdgeWitness {
fn new(
tree_edge: (VertexId, VertexId),
cut_value: Weight,
cut_side: HashSet<VertexId>,
) -> Self {
Self {
tree_edge,
cut_value,
cut_side,
}
}
}
pub struct WitnessTree {
lct: LinkCutTree,
witnesses: HashMap<(VertexId, VertexId), EdgeWitness>,
min_cut: Weight,
min_cut_edges: Vec<Edge>,
graph: Arc<RwLock<DynamicGraph>>,
dirty: bool,
tree_edges: HashSet<(VertexId, VertexId)>,
non_tree_edges: HashSet<(VertexId, VertexId)>,
}
impl WitnessTree {
pub fn build(graph: Arc<RwLock<DynamicGraph>>) -> Result<Self> {
let mut witness_tree = Self {
lct: LinkCutTree::new(),
witnesses: HashMap::new(),
min_cut: f64::INFINITY,
min_cut_edges: Vec::new(),
graph: graph.clone(),
dirty: true,
tree_edges: HashSet::new(),
non_tree_edges: HashSet::new(),
};
witness_tree.build_spanning_tree()?;
witness_tree.recompute_min_cut();
Ok(witness_tree)
}
#[inline]
pub fn min_cut_value(&self) -> Weight {
self.min_cut
}
pub fn min_cut_edges(&self) -> &[Edge] {
&self.min_cut_edges
}
pub fn insert_edge(&mut self, u: VertexId, v: VertexId, _weight: Weight) -> Result<Weight> {
let u_exists = (0..self.lct.len()).any(|_| true);
if u_exists {
match self.lct.find_root(u) {
Err(_) => {
self.lct.make_tree(u, 0.0);
}
Ok(_) => {}
}
} else {
self.lct.make_tree(u, 0.0);
}
match self.lct.find_root(v) {
Err(_) => {
self.lct.make_tree(v, 0.0);
}
Ok(_) => {}
}
let connected = self.lct.connected(u, v);
let key = Self::canonical_key(u, v);
if connected {
self.non_tree_edges.insert(key);
self.dirty = true;
} else {
self.tree_edges.insert(key);
self.lct.link(u, v)?;
self.update_witness((u, v));
self.dirty = true;
}
if self.dirty {
self.recompute_min_cut();
}
Ok(self.min_cut)
}
pub fn delete_edge(&mut self, u: VertexId, v: VertexId) -> Result<Weight> {
let key = Self::canonical_key(u, v);
if self.tree_edges.contains(&key) {
self.tree_edges.remove(&key);
self.witnesses.remove(&key);
if self.lct.cut(v).is_err() {
let _ = self.lct.cut(u); }
if let Some(replacement) = self.find_replacement(u, v) {
let (ru, rv) = replacement;
self.tree_edges.insert(Self::canonical_key(ru, rv));
self.lct.link(ru, rv)?;
self.update_witness(replacement);
}
self.dirty = true;
} else if self.non_tree_edges.contains(&key) {
self.non_tree_edges.remove(&key);
self.dirty = true;
}
if self.dirty {
self.recompute_min_cut();
}
Ok(self.min_cut)
}
pub fn is_tree_edge(&self, u: VertexId, v: VertexId) -> bool {
let key = Self::canonical_key(u, v);
self.tree_edges.contains(&key)
}
pub fn find_witness(&self, u: VertexId, v: VertexId) -> Option<&EdgeWitness> {
let key = Self::canonical_key(u, v);
self.witnesses.get(&key)
}
fn recompute_min_cut(&mut self) {
let graph = self.graph.read();
if !graph.is_connected() {
self.min_cut = 0.0;
self.min_cut_edges = Vec::new();
self.dirty = false;
return;
}
let mut min_value = f64::INFINITY;
let mut min_edges = Vec::new();
for (_edge_key, witness) in &self.witnesses {
if witness.cut_value < min_value {
min_value = witness.cut_value;
min_edges = self.compute_cut_edges(&witness.cut_side);
}
}
self.min_cut = min_value;
self.min_cut_edges = min_edges;
self.dirty = false;
}
fn update_witness(&mut self, edge: (VertexId, VertexId)) {
let (u, v) = edge;
let cut_value = self.tree_edge_cut(u, v);
let cut_side = self.find_component(u, v);
let key = Self::canonical_key(u, v);
let witness = EdgeWitness::new(key, cut_value, cut_side);
self.witnesses.insert(key, witness);
}
fn find_replacement(&mut self, u: VertexId, v: VertexId) -> Option<(VertexId, VertexId)> {
let graph = self.graph.read();
let component_u = self.find_component(u, v);
for &vertex in &component_u {
for (neighbor, _) in graph.neighbors(vertex) {
if !component_u.contains(&neighbor) {
let key = Self::canonical_key(vertex, neighbor);
if self.non_tree_edges.contains(&key) {
self.non_tree_edges.remove(&key);
return Some((vertex, neighbor));
}
}
}
}
None
}
fn tree_edge_cut(&self, u: VertexId, v: VertexId) -> Weight {
let component_u = self.find_component(u, v);
self.compute_cut_value(&component_u)
}
fn find_component(&self, u: VertexId, v: VertexId) -> HashSet<VertexId> {
let graph = self.graph.read();
let mut component = HashSet::new();
let mut queue = VecDeque::new();
queue.push_back(u);
component.insert(u);
while let Some(current) = queue.pop_front() {
for (neighbor, _) in graph.neighbors(current) {
if (current == u && neighbor == v) || (current == v && neighbor == u) {
continue;
}
if !self.is_tree_edge(current, neighbor) {
continue;
}
if component.insert(neighbor) {
queue.push_back(neighbor);
}
}
}
component
}
fn compute_cut_value(&self, side_a: &HashSet<VertexId>) -> Weight {
let graph = self.graph.read();
let mut cut_value = 0.0;
for &vertex in side_a {
for (neighbor, _) in graph.neighbors(vertex) {
if !side_a.contains(&neighbor) {
if let Some(weight) = graph.edge_weight(vertex, neighbor) {
cut_value += weight;
}
}
}
}
cut_value
}
fn compute_cut_edges(&self, side_a: &HashSet<VertexId>) -> Vec<Edge> {
let graph = self.graph.read();
let mut cut_edges = Vec::new();
for &vertex in side_a {
for (neighbor, _) in graph.neighbors(vertex) {
if !side_a.contains(&neighbor) {
if let Some(edge) = graph.get_edge(vertex, neighbor) {
cut_edges.push(edge);
}
}
}
}
cut_edges
}
fn build_spanning_tree(&mut self) -> Result<()> {
let vertices = {
let graph = self.graph.read();
let v = graph.vertices();
if v.is_empty() {
return Ok(());
}
v
};
for &vertex in &vertices {
self.lct.make_tree(vertex, 0.0);
}
let mut visited = HashSet::new();
for &start in &vertices {
if visited.contains(&start) {
continue;
}
let mut queue = VecDeque::new();
queue.push_back(start);
visited.insert(start);
while let Some(current) = queue.pop_front() {
let neighbors = {
let graph = self.graph.read();
graph.neighbors(current)
};
for (neighbor, _) in neighbors {
if visited.insert(neighbor) {
let key = Self::canonical_key(current, neighbor);
self.tree_edges.insert(key);
self.lct.link(current, neighbor)?;
queue.push_back(neighbor);
} else if !self.is_tree_edge(current, neighbor) {
let key = Self::canonical_key(current, neighbor);
self.non_tree_edges.insert(key);
}
}
}
}
let tree_edges: Vec<_> = self.tree_edges.iter().copied().collect();
for (u, v) in tree_edges {
self.update_witness((u, v));
}
Ok(())
}
fn canonical_key(u: VertexId, v: VertexId) -> (VertexId, VertexId) {
if u <= v {
(u, v)
} else {
(v, u)
}
}
}
pub struct LazyWitnessTree {
inner: WitnessTree,
pending_updates: Vec<(VertexId, VertexId, bool)>,
batch_threshold: usize,
}
impl LazyWitnessTree {
pub fn new(graph: Arc<RwLock<DynamicGraph>>) -> Result<Self> {
Ok(Self {
inner: WitnessTree::build(graph)?,
pending_updates: Vec::new(),
batch_threshold: 10,
})
}
pub fn with_threshold(graph: Arc<RwLock<DynamicGraph>>, threshold: usize) -> Result<Self> {
Ok(Self {
inner: WitnessTree::build(graph)?,
pending_updates: Vec::new(),
batch_threshold: threshold,
})
}
pub fn insert_edge(&mut self, u: VertexId, v: VertexId, _weight: Weight) -> Result<Weight> {
self.pending_updates.push((u, v, true));
if self.pending_updates.len() >= self.batch_threshold {
self.flush_pending();
}
Ok(self.inner.min_cut_value())
}
pub fn delete_edge(&mut self, u: VertexId, v: VertexId) -> Result<Weight> {
self.pending_updates.push((u, v, false));
if self.pending_updates.len() >= self.batch_threshold {
self.flush_pending();
}
Ok(self.inner.min_cut_value())
}
pub fn min_cut_value(&mut self) -> Weight {
self.flush_pending();
self.inner.min_cut_value()
}
pub fn min_cut_edges(&mut self) -> &[Edge] {
self.flush_pending();
self.inner.min_cut_edges()
}
fn flush_pending(&mut self) {
if self.pending_updates.is_empty() {
return;
}
for (u, v, is_insert) in self.pending_updates.drain(..) {
if is_insert {
let weight = self.inner.graph.read().edge_weight(u, v).unwrap_or(1.0);
let _ = self.inner.insert_edge(u, v, weight);
} else {
let _ = self.inner.delete_edge(u, v);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_triangle_graph() -> Arc<RwLock<DynamicGraph>> {
let graph = Arc::new(RwLock::new(DynamicGraph::new()));
graph.write().insert_edge(1, 2, 1.0).unwrap();
graph.write().insert_edge(2, 3, 1.0).unwrap();
graph.write().insert_edge(3, 1, 1.0).unwrap();
graph
}
fn create_bridge_graph() -> Arc<RwLock<DynamicGraph>> {
let graph = Arc::new(RwLock::new(DynamicGraph::new()));
graph.write().insert_edge(1, 2, 2.0).unwrap();
graph.write().insert_edge(2, 3, 2.0).unwrap();
graph.write().insert_edge(3, 1, 2.0).unwrap();
graph.write().insert_edge(3, 4, 1.0).unwrap();
graph.write().insert_edge(4, 5, 2.0).unwrap();
graph.write().insert_edge(5, 6, 2.0).unwrap();
graph.write().insert_edge(6, 4, 2.0).unwrap();
graph
}
#[test]
fn test_build_empty() {
let graph = Arc::new(RwLock::new(DynamicGraph::new()));
let witness = WitnessTree::build(graph).unwrap();
assert!(witness.min_cut_value().is_infinite());
}
#[test]
fn test_build_single_vertex() {
let graph = Arc::new(RwLock::new(DynamicGraph::new()));
graph.write().add_vertex(1);
let witness = WitnessTree::build(graph).unwrap();
assert!(witness.min_cut_value().is_infinite());
}
#[test]
fn test_build_triangle() {
let graph = create_triangle_graph();
let witness = WitnessTree::build(graph).unwrap();
assert_eq!(witness.min_cut_value(), 2.0);
assert_eq!(witness.min_cut_edges().len(), 2);
}
#[test]
fn test_build_bridge() {
let graph = create_bridge_graph();
let witness = WitnessTree::build(graph).unwrap();
assert_eq!(witness.min_cut_value(), 1.0);
}
#[test]
fn test_is_tree_edge() {
let graph = create_triangle_graph();
let witness = WitnessTree::build(graph).unwrap();
let tree_edge_count = [(1, 2), (2, 3), (3, 1)]
.iter()
.filter(|(u, v)| witness.is_tree_edge(*u, *v))
.count();
assert_eq!(tree_edge_count, 2);
}
#[test]
fn test_find_witness() {
let graph = create_triangle_graph();
let witness = WitnessTree::build(graph).unwrap();
for (u, v) in [(1, 2), (2, 3), (3, 1)] {
if witness.is_tree_edge(u, v) {
let edge_witness = witness.find_witness(u, v);
assert!(edge_witness.is_some());
let w = edge_witness.unwrap();
let canonical = WitnessTree::canonical_key(u, v);
assert_eq!(w.tree_edge, canonical);
assert!(w.cut_value.is_finite());
}
}
}
#[test]
fn test_insert_bridge_edge() {
let graph = Arc::new(RwLock::new(DynamicGraph::new()));
graph.write().add_vertex(1);
graph.write().add_vertex(2);
let mut witness = WitnessTree::build(graph.clone()).unwrap();
assert_eq!(witness.min_cut_value(), 0.0);
graph.write().insert_edge(1, 2, 3.0).unwrap();
let new_cut = witness.insert_edge(1, 2, 3.0).unwrap();
assert_eq!(new_cut, 3.0);
assert!(witness.is_tree_edge(1, 2));
}
#[test]
fn test_insert_cycle_edge() {
let graph = create_triangle_graph();
let mut witness = WitnessTree::build(graph.clone()).unwrap();
let _old_cut = witness.min_cut_value();
graph.write().insert_edge(1, 4, 2.0).unwrap();
graph.write().insert_edge(2, 4, 2.0).unwrap();
let new_cut = witness.insert_edge(1, 4, 2.0).unwrap();
witness.insert_edge(2, 4, 2.0).unwrap();
assert!(new_cut.is_finite());
}
#[test]
fn test_delete_tree_edge() {
let graph = create_triangle_graph();
let mut witness = WitnessTree::build(graph.clone()).unwrap();
let tree_edge = [(1, 2), (2, 3), (3, 1)]
.iter()
.find(|(u, v)| witness.is_tree_edge(*u, *v))
.copied()
.unwrap();
let (u, v) = tree_edge;
graph.write().delete_edge(u, v).unwrap();
let new_cut = witness.delete_edge(u, v).unwrap();
assert!(new_cut.is_finite());
assert!(!witness.is_tree_edge(u, v));
}
#[test]
fn test_delete_non_tree_edge() {
let graph = create_triangle_graph();
let mut witness = WitnessTree::build(graph.clone()).unwrap();
let non_tree_edge = [(1, 2), (2, 3), (3, 1)]
.iter()
.find(|(u, v)| !witness.is_tree_edge(*u, *v))
.copied()
.unwrap();
let (u, v) = non_tree_edge;
graph.write().delete_edge(u, v).unwrap();
let new_cut = witness.delete_edge(u, v).unwrap();
assert!(new_cut.is_finite());
}
#[test]
fn test_tree_edge_cut() {
let graph = create_bridge_graph();
let witness = WitnessTree::build(graph).unwrap();
if witness.is_tree_edge(3, 4) {
let cut_value = witness.tree_edge_cut(3, 4);
assert_eq!(cut_value, 1.0);
}
}
#[test]
fn test_find_component() {
let graph = create_bridge_graph();
let witness = WitnessTree::build(graph).unwrap();
let component = witness.find_component(1, 4);
assert!(component.contains(&1) || component.len() >= 1);
}
#[test]
fn test_canonical_key() {
assert_eq!(WitnessTree::canonical_key(1, 2), (1, 2));
assert_eq!(WitnessTree::canonical_key(2, 1), (1, 2));
assert_eq!(WitnessTree::canonical_key(5, 3), (3, 5));
}
#[test]
fn test_lazy_witness_tree() {
let graph = create_triangle_graph();
let mut lazy = LazyWitnessTree::new(graph.clone()).unwrap();
graph.write().insert_edge(1, 4, 1.0).unwrap();
lazy.insert_edge(1, 4, 1.0).unwrap();
graph.write().insert_edge(2, 4, 1.0).unwrap();
lazy.insert_edge(2, 4, 1.0).unwrap();
let min_cut = lazy.min_cut_value();
assert!(min_cut.is_finite());
}
#[test]
fn test_lazy_witness_batch_threshold() {
let graph = create_triangle_graph();
let mut lazy = LazyWitnessTree::with_threshold(graph.clone(), 2).unwrap();
graph.write().insert_edge(1, 4, 1.0).unwrap();
lazy.insert_edge(1, 4, 1.0).unwrap();
graph.write().insert_edge(2, 4, 1.0).unwrap();
lazy.insert_edge(2, 4, 1.0).unwrap();
let min_cut = lazy.min_cut_value();
assert!(min_cut.is_finite());
}
#[test]
fn test_disconnected_graph() {
let graph = Arc::new(RwLock::new(DynamicGraph::new()));
graph.write().insert_edge(1, 2, 1.0).unwrap();
graph.write().insert_edge(3, 4, 1.0).unwrap();
let witness = WitnessTree::build(graph).unwrap();
assert_eq!(witness.min_cut_value(), 0.0);
}
#[test]
fn test_dynamic_sequence() {
let graph = Arc::new(RwLock::new(DynamicGraph::new()));
let mut witness = WitnessTree::build(graph.clone()).unwrap();
graph.write().insert_edge(1, 2, 1.0).unwrap();
witness.insert_edge(1, 2, 1.0).unwrap();
assert_eq!(witness.min_cut_value(), 1.0);
graph.write().insert_edge(2, 3, 1.0).unwrap();
witness.insert_edge(2, 3, 1.0).unwrap();
assert_eq!(witness.min_cut_value(), 1.0);
graph.write().insert_edge(3, 1, 1.0).unwrap();
witness.insert_edge(3, 1, 1.0).unwrap();
let cut_after_triangle = witness.min_cut_value();
assert!(cut_after_triangle >= 1.0 && cut_after_triangle <= 2.0);
graph.write().delete_edge(1, 2).unwrap();
witness.delete_edge(1, 2).unwrap();
assert_eq!(witness.min_cut_value(), 1.0);
}
#[test]
fn test_weighted_edges() {
let graph = Arc::new(RwLock::new(DynamicGraph::new()));
graph.write().insert_edge(1, 2, 5.0).unwrap();
graph.write().insert_edge(2, 3, 3.0).unwrap();
graph.write().insert_edge(3, 1, 2.0).unwrap();
let witness = WitnessTree::build(graph).unwrap();
let min_cut = witness.min_cut_value();
assert!(
min_cut >= 5.0 && min_cut <= 7.0,
"Min cut should be between 5.0 and 7.0, got {}",
min_cut
);
}
#[test]
fn test_large_graph() {
let graph = Arc::new(RwLock::new(DynamicGraph::new()));
for i in 1..10 {
graph.write().insert_edge(i, i + 1, 1.0).unwrap();
}
let witness = WitnessTree::build(graph).unwrap();
assert_eq!(witness.min_cut_value(), 1.0);
}
#[test]
fn test_complete_graph() {
let graph = Arc::new(RwLock::new(DynamicGraph::new()));
for i in 1..=4 {
for j in (i + 1)..=4 {
graph.write().insert_edge(i, j, 1.0).unwrap();
}
}
let witness = WitnessTree::build(graph).unwrap();
assert_eq!(witness.min_cut_value(), 3.0);
}
}