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