ruvector_mincut/graph/
mod.rs

1//! Graph representation for dynamic minimum cut
2//!
3//! Provides an adjacency-based graph structure optimized for:
4//! - O(1) edge existence queries
5//! - O(deg(v)) neighbor iteration
6//! - Efficient edge insertion/deletion
7//! - Support for weighted edges
8
9use std::collections::{HashSet, VecDeque};
10use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
11use dashmap::DashMap;
12use serde::{Deserialize, Serialize};
13use crate::error::{MinCutError, Result};
14
15/// Unique vertex identifier
16pub type VertexId = u64;
17
18/// Unique edge identifier
19pub type EdgeId = u64;
20
21/// Edge weight type
22pub type Weight = f64;
23
24/// An edge in the graph
25#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
26pub struct Edge {
27    /// Unique identifier for this edge
28    pub id: EdgeId,
29    /// Source vertex of the edge
30    pub source: VertexId,
31    /// Target vertex of the edge
32    pub target: VertexId,
33    /// Weight of the edge
34    pub weight: Weight,
35}
36
37impl Edge {
38    /// Create a new edge
39    pub fn new(id: EdgeId, source: VertexId, target: VertexId, weight: Weight) -> Self {
40        Self {
41            id,
42            source,
43            target,
44            weight,
45        }
46    }
47
48    /// Get the canonical (ordered) endpoints
49    pub fn canonical_endpoints(&self) -> (VertexId, VertexId) {
50        if self.source <= self.target {
51            (self.source, self.target)
52        } else {
53            (self.target, self.source)
54        }
55    }
56
57    /// Get the other endpoint of the edge given one endpoint
58    pub fn other(&self, v: VertexId) -> Option<VertexId> {
59        if self.source == v {
60            Some(self.target)
61        } else if self.target == v {
62            Some(self.source)
63        } else {
64            None
65        }
66    }
67}
68
69/// Statistics about the graph
70#[derive(Debug, Clone, Default, Serialize, Deserialize)]
71pub struct GraphStats {
72    /// Number of vertices in the graph
73    pub num_vertices: usize,
74    /// Number of edges in the graph
75    pub num_edges: usize,
76    /// Sum of all edge weights
77    pub total_weight: f64,
78    /// Minimum vertex degree
79    pub min_degree: usize,
80    /// Maximum vertex degree
81    pub max_degree: usize,
82    /// Average vertex degree
83    pub avg_degree: f64,
84}
85
86/// Dynamic graph structure for minimum cut algorithm
87pub struct DynamicGraph {
88    /// Adjacency list: vertex -> set of (neighbor, edge_id)
89    adjacency: DashMap<VertexId, HashSet<(VertexId, EdgeId)>>,
90    /// Edge storage: edge_id -> Edge
91    edges: DashMap<EdgeId, Edge>,
92    /// Edge lookup: (min(u,v), max(u,v)) -> edge_id
93    edge_index: DashMap<(VertexId, VertexId), EdgeId>,
94    /// Next edge ID
95    next_edge_id: AtomicU64,
96    /// Number of vertices
97    num_vertices: AtomicUsize,
98}
99
100impl DynamicGraph {
101    /// Create a new empty graph
102    pub fn new() -> Self {
103        Self {
104            adjacency: DashMap::new(),
105            edges: DashMap::new(),
106            edge_index: DashMap::new(),
107            next_edge_id: AtomicU64::new(0),
108            num_vertices: AtomicUsize::new(0),
109        }
110    }
111
112    /// Create with capacity hint
113    pub fn with_capacity(vertices: usize, edges: usize) -> Self {
114        Self {
115            adjacency: DashMap::with_capacity(vertices),
116            edges: DashMap::with_capacity(edges),
117            edge_index: DashMap::with_capacity(edges),
118            next_edge_id: AtomicU64::new(0),
119            num_vertices: AtomicUsize::new(0),
120        }
121    }
122
123    /// Add a vertex (returns true if new)
124    pub fn add_vertex(&self, v: VertexId) -> bool {
125        if self.adjacency.contains_key(&v) {
126            false
127        } else {
128            self.adjacency.insert(v, HashSet::new());
129            self.num_vertices.fetch_add(1, Ordering::SeqCst);
130            true
131        }
132    }
133
134    /// Check if vertex exists
135    pub fn has_vertex(&self, v: VertexId) -> bool {
136        self.adjacency.contains_key(&v)
137    }
138
139    /// Get canonical edge key (min, max) for consistent lookup
140    fn canonical_key(u: VertexId, v: VertexId) -> (VertexId, VertexId) {
141        if u <= v {
142            (u, v)
143        } else {
144            (v, u)
145        }
146    }
147
148    /// Insert an edge (returns edge ID if successful)
149    pub fn insert_edge(&self, u: VertexId, v: VertexId, weight: Weight) -> Result<EdgeId> {
150        // Self-loops are not allowed
151        if u == v {
152            return Err(MinCutError::InvalidEdge(u, v));
153        }
154
155        // Ensure both vertices exist
156        self.add_vertex(u);
157        self.add_vertex(v);
158
159        let key = Self::canonical_key(u, v);
160
161        // Check if edge already exists
162        if self.edge_index.contains_key(&key) {
163            return Err(MinCutError::EdgeExists(u, v));
164        }
165
166        // Generate new edge ID
167        let edge_id = self.next_edge_id.fetch_add(1, Ordering::SeqCst);
168
169        // Create edge
170        let edge = Edge::new(edge_id, u, v, weight);
171
172        // Insert into edge storage
173        self.edges.insert(edge_id, edge);
174
175        // Insert into edge index
176        self.edge_index.insert(key, edge_id);
177
178        // Update adjacency lists
179        self.adjacency.get_mut(&u).unwrap().insert((v, edge_id));
180        self.adjacency.get_mut(&v).unwrap().insert((u, edge_id));
181
182        Ok(edge_id)
183    }
184
185    /// Delete an edge (returns the removed edge)
186    pub fn delete_edge(&self, u: VertexId, v: VertexId) -> Result<Edge> {
187        let key = Self::canonical_key(u, v);
188
189        // Get edge ID
190        let edge_id = self.edge_index
191            .remove(&key)
192            .ok_or_else(|| MinCutError::EdgeNotFound(u, v))?
193            .1;
194
195        // Remove from edge storage
196        let (_, edge) = self.edges
197            .remove(&edge_id)
198            .ok_or_else(|| MinCutError::EdgeNotFound(u, v))?;
199
200        // Update adjacency lists
201        if let Some(mut neighbors) = self.adjacency.get_mut(&u) {
202            neighbors.retain(|(neighbor, eid)| !(*neighbor == v && *eid == edge_id));
203        }
204        if let Some(mut neighbors) = self.adjacency.get_mut(&v) {
205            neighbors.retain(|(neighbor, eid)| !(*neighbor == u && *eid == edge_id));
206        }
207
208        Ok(edge)
209    }
210
211    /// Check if edge exists
212    pub fn has_edge(&self, u: VertexId, v: VertexId) -> bool {
213        let key = Self::canonical_key(u, v);
214        self.edge_index.contains_key(&key)
215    }
216
217    /// Get edge by endpoints
218    pub fn get_edge(&self, u: VertexId, v: VertexId) -> Option<Edge> {
219        let key = Self::canonical_key(u, v);
220        self.edge_index.get(&key).and_then(|edge_id| {
221            self.edges.get(edge_id.value()).map(|e| *e.value())
222        })
223    }
224
225    /// Get all neighbors of a vertex
226    pub fn neighbors(&self, v: VertexId) -> Vec<(VertexId, EdgeId)> {
227        self.adjacency
228            .get(&v)
229            .map(|neighbors| neighbors.iter().copied().collect())
230            .unwrap_or_default()
231    }
232
233    /// Get degree of vertex
234    pub fn degree(&self, v: VertexId) -> usize {
235        self.adjacency
236            .get(&v)
237            .map(|neighbors| neighbors.len())
238            .unwrap_or(0)
239    }
240
241    /// Get number of vertices
242    pub fn num_vertices(&self) -> usize {
243        self.num_vertices.load(Ordering::SeqCst)
244    }
245
246    /// Get number of edges
247    pub fn num_edges(&self) -> usize {
248        self.edges.len()
249    }
250
251    /// Get all vertices
252    pub fn vertices(&self) -> Vec<VertexId> {
253        self.adjacency.iter().map(|entry| *entry.key()).collect()
254    }
255
256    /// Get all edges
257    pub fn edges(&self) -> Vec<Edge> {
258        self.edges.iter().map(|entry| *entry.value()).collect()
259    }
260
261    /// Get graph statistics
262    pub fn stats(&self) -> GraphStats {
263        let num_vertices = self.num_vertices();
264        let num_edges = self.num_edges();
265
266        if num_vertices == 0 {
267            return GraphStats::default();
268        }
269
270        let mut degrees: Vec<usize> = self.adjacency
271            .iter()
272            .map(|entry| entry.value().len())
273            .collect();
274
275        degrees.sort_unstable();
276
277        let min_degree = degrees.first().copied().unwrap_or(0);
278        let max_degree = degrees.last().copied().unwrap_or(0);
279        let total_degree: usize = degrees.iter().sum();
280        let avg_degree = total_degree as f64 / num_vertices as f64;
281
282        let total_weight: f64 = self.edges
283            .iter()
284            .map(|entry| entry.value().weight)
285            .sum();
286
287        GraphStats {
288            num_vertices,
289            num_edges,
290            total_weight,
291            min_degree,
292            max_degree,
293            avg_degree,
294        }
295    }
296
297    /// Check if graph is connected using BFS
298    pub fn is_connected(&self) -> bool {
299        let num_vertices = self.num_vertices();
300
301        if num_vertices == 0 {
302            return true; // Empty graph is considered connected
303        }
304
305        if num_vertices == 1 {
306            return true;
307        }
308
309        // Get an arbitrary starting vertex
310        let start = match self.adjacency.iter().next() {
311            Some(entry) => *entry.key(),
312            None => return true,
313        };
314
315        let mut visited = HashSet::new();
316        let mut queue = VecDeque::new();
317
318        queue.push_back(start);
319        visited.insert(start);
320
321        while let Some(v) = queue.pop_front() {
322            if let Some(neighbors) = self.adjacency.get(&v) {
323                for (neighbor, _) in neighbors.iter() {
324                    if visited.insert(*neighbor) {
325                        queue.push_back(*neighbor);
326                    }
327                }
328            }
329        }
330
331        visited.len() == num_vertices
332    }
333
334    /// Get connected components using BFS
335    pub fn connected_components(&self) -> Vec<Vec<VertexId>> {
336        let mut visited = HashSet::new();
337        let mut components = Vec::new();
338
339        for entry in self.adjacency.iter() {
340            let start = *entry.key();
341
342            if visited.contains(&start) {
343                continue;
344            }
345
346            let mut component = Vec::new();
347            let mut queue = VecDeque::new();
348
349            queue.push_back(start);
350            visited.insert(start);
351
352            while let Some(v) = queue.pop_front() {
353                component.push(v);
354
355                if let Some(neighbors) = self.adjacency.get(&v) {
356                    for (neighbor, _) in neighbors.iter() {
357                        if visited.insert(*neighbor) {
358                            queue.push_back(*neighbor);
359                        }
360                    }
361                }
362            }
363
364            components.push(component);
365        }
366
367        components
368    }
369
370    /// Clear all vertices and edges from the graph
371    pub fn clear(&self) {
372        self.adjacency.clear();
373        self.edges.clear();
374        self.edge_index.clear();
375        self.next_edge_id.store(0, Ordering::SeqCst);
376        self.num_vertices.store(0, Ordering::SeqCst);
377    }
378
379    /// Remove a vertex and all its incident edges
380    pub fn remove_vertex(&self, v: VertexId) -> Result<()> {
381        if !self.has_vertex(v) {
382            return Err(MinCutError::InvalidVertex(v));
383        }
384
385        // Get all incident edges
386        let incident_edges: Vec<(VertexId, EdgeId)> = self.neighbors(v);
387
388        // Remove all incident edges
389        for (neighbor, _) in incident_edges {
390            // Use delete_edge to properly clean up
391            let _ = self.delete_edge(v, neighbor);
392        }
393
394        // Remove the vertex from adjacency list
395        self.adjacency.remove(&v);
396        self.num_vertices.fetch_sub(1, Ordering::SeqCst);
397
398        Ok(())
399    }
400
401    /// Get the weight of an edge
402    pub fn edge_weight(&self, u: VertexId, v: VertexId) -> Option<Weight> {
403        self.get_edge(u, v).map(|e| e.weight)
404    }
405
406    /// Update the weight of an existing edge
407    pub fn update_edge_weight(&self, u: VertexId, v: VertexId, new_weight: Weight) -> Result<()> {
408        let key = Self::canonical_key(u, v);
409
410        let edge_id = self.edge_index
411            .get(&key)
412            .ok_or_else(|| MinCutError::EdgeNotFound(u, v))?;
413
414        let edge_id = *edge_id.value();
415
416        if let Some(mut edge_ref) = self.edges.get_mut(&edge_id) {
417            edge_ref.weight = new_weight;
418            Ok(())
419        } else {
420            Err(MinCutError::EdgeNotFound(u, v))
421        }
422    }
423}
424
425impl Default for DynamicGraph {
426    fn default() -> Self {
427        Self::new()
428    }
429}
430
431impl Clone for DynamicGraph {
432    fn clone(&self) -> Self {
433        let new_graph = Self::with_capacity(self.num_vertices(), self.num_edges());
434
435        // Clone vertices
436        for entry in self.adjacency.iter() {
437            new_graph.add_vertex(*entry.key());
438        }
439
440        // Clone edges
441        for entry in self.edges.iter() {
442            let edge = entry.value();
443            let _ = new_graph.insert_edge(edge.source, edge.target, edge.weight);
444        }
445
446        new_graph
447    }
448}
449
450#[cfg(test)]
451mod tests {
452    use super::*;
453
454    #[test]
455    fn test_empty_graph() {
456        let g = DynamicGraph::new();
457        assert_eq!(g.num_vertices(), 0);
458        assert_eq!(g.num_edges(), 0);
459        assert!(g.is_connected());
460    }
461
462    #[test]
463    fn test_add_vertex() {
464        let g = DynamicGraph::new();
465        assert!(g.add_vertex(1));
466        assert!(!g.add_vertex(1)); // Adding again returns false
467        assert_eq!(g.num_vertices(), 1);
468        assert!(g.has_vertex(1));
469        assert!(!g.has_vertex(2));
470    }
471
472    #[test]
473    fn test_insert_edge() {
474        let g = DynamicGraph::new();
475        let edge_id = g.insert_edge(1, 2, 1.0).unwrap();
476        assert_eq!(g.num_edges(), 1);
477        assert_eq!(g.num_vertices(), 2);
478        assert!(g.has_edge(1, 2));
479        assert!(g.has_edge(2, 1)); // Undirected
480
481        // Check edge ID is returned
482        assert_eq!(edge_id, 0);
483    }
484
485    #[test]
486    fn test_insert_duplicate_edge() {
487        let g = DynamicGraph::new();
488        g.insert_edge(1, 2, 1.0).unwrap();
489        let result = g.insert_edge(1, 2, 2.0);
490        assert!(matches!(result, Err(MinCutError::EdgeExists(1, 2))));
491    }
492
493    #[test]
494    fn test_insert_self_loop() {
495        let g = DynamicGraph::new();
496        let result = g.insert_edge(1, 1, 1.0);
497        assert!(matches!(result, Err(MinCutError::InvalidEdge(1, 1))));
498    }
499
500    #[test]
501    fn test_delete_edge() {
502        let g = DynamicGraph::new();
503        g.insert_edge(1, 2, 1.5).unwrap();
504        assert_eq!(g.num_edges(), 1);
505
506        let edge = g.delete_edge(1, 2).unwrap();
507        assert_eq!(edge.weight, 1.5);
508        assert_eq!(g.num_edges(), 0);
509        assert!(!g.has_edge(1, 2));
510    }
511
512    #[test]
513    fn test_delete_nonexistent_edge() {
514        let g = DynamicGraph::new();
515        let result = g.delete_edge(1, 2);
516        assert!(matches!(result, Err(MinCutError::EdgeNotFound(1, 2))));
517    }
518
519    #[test]
520    fn test_neighbors() {
521        let g = DynamicGraph::new();
522        g.insert_edge(1, 2, 1.0).unwrap();
523        g.insert_edge(1, 3, 1.0).unwrap();
524        g.insert_edge(1, 4, 1.0).unwrap();
525
526        let neighbors = g.neighbors(1);
527        assert_eq!(neighbors.len(), 3);
528
529        let neighbor_ids: HashSet<VertexId> = neighbors.iter().map(|(v, _)| *v).collect();
530        assert!(neighbor_ids.contains(&2));
531        assert!(neighbor_ids.contains(&3));
532        assert!(neighbor_ids.contains(&4));
533    }
534
535    #[test]
536    fn test_degree() {
537        let g = DynamicGraph::new();
538        g.insert_edge(1, 2, 1.0).unwrap();
539        g.insert_edge(1, 3, 1.0).unwrap();
540
541        assert_eq!(g.degree(1), 2);
542        assert_eq!(g.degree(2), 1);
543        assert_eq!(g.degree(3), 1);
544        assert_eq!(g.degree(4), 0); // Non-existent vertex
545    }
546
547    #[test]
548    fn test_get_edge() {
549        let g = DynamicGraph::new();
550        g.insert_edge(1, 2, 2.5).unwrap();
551
552        let edge = g.get_edge(1, 2).unwrap();
553        assert_eq!(edge.weight, 2.5);
554        assert_eq!(edge.source, 1);
555        assert_eq!(edge.target, 2);
556
557        // Symmetric
558        let edge = g.get_edge(2, 1).unwrap();
559        assert_eq!(edge.weight, 2.5);
560
561        assert!(g.get_edge(1, 3).is_none());
562    }
563
564    #[test]
565    fn test_stats() {
566        let g = DynamicGraph::new();
567        g.insert_edge(1, 2, 1.0).unwrap();
568        g.insert_edge(2, 3, 2.0).unwrap();
569        g.insert_edge(3, 1, 3.0).unwrap();
570
571        let stats = g.stats();
572        assert_eq!(stats.num_vertices, 3);
573        assert_eq!(stats.num_edges, 3);
574        assert_eq!(stats.total_weight, 6.0);
575        assert_eq!(stats.min_degree, 2);
576        assert_eq!(stats.max_degree, 2);
577        assert_eq!(stats.avg_degree, 2.0);
578    }
579
580    #[test]
581    fn test_is_connected_single_component() {
582        let g = DynamicGraph::new();
583        g.insert_edge(1, 2, 1.0).unwrap();
584        g.insert_edge(2, 3, 1.0).unwrap();
585        g.insert_edge(3, 4, 1.0).unwrap();
586
587        assert!(g.is_connected());
588    }
589
590    #[test]
591    fn test_is_connected_disconnected() {
592        let g = DynamicGraph::new();
593        g.insert_edge(1, 2, 1.0).unwrap();
594        g.insert_edge(3, 4, 1.0).unwrap();
595
596        assert!(!g.is_connected());
597    }
598
599    #[test]
600    fn test_connected_components() {
601        let g = DynamicGraph::new();
602        g.insert_edge(1, 2, 1.0).unwrap();
603        g.insert_edge(2, 3, 1.0).unwrap();
604        g.insert_edge(4, 5, 1.0).unwrap();
605        g.insert_edge(6, 7, 1.0).unwrap();
606        g.insert_edge(7, 8, 1.0).unwrap();
607
608        let components = g.connected_components();
609        assert_eq!(components.len(), 3);
610
611        // Each component should have the right size
612        let mut sizes: Vec<usize> = components.iter().map(|c| c.len()).collect();
613        sizes.sort_unstable();
614        assert_eq!(sizes, vec![2, 3, 3]);
615    }
616
617    #[test]
618    fn test_clear() {
619        let g = DynamicGraph::new();
620        g.insert_edge(1, 2, 1.0).unwrap();
621        g.insert_edge(2, 3, 1.0).unwrap();
622
623        assert_eq!(g.num_vertices(), 3);
624        assert_eq!(g.num_edges(), 2);
625
626        g.clear();
627
628        assert_eq!(g.num_vertices(), 0);
629        assert_eq!(g.num_edges(), 0);
630    }
631
632    #[test]
633    fn test_remove_vertex() {
634        let g = DynamicGraph::new();
635        g.insert_edge(1, 2, 1.0).unwrap();
636        g.insert_edge(2, 3, 1.0).unwrap();
637        g.insert_edge(1, 3, 1.0).unwrap();
638
639        assert_eq!(g.num_vertices(), 3);
640        assert_eq!(g.num_edges(), 3);
641
642        g.remove_vertex(2).unwrap();
643
644        assert_eq!(g.num_vertices(), 2);
645        assert_eq!(g.num_edges(), 1);
646        assert!(!g.has_vertex(2));
647        assert!(g.has_edge(1, 3));
648        assert!(!g.has_edge(1, 2));
649        assert!(!g.has_edge(2, 3));
650    }
651
652    #[test]
653    fn test_edge_weight() {
654        let g = DynamicGraph::new();
655        g.insert_edge(1, 2, 3.5).unwrap();
656
657        assert_eq!(g.edge_weight(1, 2), Some(3.5));
658        assert_eq!(g.edge_weight(2, 1), Some(3.5));
659        assert_eq!(g.edge_weight(1, 3), None);
660    }
661
662    #[test]
663    fn test_update_edge_weight() {
664        let g = DynamicGraph::new();
665        g.insert_edge(1, 2, 1.0).unwrap();
666
667        g.update_edge_weight(1, 2, 5.0).unwrap();
668        assert_eq!(g.edge_weight(1, 2), Some(5.0));
669
670        let result = g.update_edge_weight(1, 3, 2.0);
671        assert!(matches!(result, Err(MinCutError::EdgeNotFound(1, 3))));
672    }
673
674    #[test]
675    fn test_clone() {
676        let g = DynamicGraph::new();
677        g.insert_edge(1, 2, 1.0).unwrap();
678        g.insert_edge(2, 3, 2.0).unwrap();
679
680        let g2 = g.clone();
681
682        assert_eq!(g2.num_vertices(), 3);
683        assert_eq!(g2.num_edges(), 2);
684        assert!(g2.has_edge(1, 2));
685        assert!(g2.has_edge(2, 3));
686        assert_eq!(g2.edge_weight(1, 2), Some(1.0));
687        assert_eq!(g2.edge_weight(2, 3), Some(2.0));
688    }
689
690    #[test]
691    fn test_edge_canonical_endpoints() {
692        let edge = Edge::new(0, 5, 3, 1.0);
693        assert_eq!(edge.canonical_endpoints(), (3, 5));
694
695        let edge = Edge::new(0, 2, 7, 1.0);
696        assert_eq!(edge.canonical_endpoints(), (2, 7));
697    }
698
699    #[test]
700    fn test_edge_other() {
701        let edge = Edge::new(0, 1, 2, 1.0);
702        assert_eq!(edge.other(1), Some(2));
703        assert_eq!(edge.other(2), Some(1));
704        assert_eq!(edge.other(3), None);
705    }
706
707    #[test]
708    fn test_with_capacity() {
709        let g = DynamicGraph::with_capacity(100, 200);
710        assert_eq!(g.num_vertices(), 0);
711        assert_eq!(g.num_edges(), 0);
712
713        // Should work normally
714        g.insert_edge(1, 2, 1.0).unwrap();
715        assert_eq!(g.num_edges(), 1);
716    }
717
718    #[test]
719    fn test_vertices_and_edges() {
720        let g = DynamicGraph::new();
721        g.insert_edge(1, 2, 1.0).unwrap();
722        g.insert_edge(2, 3, 2.0).unwrap();
723
724        let vertices = g.vertices();
725        assert_eq!(vertices.len(), 3);
726        assert!(vertices.contains(&1));
727        assert!(vertices.contains(&2));
728        assert!(vertices.contains(&3));
729
730        let edges = g.edges();
731        assert_eq!(edges.len(), 2);
732    }
733}