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 crate::error::{MinCutError, Result};
10use dashmap::DashMap;
11use serde::{Deserialize, Serialize};
12use std::collections::{HashSet, VecDeque};
13use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
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
191            .edge_index
192            .remove(&key)
193            .ok_or_else(|| MinCutError::EdgeNotFound(u, v))?
194            .1;
195
196        // Remove from edge storage
197        let (_, edge) = self
198            .edges
199            .remove(&edge_id)
200            .ok_or_else(|| MinCutError::EdgeNotFound(u, v))?;
201
202        // Update adjacency lists
203        if let Some(mut neighbors) = self.adjacency.get_mut(&u) {
204            neighbors.retain(|(neighbor, eid)| !(*neighbor == v && *eid == edge_id));
205        }
206        if let Some(mut neighbors) = self.adjacency.get_mut(&v) {
207            neighbors.retain(|(neighbor, eid)| !(*neighbor == u && *eid == edge_id));
208        }
209
210        Ok(edge)
211    }
212
213    /// Check if edge exists
214    pub fn has_edge(&self, u: VertexId, v: VertexId) -> bool {
215        let key = Self::canonical_key(u, v);
216        self.edge_index.contains_key(&key)
217    }
218
219    /// Get edge by endpoints
220    pub fn get_edge(&self, u: VertexId, v: VertexId) -> Option<Edge> {
221        let key = Self::canonical_key(u, v);
222        self.edge_index
223            .get(&key)
224            .and_then(|edge_id| self.edges.get(edge_id.value()).map(|e| *e.value()))
225    }
226
227    /// Get all neighbors of a vertex
228    pub fn neighbors(&self, v: VertexId) -> Vec<(VertexId, EdgeId)> {
229        self.adjacency
230            .get(&v)
231            .map(|neighbors| neighbors.iter().copied().collect())
232            .unwrap_or_default()
233    }
234
235    /// Get degree of vertex
236    pub fn degree(&self, v: VertexId) -> usize {
237        self.adjacency
238            .get(&v)
239            .map(|neighbors| neighbors.len())
240            .unwrap_or(0)
241    }
242
243    /// Get number of vertices
244    pub fn num_vertices(&self) -> usize {
245        self.num_vertices.load(Ordering::SeqCst)
246    }
247
248    /// Get number of edges
249    pub fn num_edges(&self) -> usize {
250        self.edges.len()
251    }
252
253    /// Get all vertices
254    pub fn vertices(&self) -> Vec<VertexId> {
255        self.adjacency.iter().map(|entry| *entry.key()).collect()
256    }
257
258    /// Get all edges
259    pub fn edges(&self) -> Vec<Edge> {
260        self.edges.iter().map(|entry| *entry.value()).collect()
261    }
262
263    /// Get graph statistics
264    pub fn stats(&self) -> GraphStats {
265        let num_vertices = self.num_vertices();
266        let num_edges = self.num_edges();
267
268        if num_vertices == 0 {
269            return GraphStats::default();
270        }
271
272        let mut degrees: Vec<usize> = self
273            .adjacency
274            .iter()
275            .map(|entry| entry.value().len())
276            .collect();
277
278        degrees.sort_unstable();
279
280        let min_degree = degrees.first().copied().unwrap_or(0);
281        let max_degree = degrees.last().copied().unwrap_or(0);
282        let total_degree: usize = degrees.iter().sum();
283        let avg_degree = total_degree as f64 / num_vertices as f64;
284
285        let total_weight: f64 = self.edges.iter().map(|entry| entry.value().weight).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
411            .edge_index
412            .get(&key)
413            .ok_or_else(|| MinCutError::EdgeNotFound(u, v))?;
414
415        let edge_id = *edge_id.value();
416
417        if let Some(mut edge_ref) = self.edges.get_mut(&edge_id) {
418            edge_ref.weight = new_weight;
419            Ok(())
420        } else {
421            Err(MinCutError::EdgeNotFound(u, v))
422        }
423    }
424}
425
426impl Default for DynamicGraph {
427    fn default() -> Self {
428        Self::new()
429    }
430}
431
432impl Clone for DynamicGraph {
433    fn clone(&self) -> Self {
434        let new_graph = Self::with_capacity(self.num_vertices(), self.num_edges());
435
436        // Clone vertices
437        for entry in self.adjacency.iter() {
438            new_graph.add_vertex(*entry.key());
439        }
440
441        // Clone edges
442        for entry in self.edges.iter() {
443            let edge = entry.value();
444            let _ = new_graph.insert_edge(edge.source, edge.target, edge.weight);
445        }
446
447        new_graph
448    }
449}
450
451#[cfg(test)]
452mod tests {
453    use super::*;
454
455    #[test]
456    fn test_empty_graph() {
457        let g = DynamicGraph::new();
458        assert_eq!(g.num_vertices(), 0);
459        assert_eq!(g.num_edges(), 0);
460        assert!(g.is_connected());
461    }
462
463    #[test]
464    fn test_add_vertex() {
465        let g = DynamicGraph::new();
466        assert!(g.add_vertex(1));
467        assert!(!g.add_vertex(1)); // Adding again returns false
468        assert_eq!(g.num_vertices(), 1);
469        assert!(g.has_vertex(1));
470        assert!(!g.has_vertex(2));
471    }
472
473    #[test]
474    fn test_insert_edge() {
475        let g = DynamicGraph::new();
476        let edge_id = g.insert_edge(1, 2, 1.0).unwrap();
477        assert_eq!(g.num_edges(), 1);
478        assert_eq!(g.num_vertices(), 2);
479        assert!(g.has_edge(1, 2));
480        assert!(g.has_edge(2, 1)); // Undirected
481
482        // Check edge ID is returned
483        assert_eq!(edge_id, 0);
484    }
485
486    #[test]
487    fn test_insert_duplicate_edge() {
488        let g = DynamicGraph::new();
489        g.insert_edge(1, 2, 1.0).unwrap();
490        let result = g.insert_edge(1, 2, 2.0);
491        assert!(matches!(result, Err(MinCutError::EdgeExists(1, 2))));
492    }
493
494    #[test]
495    fn test_insert_self_loop() {
496        let g = DynamicGraph::new();
497        let result = g.insert_edge(1, 1, 1.0);
498        assert!(matches!(result, Err(MinCutError::InvalidEdge(1, 1))));
499    }
500
501    #[test]
502    fn test_delete_edge() {
503        let g = DynamicGraph::new();
504        g.insert_edge(1, 2, 1.5).unwrap();
505        assert_eq!(g.num_edges(), 1);
506
507        let edge = g.delete_edge(1, 2).unwrap();
508        assert_eq!(edge.weight, 1.5);
509        assert_eq!(g.num_edges(), 0);
510        assert!(!g.has_edge(1, 2));
511    }
512
513    #[test]
514    fn test_delete_nonexistent_edge() {
515        let g = DynamicGraph::new();
516        let result = g.delete_edge(1, 2);
517        assert!(matches!(result, Err(MinCutError::EdgeNotFound(1, 2))));
518    }
519
520    #[test]
521    fn test_neighbors() {
522        let g = DynamicGraph::new();
523        g.insert_edge(1, 2, 1.0).unwrap();
524        g.insert_edge(1, 3, 1.0).unwrap();
525        g.insert_edge(1, 4, 1.0).unwrap();
526
527        let neighbors = g.neighbors(1);
528        assert_eq!(neighbors.len(), 3);
529
530        let neighbor_ids: HashSet<VertexId> = neighbors.iter().map(|(v, _)| *v).collect();
531        assert!(neighbor_ids.contains(&2));
532        assert!(neighbor_ids.contains(&3));
533        assert!(neighbor_ids.contains(&4));
534    }
535
536    #[test]
537    fn test_degree() {
538        let g = DynamicGraph::new();
539        g.insert_edge(1, 2, 1.0).unwrap();
540        g.insert_edge(1, 3, 1.0).unwrap();
541
542        assert_eq!(g.degree(1), 2);
543        assert_eq!(g.degree(2), 1);
544        assert_eq!(g.degree(3), 1);
545        assert_eq!(g.degree(4), 0); // Non-existent vertex
546    }
547
548    #[test]
549    fn test_get_edge() {
550        let g = DynamicGraph::new();
551        g.insert_edge(1, 2, 2.5).unwrap();
552
553        let edge = g.get_edge(1, 2).unwrap();
554        assert_eq!(edge.weight, 2.5);
555        assert_eq!(edge.source, 1);
556        assert_eq!(edge.target, 2);
557
558        // Symmetric
559        let edge = g.get_edge(2, 1).unwrap();
560        assert_eq!(edge.weight, 2.5);
561
562        assert!(g.get_edge(1, 3).is_none());
563    }
564
565    #[test]
566    fn test_stats() {
567        let g = DynamicGraph::new();
568        g.insert_edge(1, 2, 1.0).unwrap();
569        g.insert_edge(2, 3, 2.0).unwrap();
570        g.insert_edge(3, 1, 3.0).unwrap();
571
572        let stats = g.stats();
573        assert_eq!(stats.num_vertices, 3);
574        assert_eq!(stats.num_edges, 3);
575        assert_eq!(stats.total_weight, 6.0);
576        assert_eq!(stats.min_degree, 2);
577        assert_eq!(stats.max_degree, 2);
578        assert_eq!(stats.avg_degree, 2.0);
579    }
580
581    #[test]
582    fn test_is_connected_single_component() {
583        let g = DynamicGraph::new();
584        g.insert_edge(1, 2, 1.0).unwrap();
585        g.insert_edge(2, 3, 1.0).unwrap();
586        g.insert_edge(3, 4, 1.0).unwrap();
587
588        assert!(g.is_connected());
589    }
590
591    #[test]
592    fn test_is_connected_disconnected() {
593        let g = DynamicGraph::new();
594        g.insert_edge(1, 2, 1.0).unwrap();
595        g.insert_edge(3, 4, 1.0).unwrap();
596
597        assert!(!g.is_connected());
598    }
599
600    #[test]
601    fn test_connected_components() {
602        let g = DynamicGraph::new();
603        g.insert_edge(1, 2, 1.0).unwrap();
604        g.insert_edge(2, 3, 1.0).unwrap();
605        g.insert_edge(4, 5, 1.0).unwrap();
606        g.insert_edge(6, 7, 1.0).unwrap();
607        g.insert_edge(7, 8, 1.0).unwrap();
608
609        let components = g.connected_components();
610        assert_eq!(components.len(), 3);
611
612        // Each component should have the right size
613        let mut sizes: Vec<usize> = components.iter().map(|c| c.len()).collect();
614        sizes.sort_unstable();
615        assert_eq!(sizes, vec![2, 3, 3]);
616    }
617
618    #[test]
619    fn test_clear() {
620        let g = DynamicGraph::new();
621        g.insert_edge(1, 2, 1.0).unwrap();
622        g.insert_edge(2, 3, 1.0).unwrap();
623
624        assert_eq!(g.num_vertices(), 3);
625        assert_eq!(g.num_edges(), 2);
626
627        g.clear();
628
629        assert_eq!(g.num_vertices(), 0);
630        assert_eq!(g.num_edges(), 0);
631    }
632
633    #[test]
634    fn test_remove_vertex() {
635        let g = DynamicGraph::new();
636        g.insert_edge(1, 2, 1.0).unwrap();
637        g.insert_edge(2, 3, 1.0).unwrap();
638        g.insert_edge(1, 3, 1.0).unwrap();
639
640        assert_eq!(g.num_vertices(), 3);
641        assert_eq!(g.num_edges(), 3);
642
643        g.remove_vertex(2).unwrap();
644
645        assert_eq!(g.num_vertices(), 2);
646        assert_eq!(g.num_edges(), 1);
647        assert!(!g.has_vertex(2));
648        assert!(g.has_edge(1, 3));
649        assert!(!g.has_edge(1, 2));
650        assert!(!g.has_edge(2, 3));
651    }
652
653    #[test]
654    fn test_edge_weight() {
655        let g = DynamicGraph::new();
656        g.insert_edge(1, 2, 3.5).unwrap();
657
658        assert_eq!(g.edge_weight(1, 2), Some(3.5));
659        assert_eq!(g.edge_weight(2, 1), Some(3.5));
660        assert_eq!(g.edge_weight(1, 3), None);
661    }
662
663    #[test]
664    fn test_update_edge_weight() {
665        let g = DynamicGraph::new();
666        g.insert_edge(1, 2, 1.0).unwrap();
667
668        g.update_edge_weight(1, 2, 5.0).unwrap();
669        assert_eq!(g.edge_weight(1, 2), Some(5.0));
670
671        let result = g.update_edge_weight(1, 3, 2.0);
672        assert!(matches!(result, Err(MinCutError::EdgeNotFound(1, 3))));
673    }
674
675    #[test]
676    fn test_clone() {
677        let g = DynamicGraph::new();
678        g.insert_edge(1, 2, 1.0).unwrap();
679        g.insert_edge(2, 3, 2.0).unwrap();
680
681        let g2 = g.clone();
682
683        assert_eq!(g2.num_vertices(), 3);
684        assert_eq!(g2.num_edges(), 2);
685        assert!(g2.has_edge(1, 2));
686        assert!(g2.has_edge(2, 3));
687        assert_eq!(g2.edge_weight(1, 2), Some(1.0));
688        assert_eq!(g2.edge_weight(2, 3), Some(2.0));
689    }
690
691    #[test]
692    fn test_edge_canonical_endpoints() {
693        let edge = Edge::new(0, 5, 3, 1.0);
694        assert_eq!(edge.canonical_endpoints(), (3, 5));
695
696        let edge = Edge::new(0, 2, 7, 1.0);
697        assert_eq!(edge.canonical_endpoints(), (2, 7));
698    }
699
700    #[test]
701    fn test_edge_other() {
702        let edge = Edge::new(0, 1, 2, 1.0);
703        assert_eq!(edge.other(1), Some(2));
704        assert_eq!(edge.other(2), Some(1));
705        assert_eq!(edge.other(3), None);
706    }
707
708    #[test]
709    fn test_with_capacity() {
710        let g = DynamicGraph::with_capacity(100, 200);
711        assert_eq!(g.num_vertices(), 0);
712        assert_eq!(g.num_edges(), 0);
713
714        // Should work normally
715        g.insert_edge(1, 2, 1.0).unwrap();
716        assert_eq!(g.num_edges(), 1);
717    }
718
719    #[test]
720    fn test_vertices_and_edges() {
721        let g = DynamicGraph::new();
722        g.insert_edge(1, 2, 1.0).unwrap();
723        g.insert_edge(2, 3, 2.0).unwrap();
724
725        let vertices = g.vertices();
726        assert_eq!(vertices.len(), 3);
727        assert!(vertices.contains(&1));
728        assert!(vertices.contains(&2));
729        assert!(vertices.contains(&3));
730
731        let edges = g.edges();
732        assert_eq!(edges.len(), 2);
733    }
734}