Skip to main content

gen_graph/
traits.rs

1use crate::GenGraph;
2
3pub trait MergeGraph {
4    fn merge_graph(&mut self, other: &GenGraph);
5}
6
7impl MergeGraph for GenGraph {
8    fn merge_graph(&mut self, other: &GenGraph) {
9        for node in other.nodes() {
10            self.add_node(node);
11        }
12
13        for (source, target, edges) in other.all_edges() {
14            if let Some(existing_edges) = self.edge_weight_mut(source, target) {
15                for edge in edges.iter().copied() {
16                    if !existing_edges.contains(&edge) {
17                        existing_edges.push(edge);
18                    }
19                }
20            } else {
21                self.add_edge(source, target, edges.clone());
22            }
23        }
24    }
25}
26
27#[cfg(test)]
28mod tests {
29    use std::collections::HashSet;
30
31    use gen_core::{HashId, Strand};
32
33    use super::*;
34    use crate::{GraphEdge, GraphNode};
35
36    #[test]
37    fn merges_gen_graphs_and_preserves_distinct_edges() {
38        let start = GraphNode {
39            node_id: HashId::convert_str("merge-start"),
40            sequence_start: 0,
41            sequence_end: 0,
42        };
43        let middle = GraphNode {
44            node_id: HashId::convert_str("merge-middle"),
45            sequence_start: 0,
46            sequence_end: 5,
47        };
48        let end = GraphNode {
49            node_id: HashId::convert_str("merge-end"),
50            sequence_start: 0,
51            sequence_end: 0,
52        };
53        let chrom_index0_edge = GraphEdge {
54            edge_id: HashId::convert_str("merge-edge-ci0"),
55            source_strand: Strand::Forward,
56            target_strand: Strand::Forward,
57            chromosome_index: 0,
58            phased: 0,
59            created_on: 1,
60        };
61        let chrom_index1_edge = GraphEdge {
62            edge_id: HashId::convert_str("merge-edge-ci1"),
63            source_strand: Strand::Forward,
64            target_strand: Strand::Forward,
65            chromosome_index: 1,
66            phased: 1,
67            created_on: 2,
68        };
69
70        let mut graph_a = GenGraph::new();
71        graph_a.add_edge(start, middle, vec![chrom_index0_edge]);
72
73        let mut graph_b = GenGraph::new();
74        graph_b.add_edge(start, middle, vec![chrom_index1_edge]);
75        graph_b.add_edge(middle, end, vec![chrom_index0_edge]);
76
77        graph_a.merge_graph(&graph_b);
78
79        let graph_a_edges = graph_a
80            .edge_weight(start, middle)
81            .unwrap()
82            .iter()
83            .copied()
84            .collect::<HashSet<_>>();
85        assert_eq!(
86            graph_a_edges,
87            HashSet::from([chrom_index0_edge, chrom_index1_edge])
88        );
89        assert_eq!(
90            graph_a.edge_weight(middle, end).unwrap(),
91            &vec![chrom_index0_edge]
92        );
93    }
94
95    #[test]
96    fn merges_gen_graphs_without_duplicating_identical_edges() {
97        let start = GraphNode {
98            node_id: HashId::convert_str("dedup-start"),
99            sequence_start: 0,
100            sequence_end: 0,
101        };
102        let end = GraphNode {
103            node_id: HashId::convert_str("dedup-end"),
104            sequence_start: 0,
105            sequence_end: 0,
106        };
107        let edge = GraphEdge {
108            edge_id: HashId::convert_str("dedup-edge"),
109            source_strand: Strand::Forward,
110            target_strand: Strand::Forward,
111            chromosome_index: 0,
112            phased: 0,
113            created_on: 1,
114        };
115
116        let mut graph_a = GenGraph::new();
117        graph_a.add_edge(start, end, vec![edge]);
118
119        let mut graph_b = GenGraph::new();
120        graph_b.add_edge(start, end, vec![edge]);
121
122        graph_a.merge_graph(&graph_b);
123
124        assert_eq!(graph_a.edge_weight(start, end).unwrap(), &vec![edge]);
125    }
126
127    #[test]
128    fn merges_gen_graphs_by_graph_node_value() {
129        // Ensure when merging the same graph into itself, it dedupes nodes but will keep multiple edges between identical nodes
130        // between graphs
131        let source_a = GraphNode {
132            node_id: HashId::convert_str("shared-node"),
133            sequence_start: 0,
134            sequence_end: 5,
135        };
136        let target_a = GraphNode {
137            node_id: HashId::convert_str("target-node"),
138            sequence_start: 0,
139            sequence_end: 5,
140        };
141        let source_b = GraphNode {
142            node_id: source_a.node_id,
143            sequence_start: source_a.sequence_start,
144            sequence_end: source_a.sequence_end,
145        };
146        let target_b = GraphNode {
147            node_id: target_a.node_id,
148            sequence_start: target_a.sequence_start,
149            sequence_end: target_a.sequence_end,
150        };
151        let edge_a = GraphEdge {
152            edge_id: HashId::convert_str("logical-edge-a"),
153            source_strand: Strand::Forward,
154            target_strand: Strand::Forward,
155            chromosome_index: 0,
156            phased: 0,
157            created_on: 1,
158        };
159        let edge_b = GraphEdge {
160            edge_id: HashId::convert_str("logical-edge-b"),
161            source_strand: Strand::Forward,
162            target_strand: Strand::Forward,
163            chromosome_index: 1,
164            phased: 0,
165            created_on: 2,
166        };
167
168        let mut graph_a = GenGraph::new();
169        graph_a.add_edge(source_a, target_a, vec![edge_a]);
170
171        let mut graph_b = GenGraph::new();
172        graph_b.add_edge(source_b, target_b, vec![edge_b]);
173
174        graph_a.merge_graph(&graph_b);
175
176        let nodes = graph_a.nodes().collect::<Vec<_>>();
177        let edges = graph_a
178            .edge_weight(source_a, target_a)
179            .unwrap()
180            .iter()
181            .copied()
182            .collect::<HashSet<_>>();
183        assert_eq!(nodes, vec![source_a, target_a]);
184        assert_eq!(edges, HashSet::from([edge_a, edge_b]));
185    }
186}