Skip to main content

cairn_knowledge_graph/operations/
add_edge.rs

1use crate::error::{GraphComputingError, LogicError, LogicErrorType, SystemError, SystemErrorType};
2
3use crate::graph::edge::adjacency_matrix::EdgeCoordinate;
4use crate::graph::edge::{
5    DirectedEdgeDefinedByIndices, DirectedEdgeDefinedByKeys, EdgeToEdgeCoordinate, EdgeTypeIndex,
6};
7use crate::graph::graph::Graph;
8
9use super::add_edge_type::AddEdgeType;
10
11pub trait AddEdge {
12    fn add_edge_using_keys(
13        &mut self,
14        edge: DirectedEdgeDefinedByKeys,
15    ) -> Result<(), GraphComputingError>;
16
17    /// If the EdgeType already exists, then the edge is added to it.
18    /// Existing edges for the EdgesType remain unaffected.
19    fn add_edge_and_edge_type_using_keys(
20        &mut self,
21        edge: DirectedEdgeDefinedByKeys,
22    ) -> Result<EdgeTypeIndex, GraphComputingError>;
23
24    fn add_edge_using_indices(
25        &mut self,
26        edge: DirectedEdgeDefinedByIndices,
27    ) -> Result<(), GraphComputingError>;
28}
29
30impl AddEdge for Graph {
31    fn add_edge_using_keys(
32        &mut self,
33        edge: DirectedEdgeDefinedByKeys,
34    ) -> Result<(), GraphComputingError> {
35        let edge_type_index: EdgeTypeIndex;
36        match self
37            .edge_type_to_edge_type_index_map_ref()
38            .get(edge.edge_type_ref())
39        {
40            None => {
41                return Err(LogicError::new(
42                    LogicErrorType::EdgeTypeMustExist,
43                    format!("EdgeType \"{}\" does not exist", edge.edge_type_ref()),
44                    None,
45                )
46                .into())
47            }
48            Some(index) => {
49                edge_type_index = index.clone(); // REVIEW: cloning seems inefficient but required but set_edge_in_adjacency_matrix() takes a mutable borrow of self, which the index otherwise references
50            }
51        }
52        let edge_coordinate = self.key_defined_edge_to_edge_coordinate(&edge)?;
53        self.set_edge_in_adjacency_matrix(&edge_coordinate, edge_type_index.clone())?; // TODO: by index, and by key
54        Ok(())
55    }
56
57    /// If the EdgeType already exists, then the edge is added to it.
58    /// Existing edges for the EdgesType remain unaffected.
59    fn add_edge_and_edge_type_using_keys(
60        &mut self,
61        edge: DirectedEdgeDefinedByKeys,
62    ) -> Result<EdgeTypeIndex, GraphComputingError> {
63        let edge_type_index: EdgeTypeIndex;
64        match self
65            .edge_type_to_edge_type_index_map_ref()
66            .get(edge.edge_type_ref())
67        {
68            None => {
69                edge_type_index = self.add_new_edge_type(edge.edge_type_ref().to_owned())?;
70            }
71            Some(index) => {
72                edge_type_index = index.clone(); // REVIEW: cloning seems inefficient but required but set_edge_in_adjacency_matrix() takes a mutable borrow of self, which the index otherwise references
73            }
74        }
75        let edge_coordinate = self.key_defined_edge_to_edge_coordinate(&edge)?;
76        self.set_edge_in_adjacency_matrix(&edge_coordinate, edge_type_index.clone())?;
77        Ok(edge_type_index)
78    }
79
80    fn add_edge_using_indices(
81        &mut self,
82        edge: DirectedEdgeDefinedByIndices,
83    ) -> Result<(), GraphComputingError> {
84        let edge_coordinate = self.index_defined_edge_to_edge_coordinate(&edge)?;
85        self.set_edge_in_adjacency_matrix(&edge_coordinate, edge.edge_type().clone())?;
86        Ok(())
87    }
88}
89
90impl Graph {
91    fn set_edge_in_adjacency_matrix(
92        &mut self,
93        edge_coordinate: &EdgeCoordinate,
94        edge_type_index: EdgeTypeIndex,
95    ) -> Result<(), GraphComputingError> {
96        match self
97            .adjacency_matrices_mut_ref()
98            .get_mut_ref(edge_type_index)
99        {
100            Ok(edge_type_adjacency_matrix) => {
101                edge_type_adjacency_matrix.add_edge(&edge_coordinate)?
102            }
103            Err(_) => {
104                // TODO: check actual error type
105                return Err(SystemError::new(
106                    SystemErrorType::IndexOutOfBounds,
107                    format!(
108                        "Unable to access adjacency matrix at index: {}",
109                        edge_type_index.index_ref()
110                    ),
111                    None,
112                )
113                .into());
114            }
115        }
116        Ok(())
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    use crate::graph::graph::Graph;
125    use crate::graph::vertex::Vertex;
126    use crate::operations::add_vertex::AddVertex;
127    use crate::operations::read_edge::ReadEdge;
128
129    #[test]
130    fn add_edge() {
131        let mut graph = Graph::new(5, 5).unwrap();
132
133        let vertex_1 = Vertex::new(String::from("vertex_1"), String::from("vertex_1").into());
134        let vertex_2 = Vertex::new(String::from("vertex_2"), String::from("vertex_2").into());
135
136        let edge_vertex1_vertex2 = DirectedEdgeDefinedByKeys::new(
137            vertex_1.clone().into(),
138            String::from("edge_type_1"),
139            vertex_2.clone().into(),
140        );
141        let edge_vertex2_vertex1 = DirectedEdgeDefinedByKeys::new(
142            vertex_2.clone().into(),
143            String::from("edge_type_1"),
144            vertex_1.clone().into(),
145        );
146        let edge_vertex1_vertex2_type2 = DirectedEdgeDefinedByKeys::new(
147            vertex_1.clone().into(),
148            String::from("edge_type_2"),
149            vertex_2.clone().into(),
150        );
151
152        graph.add_or_replace_vertex(vertex_1.clone()).unwrap();
153        graph.add_or_replace_vertex(vertex_2.clone()).unwrap();
154
155        graph
156            .add_edge_and_edge_type_using_keys(edge_vertex1_vertex2.clone())
157            .unwrap();
158        assert_eq!(
159            graph
160                .is_key_defined_edge_in_graph(&edge_vertex1_vertex2)
161                .unwrap(),
162            true
163        );
164        assert!(!graph
165            .is_key_defined_edge_in_graph(&edge_vertex2_vertex1)
166            .unwrap());
167        assert!(!graph
168            .is_key_defined_edge_in_graph(&edge_vertex1_vertex2_type2)
169            .unwrap());
170
171        graph
172            .add_edge_and_edge_type_using_keys(edge_vertex1_vertex2.clone())
173            .unwrap();
174        graph
175            .add_edge_and_edge_type_using_keys(edge_vertex2_vertex1.clone())
176            .unwrap();
177        assert!(graph
178            .is_key_defined_edge_in_graph(&edge_vertex1_vertex2)
179            .unwrap());
180        assert!(graph
181            .is_key_defined_edge_in_graph(&edge_vertex2_vertex1)
182            .unwrap());
183        assert!(!graph
184            .is_key_defined_edge_in_graph(&edge_vertex1_vertex2_type2)
185            .unwrap());
186
187        graph
188            .add_edge_and_edge_type_using_keys(edge_vertex1_vertex2_type2.clone())
189            .unwrap();
190        assert!(graph
191            .is_key_defined_edge_in_graph(&edge_vertex1_vertex2)
192            .unwrap());
193        assert!(graph
194            .is_key_defined_edge_in_graph(&edge_vertex2_vertex1)
195            .unwrap());
196        assert!(graph
197            .is_key_defined_edge_in_graph(&edge_vertex1_vertex2_type2)
198            .unwrap());
199    }
200
201    #[test]
202    fn add_edge_errors() {
203        let mut graph = Graph::new(5, 5).unwrap();
204
205        let vertex_1 = Vertex::new(String::from("vertex_1"), String::from("vertex_1").into());
206        let vertex_2 = Vertex::new(String::from("vertex_2"), String::from("vertex_2").into());
207
208        let edge_vertex1_vertex2 = DirectedEdgeDefinedByKeys::new(
209            vertex_1.clone().into(),
210            String::from("edge_type_1"),
211            vertex_2.clone().into(),
212        );
213
214        match graph.add_edge_and_edge_type_using_keys(edge_vertex1_vertex2.clone()) {
215            Err(_) => assert!(true),
216            Ok(_) => assert!(false),
217        }
218
219        graph.add_or_replace_vertex(vertex_1.clone()).unwrap();
220        match graph.add_edge_and_edge_type_using_keys(edge_vertex1_vertex2) {
221            Err(_) => assert!(true),
222            Ok(_) => assert!(false),
223        }
224    }
225}