use crate::error::{MinCutError, Result};
use dashmap::DashMap;
use serde::{Deserialize, Serialize};
use std::collections::{HashSet, VecDeque};
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
pub type VertexId = u64;
pub type EdgeId = u64;
pub type Weight = f64;
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Edge {
pub id: EdgeId,
pub source: VertexId,
pub target: VertexId,
pub weight: Weight,
}
impl Edge {
pub fn new(id: EdgeId, source: VertexId, target: VertexId, weight: Weight) -> Self {
Self {
id,
source,
target,
weight,
}
}
pub fn canonical_endpoints(&self) -> (VertexId, VertexId) {
if self.source <= self.target {
(self.source, self.target)
} else {
(self.target, self.source)
}
}
pub fn other(&self, v: VertexId) -> Option<VertexId> {
if self.source == v {
Some(self.target)
} else if self.target == v {
Some(self.source)
} else {
None
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct GraphStats {
pub num_vertices: usize,
pub num_edges: usize,
pub total_weight: f64,
pub min_degree: usize,
pub max_degree: usize,
pub avg_degree: f64,
}
pub struct DynamicGraph {
adjacency: DashMap<VertexId, HashSet<(VertexId, EdgeId)>>,
edges: DashMap<EdgeId, Edge>,
edge_index: DashMap<(VertexId, VertexId), EdgeId>,
next_edge_id: AtomicU64,
num_vertices: AtomicUsize,
}
impl DynamicGraph {
pub fn new() -> Self {
Self {
adjacency: DashMap::new(),
edges: DashMap::new(),
edge_index: DashMap::new(),
next_edge_id: AtomicU64::new(0),
num_vertices: AtomicUsize::new(0),
}
}
pub fn with_capacity(vertices: usize, edges: usize) -> Self {
Self {
adjacency: DashMap::with_capacity(vertices),
edges: DashMap::with_capacity(edges),
edge_index: DashMap::with_capacity(edges),
next_edge_id: AtomicU64::new(0),
num_vertices: AtomicUsize::new(0),
}
}
pub fn add_vertex(&self, v: VertexId) -> bool {
if self.adjacency.contains_key(&v) {
false
} else {
self.adjacency.insert(v, HashSet::new());
self.num_vertices.fetch_add(1, Ordering::SeqCst);
true
}
}
pub fn has_vertex(&self, v: VertexId) -> bool {
self.adjacency.contains_key(&v)
}
fn canonical_key(u: VertexId, v: VertexId) -> (VertexId, VertexId) {
if u <= v {
(u, v)
} else {
(v, u)
}
}
pub fn insert_edge(&self, u: VertexId, v: VertexId, weight: Weight) -> Result<EdgeId> {
if u == v {
return Err(MinCutError::InvalidEdge(u, v));
}
self.add_vertex(u);
self.add_vertex(v);
let key = Self::canonical_key(u, v);
if self.edge_index.contains_key(&key) {
return Err(MinCutError::EdgeExists(u, v));
}
let edge_id = self.next_edge_id.fetch_add(1, Ordering::SeqCst);
let edge = Edge::new(edge_id, u, v, weight);
self.edges.insert(edge_id, edge);
self.edge_index.insert(key, edge_id);
self.adjacency.get_mut(&u).unwrap().insert((v, edge_id));
self.adjacency.get_mut(&v).unwrap().insert((u, edge_id));
Ok(edge_id)
}
pub fn delete_edge(&self, u: VertexId, v: VertexId) -> Result<Edge> {
let key = Self::canonical_key(u, v);
let edge_id = self
.edge_index
.remove(&key)
.ok_or_else(|| MinCutError::EdgeNotFound(u, v))?
.1;
let (_, edge) = self
.edges
.remove(&edge_id)
.ok_or_else(|| MinCutError::EdgeNotFound(u, v))?;
if let Some(mut neighbors) = self.adjacency.get_mut(&u) {
neighbors.retain(|(neighbor, eid)| !(*neighbor == v && *eid == edge_id));
}
if let Some(mut neighbors) = self.adjacency.get_mut(&v) {
neighbors.retain(|(neighbor, eid)| !(*neighbor == u && *eid == edge_id));
}
Ok(edge)
}
pub fn has_edge(&self, u: VertexId, v: VertexId) -> bool {
let key = Self::canonical_key(u, v);
self.edge_index.contains_key(&key)
}
pub fn get_edge(&self, u: VertexId, v: VertexId) -> Option<Edge> {
let key = Self::canonical_key(u, v);
self.edge_index
.get(&key)
.and_then(|edge_id| self.edges.get(edge_id.value()).map(|e| *e.value()))
}
pub fn neighbors(&self, v: VertexId) -> Vec<(VertexId, EdgeId)> {
self.adjacency
.get(&v)
.map(|neighbors| neighbors.iter().copied().collect())
.unwrap_or_default()
}
pub fn degree(&self, v: VertexId) -> usize {
self.adjacency
.get(&v)
.map(|neighbors| neighbors.len())
.unwrap_or(0)
}
pub fn num_vertices(&self) -> usize {
self.num_vertices.load(Ordering::SeqCst)
}
pub fn num_edges(&self) -> usize {
self.edges.len()
}
pub fn vertices(&self) -> Vec<VertexId> {
self.adjacency.iter().map(|entry| *entry.key()).collect()
}
pub fn edges(&self) -> Vec<Edge> {
self.edges.iter().map(|entry| *entry.value()).collect()
}
pub fn stats(&self) -> GraphStats {
let num_vertices = self.num_vertices();
let num_edges = self.num_edges();
if num_vertices == 0 {
return GraphStats::default();
}
let mut degrees: Vec<usize> = self
.adjacency
.iter()
.map(|entry| entry.value().len())
.collect();
degrees.sort_unstable();
let min_degree = degrees.first().copied().unwrap_or(0);
let max_degree = degrees.last().copied().unwrap_or(0);
let total_degree: usize = degrees.iter().sum();
let avg_degree = total_degree as f64 / num_vertices as f64;
let total_weight: f64 = self.edges.iter().map(|entry| entry.value().weight).sum();
GraphStats {
num_vertices,
num_edges,
total_weight,
min_degree,
max_degree,
avg_degree,
}
}
pub fn is_connected(&self) -> bool {
let num_vertices = self.num_vertices();
if num_vertices == 0 {
return true; }
if num_vertices == 1 {
return true;
}
let start = match self.adjacency.iter().next() {
Some(entry) => *entry.key(),
None => return true,
};
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
queue.push_back(start);
visited.insert(start);
while let Some(v) = queue.pop_front() {
if let Some(neighbors) = self.adjacency.get(&v) {
for (neighbor, _) in neighbors.iter() {
if visited.insert(*neighbor) {
queue.push_back(*neighbor);
}
}
}
}
visited.len() == num_vertices
}
pub fn connected_components(&self) -> Vec<Vec<VertexId>> {
let mut visited = HashSet::new();
let mut components = Vec::new();
for entry in self.adjacency.iter() {
let start = *entry.key();
if visited.contains(&start) {
continue;
}
let mut component = Vec::new();
let mut queue = VecDeque::new();
queue.push_back(start);
visited.insert(start);
while let Some(v) = queue.pop_front() {
component.push(v);
if let Some(neighbors) = self.adjacency.get(&v) {
for (neighbor, _) in neighbors.iter() {
if visited.insert(*neighbor) {
queue.push_back(*neighbor);
}
}
}
}
components.push(component);
}
components
}
pub fn clear(&self) {
self.adjacency.clear();
self.edges.clear();
self.edge_index.clear();
self.next_edge_id.store(0, Ordering::SeqCst);
self.num_vertices.store(0, Ordering::SeqCst);
}
pub fn remove_vertex(&self, v: VertexId) -> Result<()> {
if !self.has_vertex(v) {
return Err(MinCutError::InvalidVertex(v));
}
let incident_edges: Vec<(VertexId, EdgeId)> = self.neighbors(v);
for (neighbor, _) in incident_edges {
let _ = self.delete_edge(v, neighbor);
}
self.adjacency.remove(&v);
self.num_vertices.fetch_sub(1, Ordering::SeqCst);
Ok(())
}
pub fn edge_weight(&self, u: VertexId, v: VertexId) -> Option<Weight> {
self.get_edge(u, v).map(|e| e.weight)
}
pub fn update_edge_weight(&self, u: VertexId, v: VertexId, new_weight: Weight) -> Result<()> {
let key = Self::canonical_key(u, v);
let edge_id = self
.edge_index
.get(&key)
.ok_or_else(|| MinCutError::EdgeNotFound(u, v))?;
let edge_id = *edge_id.value();
if let Some(mut edge_ref) = self.edges.get_mut(&edge_id) {
edge_ref.weight = new_weight;
Ok(())
} else {
Err(MinCutError::EdgeNotFound(u, v))
}
}
}
impl Default for DynamicGraph {
fn default() -> Self {
Self::new()
}
}
impl Clone for DynamicGraph {
fn clone(&self) -> Self {
let new_graph = Self::with_capacity(self.num_vertices(), self.num_edges());
for entry in self.adjacency.iter() {
new_graph.add_vertex(*entry.key());
}
for entry in self.edges.iter() {
let edge = entry.value();
let _ = new_graph.insert_edge(edge.source, edge.target, edge.weight);
}
new_graph
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_graph() {
let g = DynamicGraph::new();
assert_eq!(g.num_vertices(), 0);
assert_eq!(g.num_edges(), 0);
assert!(g.is_connected());
}
#[test]
fn test_add_vertex() {
let g = DynamicGraph::new();
assert!(g.add_vertex(1));
assert!(!g.add_vertex(1)); assert_eq!(g.num_vertices(), 1);
assert!(g.has_vertex(1));
assert!(!g.has_vertex(2));
}
#[test]
fn test_insert_edge() {
let g = DynamicGraph::new();
let edge_id = g.insert_edge(1, 2, 1.0).unwrap();
assert_eq!(g.num_edges(), 1);
assert_eq!(g.num_vertices(), 2);
assert!(g.has_edge(1, 2));
assert!(g.has_edge(2, 1));
assert_eq!(edge_id, 0);
}
#[test]
fn test_insert_duplicate_edge() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
let result = g.insert_edge(1, 2, 2.0);
assert!(matches!(result, Err(MinCutError::EdgeExists(1, 2))));
}
#[test]
fn test_insert_self_loop() {
let g = DynamicGraph::new();
let result = g.insert_edge(1, 1, 1.0);
assert!(matches!(result, Err(MinCutError::InvalidEdge(1, 1))));
}
#[test]
fn test_delete_edge() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.5).unwrap();
assert_eq!(g.num_edges(), 1);
let edge = g.delete_edge(1, 2).unwrap();
assert_eq!(edge.weight, 1.5);
assert_eq!(g.num_edges(), 0);
assert!(!g.has_edge(1, 2));
}
#[test]
fn test_delete_nonexistent_edge() {
let g = DynamicGraph::new();
let result = g.delete_edge(1, 2);
assert!(matches!(result, Err(MinCutError::EdgeNotFound(1, 2))));
}
#[test]
fn test_neighbors() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.insert_edge(1, 3, 1.0).unwrap();
g.insert_edge(1, 4, 1.0).unwrap();
let neighbors = g.neighbors(1);
assert_eq!(neighbors.len(), 3);
let neighbor_ids: HashSet<VertexId> = neighbors.iter().map(|(v, _)| *v).collect();
assert!(neighbor_ids.contains(&2));
assert!(neighbor_ids.contains(&3));
assert!(neighbor_ids.contains(&4));
}
#[test]
fn test_degree() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.insert_edge(1, 3, 1.0).unwrap();
assert_eq!(g.degree(1), 2);
assert_eq!(g.degree(2), 1);
assert_eq!(g.degree(3), 1);
assert_eq!(g.degree(4), 0); }
#[test]
fn test_get_edge() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 2.5).unwrap();
let edge = g.get_edge(1, 2).unwrap();
assert_eq!(edge.weight, 2.5);
assert_eq!(edge.source, 1);
assert_eq!(edge.target, 2);
let edge = g.get_edge(2, 1).unwrap();
assert_eq!(edge.weight, 2.5);
assert!(g.get_edge(1, 3).is_none());
}
#[test]
fn test_stats() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.insert_edge(2, 3, 2.0).unwrap();
g.insert_edge(3, 1, 3.0).unwrap();
let stats = g.stats();
assert_eq!(stats.num_vertices, 3);
assert_eq!(stats.num_edges, 3);
assert_eq!(stats.total_weight, 6.0);
assert_eq!(stats.min_degree, 2);
assert_eq!(stats.max_degree, 2);
assert_eq!(stats.avg_degree, 2.0);
}
#[test]
fn test_is_connected_single_component() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.insert_edge(2, 3, 1.0).unwrap();
g.insert_edge(3, 4, 1.0).unwrap();
assert!(g.is_connected());
}
#[test]
fn test_is_connected_disconnected() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.insert_edge(3, 4, 1.0).unwrap();
assert!(!g.is_connected());
}
#[test]
fn test_connected_components() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.insert_edge(2, 3, 1.0).unwrap();
g.insert_edge(4, 5, 1.0).unwrap();
g.insert_edge(6, 7, 1.0).unwrap();
g.insert_edge(7, 8, 1.0).unwrap();
let components = g.connected_components();
assert_eq!(components.len(), 3);
let mut sizes: Vec<usize> = components.iter().map(|c| c.len()).collect();
sizes.sort_unstable();
assert_eq!(sizes, vec![2, 3, 3]);
}
#[test]
fn test_clear() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.insert_edge(2, 3, 1.0).unwrap();
assert_eq!(g.num_vertices(), 3);
assert_eq!(g.num_edges(), 2);
g.clear();
assert_eq!(g.num_vertices(), 0);
assert_eq!(g.num_edges(), 0);
}
#[test]
fn test_remove_vertex() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.insert_edge(2, 3, 1.0).unwrap();
g.insert_edge(1, 3, 1.0).unwrap();
assert_eq!(g.num_vertices(), 3);
assert_eq!(g.num_edges(), 3);
g.remove_vertex(2).unwrap();
assert_eq!(g.num_vertices(), 2);
assert_eq!(g.num_edges(), 1);
assert!(!g.has_vertex(2));
assert!(g.has_edge(1, 3));
assert!(!g.has_edge(1, 2));
assert!(!g.has_edge(2, 3));
}
#[test]
fn test_edge_weight() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 3.5).unwrap();
assert_eq!(g.edge_weight(1, 2), Some(3.5));
assert_eq!(g.edge_weight(2, 1), Some(3.5));
assert_eq!(g.edge_weight(1, 3), None);
}
#[test]
fn test_update_edge_weight() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.update_edge_weight(1, 2, 5.0).unwrap();
assert_eq!(g.edge_weight(1, 2), Some(5.0));
let result = g.update_edge_weight(1, 3, 2.0);
assert!(matches!(result, Err(MinCutError::EdgeNotFound(1, 3))));
}
#[test]
fn test_clone() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.insert_edge(2, 3, 2.0).unwrap();
let g2 = g.clone();
assert_eq!(g2.num_vertices(), 3);
assert_eq!(g2.num_edges(), 2);
assert!(g2.has_edge(1, 2));
assert!(g2.has_edge(2, 3));
assert_eq!(g2.edge_weight(1, 2), Some(1.0));
assert_eq!(g2.edge_weight(2, 3), Some(2.0));
}
#[test]
fn test_edge_canonical_endpoints() {
let edge = Edge::new(0, 5, 3, 1.0);
assert_eq!(edge.canonical_endpoints(), (3, 5));
let edge = Edge::new(0, 2, 7, 1.0);
assert_eq!(edge.canonical_endpoints(), (2, 7));
}
#[test]
fn test_edge_other() {
let edge = Edge::new(0, 1, 2, 1.0);
assert_eq!(edge.other(1), Some(2));
assert_eq!(edge.other(2), Some(1));
assert_eq!(edge.other(3), None);
}
#[test]
fn test_with_capacity() {
let g = DynamicGraph::with_capacity(100, 200);
assert_eq!(g.num_vertices(), 0);
assert_eq!(g.num_edges(), 0);
g.insert_edge(1, 2, 1.0).unwrap();
assert_eq!(g.num_edges(), 1);
}
#[test]
fn test_vertices_and_edges() {
let g = DynamicGraph::new();
g.insert_edge(1, 2, 1.0).unwrap();
g.insert_edge(2, 3, 2.0).unwrap();
let vertices = g.vertices();
assert_eq!(vertices.len(), 3);
assert!(vertices.contains(&1));
assert!(vertices.contains(&2));
assert!(vertices.contains(&3));
let edges = g.edges();
assert_eq!(edges.len(), 2);
}
}