graphalgos/graphs.rs
1// Contains definition of graph structures.
2use std::cmp::Ordering;
3use std::collections::HashMap;
4use std::fmt;
5use std::fmt::Debug;
6use std::fs::File;
7use std::io::Write;
8use std::io::{BufRead, BufReader, Error};
9
10/// vertex_label_type
11type VLT = String;
12
13/// Edge Type - Directed and Undirected Edge
14#[derive(Debug, Copy, Clone, PartialEq)]
15pub enum EdgeType {
16 Directed,
17 Undirected,
18}
19
20/// Edge Weight Type constraint enum
21///
22/// Weight can only be a numeric type
23///
24/// eg: GNumber::I32(10)
25#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
26pub enum GNumber {
27 U16(u16),
28 U32(u32),
29 U64(u64),
30 I16(i16),
31 I32(i32),
32 I64(i64),
33 F32(f32),
34 F64(f64),
35}
36
37impl fmt::Display for GNumber {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 GNumber::U16(x) => write!(f, "{}", x),
41 GNumber::U32(x) => write!(f, "{}", x),
42 GNumber::U64(x) => write!(f, "{}", x),
43 GNumber::I16(x) => write!(f, "{}", x),
44 GNumber::I32(x) => write!(f, "{}", x),
45 GNumber::I64(x) => write!(f, "{}", x),
46 GNumber::F32(x) => write!(f, "{}", x),
47 GNumber::F64(x) => write!(f, "{}", x),
48 }
49 }
50}
51
52/// This is the basic graph structure. Graph consists of vertices, edges and edge_type
53///
54/// # Vertices:
55///
56/// Vertices - Hashmap of type String, Vertex. Vertex has a label and a value
57///
58/// Example: A vertex with label A and value 10 will look like this
59/// ```
60/// self.vertices.insert(
61/// String::from("A");
62/// Vertex {
63/// label: String::from("A"),
64/// value: 10,
65/// },
66/// );
67/// ```
68///
69/// The structure of the vertex
70///
71/// ```
72/// pub struct Vertex<T> {
73/// pub label: VLT,
74/// pub value: T,
75/// }
76/// ```
77///
78/// # Edges:
79///
80/// Edges - Hashmap of type (VLT, VLT), Edge.
81///
82/// (VLT, VLT) are two end points of the edge.
83///
84/// Edge has weight and edge type
85///
86/// Example:
87///
88/// ```
89/// HashMap - Key: (String::from("A"), String::from("B")) | Value: Edge
90/// ```
91///
92/// Edge Looks like this:
93///
94/// ```
95/// pub struct Edge {
96/// pub endpoints: (VLT, VLT),
97/// pub weight: GNumber,
98/// pub edge_type: EdgeType,
99///}
100/// ```
101///
102/// # Edge Type
103///
104/// edge_type: EdgeType - Directed or Undirected
105#[derive(Clone)]
106pub struct Graph {
107 pub vertices: HashMap<VLT, Vertex>,
108 pub edges: HashMap<(VLT, VLT), Edge>,
109 pub edge_type: EdgeType,
110}
111
112impl Graph {
113 /// Creates a new Graph
114 ///
115 /// # Parameters:
116 ///
117 /// directed - type boolean
118 ///
119 /// directed = true if we want a directed graph
120 ///
121 /// directed = false if we want an undirected graph
122 ///
123 /// # Return value
124 ///
125 /// This function returns Graph - directed or undirected based on the parameter passed (Graph)
126 ///
127 /// # Example
128 ///
129 /// Basic Usage:
130 ///
131 /// 1. Undirected graph:
132 /// ```
133 /// let mut g: graphs::Graph = graphs::Graph::new(false);
134 /// ```
135 /// 2. Directed graph:
136 /// ```
137 /// let mut g: graphs::Graph = graphs::Graph::new(true);
138 /// ```
139 pub fn new(directed: bool) -> Graph {
140 //Create an empty graph.
141 let v: HashMap<VLT, Vertex> = HashMap::new();
142 let e: HashMap<(VLT, VLT), Edge> = HashMap::new();
143 let edge_type = if directed {
144 EdgeType::Directed
145 } else {
146 EdgeType::Undirected
147 };
148 Graph {
149 vertices: v,
150 edges: e,
151 edge_type: edge_type,
152 }
153 }
154
155 /// Prints the graph
156 ///
157 /// # usage:
158 /// ```
159 /// let mut g: graphs::Graph = graphs::Graph::new(false); // creates undirected graph
160 /// g.print() // prints the graph
161 /// ```
162 pub fn print(&self) {
163 println!("Vertices:");
164 for (id, vertex) in &self.vertices {
165 println!("{:?}: {:?}", id, vertex);
166 }
167
168 println!("Edges:");
169 for ((src, dst), edge) in &self.edges {
170 println!("({:?}, {:?}) -> {:?}", src, dst, edge);
171 }
172 }
173
174 /// Returns topological sorted order of the vertice of the graph
175 ///
176 pub fn get_topological_order(&mut self) -> Vec<VLT> {
177 //FIXME: Function not finished.
178 //TODO: Consider moving to utils.
179 let mut g: Graph = Graph::new(true);
180 let nodes = g.get_vertices().keys();
181 // let nodes = g.edges;
182 let mut order: Vec<VLT> = vec![];
183 let visited_vertex: HashMap<VLT, bool> = HashMap::new();
184
185 for node in nodes {
186 if visited_vertex.get(node) == None {
187 self.get_order(node, &mut order);
188 }
189 }
190 order.reverse();
191 println!("{:?}", order);
192 return order;
193 }
194
195 pub fn get_order(&mut self, node: &VLT, order: &mut Vec<VLT>) {
196 //TODO: Consider moving to utils.
197 let mut g: Graph = Graph::new(true);
198 //let coming_nodes = self.get_vertices().get(node);
199 let coming_nodes = g.get_vertices().keys();
200
201 for _value in coming_nodes {
202 self.get_order(node, order)
203 }
204 // if new_graph.get(node) == None {
205 // if coming_nodes != None {
206 // for value in coming_nodes. {
207 // self.get_order(value, order);
208 // }
209 // }
210 if !order.contains(node) {
211 order.push(node.to_string()); //FIXME: Is .to_string needed here?
212 }
213 }
214
215 pub fn get_vertices(&mut self) -> &mut HashMap<VLT, Vertex> {
216 &mut self.vertices
217 }
218
219 pub fn get_edges(&mut self) -> &mut HashMap<(VLT, VLT), Edge> {
220 &mut self.edges
221 }
222
223 /// Add vertex to the graph
224 ///
225 /// # Parameters:
226 ///
227 /// 1. label - the label of the vertex which should be of type String
228 ///
229 /// 2. value - value of the vertex, any generic
230 ///
231 /// # Example
232 ///
233 /// ```
234 /// let mut G: graphs::Graph = graphs::Graph::new(false); // create undirected graph
235 /// g.add_vertex(String::from("A")); // add vertex to the graph with label A and value 0
236 /// ```
237 pub fn add_vertex(&mut self, label: VLT) {
238 //Add vertex to graph.
239 if self.contains_vertex(&label) {
240 // self.vertices.iter().any(|vert| vert.label.eq(&label)){
241 //TODO: Create more sophosticated handling.
242 //println!("Vertex '{}' already in graph", label);
243 } else {
244 self.vertices.insert(
245 label.clone(),
246 Vertex {
247 label: label,
248 value: 0f64,
249 },
250 );
251 }
252 }
253
254 /// Remove vertex and all of its adjacent edges.
255 ///
256 /// # Parameters
257 ///
258 /// 1. label: The label of the vertex
259 ///
260 /// # Example
261 ///
262 /// ```
263 /// g.remove_vertex(String::from("A")); // Remove vertex A from the graph G
264 /// ```
265 ///
266 pub fn remove_vertex(&mut self, label: VLT) {
267 // Find all neighbors.
268 let neighbors = self.get_neighbors(&label);
269
270 // Remove all edges, regardless of direction.
271 // TODO: Decide on handling of directed vs undirected graphs.
272 for vert_label in neighbors.into_iter() {
273 //FIXME: Keep an eye on these '.to_string' uses.
274 self.remove_edge((label.clone(), vert_label.to_string()));
275 self.remove_edge((vert_label.to_string(), label.clone()));
276 }
277
278 //Remove central vertex.
279 self.vertices.remove(&label);
280 }
281
282 /// Adds an edge to the graph (Endpoint vertices must be present in graph)
283 ///
284 /// # Parameters
285 ///
286 /// 1. (endpoint1, endpoint2) - the two endpoints of the edge each will be of type String
287 ///
288 /// 2. weight - The weight of the edge
289 ///
290 /// # Example
291 ///
292 /// ```
293 /// // Edge with I32 weights having endpoints "A" and "B"
294 /// g.add_edge(
295 /// (String::from("A"), String::from('B')),
296 /// graphs::GNumber::I32(4),
297 /// );
298 ///
299 /// // Edge with F32 weights having endpoints "A" and "B"
300 /// g2.add_edge(
301 /// (String::from("A"), String::from('B')),
302 /// graphs::GNumber::F32(4.),
303 /// );
304 ///
305 /// // Edge with U32 weights having endpoints "A" and "B"
306 /// g3.add_edge(
307 /// (String::from("A"), String::from('B')),
308 /// graphs::GNumber::U32(2),
309 /// );
310 /// ```
311 pub fn add_edge(&mut self, e: (VLT, VLT), weight: GNumber) {
312 let edge_type = self.edge_type;
313
314 let is_undirected = match edge_type {
315 EdgeType::Directed => false,
316 EdgeType::Undirected => true,
317 };
318
319 if self.contains_edge(&e) {
320 //println!("Edge '{}'-'{}' already in graph", e.0, e.1);
321 return;
322 }
323
324 if is_undirected {
325 let rev = (e.1.clone(), e.0.clone());
326 if self.contains_edge(&rev) {
327 //println!("Edge '{}'-'{}' already in graph", e.1, e.0);
328 return;
329 }
330 }
331
332 if self.contains_vertex(&e.0) && self.contains_vertex(&e.1) {
333 self.edges.entry(e.clone()).or_insert(Edge {
334 endpoints: e,
335 weight: weight,
336 edge_type,
337 });
338 }
339 }
340
341 /// Update the weight of an edge to the graph (Edge must be present in graph)
342 ///
343 /// # Parameters
344 ///
345 /// 1. (endpoint1, endpoint2) - the two endpoints of the edge each will be of type String
346 ///
347 /// 2. weight - The weight of the edge
348 ///
349 /// # Example
350 ///
351 /// ```
352 /// // This will update the value of the edge with endpoint (A, B) to 10 (I32 value)
353 /// g.update_edge(
354 /// (String::from("A"), String::from('B')),
355 /// graphs::GNumber::I32(10),
356 /// );
357 /// ```
358 pub fn update_edge(&mut self, e: (VLT, VLT), weight: GNumber) {
359 if self.contains_edge(&e) {
360 self.edges.insert(
361 e.clone(),
362 Edge {
363 endpoints: e,
364 weight: weight,
365 edge_type: EdgeType::Undirected,
366 },
367 );
368 }
369 }
370
371 /// Removes an edge from a graph (Endpoint vertices are not affected)
372 ///
373 /// # Parameters
374 ///
375 /// 1. (endpoint1, endpoint2) - the two endpoints of the edge (type String)
376 ///
377 /// # Example
378 ///
379 /// ```
380 /// // This will remove edge with endpoints A and B
381 /// g.remove_edge(
382 /// (String::from("A"), String::from('B')),
383 /// );
384 /// ```
385 pub fn remove_edge(&mut self, e: (VLT, VLT)) {
386 let target_edge = self.edges.get(&e);
387 match target_edge {
388 Some(te) => match te.edge_type {
389 EdgeType::Directed => {
390 if self.edges.contains_key(&e) {
391 self.edges.remove(&e);
392 }
393 }
394 EdgeType::Undirected => {
395 let re = (e.1.clone(), e.0.clone()); //reverse_edge
396 if self.edges.contains_key(&e) || self.edges.contains_key(&re) {
397 self.edges.remove(&e);
398 self.edges.remove(&re);
399 }
400 }
401 },
402 None => println!("Edge '{}'-'{}' not in graph", e.0, e.1),
403 }
404 }
405
406 /// Input a vertex label (Returns a vector of vertex labels which correspond to the neighbors of the input vertex)
407 ///
408 /// # Parameter:
409 ///
410 /// 1. label - Label of type String
411 ///
412 /// # Return Value:
413 ///
414 /// Returns a vector of labels of all the vertices that are neighbors of this vertex
415 ///
416 /// # Example
417 ///
418 /// ```
419 /// G.get_neighbors(String::from("A")) // returns all the neighbors of A
420 ///
421 /// // example return: ["B", "C", "D"]. If B, C and D are neighbors of A
422 /// ```
423 pub fn get_neighbors(&self, label: &VLT) -> Vec<VLT> {
424 let mut neighbors: Vec<VLT> = Vec::<VLT>::new();
425 for (edge_labels, _edge) in self.edges.iter() {
426 if (label).eq(&edge_labels.0) {
427 neighbors.push(edge_labels.1.clone())
428 } else if (label).eq(&edge_labels.1) {
429 neighbors.push(edge_labels.0.clone())
430 }
431 }
432 neighbors
433 }
434
435 /// Input a vertex label. Returns a vector of vertex labels which correspond to the outgoing neighbors of the input vertex.
436 ///
437 /// # Parameter:
438 ///
439 /// 1. label - Label of type String
440 ///
441 /// # Return Value:
442 ///
443 /// Returns a vector of labels of all the vertices that are outgoing neighbors of this vertex.
444 /// This is for a directed graph
445 ///
446 /// # Example
447 ///
448 /// ```
449 /// g.get_out_neighbors(String::from("A")) // returns all the outgoing neighbors of A
450 ///
451 /// // example return: ["B", "C", "D"].
452 /// // A -> B, A -> C, A -> D
453 pub fn get_out_neighbors(&self, label: &VLT) -> Vec<VLT> {
454 let mut neighbors: Vec<VLT> = Vec::<VLT>::new();
455 for (edge_labels, _edge) in self.edges.iter() {
456 if (label).eq(&edge_labels.0) {
457 neighbors.push(edge_labels.1.clone())
458 }
459 }
460 neighbors
461 }
462
463 /// Input a vertex label. Returns a vector of vertex labels which correspond to the incoming neighbors of the input vertex.
464 ///
465 /// # Parameter:
466 ///
467 /// 1. label - Label of type String
468 ///
469 /// # Return Value:
470 ///
471 /// Returns a vector of labels of all the vertices that are incoming neighbors of this vertex.
472 /// This is for a directed graph
473 ///
474 /// # Example
475 ///
476 /// ```
477 /// G.get_in_neighbors(String::from("A")) // returns all the incoming neighbors of A
478 ///
479 /// // example return: ["B", "C", "D"].
480 /// // B -> A, C -> A, D -> A
481 pub fn get_in_neighbors(&self, label: &VLT) -> Vec<VLT> {
482 let mut neighbors: Vec<VLT> = Vec::<VLT>::new();
483 for (edge_labels, _edge) in self.edges.iter() {
484 if (label).eq(&edge_labels.1) {
485 neighbors.push(edge_labels.0.clone())
486 }
487 }
488 neighbors
489 }
490
491 // TODO: Documentation
492 /// Reads an adjacency matrix from a file and returns it as a `Vec<Vec<u32>>`
493 pub fn read_adjacency_matrix(filename: &str) -> Result<Vec<Vec<u32>>, Error> {
494 // Open the file for reading.
495 let file = File::open(filename)?;
496 // Create a buffered reader to read the file line by line.
497 let reader = BufReader::new(file);
498 // Initialize an empty vector to hold the matrix.
499 let mut matrix: Vec<Vec<u32>> = Vec::new();
500 // Iterate over each line in the file.
501 for line in reader.lines() {
502 // Parse each line as a vector of u32 values.
503 let row: Vec<u32> = line?
504 .split_whitespace() // Split the line by space.
505 .map(|s| s.parse().unwrap()) // Parse each value as u32
506 .collect(); // Collect the values into a vector.
507 // Add the row to the matrix.
508 matrix.push(row);
509 }
510
511 // Return the completed matrix.
512 Ok(matrix)
513 }
514
515 // TODO: Documentation
516 /// Writes an adjacency matrix to a file.
517 pub fn write_adjacency_matrix(matrix: &[Vec<u32>], filename: &str) -> Result<(), Error> {
518 // Open the file for writing.
519 let mut file = File::create(filename)?;
520
521 // Iterate over each row in the matrix.
522 for row in matrix.iter() {
523 // Convert the row to a string, separating each value with a space.
524 let row_str = row
525 .iter()
526 .map(|x| x.to_string())
527 .collect::<Vec<String>>()
528 .join(" ");
529
530 // Write the row string to the file, followed by a newline character.
531 writeln!(file, "{}", row_str)?;
532 }
533
534 // Return success.
535 Ok(())
536 }
537
538 /// Function to get the vertex given the label
539 ///
540 /// # Parameters:
541 ///
542 /// 1. label - Label of the vertex - type String
543 ///
544 /// # Return Type:
545 ///
546 /// Returns an Option of type mutable `Vertex`. If there are no vertex with the provided label - None will be returned
547 ///
548 /// # Example
549 ///
550 /// ```
551 /// let vertex_A = g.get_vertex(String::from("A")); // this wil return the vertex A which is mutable (We can change the value of the vertex)
552 /// ```
553 pub fn get_vertex(&mut self, label: &VLT) -> Option<&mut Vertex> {
554 self.vertices.get_mut(label)
555 }
556
557 /// Function to check if the given vertex is present in the graph
558 ///
559 /// # Parameters
560 ///
561 /// 1. label - Label of the vertex - type String
562 ///
563 /// # Return Type
564 ///
565 /// Returns a boolean value.
566 ///
567 /// true - if the vertex is present in the graph
568 ///
569 /// false - if the vertex is not present in the graph
570 ///
571 /// # Example
572 ///
573 /// ```
574 /// if g.contains_vertex(String::from("A")){
575 /// // Do something
576 /// }
577 /// ```
578 fn contains_vertex(&self, label: &VLT) -> bool {
579 //Check if graph contain vertex with label.
580 self.vertices.contains_key(label)
581 }
582
583 /// Function to check if the given edge is present in the graph
584 ///
585 /// # Parameters
586 ///
587 /// 1. (endpoint1, endpoint2) - endpoints of the edge (String, String)
588 ///
589 /// # Return Type
590 ///
591 /// Returns a boolean value.
592 ///
593 /// true - if the edge is present in the graph
594 ///
595 /// false - if the edge is not present in the graph
596 ///
597 /// # Example
598 ///
599 /// ```
600 /// // Check if the edge A-B is present in the graph
601 /// // Note if the graph is directed, it will return true only if the edge A -> B is present. B -> A will not be counted
602 /// if g.contains_edge((String::from("A"), String::from("B"))){
603 /// // Do something
604 /// }
605 /// ```
606 fn contains_edge(&self, e: &(VLT, VLT)) -> bool {
607 //Check if graph contain an edge.
608 self.edges.contains_key(e)
609 }
610}
611
612//Internal macro that matches the pattern of a single expession (indicating the user would like to add a vertex,
613//or a tuple-like pattern (str, i32, str), indicating the user would like an edge.
614#[allow(unused_macros)]
615#[macro_export]
616#[doc(hidden)]
617macro_rules! edg_or_vert {
618 ( $G:expr, ($a:literal, $b:literal, $c:literal) ) => {
619 {
620 $G.add_vertex(String::from($a));
621 $G.add_vertex(String::from($c));
622 $G.add_edge((String::from($a), String::from($c)), GNumber::I32($b));
623 }
624 };
625
626 ( $G:expr, $($x:expr ),* ) => {
627 {
628 {
629 $(
630 $G.add_vertex(String::from($x));
631 )*
632 }
633 }
634 };
635}
636
637/// Function to check if the given vertex is present in the graph
638///
639/// # Parameters
640///
641/// 1. label - Label of the vertex - type String
642///
643/// # Return Type
644///
645/// Returns a boolean value.
646///
647/// true - if the vertex is present in the graph
648///
649/// false - if the vertex is not present in the graph
650///
651/// # Example
652///
653/// ```
654/// if g.contains_vertex(String::from("A")){
655/// // Do something
656/// }
657/// ```
658
659///Build an undirected graph
660///
661///Requires importing at least graphalgos::graphs::{Graph, GNumber} and graphalgos::gph.
662///This macro can make both vertices and edges.
663///For a vertex, simple pass a string literal to be that vertex's label.
664///For an edge, write a pattern of the form (str, i32, str) where the first and last element represent the label of a vertex, and the middle value is the edges weight.
665///
666///# Example
667/// ```
668/// let G = gph!("A", "B", "C", ("A", 3, "C"), ("B", 7, "D"))
669/// ```
670///Notice that we do not need to list all vertices before adding edges for them, as shown in the last edge pattern.
671#[macro_export]
672macro_rules! gph {
673 ( $($sub:tt),* ) => { //iterate over every token. Could be a single string or an edge tuple.
674 {
675 let mut g: Graph = Graph::new(false);
676 $(
677 $crate::edg_or_vert!(&mut g, $sub);
678 )*
679 g
680 }
681 };
682}
683
684/// Vertex Structure
685///
686/// The structure of the vertex
687///
688/// A vertex has a label and a value
689///
690/// Label is a string and value is f64
691#[derive(Debug, Clone)]
692pub struct Vertex {
693 pub label: VLT,
694 pub value: f64,
695}
696
697impl Vertex {
698 pub fn get_value(&self) -> f64 {
699 self.value.clone()
700 }
701}
702
703impl Vertex {
704 pub fn set_value(&mut self, new_value: f64) {
705 self.value = new_value;
706 }
707}
708
709impl PartialEq for Vertex {
710 //Two vertices are equal if they have the same label.
711 fn eq(&self, other: &Self) -> bool {
712 self.label == other.label
713 }
714}
715
716impl Eq for Edge {}
717
718impl Ord for Edge {
719 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
720 self.weight.partial_cmp(&other.weight).unwrap()
721 }
722}
723
724impl PartialOrd for Edge {
725 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
726 self.weight.partial_cmp(&other.weight)
727 }
728}
729
730/// Edge Structure
731///
732/// Edges have three fields
733///
734/// 1. endpoints (a,b) - this contains the info of the two vertices of the edge (A -- B)
735/// 2. weight - the weight of the edge. It's of type GNumber
736/// 3. edge_type - the type of the edge (Directed / Undirected)
737#[derive(Debug, Clone)]
738pub struct Edge {
739 pub endpoints: (VLT, VLT),
740 pub weight: GNumber,
741 pub edge_type: EdgeType,
742}
743
744impl PartialEq for Edge {
745 fn eq(&self, e: &Edge) -> bool {
746 let ends1 = &self.endpoints;
747 let ends2 = &e.endpoints;
748 match self.edge_type {
749 EdgeType::Directed => (ends1.0).eq(&ends2.0) && (ends1.1).eq(&ends2.1),
750 EdgeType::Undirected => {
751 (ends1.0).eq(&ends2.0) && (ends1.1).eq(&ends2.1)
752 || (ends1.1).eq(&ends2.1) && (ends1.0).eq(&ends2.0)
753 }
754 }
755 }
756}
757
758/// Test cases
759#[cfg(test)]
760mod graph_tests {
761 //extern crate graphs;
762 //use graphs::Graph;
763 use super::*;
764
765 fn get_test_graph_1() -> Graph {
766 let mut g: Graph = Graph::new(false);
767 g.add_vertex(String::from("A"));
768 g.add_vertex(String::from("B"));
769 g.add_vertex(String::from("C"));
770 g.add_vertex(String::from("D"));
771 g.add_vertex(String::from("E"));
772 g.add_vertex(String::from("F"));
773 g.add_vertex(String::from("G"));
774 g.add_vertex(String::from("H"));
775 g.add_vertex(String::from("I"));
776 g
777 }
778
779 #[test]
780 fn add_one_vertex() {
781 let mut g: Graph = Graph::new(false);
782 g.add_vertex(String::from("A"));
783 assert_eq!(g.get_vertices().len(), 1);
784 assert_eq!(g.get_vertex(&String::from("A")).unwrap().label, "A");
785 }
786
787 #[test]
788 fn add_multiple_vertices() {
789 let mut g = get_test_graph_1();
790 assert_eq!(g.get_vertices().len(), 9);
791 assert_eq!(g.get_vertex(&String::from("A")).unwrap().label, "A");
792 assert_eq!(g.get_vertex(&String::from("C")).unwrap().label, "C");
793 assert_eq!(g.get_vertex(&String::from("H")).unwrap().label, "H");
794 assert_eq!(g.get_vertex(&String::from("H")).unwrap().label, "H");
795 assert_eq!(g.get_vertex(&String::from("I")).unwrap().label, "I");
796 }
797
798 #[test]
799 fn remove_one_vertex() {
800 let mut g = get_test_graph_1();
801 g.remove_vertex(String::from("F"));
802 assert_eq!(g.get_vertices().len(), 8);
803 assert_eq!(g.get_vertices().get("F").is_none(), true);
804 }
805
806 #[test]
807 fn remove_multiple_vertices() {
808 let mut g = get_test_graph_1();
809 g.remove_vertex(String::from("I"));
810 g.remove_vertex(String::from("H"));
811 assert_eq!(g.get_vertices().len(), 7);
812 g.remove_vertex(String::from("E"));
813 assert_eq!(g.get_vertices().len(), 6);
814 g.remove_vertex(String::from("A"));
815 g.remove_vertex(String::from("B"));
816 assert_eq!(g.get_vertices().len(), 4);
817 g.remove_vertex(String::from("I"));
818 assert_eq!(g.get_vertices().len(), 4);
819 g.remove_vertex(String::from("G"));
820 g.remove_vertex(String::from("F"));
821 g.remove_vertex(String::from("D"));
822 g.remove_vertex(String::from("C"));
823 assert_eq!(g.get_vertices().len(), 0);
824 }
825
826 #[test]
827 fn add_one_undirected_edge() {
828 let mut g = get_test_graph_1();
829 g.add_edge((String::from("A"), String::from('B')), GNumber::F64(4.));
830 assert_eq!(g.get_edges().len(), 1);
831 }
832
833 #[test]
834 fn make_from_macro() {
835 let mut g = gph!("A", "B");
836 assert_eq!(g.get_vertices().len(), 2);
837 let mut g = gph!("C", ("A", 5, "B"));
838 assert_eq!(g.get_vertices().len(), 3);
839 assert_eq!(g.get_edges().len(), 1);
840 }
841}