easy_graph/
lib.rs

1use std::collections::{HashMap, HashSet};
2use std::fmt::Debug;
3use std::hash::Hash;
4pub mod connected_graph;
5
6/// Determine default capacity of connections set for every vertex.
7pub const DEFAULT_CONNECTIONS_PER_VERTEX: usize = 4;
8
9/// Data structure that represent generic *vertices* and undirected connections
10/// between them - *edges*.
11#[derive(Clone, Debug, Default)]
12pub struct Graph<T: Hash + Eq> {
13    verts: HashMap<T, HashSet<T>>,
14    edge_per_vertex_capacity: usize,
15}
16
17impl<T: Hash + Eq + Clone> Graph<T> {
18    /// Creates new empty graph.
19    pub fn new() -> Self {
20        Self {
21            verts: HashMap::new(),
22            edge_per_vertex_capacity: DEFAULT_CONNECTIONS_PER_VERTEX,
23        }
24    }
25
26    /// Creates empty graph with preallocated memory for vertices and edges.
27    /// # Arguments:
28    /// `vertices_capacity` - capacity for collection of vertices.
29    /// `edge_per_vertex_capacity` - capacity for connections collections for each vertex.
30    /// Default value `const DEFAULT_CONNECTIONS_PER_VERTEX: usize = 4`
31    pub fn with_capacity(vertices_capacity: usize, edge_per_vertex_capacity: usize) -> Self {
32        Self {
33            verts: HashMap::with_capacity(vertices_capacity),
34            edge_per_vertex_capacity,
35        }
36    }
37
38    /// Creates graph filled by `vertices` with `edges`.
39    /// # Arguments:
40    /// `vertices` - iterator of vertices.
41    /// `edges` - iterator of pairs of vertices indices, which must be connected.
42    pub fn from_data(
43        vertices: impl Iterator<Item=T>,
44        edges: impl Iterator<Item=(T, T)>,
45    ) -> Self {
46        let verts: HashMap<T, HashSet<T>> = vertices
47            .map(|v| (v, HashSet::with_capacity(DEFAULT_CONNECTIONS_PER_VERTEX)))
48            .collect();
49
50        let mut temp = Self {
51            verts,
52            edge_per_vertex_capacity: DEFAULT_CONNECTIONS_PER_VERTEX,
53        };
54
55        for (v1, v2) in edges {
56            temp.add_edge(&v1, &v2);
57        }
58
59        temp
60    }
61
62    /// Tests if graph contains `v`.
63    pub fn contains(&self, v: &T) -> bool {
64        self.verts.contains_key(v)
65    }
66
67    /// Adds vertex to graph.
68    /// # Arguments:
69    /// `vertex` - vertex, that must be added.
70    /// # Returns:
71    /// `true` if vertex is new and was really added
72    pub fn add_vertex(&mut self, v: T) -> bool {
73        if self.verts.contains_key(&v) {
74            return false;
75        }
76        self.verts
77            .insert(v, HashSet::with_capacity(self.edge_per_vertex_capacity));
78        true
79    }
80
81    /// Removes vertex from graph.
82    /// # Arguments:
83    /// `vertex` - vertex, that must be removed.
84    /// # Returns:
85    /// If vertex exist, than set of its connections. Else `None`.
86    pub fn remove_vertex(&mut self, v: &T) -> Option<HashSet<T>> {
87        if let Some(connections) = self.verts.remove(v) {
88            for c in &connections {
89                self.verts.get_mut(c).unwrap().remove(v);
90            }
91            return Some(connections);
92        }
93
94        None
95    }
96
97    /// Adds edge to graph.
98    /// # Arguments:
99    /// `v1` - vertex, that will be connected with `v2`.
100    /// `v2` - vertex, that will be connected with `v1`.
101    /// # Returns:
102    /// `true` if edge was added actualy;
103    /// `false` if edge was presented already;
104    pub fn add_edge(&mut self, v1: &T, v2: &T) -> bool {
105        if self.verts.contains_key(v1) && self.verts.contains_key(v2) {
106            if v1 == v2 {
107                return false;
108            }
109            self.verts.get_mut(v1).unwrap().insert(v2.clone());
110            self.verts.get_mut(v2).unwrap().insert(v1.clone());
111            return true;
112        }
113        false
114    }
115
116    /// Removes edge from graph.
117    /// If edge is not present, that function does nothing.
118    /// # Arguments:
119    /// `v1` - vertex, that will be disconnected with `v2`.
120    /// `v2` - vertex, that will be disconnected with `v1`.
121    /// # Returns:
122    /// `true` if edge was removed actualy;
123    /// `false` if edge wasn't presented already;
124    pub fn remove_edge(&mut self, v1: &T, v2: &T) -> bool {
125        if self.verts.contains_key(v1) && self.verts.contains_key(v2) {
126            self.verts.get_mut(v1).unwrap().remove(v2);
127            self.verts.get_mut(v2).unwrap().remove(v1);
128            return true;
129        }
130        false
131    }
132
133    /// Checks if edge, that connects specified vertices, is present.
134    /// Connections are undirectional, thats why always
135    /// `is_connected(v1, v2) == is_connected(v2, v1)`
136    /// # Arguments:
137    /// `v1` - first vertex to check.
138    /// `v2` - second vertex to check.
139    pub fn is_connected(&self, v1: &T, v2: &T) -> bool {
140        if let Some(v) = self.verts.get(v1) {
141            if v1 == v2 {
142                return true;
143            }
144            return v.contains(v2);
145        }
146        false
147    }
148
149    /// Connects of vertices with specified index.
150    /// # Arguments:
151    /// `v` - vertex of interest;
152    /// # Returns:
153    /// Set of vertices, that connected to `v`, or None if `v` is not in graph.
154    pub fn connects_of(&self, v: &T) -> Option<&HashSet<T>> {
155        self.verts.get(v)
156    }
157
158    /// Iterator of all current vertices.
159    pub fn vertices(&self) -> impl Iterator<Item=&T> {
160        self.verts.keys()
161    }
162
163    /// Current count of vertices.
164    pub fn len(&self) -> usize {
165        self.verts.len()
166    }
167
168    /// True, if graph does not contain vertices.
169    pub fn is_empty(&self) -> bool {
170        self.verts.is_empty()
171    }
172
173    /// Removes all points, that have less connections than `weak_level`.
174    /// In other words, only vertices with more or equal connections than `weak_level`
175    /// remains. Complexity: `O(n)`
176    /// # Returns:
177    /// Set of removed vertices
178    /// # Example:
179    /// ```
180    /// use easy_graph::Graph;
181    /// let verts = vec![0,1,2,3];
182    /// let conns = vec![(0, 1), (1, 2), (2, 0), (2, 3)];
183    /// let mut graph = Graph::from_data(verts.into_iter(), conns.into_iter());
184    /// graph.remove_weak_connected(2);
185    /// assert_eq!(graph.len(), 3);
186    /// assert!(graph.contains(&0));
187    /// assert!(graph.contains(&1));
188    /// assert!(graph.contains(&2));
189    /// assert!(!graph.contains(&3));
190    /// assert!(!graph.connects_of(&2).unwrap().contains(&3));
191    /// ```
192    pub fn remove_weak_connected(&mut self, weak_level: usize) -> HashSet<T> {
193        let mut to_process: HashSet<T> = self.verts.iter()
194            .filter(|(_, c)| c.len() < weak_level)
195            .map(|(v, _)| v.clone()).collect();
196
197        let mut all_removed = HashSet::with_capacity(self.len());
198
199        while !to_process.is_empty() {
200            let processing = to_process;
201            to_process = HashSet::with_capacity(processing.len() * 4);
202            for v in processing {
203                if self.contains(&v) {
204                    let removed_vert_neighbors = self.remove_vertex(&v).unwrap();
205                    all_removed.insert(v);
206                    let weak_connected_neighbors = removed_vert_neighbors
207                        .into_iter()
208                        .filter(|n| self.connects_of(n).unwrap().len() < weak_level);
209                    to_process.extend(weak_connected_neighbors);
210                }
211            }
212        }
213        all_removed
214    }
215
216    /// Returns set of vertices, for which exists path to `vertex`.
217    pub fn verts_with_path_to(&self, vertex: &T) -> HashSet<T> {
218        let mut to_process = HashSet::with_capacity(self.len());
219        to_process.insert(vertex.clone());
220        let mut separate_part_verts = HashSet::with_capacity(self.len());
221        while !to_process.is_empty() {
222            let to_process_iter = to_process.into_iter();
223            to_process = HashSet::with_capacity(self.len());
224            for v in to_process_iter {
225                let connections_iter = self.verts.get(&v).unwrap().clone().into_iter();
226                to_process.extend(connections_iter.filter(|c| !separate_part_verts.contains(c)));
227                separate_part_verts.insert(v);
228            }
229        }
230        separate_part_verts
231    }
232
233    /// Takes connected graph that contains `vertex`.
234    pub fn take_connected_graph(&mut self, vertex: &T) -> Self {
235        if !self.verts.contains_key(vertex) {
236            return Self::new();
237        }
238
239        let separate_part_verts = self.verts_with_path_to(vertex);
240
241        let mut separate_part = Self::with_capacity(self.len(), self.edge_per_vertex_capacity);
242        for v in separate_part_verts {
243            let (v, c) = self.verts.remove_entry(&v).unwrap();
244            separate_part.verts.insert(v, c);
245        }
246
247        separate_part
248    }
249
250    /// Split `self` into connected graphs.
251    pub fn into_connected_graphs(mut self) -> Vec<Self> {
252        let separate_part_capacity = 4;
253        let mut separate_parts = Vec::with_capacity(separate_part_capacity);
254        while !self.is_empty() {
255            let start = self.verts.iter().next().unwrap().0.clone();
256            separate_parts.push(self.take_connected_graph(&start));
257        }
258
259        separate_parts
260    }
261}
262
263impl<T: Eq + Hash> PartialEq<Graph<T>> for Graph<T> {
264    fn eq(&self, other: &Graph<T>) -> bool {
265        self.verts == other.verts
266    }
267}
268
269impl<T: Eq + Hash> Eq for Graph<T> {}
270
271#[cfg(test)]
272mod tests {
273    use super::*;
274
275    fn test_data() -> (Vec<i32>, Vec<(i32, i32)>) {
276        let verts = vec![0, 1, 2, 3, 4, 10];
277        let conns = vec![(0, 1), (1, 2), (2, 3), (3, 4), (10, 0), (4, 10), ];
278        (verts, conns)
279    }
280
281    fn test_graph() -> Graph<i32> {
282        let (verts, conns) = test_data();
283        Graph::from_data(verts.into_iter(), conns.into_iter())
284    }
285
286    #[test]
287    fn from_data() {
288        let verts = test_data().0;
289        let g = test_graph();
290
291        assert_eq!(verts.len(), g.len());
292
293        assert_test_data(g);
294    }
295
296    fn assert_test_data(g: Graph<i32>) {
297        assert!(g.contains(&0));
298        assert!(g.contains(&1));
299        assert!(g.contains(&2));
300        assert!(g.contains(&3));
301        assert!(g.contains(&4));
302        assert!(g.contains(&10));
303        assert!(g.is_connected(&0, &10));
304        assert!(g.is_connected(&0, &1));
305        assert!(g.is_connected(&1, &0));
306        assert!(g.is_connected(&1, &2));
307        assert!(g.is_connected(&2, &3));
308        assert!(g.is_connected(&2, &1));
309        assert!(g.is_connected(&3, &2));
310        assert!(g.is_connected(&3, &4));
311        assert!(g.is_connected(&4, &3));
312        assert!(g.is_connected(&4, &10));
313        assert!(g.is_connected(&10, &0));
314        assert!(g.is_connected(&10, &4));
315    }
316
317    #[test]
318    fn add_vertex() {
319        let mut g = test_graph();
320        let new_vertex = 15;
321        assert!(g.add_vertex(new_vertex));
322        let presented_vertex = 3;
323        assert!(!g.add_vertex(presented_vertex));
324        assert!(g.contains(&new_vertex));
325        assert!(g.contains(&presented_vertex));
326        assert!(g.connects_of(&new_vertex).unwrap().is_empty());
327        assert_eq!(g.connects_of(&presented_vertex).unwrap().len(), 2);
328    }
329
330    #[test]
331    fn remove_vertex() {
332        let mut g = test_graph();
333        assert!(g.remove_vertex(&22).is_none());
334        let c = g.remove_vertex(&2);
335        assert!(c.is_some());
336        let c = c.unwrap();
337        assert_eq!(c.len(), 2);
338        assert!(c.contains(&1));
339        assert!(c.contains(&3));
340    }
341
342    #[test]
343    fn add_edge() {
344        let mut g = test_graph();
345        g.add_edge(&1, &4);
346        assert!(g.is_connected(&1, &4));
347        assert!(g.is_connected(&4, &1));
348    }
349
350    #[test]
351    fn remove_edge() {
352        let mut g = test_graph();
353        assert!(g.remove_edge(&0, &1));
354        assert!(!g.is_connected(&0, &1));
355        assert!(!g.is_connected(&1, &0));
356        g.remove_edge(&1, &0);
357    }
358
359    #[test]
360    fn remove_weak_connected() {
361        let mut g = test_graph();
362        g.add_vertex(11);
363        g.add_vertex(12);
364        g.add_edge(&0, &11);
365        g.add_edge(&11, &12);
366        g.add_edge(&2, &4);
367        g.add_edge(&10, &3);
368        g.add_edge(&10, &2);
369        g.add_edge(&1, &2);
370        assert_eq!(g.len(), 8);
371        g.remove_weak_connected(2);
372        assert_eq!(g.len(), 6);
373        assert!(g.contains(&0));
374        assert!(g.contains(&1));
375        assert!(g.contains(&2));
376        assert!(g.contains(&3));
377        assert!(g.contains(&4));
378        assert!(g.contains(&10));
379        g.remove_weak_connected(3);
380        assert_eq!(g.len(), 4);
381        assert!(g.contains(&2));
382        assert!(g.contains(&3));
383        assert!(g.contains(&4));
384        assert!(g.contains(&10));
385    }
386
387
388    #[test]
389    fn verts_with_path_to() {
390        let mut g = test_graph();
391        g.add_vertex(20);
392        g.add_vertex(30);
393        g.add_vertex(40);
394        g.add_edge(&20, &30);
395        g.add_edge(&30, &40);
396        g.add_edge(&40, &20);
397
398        let cg1 = g.verts_with_path_to(&0);
399        let cg2 = g.verts_with_path_to(&20);
400
401        assert_eq!(cg1.len(), 6);
402        assert_eq!(cg2.len(), 3);
403
404        assert!(cg1.contains(&0));
405        assert!(cg1.contains(&1));
406        assert!(cg1.contains(&2));
407        assert!(cg1.contains(&3));
408        assert!(cg1.contains(&4));
409        assert!(cg1.contains(&10));
410
411        assert!(cg2.contains(&20));
412        assert!(cg2.contains(&30));
413        assert!(cg2.contains(&40));
414    }
415
416    #[test]
417    fn take_connected_graph() {
418        let mut g = test_graph();
419        g.add_vertex(20);
420        g.add_vertex(30);
421        g.add_vertex(40);
422        g.add_edge(&20, &30);
423        g.add_edge(&30, &40);
424        g.add_edge(&40, &20);
425
426        assert!(g.take_connected_graph(&50).is_empty());
427        assert_eq!(g.len(), 9);
428
429        let sp = g.take_connected_graph(&20);
430        assert_eq!(g.len(), 6);
431        assert_eq!(sp.len(), 3);
432
433        assert_test_data(g);
434
435        assert_separate_part(sp);
436    }
437
438    fn assert_separate_part(sp: Graph<i32>) {
439        assert!(sp.contains(&20));
440        assert!(sp.contains(&30));
441        assert!(sp.contains(&40));
442        assert!(sp.is_connected(&20, &30));
443        assert!(sp.is_connected(&30, &40));
444        assert!(sp.is_connected(&40, &20));
445    }
446
447    #[test]
448    fn into_connected_graphs() {
449        let mut g = test_graph();
450        g.add_vertex(20);
451        g.add_vertex(30);
452        g.add_vertex(40);
453        g.add_edge(&20, &30);
454        g.add_edge(&30, &40);
455        g.add_edge(&40, &20);
456
457        let mut  separate_parts = g.into_connected_graphs();
458        assert_eq!(separate_parts.len(), 2);
459
460        if separate_parts[0].contains(&20) {
461            assert_test_data(separate_parts.remove(1));
462            assert_separate_part(separate_parts.remove(0));
463        } else {
464            assert_separate_part(separate_parts.remove(1));
465            assert_test_data(separate_parts.remove(0));
466        }
467    }
468}