1use std::{
2 collections::{HashMap, HashSet, VecDeque},
3 fmt::{self, Debug},
4 hash::Hash,
5 iter::from_fn,
6 rc::Rc,
7};
8
9use gen_core::{
10 HashId, NodeIntervalBlock, PATH_END_NODE_ID, PATH_START_NODE_ID, PathBlock, Strand,
11 is_end_node, is_start_node,
12};
13use interavl::IntervalTree as IT2;
14use intervaltree::IntervalTree;
15use petgraph::{
16 Direction,
17 graphmap::DiGraphMap,
18 prelude::EdgeRef,
19 visit::{
20 Dfs, GraphRef, IntoEdgeReferences, IntoEdges, IntoNeighbors, IntoNeighborsDirected,
21 NodeCount, Reversed,
22 },
23};
24use serde::{Deserialize, Serialize};
25
26pub mod traits;
27pub use traits::MergeGraph;
28
29#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
30pub struct GraphNode {
31 pub node_id: HashId,
32 pub sequence_start: i64,
33 pub sequence_end: i64,
34}
35
36impl fmt::Display for GraphNode {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(
39 f,
40 "{}[{}-{}]",
41 self.node_id, self.sequence_start, self.sequence_end
42 )
43 }
44}
45
46impl GraphNode {
47 pub fn length(&self) -> i64 {
48 self.sequence_end - self.sequence_start
49 }
50}
51
52pub type GenGraph = DiGraphMap<GraphNode, Vec<GraphEdge>>;
53pub type OperationGraph = DiGraphMap<HashId, ()>;
54
55#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
56pub struct GraphEdge {
57 pub edge_id: HashId,
58 pub source_strand: Strand,
59 pub target_strand: Strand,
60 pub chromosome_index: i64,
61 pub phased: i64,
62 pub created_on: i64,
63}
64
65pub fn all_simple_paths<G>(
132 graph: G,
133 from: G::NodeId,
134 to: G::NodeId,
135) -> impl Iterator<Item = Vec<G::NodeId>>
136where
137 G: NodeCount,
138 G: IntoNeighborsDirected,
139 G::NodeId: Eq + Hash,
140{
141 let mut visited = vec![from];
143 let mut stack = vec![graph.neighbors_directed(from, Direction::Outgoing)];
146
147 from_fn(move || {
148 while let Some(children) = stack.last_mut() {
149 if let Some(child) = children.next() {
150 if child == to {
151 let path = visited.iter().cloned().chain(Some(to)).collect::<_>();
152 return Some(path);
153 } else if !visited.contains(&child) {
154 visited.push(child);
155 stack.push(graph.neighbors_directed(child, Direction::Outgoing));
156 }
157 } else {
158 stack.pop();
159 visited.pop();
160 }
161 }
162 None
163 })
164}
165
166pub fn all_intermediate_edges<G>(
167 graph: G,
168 from: G::NodeId,
169 to: G::NodeId,
170) -> Vec<<G as IntoEdgeReferences>::EdgeRef>
171where
172 G: GraphRef + IntoEdges + petgraph::visit::IntoNeighborsDirected + petgraph::visit::Visitable,
173 G::NodeId: Eq + Hash + std::fmt::Display,
174{
175 let mut outgoing_nodes = HashSet::new();
176 outgoing_nodes.insert(from);
177 let mut dfs_outbound = Dfs::new(graph, from);
178
179 while let Some(outgoing_node) = dfs_outbound.next(graph) {
180 outgoing_nodes.insert(outgoing_node);
181 }
182
183 let reversed_graph = Reversed(&graph);
188 let mut incoming_nodes = HashSet::new();
189 incoming_nodes.insert(to);
190 let mut dfs_inbound = Dfs::new(reversed_graph, to);
191 while let Some(incoming_node) = dfs_inbound.next(reversed_graph) {
192 incoming_nodes.insert(incoming_node);
193 }
194
195 let common_nodes: HashSet<&<G as petgraph::visit::GraphBase>::NodeId> =
196 outgoing_nodes.intersection(&incoming_nodes).collect();
197 let mut common_edgerefs = vec![];
198 for edge in graph.edge_references() {
199 let (source, target) = (edge.source(), edge.target());
200
201 if common_nodes.contains(&source) && common_nodes.contains(&target) {
202 common_edgerefs.push(edge);
203 }
204 }
205
206 common_edgerefs
207}
208
209pub fn all_simple_paths_by_edge<G>(
210 graph: G,
211 from: G::NodeId,
212 to: G::NodeId,
213) -> impl Iterator<Item = Vec<G::EdgeRef>>
214where
215 G: NodeCount + IntoEdges,
216 G: IntoNeighborsDirected,
217 G::NodeId: Eq + Hash,
218{
219 let mut visited = vec![from];
221 let mut path: Vec<G::EdgeRef> = vec![];
224 let mut stack = vec![graph.edges(from)];
225
226 from_fn(move || {
227 while let Some(edges) = stack.last_mut() {
228 if let Some(edge) = edges.next() {
229 let target = edge.target();
230 if target == to {
231 let a_path = path.iter().cloned().chain(Some(edge)).collect::<_>();
232 return Some(a_path);
233 } else if !visited.contains(&target) {
234 path.push(edge);
235 visited.push(target);
236 stack.push(graph.edges(target));
237 }
238 } else {
239 stack.pop();
240 path.pop();
241 visited.pop();
242 }
243 }
244 None
245 })
246}
247
248pub fn all_reachable_nodes<G>(graph: G, nodes: &[G::NodeId]) -> HashSet<G::NodeId>
249where
250 G: GraphRef + IntoNeighbors,
251 G::NodeId: Eq + Hash + Debug,
252{
253 let mut stack = VecDeque::new();
254 let mut reachable = HashSet::new();
255 for node in nodes.iter() {
256 stack.push_front(*node);
257 reachable.insert(*node);
258 while let Some(nx) = stack.pop_front() {
259 for succ in graph.neighbors(nx) {
260 if !reachable.contains(&succ) {
261 reachable.insert(succ);
262 stack.push_back(succ);
263 }
264 }
265 }
266 }
267 reachable
268}
269
270pub fn flatten_to_interval_tree(
271 graph: &GenGraph,
272 remove_ambiguous_positions: bool,
273) -> IntervalTree<i64, NodeIntervalBlock> {
274 #[derive(Clone, Debug, Ord, PartialOrd, Eq, Hash, PartialEq)]
275 struct NodeP {
276 x: i64,
277 y: i64,
278 }
279 let mut excluded_nodes = HashSet::new();
280 let mut node_tree: HashMap<HashId, IT2<NodeP, HashId>> = HashMap::new();
281
282 let mut start_nodes = vec![];
283 let mut end_nodes = vec![];
284 for node in graph.nodes() {
285 if is_start_node(node.node_id) {
286 start_nodes.push(node);
287 }
288 if is_end_node(node.node_id) {
289 end_nodes.push(node);
290 }
291 }
292
293 let mut spans: HashSet<NodeIntervalBlock> = HashSet::new();
294
295 for start in start_nodes.iter() {
296 for end_node in end_nodes.iter() {
297 for path in all_simple_paths_by_edge(&graph, *start, *end_node) {
298 let mut offset = 0;
299 for (source_node, target_node, edges) in path.iter() {
300 let block_len = source_node.length();
301 let node_start = offset;
302 let node_end = offset + block_len;
303 let edge = &edges[0];
305 spans.insert(NodeIntervalBlock {
306 node_id: source_node.node_id,
307 start: node_start,
308 end: node_end,
309 sequence_start: source_node.sequence_start,
310 sequence_end: source_node.sequence_end,
311 strand: edge.source_strand,
312 });
313 spans.insert(NodeIntervalBlock {
314 node_id: target_node.node_id,
315 start: node_end,
316 end: node_end + target_node.length(),
317 sequence_start: target_node.sequence_start,
318 sequence_end: target_node.sequence_end,
319 strand: edge.target_strand,
320 });
321 if remove_ambiguous_positions {
322 for (node_id, node_range) in [
323 (
324 source_node.node_id,
325 NodeP {
326 x: node_start,
327 y: source_node.sequence_start,
328 }..NodeP {
329 x: node_end,
330 y: source_node.sequence_end,
331 },
332 ),
333 (
334 target_node.node_id,
335 NodeP {
336 x: node_end,
337 y: target_node.sequence_start,
338 }..NodeP {
339 x: node_end + target_node.length(),
340 y: target_node.sequence_end,
341 },
342 ),
343 ] {
344 node_tree
348 .entry(node_id)
349 .and_modify(|tree| {
350 for (stored_range, _stored_node_id) in
351 tree.iter_overlaps(&node_range)
352 {
353 if *stored_range != node_range {
354 excluded_nodes.insert(node_id);
355 break;
356 }
357 }
358 tree.insert(node_range.clone(), node_id);
359 })
360 .or_insert_with(|| {
361 let mut t = IT2::default();
362 t.insert(node_range.clone(), node_id);
363 t
364 });
365 }
366 }
367 offset += block_len;
368 }
369 }
370 }
371 }
372
373 let tree: IntervalTree<i64, NodeIntervalBlock> = spans
374 .iter()
375 .filter(|block| !remove_ambiguous_positions || !excluded_nodes.contains(&block.node_id))
376 .map(|block| {
377 if block.node_id == PATH_START_NODE_ID {
378 (i64::MIN + 1..0, *block)
379 } else if block.node_id == PATH_END_NODE_ID {
380 (block.end..i64::MAX, *block)
381 } else {
382 (block.start..block.end, *block)
383 }
384 })
385 .collect();
386 tree
387}
388
389pub fn project_path(graph: &GenGraph, path_blocks: &[PathBlock]) -> Vec<(GraphNode, Strand)> {
390 #[derive(Debug)]
397 struct PathNode {
398 node: (GraphNode, Strand),
399 path_index: usize,
403 prev: Option<Rc<PathNode>>,
404 }
405
406 let start_nodes = graph
407 .nodes()
408 .filter(|node| node.node_id == PATH_START_NODE_ID)
409 .collect::<Vec<GraphNode>>();
410 let start_node = start_nodes.first().unwrap();
411
412 let mut final_path = vec![];
413 let mut stack: VecDeque<Rc<PathNode>> = VecDeque::new();
414 let mut visited: HashSet<(GraphNode, Strand)> = HashSet::new();
415 let mut path_index = 0;
416 let mut current_pos;
417
418 stack.push_back(Rc::new(PathNode {
420 node: (*start_node, Strand::Forward),
421 path_index,
422 prev: None,
423 }));
424
425 while let Some(current_node) = stack.pop_back() {
426 let current = current_node.node;
427 let mut current_block = &path_blocks[current_node.path_index];
428
429 if !visited.insert(current) {
430 continue;
431 }
432
433 if current.0.sequence_end == current_block.sequence_end {
435 path_index += 1;
436 if path_index < path_blocks.len() {
437 current_block = &path_blocks[path_index];
438 current_pos = current_block.sequence_start;
439 } else {
440 let mut path = vec![];
442 let mut path_ref = Some(Rc::clone(¤t_node));
443 while let Some(pn) = path_ref {
444 path.push(pn.node);
445 path_ref = pn.prev.clone();
446 }
447 final_path = path.into_iter().rev().collect();
448 break;
449 }
450 } else {
451 current_pos = current.0.sequence_end;
452 }
453
454 for (_src, neighbor, edges) in graph.edges(current.0) {
455 if neighbor.node_id == current_block.node_id
457 && neighbor.sequence_start == current_pos
458 && edges
459 .iter()
460 .any(|edge| current_block.strand == edge.target_strand)
461 {
462 stack.push_back(Rc::new(PathNode {
463 node: (neighbor, current_block.strand),
464 path_index,
465 prev: Some(Rc::clone(¤t_node)),
466 }));
467 }
468 }
469 }
470 final_path
471}
472
473pub fn find_articulation_points(graph: &GenGraph) -> Vec<GraphNode> {
477 let mut articulation_points: Vec<GraphNode> = Vec::new();
478 let mut discovery_time: HashMap<GraphNode, usize> = HashMap::new();
479 let mut low: HashMap<GraphNode, usize> = HashMap::new();
480 let mut parent: HashMap<GraphNode, Option<GraphNode>> = HashMap::new();
481 let mut time = 0;
482
483 for node in graph.nodes() {
484 if !discovery_time.contains_key(&node) {
485 let mut stack = vec![(node, None, true)];
486 while let Some((u, p, is_first_time)) = stack.pop() {
487 if is_first_time {
488 discovery_time.insert(u, time);
490 low.insert(u, time);
491 time += 1;
492 parent.insert(u, p);
493
494 stack.push((u, p, false));
496
497 let neighbors: Vec<_> = graph
499 .neighbors_directed(u, Direction::Outgoing)
500 .chain(graph.neighbors_directed(u, Direction::Incoming))
501 .collect();
502
503 for v in neighbors {
504 if !discovery_time.contains_key(&v) {
505 stack.push((v, Some(u), true));
506 } else if Some(v) != p {
507 let current_low = low.get(&u).cloned().unwrap_or(usize::MAX);
509 let v_disc = discovery_time.get(&v).cloned().unwrap_or(usize::MAX);
510 low.insert(u, current_low.min(v_disc));
511 }
512 }
513 } else {
514 let mut is_articulation = false;
516 let mut child_count = 0;
517
518 let neighbors: Vec<_> = graph
519 .neighbors_directed(u, Direction::Outgoing)
520 .chain(graph.neighbors_directed(u, Direction::Incoming))
521 .collect();
522
523 for v in neighbors {
524 if parent.get(&v).cloned() == Some(Some(u)) {
525 child_count += 1;
526 let v_low = low.get(&v).cloned().unwrap_or(usize::MAX);
527 let u_disc = discovery_time.get(&u).cloned().unwrap_or(usize::MAX);
528 if v_low >= u_disc {
529 is_articulation = true;
530 }
531 let current_low = low.get(&u).cloned().unwrap_or(usize::MAX);
532 let v_low = low.get(&v).cloned().unwrap_or(usize::MAX);
533 low.insert(u, current_low.min(v_low));
534 } else if Some(v) != parent.get(&u).cloned().unwrap_or(None) {
535 let v_disc = discovery_time.get(&v).cloned().unwrap_or(usize::MAX);
536 let current_low = low.get(&u).cloned().unwrap_or(usize::MAX);
537 low.insert(u, current_low.min(v_disc));
538 }
539 }
540
541 let u_parent = parent.get(&u).cloned().unwrap_or(None);
542 if (u_parent.is_some() && is_articulation)
543 || (u_parent.is_none() && child_count > 1)
544 {
545 articulation_points.push(u);
546 }
547 }
548 }
549 }
550 }
551
552 articulation_points.sort();
553 articulation_points.dedup();
554 articulation_points
555}
556
557#[cfg(test)]
558mod tests {
559 use std::collections::HashSet;
560
561 use petgraph::graphmap::DiGraphMap;
562
563 use super::*;
564
565 #[test]
566 fn test_path_graph() {
567 let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
568 graph.add_node(1);
569 graph.add_node(2);
570 graph.add_node(3);
571
572 graph.add_edge(1, 2, ());
573 graph.add_edge(2, 3, ());
574
575 let paths = all_simple_paths(&graph, 1, 3).collect::<Vec<Vec<i64>>>();
576 assert_eq!(paths.len(), 1);
577 let path = paths.first().unwrap().clone();
578 assert_eq!(path, vec![1, 2, 3]);
579 }
580
581 #[test]
582 fn test_get_simple_paths_by_edge() {
583 let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
584 graph.add_node(1);
585 graph.add_node(2);
586 graph.add_node(3);
587 graph.add_node(4);
588 graph.add_node(5);
589 graph.add_node(6);
590 graph.add_node(7);
591 graph.add_node(8);
592 graph.add_node(9);
593
594 graph.add_edge(1, 2, ());
595 graph.add_edge(2, 3, ());
596 graph.add_edge(3, 4, ());
597 graph.add_edge(4, 5, ());
598 graph.add_edge(2, 6, ());
599 graph.add_edge(6, 7, ());
600 graph.add_edge(7, 4, ());
601 graph.add_edge(6, 8, ());
602 graph.add_edge(8, 7, ());
603
604 let edge_path =
605 all_simple_paths_by_edge(&graph, 1, 5).collect::<Vec<Vec<(i64, i64, &())>>>();
606 assert_eq!(
607 edge_path,
608 vec![
609 vec![(1, 2, &()), (2, 3, &()), (3, 4, &()), (4, 5, &())],
610 vec![
611 (1, 2, &()),
612 (2, 6, &()),
613 (6, 7, &()),
614 (7, 4, &()),
615 (4, 5, &())
616 ],
617 vec![
618 (1, 2, &()),
619 (2, 6, &()),
620 (6, 8, &()),
621 (8, 7, &()),
622 (7, 4, &()),
623 (4, 5, &())
624 ]
625 ]
626 );
627 }
628
629 #[test]
630 fn test_two_path_graph() {
631 let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
632 graph.add_node(1);
633 graph.add_node(2);
634 graph.add_node(3);
635 graph.add_node(4);
636
637 graph.add_edge(1, 2, ());
638 graph.add_edge(1, 3, ());
639 graph.add_edge(2, 4, ());
640 graph.add_edge(3, 4, ());
641
642 let paths = all_simple_paths(&graph, 1, 4).collect::<Vec<Vec<i64>>>();
643 assert_eq!(paths.len(), 2);
644 assert_eq!(
645 HashSet::<Vec<i64>>::from_iter::<Vec<Vec<i64>>>(paths),
646 HashSet::from_iter(vec![vec![1, 2, 4], vec![1, 3, 4]])
647 );
648 }
649
650 #[test]
651 fn test_two_by_two_combinatorial_graph() {
652 let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
653 graph.add_node(1);
654 graph.add_node(2);
655 graph.add_node(3);
656 graph.add_node(4);
657 graph.add_node(5);
658 graph.add_node(6);
659 graph.add_node(7);
660
661 graph.add_edge(1, 2, ());
662 graph.add_edge(1, 3, ());
663 graph.add_edge(2, 4, ());
664 graph.add_edge(3, 4, ());
665 graph.add_edge(4, 5, ());
666 graph.add_edge(4, 6, ());
667 graph.add_edge(5, 7, ());
668 graph.add_edge(6, 7, ());
669
670 let paths = all_simple_paths(&graph, 1, 7).collect::<Vec<Vec<i64>>>();
671 assert_eq!(paths.len(), 4);
672 assert_eq!(
673 HashSet::<Vec<i64>>::from_iter::<Vec<Vec<i64>>>(paths),
674 HashSet::from_iter(vec![
675 vec![1, 2, 4, 5, 7],
676 vec![1, 3, 4, 5, 7],
677 vec![1, 2, 4, 6, 7],
678 vec![1, 3, 4, 6, 7]
679 ])
680 );
681 }
682
683 #[test]
684 fn test_three_by_three_combinatorial_graph() {
685 let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
686 graph.add_node(1);
687 graph.add_node(2);
688 graph.add_node(3);
689 graph.add_node(4);
690 graph.add_node(5);
691 graph.add_node(6);
692 graph.add_node(7);
693 graph.add_node(8);
694 graph.add_node(9);
695
696 graph.add_edge(1, 2, ());
697 graph.add_edge(1, 3, ());
698 graph.add_edge(1, 4, ());
699 graph.add_edge(2, 5, ());
700 graph.add_edge(3, 5, ());
701 graph.add_edge(4, 5, ());
702 graph.add_edge(5, 6, ());
703 graph.add_edge(5, 7, ());
704 graph.add_edge(5, 8, ());
705 graph.add_edge(6, 9, ());
706 graph.add_edge(7, 9, ());
707 graph.add_edge(8, 9, ());
708
709 let paths = all_simple_paths(&graph, 1, 9).collect::<Vec<Vec<i64>>>();
710 assert_eq!(paths.len(), 9);
711 let expected_paths = vec![
712 vec![1, 2, 5, 6, 9],
713 vec![1, 3, 5, 6, 9],
714 vec![1, 4, 5, 6, 9],
715 vec![1, 2, 5, 7, 9],
716 vec![1, 3, 5, 7, 9],
717 vec![1, 4, 5, 7, 9],
718 vec![1, 2, 5, 8, 9],
719 vec![1, 3, 5, 8, 9],
720 vec![1, 4, 5, 8, 9],
721 ];
722 assert_eq!(
723 HashSet::<Vec<i64>>::from_iter::<Vec<Vec<i64>>>(paths),
724 HashSet::from_iter(expected_paths)
725 );
726 }
727
728 #[test]
729 fn test_super_bubble_path() {
730 let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
739 graph.add_node(1);
740 graph.add_node(2);
741 graph.add_node(3);
742 graph.add_node(4);
743 graph.add_node(5);
744 graph.add_node(6);
745 graph.add_node(7);
746 graph.add_node(8);
747 graph.add_node(9);
748
749 graph.add_edge(1, 2, ());
750 graph.add_edge(2, 3, ());
751 graph.add_edge(3, 4, ());
752 graph.add_edge(4, 5, ());
753 graph.add_edge(2, 6, ());
754 graph.add_edge(6, 7, ());
755 graph.add_edge(7, 4, ());
756 graph.add_edge(6, 8, ());
757 graph.add_edge(8, 7, ());
758
759 let paths = all_simple_paths(&graph, 1, 5).collect::<Vec<Vec<i64>>>();
760 assert_eq!(
761 HashSet::<Vec<i64>>::from_iter::<Vec<Vec<i64>>>(paths),
762 HashSet::from_iter(vec![
763 vec![1, 2, 3, 4, 5],
764 vec![1, 2, 6, 7, 4, 5],
765 vec![1, 2, 6, 8, 7, 4, 5]
766 ])
767 );
768 }
769
770 #[test]
771 fn test_finds_all_reachable_nodes() {
772 let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
778 graph.add_node(1);
779 graph.add_node(2);
780 graph.add_node(3);
781 graph.add_node(4);
782 graph.add_node(5);
783 graph.add_node(6);
784 graph.add_node(7);
785
786 graph.add_edge(1, 2, ());
787 graph.add_edge(2, 3, ());
788 graph.add_edge(3, 4, ());
789 graph.add_edge(4, 5, ());
790 graph.add_edge(6, 7, ());
791 graph.add_edge(7, 3, ());
792
793 assert_eq!(
794 all_reachable_nodes(&graph, &[1]),
795 HashSet::from_iter(vec![1, 2, 3, 4, 5])
796 );
797
798 assert_eq!(
799 all_reachable_nodes(&graph, &[1, 6]),
800 HashSet::from_iter(vec![1, 2, 3, 4, 5, 6, 7])
801 );
802
803 assert_eq!(
804 all_reachable_nodes(&graph, &[3]),
805 HashSet::from_iter(vec![3, 4, 5])
806 );
807
808 assert_eq!(
809 all_reachable_nodes(&graph, &[5]),
810 HashSet::from_iter(vec![5])
811 );
812 }
813
814 mod test_all_intermediate_edges {
815 use super::*;
816 #[test]
817 fn test_one_part_group() {
818 let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
823 graph.add_node(1);
824 graph.add_node(2);
825 graph.add_node(3);
826 graph.add_node(4);
827 graph.add_node(5);
828 graph.add_node(6);
829
830 graph.add_edge(1, 2, ());
831 graph.add_edge(2, 3, ());
832 graph.add_edge(3, 4, ());
833 graph.add_edge(4, 5, ());
834 graph.add_edge(2, 6, ());
835 graph.add_edge(6, 4, ());
836
837 let result_edges = all_intermediate_edges(&graph, 2, 4);
838 let intermediate_edges = result_edges
839 .iter()
840 .map(|(source, target, _weight)| (*source, *target))
841 .collect::<Vec<(i64, i64)>>();
842 assert_eq!(intermediate_edges, vec![(2, 3), (3, 4), (2, 6), (6, 4)]);
843 }
844
845 #[test]
846 fn test_two_part_groups() {
847 let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
852 graph.add_node(1);
853 graph.add_node(2);
854 graph.add_node(3);
855 graph.add_node(4);
856 graph.add_node(5);
857 graph.add_node(6);
858 graph.add_node(7);
859 graph.add_node(8);
860 graph.add_node(9);
861
862 graph.add_edge(1, 2, ());
863 graph.add_edge(2, 3, ());
864 graph.add_edge(3, 4, ());
865 graph.add_edge(4, 5, ());
866 graph.add_edge(5, 6, ());
867 graph.add_edge(6, 7, ());
868 graph.add_edge(2, 8, ());
869 graph.add_edge(8, 4, ());
870 graph.add_edge(4, 9, ());
871 graph.add_edge(9, 6, ());
872
873 let result_edges = all_intermediate_edges(&graph, 2, 6);
874 let intermediate_edges = result_edges
875 .iter()
876 .map(|(source, target, _weight)| (*source, *target))
877 .collect::<Vec<(i64, i64)>>();
878 assert_eq!(
879 intermediate_edges,
880 vec![
881 (2, 3),
882 (3, 4),
883 (4, 5),
884 (5, 6),
885 (2, 8),
886 (8, 4),
887 (4, 9),
888 (9, 6)
889 ]
890 );
891 }
892
893 #[test]
894 fn test_one_part_group_with_unrelated_edges() {
895 let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
902 graph.add_node(1);
903 graph.add_node(2);
904 graph.add_node(3);
905 graph.add_node(4);
906 graph.add_node(5);
907 graph.add_node(6);
908 graph.add_node(7);
909
910 graph.add_edge(1, 2, ());
911 graph.add_edge(2, 3, ());
912 graph.add_edge(3, 4, ());
913 graph.add_edge(4, 5, ());
914 graph.add_edge(2, 6, ());
915 graph.add_edge(6, 4, ());
916 graph.add_edge(2, 7, ());
917 graph.add_edge(7, 5, ());
918
919 let result_edges = all_intermediate_edges(&graph, 2, 4);
920 let intermediate_edges = result_edges
921 .iter()
922 .map(|(source, target, _weight)| (*source, *target))
923 .collect::<Vec<(i64, i64)>>();
924 assert_eq!(intermediate_edges, vec![(2, 3), (3, 4), (2, 6), (6, 4)]);
925 }
926 }
927
928 #[cfg(test)]
929 mod project_path {
930 use gen_core::PATH_END_NODE_ID;
931
932 use super::*;
933
934 #[test]
935 fn test_simple_path_projection() {
936 let mut graph = GenGraph::new();
942 graph.add_edge(
943 GraphNode {
944 node_id: PATH_START_NODE_ID,
945 sequence_start: 0,
946 sequence_end: 0,
947 },
948 GraphNode {
949 node_id: HashId::convert_str("3"),
950 sequence_start: 0,
951 sequence_end: 5,
952 },
953 vec![GraphEdge {
954 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
955 .try_into()
956 .unwrap(),
957 source_strand: Strand::Forward,
958 target_strand: Strand::Forward,
959 chromosome_index: 0,
960 phased: 0,
961 created_on: 0,
962 }],
963 );
964 graph.add_edge(
965 GraphNode {
966 node_id: HashId::convert_str("3"),
967 sequence_start: 0,
968 sequence_end: 5,
969 },
970 GraphNode {
971 node_id: HashId::convert_str("4"),
972 sequence_start: 3,
973 sequence_end: 5,
974 },
975 vec![GraphEdge {
976 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
977 .try_into()
978 .unwrap(),
979 source_strand: Strand::Forward,
980 target_strand: Strand::Forward,
981 chromosome_index: 0,
982 phased: 0,
983 created_on: 0,
984 }],
985 );
986 graph.add_edge(
987 GraphNode {
988 node_id: HashId::convert_str("4"),
989 sequence_start: 3,
990 sequence_end: 5,
991 },
992 GraphNode {
993 node_id: HashId::convert_str("5"),
994 sequence_start: 0,
995 sequence_end: 3,
996 },
997 vec![GraphEdge {
998 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
999 .try_into()
1000 .unwrap(),
1001 source_strand: Strand::Forward,
1002 target_strand: Strand::Forward,
1003 chromosome_index: 0,
1004 phased: 0,
1005 created_on: 0,
1006 }],
1007 );
1008 graph.add_edge(
1009 GraphNode {
1010 node_id: HashId::convert_str("5"),
1011 sequence_start: 0,
1012 sequence_end: 3,
1013 },
1014 GraphNode {
1015 node_id: HashId::convert_str("6"),
1016 sequence_start: 5,
1017 sequence_end: 15,
1018 },
1019 vec![GraphEdge {
1020 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1021 .try_into()
1022 .unwrap(),
1023 source_strand: Strand::Forward,
1024 target_strand: Strand::Forward,
1025 chromosome_index: 0,
1026 phased: 0,
1027 created_on: 0,
1028 }],
1029 );
1030 graph.add_edge(
1031 GraphNode {
1032 node_id: HashId::convert_str("3"),
1033 sequence_start: 0,
1034 sequence_end: 5,
1035 },
1036 GraphNode {
1037 node_id: HashId::convert_str("3"),
1038 sequence_start: 5,
1039 sequence_end: 15,
1040 },
1041 vec![GraphEdge {
1042 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1043 .try_into()
1044 .unwrap(),
1045 source_strand: Strand::Forward,
1046 target_strand: Strand::Forward,
1047 chromosome_index: 0,
1048 phased: 0,
1049 created_on: 0,
1050 }],
1051 );
1052 graph.add_edge(
1053 GraphNode {
1054 node_id: HashId::convert_str("3"),
1055 sequence_start: 5,
1056 sequence_end: 15,
1057 },
1058 GraphNode {
1059 node_id: PATH_END_NODE_ID,
1060 sequence_start: 0,
1061 sequence_end: 0,
1062 },
1063 vec![GraphEdge {
1064 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1065 .try_into()
1066 .unwrap(),
1067 source_strand: Strand::Forward,
1068 target_strand: Strand::Forward,
1069 chromosome_index: 0,
1070 phased: 0,
1071 created_on: 0,
1072 }],
1073 );
1074 let path_blocks = vec![
1075 PathBlock {
1076 node_id: PATH_START_NODE_ID,
1077 block_sequence: "".to_string(),
1078 sequence_start: 0,
1079 sequence_end: 0,
1080 path_start: 0,
1081 path_end: 0,
1082 strand: Strand::Forward,
1083 },
1084 PathBlock {
1085 node_id: HashId::convert_str("3"),
1086 block_sequence: "".to_string(),
1087 sequence_start: 0,
1088 sequence_end: 15,
1089 path_start: 0,
1090 path_end: 0,
1091 strand: Strand::Forward,
1092 },
1093 PathBlock {
1094 node_id: PATH_END_NODE_ID,
1095 block_sequence: "".to_string(),
1096 sequence_start: 0,
1097 sequence_end: 0,
1098 path_start: 0,
1099 path_end: 0,
1100 strand: Strand::Forward,
1101 },
1102 ];
1103 let projection = project_path(&graph, &path_blocks);
1104 assert_eq!(
1105 projection,
1106 [
1107 (
1108 GraphNode {
1109 node_id: PATH_START_NODE_ID,
1110 sequence_start: 0,
1111 sequence_end: 0
1112 },
1113 Strand::Forward
1114 ),
1115 (
1116 GraphNode {
1117 node_id: HashId::convert_str("3"),
1118 sequence_start: 0,
1119 sequence_end: 5
1120 },
1121 Strand::Forward
1122 ),
1123 (
1124 GraphNode {
1125 node_id: HashId::convert_str("3"),
1126 sequence_start: 5,
1127 sequence_end: 15
1128 },
1129 Strand::Forward
1130 ),
1131 (
1132 GraphNode {
1133 node_id: PATH_END_NODE_ID,
1134 sequence_start: 0,
1135 sequence_end: 0
1136 },
1137 Strand::Forward
1138 )
1139 ]
1140 )
1141 }
1142
1143 #[test]
1144 fn test_nested_path_projection() {
1145 let mut graph = GenGraph::new();
1151 graph.add_edge(
1152 GraphNode {
1153 node_id: PATH_START_NODE_ID,
1154 sequence_start: 0,
1155 sequence_end: 0,
1156 },
1157 GraphNode {
1158 node_id: HashId::convert_str("3"),
1159 sequence_start: 0,
1160 sequence_end: 5,
1161 },
1162 vec![GraphEdge {
1163 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1164 .try_into()
1165 .unwrap(),
1166 source_strand: Strand::Forward,
1167 target_strand: Strand::Forward,
1168 chromosome_index: 0,
1169 phased: 0,
1170 created_on: 0,
1171 }],
1172 );
1173 graph.add_edge(
1174 GraphNode {
1175 node_id: HashId::convert_str("3"),
1176 sequence_start: 0,
1177 sequence_end: 5,
1178 },
1179 GraphNode {
1180 node_id: HashId::convert_str("4"),
1181 sequence_start: 3,
1182 sequence_end: 5,
1183 },
1184 vec![GraphEdge {
1185 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1186 .try_into()
1187 .unwrap(),
1188 source_strand: Strand::Forward,
1189 target_strand: Strand::Forward,
1190 chromosome_index: 0,
1191 phased: 0,
1192 created_on: 0,
1193 }],
1194 );
1195 graph.add_edge(
1196 GraphNode {
1197 node_id: HashId::convert_str("4"),
1198 sequence_start: 3,
1199 sequence_end: 5,
1200 },
1201 GraphNode {
1202 node_id: HashId::convert_str("5"),
1203 sequence_start: 0,
1204 sequence_end: 3,
1205 },
1206 vec![GraphEdge {
1207 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1208 .try_into()
1209 .unwrap(),
1210 source_strand: Strand::Forward,
1211 target_strand: Strand::Forward,
1212 chromosome_index: 0,
1213 phased: 0,
1214 created_on: 0,
1215 }],
1216 );
1217 graph.add_edge(
1218 GraphNode {
1219 node_id: HashId::convert_str("5"),
1220 sequence_start: 0,
1221 sequence_end: 3,
1222 },
1223 GraphNode {
1224 node_id: HashId::convert_str("3"),
1225 sequence_start: 5,
1226 sequence_end: 10,
1227 },
1228 vec![GraphEdge {
1229 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1230 .try_into()
1231 .unwrap(),
1232 source_strand: Strand::Forward,
1233 target_strand: Strand::Forward,
1234 chromosome_index: 0,
1235 phased: 0,
1236 created_on: 0,
1237 }],
1238 );
1239 graph.add_edge(
1240 GraphNode {
1241 node_id: HashId::convert_str("3"),
1242 sequence_start: 0,
1243 sequence_end: 5,
1244 },
1245 GraphNode {
1246 node_id: HashId::convert_str("3"),
1247 sequence_start: 5,
1248 sequence_end: 10,
1249 },
1250 vec![GraphEdge {
1251 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1252 .try_into()
1253 .unwrap(),
1254 source_strand: Strand::Forward,
1255 target_strand: Strand::Forward,
1256 chromosome_index: 0,
1257 phased: 0,
1258 created_on: 0,
1259 }],
1260 );
1261
1262 graph.add_edge(
1263 GraphNode {
1264 node_id: HashId::convert_str("3"),
1265 sequence_start: 5,
1266 sequence_end: 10,
1267 },
1268 GraphNode {
1269 node_id: HashId::convert_str("3"),
1270 sequence_start: 10,
1271 sequence_end: 15,
1272 },
1273 vec![GraphEdge {
1274 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1275 .try_into()
1276 .unwrap(),
1277 source_strand: Strand::Forward,
1278 target_strand: Strand::Forward,
1279 chromosome_index: 0,
1280 phased: 0,
1281 created_on: 0,
1282 }],
1283 );
1284
1285 graph.add_edge(
1286 GraphNode {
1287 node_id: HashId::convert_str("3"),
1288 sequence_start: 5,
1289 sequence_end: 10,
1290 },
1291 GraphNode {
1292 node_id: HashId::convert_str("6"),
1293 sequence_start: 0,
1294 sequence_end: 3,
1295 },
1296 vec![GraphEdge {
1297 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1298 .try_into()
1299 .unwrap(),
1300 source_strand: Strand::Forward,
1301 target_strand: Strand::Forward,
1302 chromosome_index: 0,
1303 phased: 0,
1304 created_on: 0,
1305 }],
1306 );
1307
1308 graph.add_edge(
1309 GraphNode {
1310 node_id: HashId::convert_str("6"),
1311 sequence_start: 0,
1312 sequence_end: 3,
1313 },
1314 GraphNode {
1315 node_id: HashId::convert_str("6"),
1316 sequence_start: 3,
1317 sequence_end: 7,
1318 },
1319 vec![GraphEdge {
1320 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1321 .try_into()
1322 .unwrap(),
1323 source_strand: Strand::Forward,
1324 target_strand: Strand::Forward,
1325 chromosome_index: 0,
1326 phased: 0,
1327 created_on: 0,
1328 }],
1329 );
1330
1331 graph.add_edge(
1332 GraphNode {
1333 node_id: HashId::convert_str("6"),
1334 sequence_start: 0,
1335 sequence_end: 3,
1336 },
1337 GraphNode {
1338 node_id: HashId::convert_str("7"),
1339 sequence_start: 0,
1340 sequence_end: 2,
1341 },
1342 vec![GraphEdge {
1343 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1344 .try_into()
1345 .unwrap(),
1346 source_strand: Strand::Forward,
1347 target_strand: Strand::Forward,
1348 chromosome_index: 0,
1349 phased: 0,
1350 created_on: 0,
1351 }],
1352 );
1353 graph.add_edge(
1354 GraphNode {
1355 node_id: HashId::convert_str("7"),
1356 sequence_start: 0,
1357 sequence_end: 2,
1358 },
1359 GraphNode {
1360 node_id: HashId::convert_str("6"),
1361 sequence_start: 3,
1362 sequence_end: 7,
1363 },
1364 vec![GraphEdge {
1365 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1366 .try_into()
1367 .unwrap(),
1368 source_strand: Strand::Forward,
1369 target_strand: Strand::Forward,
1370 chromosome_index: 0,
1371 phased: 0,
1372 created_on: 0,
1373 }],
1374 );
1375
1376 graph.add_edge(
1377 GraphNode {
1378 node_id: HashId::convert_str("6"),
1379 sequence_start: 3,
1380 sequence_end: 7,
1381 },
1382 GraphNode {
1383 node_id: HashId::convert_str("3"),
1384 sequence_start: 10,
1385 sequence_end: 15,
1386 },
1387 vec![GraphEdge {
1388 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1389 .try_into()
1390 .unwrap(),
1391 source_strand: Strand::Forward,
1392 target_strand: Strand::Forward,
1393 chromosome_index: 0,
1394 phased: 0,
1395 created_on: 0,
1396 }],
1397 );
1398
1399 graph.add_edge(
1400 GraphNode {
1401 node_id: HashId::convert_str("3"),
1402 sequence_start: 10,
1403 sequence_end: 15,
1404 },
1405 GraphNode {
1406 node_id: PATH_END_NODE_ID,
1407 sequence_start: 0,
1408 sequence_end: 0,
1409 },
1410 vec![GraphEdge {
1411 edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
1412 .try_into()
1413 .unwrap(),
1414 source_strand: Strand::Forward,
1415 target_strand: Strand::Forward,
1416 chromosome_index: 0,
1417 phased: 0,
1418 created_on: 0,
1419 }],
1420 );
1421 let path_blocks = vec![
1422 PathBlock {
1423 node_id: PATH_START_NODE_ID,
1424 block_sequence: "".to_string(),
1425 sequence_start: 0,
1426 sequence_end: 0,
1427 path_start: 0,
1428 path_end: 0,
1429 strand: Strand::Forward,
1430 },
1431 PathBlock {
1432 node_id: HashId::convert_str("3"),
1433 block_sequence: "".to_string(),
1434 sequence_start: 0,
1435 sequence_end: 5,
1436 path_start: 0,
1437 path_end: 5,
1438 strand: Strand::Forward,
1439 },
1440 PathBlock {
1441 node_id: HashId::convert_str("3"),
1442 block_sequence: "".to_string(),
1443 sequence_start: 5,
1444 sequence_end: 10,
1445 path_start: 5,
1446 path_end: 10,
1447 strand: Strand::Forward,
1448 },
1449 PathBlock {
1450 node_id: HashId::convert_str("6"),
1451 block_sequence: "".to_string(),
1452 sequence_start: 0,
1453 sequence_end: 7,
1454 path_start: 10,
1455 path_end: 17,
1456 strand: Strand::Forward,
1457 },
1458 PathBlock {
1459 node_id: HashId::convert_str("3"),
1460 block_sequence: "".to_string(),
1461 sequence_start: 10,
1462 sequence_end: 15,
1463 path_start: 17,
1464 path_end: 23,
1465 strand: Strand::Forward,
1466 },
1467 PathBlock {
1468 node_id: PATH_END_NODE_ID,
1469 block_sequence: "".to_string(),
1470 sequence_start: 0,
1471 sequence_end: 0,
1472 path_start: 0,
1473 path_end: 0,
1474 strand: Strand::Forward,
1475 },
1476 ];
1477 let projection = project_path(&graph, &path_blocks);
1478 assert_eq!(
1479 projection,
1480 [
1481 (
1482 GraphNode {
1483 node_id: PATH_START_NODE_ID,
1484 sequence_start: 0,
1485 sequence_end: 0
1486 },
1487 Strand::Forward
1488 ),
1489 (
1490 GraphNode {
1491 node_id: HashId::convert_str("3"),
1492 sequence_start: 0,
1493 sequence_end: 5
1494 },
1495 Strand::Forward
1496 ),
1497 (
1498 GraphNode {
1499 node_id: HashId::convert_str("3"),
1500 sequence_start: 5,
1501 sequence_end: 10
1502 },
1503 Strand::Forward
1504 ),
1505 (
1506 GraphNode {
1507 node_id: HashId::convert_str("6"),
1508 sequence_start: 0,
1509 sequence_end: 3
1510 },
1511 Strand::Forward
1512 ),
1513 (
1514 GraphNode {
1515 node_id: HashId::convert_str("6"),
1516 sequence_start: 3,
1517 sequence_end: 7
1518 },
1519 Strand::Forward
1520 ),
1521 (
1522 GraphNode {
1523 node_id: HashId::convert_str("3"),
1524 sequence_start: 10,
1525 sequence_end: 15
1526 },
1527 Strand::Forward
1528 ),
1529 (
1530 GraphNode {
1531 node_id: PATH_END_NODE_ID,
1532 sequence_start: 0,
1533 sequence_end: 0
1534 },
1535 Strand::Forward
1536 )
1537 ]
1538 )
1539 }
1540 }
1541}