use std::{
collections::{HashMap, HashSet, VecDeque},
fmt::{self, Debug},
hash::Hash,
iter::from_fn,
rc::Rc,
};
use gen_core::{
HashId, NodeIntervalBlock, PATH_END_NODE_ID, PATH_START_NODE_ID, PathBlock, Strand,
is_end_node, is_start_node,
};
use interavl::IntervalTree as IT2;
use intervaltree::IntervalTree;
use petgraph::{
Direction,
graphmap::DiGraphMap,
prelude::EdgeRef,
visit::{
Dfs, GraphRef, IntoEdgeReferences, IntoEdges, IntoNeighbors, IntoNeighborsDirected,
NodeCount, Reversed,
},
};
use serde::{Deserialize, Serialize};
pub mod traits;
pub use traits::MergeGraph;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
pub struct GraphNode {
pub node_id: HashId,
pub sequence_start: i64,
pub sequence_end: i64,
}
impl fmt::Display for GraphNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}[{}-{}]",
self.node_id, self.sequence_start, self.sequence_end
)
}
}
impl GraphNode {
pub fn length(&self) -> i64 {
self.sequence_end - self.sequence_start
}
}
pub type GenGraph = DiGraphMap<GraphNode, Vec<GraphEdge>>;
pub type OperationGraph = DiGraphMap<HashId, ()>;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
pub struct GraphEdge {
pub edge_id: HashId,
pub source_strand: Strand,
pub target_strand: Strand,
pub chromosome_index: i64,
pub phased: i64,
pub created_on: i64,
}
pub fn all_simple_paths<G>(
graph: G,
from: G::NodeId,
to: G::NodeId,
) -> impl Iterator<Item = Vec<G::NodeId>>
where
G: NodeCount,
G: IntoNeighborsDirected,
G::NodeId: Eq + Hash,
{
let mut visited = vec![from];
let mut stack = vec![graph.neighbors_directed(from, Direction::Outgoing)];
from_fn(move || {
while let Some(children) = stack.last_mut() {
if let Some(child) = children.next() {
if child == to {
let path = visited.iter().cloned().chain(Some(to)).collect::<_>();
return Some(path);
} else if !visited.contains(&child) {
visited.push(child);
stack.push(graph.neighbors_directed(child, Direction::Outgoing));
}
} else {
stack.pop();
visited.pop();
}
}
None
})
}
pub fn all_intermediate_edges<G>(
graph: G,
from: G::NodeId,
to: G::NodeId,
) -> Vec<<G as IntoEdgeReferences>::EdgeRef>
where
G: GraphRef + IntoEdges + petgraph::visit::IntoNeighborsDirected + petgraph::visit::Visitable,
G::NodeId: Eq + Hash + std::fmt::Display,
{
let mut outgoing_nodes = HashSet::new();
outgoing_nodes.insert(from);
let mut dfs_outbound = Dfs::new(graph, from);
while let Some(outgoing_node) = dfs_outbound.next(graph) {
outgoing_nodes.insert(outgoing_node);
}
let reversed_graph = Reversed(&graph);
let mut incoming_nodes = HashSet::new();
incoming_nodes.insert(to);
let mut dfs_inbound = Dfs::new(reversed_graph, to);
while let Some(incoming_node) = dfs_inbound.next(reversed_graph) {
incoming_nodes.insert(incoming_node);
}
let common_nodes: HashSet<&<G as petgraph::visit::GraphBase>::NodeId> =
outgoing_nodes.intersection(&incoming_nodes).collect();
let mut common_edgerefs = vec![];
for edge in graph.edge_references() {
let (source, target) = (edge.source(), edge.target());
if common_nodes.contains(&source) && common_nodes.contains(&target) {
common_edgerefs.push(edge);
}
}
common_edgerefs
}
pub fn all_simple_paths_by_edge<G>(
graph: G,
from: G::NodeId,
to: G::NodeId,
) -> impl Iterator<Item = Vec<G::EdgeRef>>
where
G: NodeCount + IntoEdges,
G: IntoNeighborsDirected,
G::NodeId: Eq + Hash,
{
let mut visited = vec![from];
let mut path: Vec<G::EdgeRef> = vec![];
let mut stack = vec![graph.edges(from)];
from_fn(move || {
while let Some(edges) = stack.last_mut() {
if let Some(edge) = edges.next() {
let target = edge.target();
if target == to {
let a_path = path.iter().cloned().chain(Some(edge)).collect::<_>();
return Some(a_path);
} else if !visited.contains(&target) {
path.push(edge);
visited.push(target);
stack.push(graph.edges(target));
}
} else {
stack.pop();
path.pop();
visited.pop();
}
}
None
})
}
pub fn all_reachable_nodes<G>(graph: G, nodes: &[G::NodeId]) -> HashSet<G::NodeId>
where
G: GraphRef + IntoNeighbors,
G::NodeId: Eq + Hash + Debug,
{
let mut stack = VecDeque::new();
let mut reachable = HashSet::new();
for node in nodes.iter() {
stack.push_front(*node);
reachable.insert(*node);
while let Some(nx) = stack.pop_front() {
for succ in graph.neighbors(nx) {
if !reachable.contains(&succ) {
reachable.insert(succ);
stack.push_back(succ);
}
}
}
}
reachable
}
pub fn flatten_to_interval_tree(
graph: &GenGraph,
remove_ambiguous_positions: bool,
) -> IntervalTree<i64, NodeIntervalBlock> {
#[derive(Clone, Debug, Ord, PartialOrd, Eq, Hash, PartialEq)]
struct NodeP {
x: i64,
y: i64,
}
let mut excluded_nodes = HashSet::new();
let mut node_tree: HashMap<HashId, IT2<NodeP, HashId>> = HashMap::new();
let mut start_nodes = vec![];
let mut end_nodes = vec![];
for node in graph.nodes() {
if is_start_node(node.node_id) {
start_nodes.push(node);
}
if is_end_node(node.node_id) {
end_nodes.push(node);
}
}
let mut spans: HashSet<NodeIntervalBlock> = HashSet::new();
for start in start_nodes.iter() {
for end_node in end_nodes.iter() {
for path in all_simple_paths_by_edge(&graph, *start, *end_node) {
let mut offset = 0;
for (source_node, target_node, edges) in path.iter() {
let block_len = source_node.length();
let node_start = offset;
let node_end = offset + block_len;
let edge = &edges[0];
spans.insert(NodeIntervalBlock {
node_id: source_node.node_id,
start: node_start,
end: node_end,
sequence_start: source_node.sequence_start,
sequence_end: source_node.sequence_end,
strand: edge.source_strand,
});
spans.insert(NodeIntervalBlock {
node_id: target_node.node_id,
start: node_end,
end: node_end + target_node.length(),
sequence_start: target_node.sequence_start,
sequence_end: target_node.sequence_end,
strand: edge.target_strand,
});
if remove_ambiguous_positions {
for (node_id, node_range) in [
(
source_node.node_id,
NodeP {
x: node_start,
y: source_node.sequence_start,
}..NodeP {
x: node_end,
y: source_node.sequence_end,
},
),
(
target_node.node_id,
NodeP {
x: node_end,
y: target_node.sequence_start,
}..NodeP {
x: node_end + target_node.length(),
y: target_node.sequence_end,
},
),
] {
node_tree
.entry(node_id)
.and_modify(|tree| {
for (stored_range, _stored_node_id) in
tree.iter_overlaps(&node_range)
{
if *stored_range != node_range {
excluded_nodes.insert(node_id);
break;
}
}
tree.insert(node_range.clone(), node_id);
})
.or_insert_with(|| {
let mut t = IT2::default();
t.insert(node_range.clone(), node_id);
t
});
}
}
offset += block_len;
}
}
}
}
let tree: IntervalTree<i64, NodeIntervalBlock> = spans
.iter()
.filter(|block| !remove_ambiguous_positions || !excluded_nodes.contains(&block.node_id))
.map(|block| {
if block.node_id == PATH_START_NODE_ID {
(i64::MIN + 1..0, *block)
} else if block.node_id == PATH_END_NODE_ID {
(block.end..i64::MAX, *block)
} else {
(block.start..block.end, *block)
}
})
.collect();
tree
}
pub fn project_path(graph: &GenGraph, path_blocks: &[PathBlock]) -> Vec<(GraphNode, Strand)> {
#[derive(Debug)]
struct PathNode {
node: (GraphNode, Strand),
path_index: usize,
prev: Option<Rc<PathNode>>,
}
let start_nodes = graph
.nodes()
.filter(|node| node.node_id == PATH_START_NODE_ID)
.collect::<Vec<GraphNode>>();
let start_node = start_nodes.first().unwrap();
let mut final_path = vec![];
let mut stack: VecDeque<Rc<PathNode>> = VecDeque::new();
let mut visited: HashSet<(GraphNode, Strand)> = HashSet::new();
let mut path_index = 0;
let mut current_pos;
stack.push_back(Rc::new(PathNode {
node: (*start_node, Strand::Forward),
path_index,
prev: None,
}));
while let Some(current_node) = stack.pop_back() {
let current = current_node.node;
let mut current_block = &path_blocks[current_node.path_index];
if !visited.insert(current) {
continue;
}
if current.0.sequence_end == current_block.sequence_end {
path_index += 1;
if path_index < path_blocks.len() {
current_block = &path_blocks[path_index];
current_pos = current_block.sequence_start;
} else {
let mut path = vec![];
let mut path_ref = Some(Rc::clone(¤t_node));
while let Some(pn) = path_ref {
path.push(pn.node);
path_ref = pn.prev.clone();
}
final_path = path.into_iter().rev().collect();
break;
}
} else {
current_pos = current.0.sequence_end;
}
for (_src, neighbor, edges) in graph.edges(current.0) {
if neighbor.node_id == current_block.node_id
&& neighbor.sequence_start == current_pos
&& edges
.iter()
.any(|edge| current_block.strand == edge.target_strand)
{
stack.push_back(Rc::new(PathNode {
node: (neighbor, current_block.strand),
path_index,
prev: Some(Rc::clone(¤t_node)),
}));
}
}
}
final_path
}
pub fn find_articulation_points(graph: &GenGraph) -> Vec<GraphNode> {
let mut articulation_points: Vec<GraphNode> = Vec::new();
let mut discovery_time: HashMap<GraphNode, usize> = HashMap::new();
let mut low: HashMap<GraphNode, usize> = HashMap::new();
let mut parent: HashMap<GraphNode, Option<GraphNode>> = HashMap::new();
let mut time = 0;
for node in graph.nodes() {
if !discovery_time.contains_key(&node) {
let mut stack = vec![(node, None, true)];
while let Some((u, p, is_first_time)) = stack.pop() {
if is_first_time {
discovery_time.insert(u, time);
low.insert(u, time);
time += 1;
parent.insert(u, p);
stack.push((u, p, false));
let neighbors: Vec<_> = graph
.neighbors_directed(u, Direction::Outgoing)
.chain(graph.neighbors_directed(u, Direction::Incoming))
.collect();
for v in neighbors {
if !discovery_time.contains_key(&v) {
stack.push((v, Some(u), true));
} else if Some(v) != p {
let current_low = low.get(&u).cloned().unwrap_or(usize::MAX);
let v_disc = discovery_time.get(&v).cloned().unwrap_or(usize::MAX);
low.insert(u, current_low.min(v_disc));
}
}
} else {
let mut is_articulation = false;
let mut child_count = 0;
let neighbors: Vec<_> = graph
.neighbors_directed(u, Direction::Outgoing)
.chain(graph.neighbors_directed(u, Direction::Incoming))
.collect();
for v in neighbors {
if parent.get(&v).cloned() == Some(Some(u)) {
child_count += 1;
let v_low = low.get(&v).cloned().unwrap_or(usize::MAX);
let u_disc = discovery_time.get(&u).cloned().unwrap_or(usize::MAX);
if v_low >= u_disc {
is_articulation = true;
}
let current_low = low.get(&u).cloned().unwrap_or(usize::MAX);
let v_low = low.get(&v).cloned().unwrap_or(usize::MAX);
low.insert(u, current_low.min(v_low));
} else if Some(v) != parent.get(&u).cloned().unwrap_or(None) {
let v_disc = discovery_time.get(&v).cloned().unwrap_or(usize::MAX);
let current_low = low.get(&u).cloned().unwrap_or(usize::MAX);
low.insert(u, current_low.min(v_disc));
}
}
let u_parent = parent.get(&u).cloned().unwrap_or(None);
if (u_parent.is_some() && is_articulation)
|| (u_parent.is_none() && child_count > 1)
{
articulation_points.push(u);
}
}
}
}
}
articulation_points.sort();
articulation_points.dedup();
articulation_points
}
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use petgraph::graphmap::DiGraphMap;
use super::*;
#[test]
fn test_path_graph() {
let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
graph.add_node(1);
graph.add_node(2);
graph.add_node(3);
graph.add_edge(1, 2, ());
graph.add_edge(2, 3, ());
let paths = all_simple_paths(&graph, 1, 3).collect::<Vec<Vec<i64>>>();
assert_eq!(paths.len(), 1);
let path = paths.first().unwrap().clone();
assert_eq!(path, vec![1, 2, 3]);
}
#[test]
fn test_get_simple_paths_by_edge() {
let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
graph.add_node(1);
graph.add_node(2);
graph.add_node(3);
graph.add_node(4);
graph.add_node(5);
graph.add_node(6);
graph.add_node(7);
graph.add_node(8);
graph.add_node(9);
graph.add_edge(1, 2, ());
graph.add_edge(2, 3, ());
graph.add_edge(3, 4, ());
graph.add_edge(4, 5, ());
graph.add_edge(2, 6, ());
graph.add_edge(6, 7, ());
graph.add_edge(7, 4, ());
graph.add_edge(6, 8, ());
graph.add_edge(8, 7, ());
let edge_path =
all_simple_paths_by_edge(&graph, 1, 5).collect::<Vec<Vec<(i64, i64, &())>>>();
assert_eq!(
edge_path,
vec![
vec![(1, 2, &()), (2, 3, &()), (3, 4, &()), (4, 5, &())],
vec![
(1, 2, &()),
(2, 6, &()),
(6, 7, &()),
(7, 4, &()),
(4, 5, &())
],
vec![
(1, 2, &()),
(2, 6, &()),
(6, 8, &()),
(8, 7, &()),
(7, 4, &()),
(4, 5, &())
]
]
);
}
#[test]
fn test_two_path_graph() {
let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
graph.add_node(1);
graph.add_node(2);
graph.add_node(3);
graph.add_node(4);
graph.add_edge(1, 2, ());
graph.add_edge(1, 3, ());
graph.add_edge(2, 4, ());
graph.add_edge(3, 4, ());
let paths = all_simple_paths(&graph, 1, 4).collect::<Vec<Vec<i64>>>();
assert_eq!(paths.len(), 2);
assert_eq!(
HashSet::<Vec<i64>>::from_iter::<Vec<Vec<i64>>>(paths),
HashSet::from_iter(vec![vec![1, 2, 4], vec![1, 3, 4]])
);
}
#[test]
fn test_two_by_two_combinatorial_graph() {
let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
graph.add_node(1);
graph.add_node(2);
graph.add_node(3);
graph.add_node(4);
graph.add_node(5);
graph.add_node(6);
graph.add_node(7);
graph.add_edge(1, 2, ());
graph.add_edge(1, 3, ());
graph.add_edge(2, 4, ());
graph.add_edge(3, 4, ());
graph.add_edge(4, 5, ());
graph.add_edge(4, 6, ());
graph.add_edge(5, 7, ());
graph.add_edge(6, 7, ());
let paths = all_simple_paths(&graph, 1, 7).collect::<Vec<Vec<i64>>>();
assert_eq!(paths.len(), 4);
assert_eq!(
HashSet::<Vec<i64>>::from_iter::<Vec<Vec<i64>>>(paths),
HashSet::from_iter(vec![
vec![1, 2, 4, 5, 7],
vec![1, 3, 4, 5, 7],
vec![1, 2, 4, 6, 7],
vec![1, 3, 4, 6, 7]
])
);
}
#[test]
fn test_three_by_three_combinatorial_graph() {
let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
graph.add_node(1);
graph.add_node(2);
graph.add_node(3);
graph.add_node(4);
graph.add_node(5);
graph.add_node(6);
graph.add_node(7);
graph.add_node(8);
graph.add_node(9);
graph.add_edge(1, 2, ());
graph.add_edge(1, 3, ());
graph.add_edge(1, 4, ());
graph.add_edge(2, 5, ());
graph.add_edge(3, 5, ());
graph.add_edge(4, 5, ());
graph.add_edge(5, 6, ());
graph.add_edge(5, 7, ());
graph.add_edge(5, 8, ());
graph.add_edge(6, 9, ());
graph.add_edge(7, 9, ());
graph.add_edge(8, 9, ());
let paths = all_simple_paths(&graph, 1, 9).collect::<Vec<Vec<i64>>>();
assert_eq!(paths.len(), 9);
let expected_paths = vec![
vec![1, 2, 5, 6, 9],
vec![1, 3, 5, 6, 9],
vec![1, 4, 5, 6, 9],
vec![1, 2, 5, 7, 9],
vec![1, 3, 5, 7, 9],
vec![1, 4, 5, 7, 9],
vec![1, 2, 5, 8, 9],
vec![1, 3, 5, 8, 9],
vec![1, 4, 5, 8, 9],
];
assert_eq!(
HashSet::<Vec<i64>>::from_iter::<Vec<Vec<i64>>>(paths),
HashSet::from_iter(expected_paths)
);
}
#[test]
fn test_super_bubble_path() {
let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
graph.add_node(1);
graph.add_node(2);
graph.add_node(3);
graph.add_node(4);
graph.add_node(5);
graph.add_node(6);
graph.add_node(7);
graph.add_node(8);
graph.add_node(9);
graph.add_edge(1, 2, ());
graph.add_edge(2, 3, ());
graph.add_edge(3, 4, ());
graph.add_edge(4, 5, ());
graph.add_edge(2, 6, ());
graph.add_edge(6, 7, ());
graph.add_edge(7, 4, ());
graph.add_edge(6, 8, ());
graph.add_edge(8, 7, ());
let paths = all_simple_paths(&graph, 1, 5).collect::<Vec<Vec<i64>>>();
assert_eq!(
HashSet::<Vec<i64>>::from_iter::<Vec<Vec<i64>>>(paths),
HashSet::from_iter(vec![
vec![1, 2, 3, 4, 5],
vec![1, 2, 6, 7, 4, 5],
vec![1, 2, 6, 8, 7, 4, 5]
])
);
}
#[test]
fn test_finds_all_reachable_nodes() {
let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
graph.add_node(1);
graph.add_node(2);
graph.add_node(3);
graph.add_node(4);
graph.add_node(5);
graph.add_node(6);
graph.add_node(7);
graph.add_edge(1, 2, ());
graph.add_edge(2, 3, ());
graph.add_edge(3, 4, ());
graph.add_edge(4, 5, ());
graph.add_edge(6, 7, ());
graph.add_edge(7, 3, ());
assert_eq!(
all_reachable_nodes(&graph, &[1]),
HashSet::from_iter(vec![1, 2, 3, 4, 5])
);
assert_eq!(
all_reachable_nodes(&graph, &[1, 6]),
HashSet::from_iter(vec![1, 2, 3, 4, 5, 6, 7])
);
assert_eq!(
all_reachable_nodes(&graph, &[3]),
HashSet::from_iter(vec![3, 4, 5])
);
assert_eq!(
all_reachable_nodes(&graph, &[5]),
HashSet::from_iter(vec![5])
);
}
mod test_all_intermediate_edges {
use super::*;
#[test]
fn test_one_part_group() {
let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
graph.add_node(1);
graph.add_node(2);
graph.add_node(3);
graph.add_node(4);
graph.add_node(5);
graph.add_node(6);
graph.add_edge(1, 2, ());
graph.add_edge(2, 3, ());
graph.add_edge(3, 4, ());
graph.add_edge(4, 5, ());
graph.add_edge(2, 6, ());
graph.add_edge(6, 4, ());
let result_edges = all_intermediate_edges(&graph, 2, 4);
let intermediate_edges = result_edges
.iter()
.map(|(source, target, _weight)| (*source, *target))
.collect::<Vec<(i64, i64)>>();
assert_eq!(intermediate_edges, vec![(2, 3), (3, 4), (2, 6), (6, 4)]);
}
#[test]
fn test_two_part_groups() {
let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
graph.add_node(1);
graph.add_node(2);
graph.add_node(3);
graph.add_node(4);
graph.add_node(5);
graph.add_node(6);
graph.add_node(7);
graph.add_node(8);
graph.add_node(9);
graph.add_edge(1, 2, ());
graph.add_edge(2, 3, ());
graph.add_edge(3, 4, ());
graph.add_edge(4, 5, ());
graph.add_edge(5, 6, ());
graph.add_edge(6, 7, ());
graph.add_edge(2, 8, ());
graph.add_edge(8, 4, ());
graph.add_edge(4, 9, ());
graph.add_edge(9, 6, ());
let result_edges = all_intermediate_edges(&graph, 2, 6);
let intermediate_edges = result_edges
.iter()
.map(|(source, target, _weight)| (*source, *target))
.collect::<Vec<(i64, i64)>>();
assert_eq!(
intermediate_edges,
vec![
(2, 3),
(3, 4),
(4, 5),
(5, 6),
(2, 8),
(8, 4),
(4, 9),
(9, 6)
]
);
}
#[test]
fn test_one_part_group_with_unrelated_edges() {
let mut graph: DiGraphMap<i64, ()> = DiGraphMap::new();
graph.add_node(1);
graph.add_node(2);
graph.add_node(3);
graph.add_node(4);
graph.add_node(5);
graph.add_node(6);
graph.add_node(7);
graph.add_edge(1, 2, ());
graph.add_edge(2, 3, ());
graph.add_edge(3, 4, ());
graph.add_edge(4, 5, ());
graph.add_edge(2, 6, ());
graph.add_edge(6, 4, ());
graph.add_edge(2, 7, ());
graph.add_edge(7, 5, ());
let result_edges = all_intermediate_edges(&graph, 2, 4);
let intermediate_edges = result_edges
.iter()
.map(|(source, target, _weight)| (*source, *target))
.collect::<Vec<(i64, i64)>>();
assert_eq!(intermediate_edges, vec![(2, 3), (3, 4), (2, 6), (6, 4)]);
}
}
#[cfg(test)]
mod project_path {
use gen_core::PATH_END_NODE_ID;
use super::*;
#[test]
fn test_simple_path_projection() {
let mut graph = GenGraph::new();
graph.add_edge(
GraphNode {
node_id: PATH_START_NODE_ID,
sequence_start: 0,
sequence_end: 0,
},
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 0,
sequence_end: 5,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 0,
sequence_end: 5,
},
GraphNode {
node_id: HashId::convert_str("4"),
sequence_start: 3,
sequence_end: 5,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("4"),
sequence_start: 3,
sequence_end: 5,
},
GraphNode {
node_id: HashId::convert_str("5"),
sequence_start: 0,
sequence_end: 3,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("5"),
sequence_start: 0,
sequence_end: 3,
},
GraphNode {
node_id: HashId::convert_str("6"),
sequence_start: 5,
sequence_end: 15,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 0,
sequence_end: 5,
},
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 5,
sequence_end: 15,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 5,
sequence_end: 15,
},
GraphNode {
node_id: PATH_END_NODE_ID,
sequence_start: 0,
sequence_end: 0,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
let path_blocks = vec![
PathBlock {
node_id: PATH_START_NODE_ID,
block_sequence: "".to_string(),
sequence_start: 0,
sequence_end: 0,
path_start: 0,
path_end: 0,
strand: Strand::Forward,
},
PathBlock {
node_id: HashId::convert_str("3"),
block_sequence: "".to_string(),
sequence_start: 0,
sequence_end: 15,
path_start: 0,
path_end: 0,
strand: Strand::Forward,
},
PathBlock {
node_id: PATH_END_NODE_ID,
block_sequence: "".to_string(),
sequence_start: 0,
sequence_end: 0,
path_start: 0,
path_end: 0,
strand: Strand::Forward,
},
];
let projection = project_path(&graph, &path_blocks);
assert_eq!(
projection,
[
(
GraphNode {
node_id: PATH_START_NODE_ID,
sequence_start: 0,
sequence_end: 0
},
Strand::Forward
),
(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 0,
sequence_end: 5
},
Strand::Forward
),
(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 5,
sequence_end: 15
},
Strand::Forward
),
(
GraphNode {
node_id: PATH_END_NODE_ID,
sequence_start: 0,
sequence_end: 0
},
Strand::Forward
)
]
)
}
#[test]
fn test_nested_path_projection() {
let mut graph = GenGraph::new();
graph.add_edge(
GraphNode {
node_id: PATH_START_NODE_ID,
sequence_start: 0,
sequence_end: 0,
},
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 0,
sequence_end: 5,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 0,
sequence_end: 5,
},
GraphNode {
node_id: HashId::convert_str("4"),
sequence_start: 3,
sequence_end: 5,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("4"),
sequence_start: 3,
sequence_end: 5,
},
GraphNode {
node_id: HashId::convert_str("5"),
sequence_start: 0,
sequence_end: 3,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("5"),
sequence_start: 0,
sequence_end: 3,
},
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 5,
sequence_end: 10,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 0,
sequence_end: 5,
},
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 5,
sequence_end: 10,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 5,
sequence_end: 10,
},
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 10,
sequence_end: 15,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 5,
sequence_end: 10,
},
GraphNode {
node_id: HashId::convert_str("6"),
sequence_start: 0,
sequence_end: 3,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("6"),
sequence_start: 0,
sequence_end: 3,
},
GraphNode {
node_id: HashId::convert_str("6"),
sequence_start: 3,
sequence_end: 7,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("6"),
sequence_start: 0,
sequence_end: 3,
},
GraphNode {
node_id: HashId::convert_str("7"),
sequence_start: 0,
sequence_end: 2,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("7"),
sequence_start: 0,
sequence_end: 2,
},
GraphNode {
node_id: HashId::convert_str("6"),
sequence_start: 3,
sequence_end: 7,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("6"),
sequence_start: 3,
sequence_end: 7,
},
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 10,
sequence_end: 15,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
graph.add_edge(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 10,
sequence_end: 15,
},
GraphNode {
node_id: PATH_END_NODE_ID,
sequence_start: 0,
sequence_end: 0,
},
vec![GraphEdge {
edge_id: "0000000000000000000000000000000000000000000000000000000000000000"
.try_into()
.unwrap(),
source_strand: Strand::Forward,
target_strand: Strand::Forward,
chromosome_index: 0,
phased: 0,
created_on: 0,
}],
);
let path_blocks = vec![
PathBlock {
node_id: PATH_START_NODE_ID,
block_sequence: "".to_string(),
sequence_start: 0,
sequence_end: 0,
path_start: 0,
path_end: 0,
strand: Strand::Forward,
},
PathBlock {
node_id: HashId::convert_str("3"),
block_sequence: "".to_string(),
sequence_start: 0,
sequence_end: 5,
path_start: 0,
path_end: 5,
strand: Strand::Forward,
},
PathBlock {
node_id: HashId::convert_str("3"),
block_sequence: "".to_string(),
sequence_start: 5,
sequence_end: 10,
path_start: 5,
path_end: 10,
strand: Strand::Forward,
},
PathBlock {
node_id: HashId::convert_str("6"),
block_sequence: "".to_string(),
sequence_start: 0,
sequence_end: 7,
path_start: 10,
path_end: 17,
strand: Strand::Forward,
},
PathBlock {
node_id: HashId::convert_str("3"),
block_sequence: "".to_string(),
sequence_start: 10,
sequence_end: 15,
path_start: 17,
path_end: 23,
strand: Strand::Forward,
},
PathBlock {
node_id: PATH_END_NODE_ID,
block_sequence: "".to_string(),
sequence_start: 0,
sequence_end: 0,
path_start: 0,
path_end: 0,
strand: Strand::Forward,
},
];
let projection = project_path(&graph, &path_blocks);
assert_eq!(
projection,
[
(
GraphNode {
node_id: PATH_START_NODE_ID,
sequence_start: 0,
sequence_end: 0
},
Strand::Forward
),
(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 0,
sequence_end: 5
},
Strand::Forward
),
(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 5,
sequence_end: 10
},
Strand::Forward
),
(
GraphNode {
node_id: HashId::convert_str("6"),
sequence_start: 0,
sequence_end: 3
},
Strand::Forward
),
(
GraphNode {
node_id: HashId::convert_str("6"),
sequence_start: 3,
sequence_end: 7
},
Strand::Forward
),
(
GraphNode {
node_id: HashId::convert_str("3"),
sequence_start: 10,
sequence_end: 15
},
Strand::Forward
),
(
GraphNode {
node_id: PATH_END_NODE_ID,
sequence_start: 0,
sequence_end: 0
},
Strand::Forward
)
]
)
}
}
}