From ce6dcb0551086b09b47151d36ae839ab8e24394d Mon Sep 17 00:00:00 2001 From: Antonio De Lucreziis Date: Fri, 24 May 2024 01:38:04 +0200 Subject: [PATCH] generic graph code and visualization --- Cargo.lock | 4 +- Cargo.toml | 2 +- examples/configurable/Cargo.toml | 1 + examples/configurable/src/main.rs | 290 +++++++++++++++----------- examples/configurable/src/settings.rs | 24 +-- examples/egui-graph-viz/Cargo.toml | 1 + examples/egui-graph-viz/src/main.rs | 49 ++++- src/gfa.rs | 13 +- src/graph.rs | 122 ++++++----- src/lib.rs | 3 + src/main.rs | 49 +++-- src/parser.rs | 4 +- 12 files changed, 335 insertions(+), 227 deletions(-) create mode 100644 src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 851d670..19ed0f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,7 +224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" [[package]] -name = "asd-2024" +name = "asd" version = "0.1.0" dependencies = [ "argh", @@ -788,6 +788,7 @@ dependencies = [ name = "configurable" version = "0.1.0" dependencies = [ + "asd", "crossbeam", "eframe", "egui", @@ -1039,6 +1040,7 @@ dependencies = [ name = "egui-graph-viz" version = "0.1.0" dependencies = [ + "asd", "eframe", "egui", "egui_graphs", diff --git a/Cargo.toml b/Cargo.toml index 4294a4f..8862ef0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "asd-2024" +name = "asd" version = "0.1.0" edition = "2021" diff --git a/examples/configurable/Cargo.toml b/examples/configurable/Cargo.toml index dc17622..f95698c 100644 --- a/examples/configurable/Cargo.toml +++ b/examples/configurable/Cargo.toml @@ -13,3 +13,4 @@ serde_json = "1.0" fdg-sim = "0.9" rand = "0.8" crossbeam = "0.8" +asd = { path = "../../" } diff --git a/examples/configurable/src/main.rs b/examples/configurable/src/main.rs index 92c5292..1428373 100644 --- a/examples/configurable/src/main.rs +++ b/examples/configurable/src/main.rs @@ -1,5 +1,9 @@ +use std::collections::HashMap; +use std::env; use std::time::Instant; +use asd::gfa::{Entry, Orientation}; +use asd::parser; use crossbeam::channel::{unbounded, Receiver, Sender}; use eframe::{run_native, App, CreationContext}; use egui::{CollapsingHeader, Context, Pos2, ScrollArea, Slider, Ui}; @@ -10,7 +14,7 @@ use fdg_sim::{ForceGraph, ForceGraphHelper, Simulation, SimulationParameters}; use petgraph::stable_graph::{DefaultIx, EdgeIndex, NodeIndex, StableGraph}; use petgraph::Directed; use rand::Rng; -use settings::{SettingsGraph, SettingsInteraction, SettingsNavigation, SettingsStyle}; +use settings::{SettingsInteraction, SettingsNavigation, SettingsStyle}; mod settings; @@ -18,10 +22,10 @@ const SIMULATION_DT: f32 = 0.035; const EVENTS_LIMIT: usize = 100; pub struct ConfigurableApp { - g: Graph<(), (), Directed, DefaultIx>, + g: Graph<(String, Orientation), (), Directed, DefaultIx>, sim: Simulation<(), f32>, - settings_graph: SettingsGraph, + // settings_graph: SettingsGraph, settings_interaction: SettingsInteraction, settings_navigation: SettingsNavigation, settings_style: SettingsStyle, @@ -43,8 +47,8 @@ pub struct ConfigurableApp { impl ConfigurableApp { fn new(_: &CreationContext<'_>) -> Self { - let settings_graph = SettingsGraph::default(); - let (g, sim) = generate(&settings_graph); + // let settings_graph = SettingsGraph::default(); + let (g, sim) = generate(); let (event_publisher, event_consumer) = unbounded(); Self { g, @@ -53,8 +57,7 @@ impl ConfigurableApp { event_consumer, event_publisher, - settings_graph, - + // settings_graph, settings_interaction: SettingsInteraction::default(), settings_navigation: SettingsNavigation::default(), settings_style: SettingsStyle::default(), @@ -149,12 +152,12 @@ impl ConfigurableApp { } fn reset_graph(&mut self, ui: &mut Ui) { - let settings_graph = SettingsGraph::default(); - let (g, sim) = generate(&settings_graph); + // let settings_graph = SettingsGraph::default(); + let (g, sim) = generate(); self.g = g; self.sim = sim; - self.settings_graph = settings_graph; + // self.settings_graph = settings_graph; self.last_events = Vec::default(); GraphView::<(), (), Directed, DefaultIx>::reset_metadata(ui); @@ -198,92 +201,92 @@ impl ConfigurableApp { }); } - fn random_node_idx(&self) -> Option { - let nodes_cnt = self.g.node_count(); - if nodes_cnt == 0 { - return None; - } + // fn random_node_idx(&self) -> Option { + // let nodes_cnt = self.g.node_count(); + // if nodes_cnt == 0 { + // return None; + // } - let random_n_idx = rand::thread_rng().gen_range(0..nodes_cnt); - self.g.g.node_indices().nth(random_n_idx) - } + // let random_n_idx = rand::thread_rng().gen_range(0..nodes_cnt); + // self.g.g.node_indices().nth(random_n_idx) + // } - fn random_edge_idx(&self) -> Option { - let edges_cnt = self.g.edge_count(); - if edges_cnt == 0 { - return None; - } + // fn random_edge_idx(&self) -> Option { + // let edges_cnt = self.g.edge_count(); + // if edges_cnt == 0 { + // return None; + // } - let random_e_idx = rand::thread_rng().gen_range(0..edges_cnt); - self.g.g.edge_indices().nth(random_e_idx) - } + // let random_e_idx = rand::thread_rng().gen_range(0..edges_cnt); + // self.g.g.edge_indices().nth(random_e_idx) + // } - fn remove_random_node(&mut self) { - let idx = self.random_node_idx().unwrap(); - self.remove_node(idx); - } + // fn remove_random_node(&mut self) { + // let idx = self.random_node_idx().unwrap(); + // self.remove_node(idx); + // } - fn add_random_node(&mut self) { - let random_n_idx = self.random_node_idx(); - if random_n_idx.is_none() { - return; - } + // fn add_random_node(&mut self) { + // let random_n_idx = self.random_node_idx(); + // if random_n_idx.is_none() { + // return; + // } - let random_n = self.g.node(random_n_idx.unwrap()).unwrap(); + // let random_n = self.g.node(random_n_idx.unwrap()).unwrap(); - // location of new node is in surrounging of random existing node - let mut rng = rand::thread_rng(); - let location = Pos2::new( - random_n.location().x + 10. + rng.gen_range(0. ..50.), - random_n.location().y + 10. + rng.gen_range(0. ..50.), - ); + // // location of new node is in surrounging of random existing node + // let mut rng = rand::thread_rng(); + // let location = Pos2::new( + // random_n.location().x + 10. + rng.gen_range(0. ..50.), + // random_n.location().y + 10. + rng.gen_range(0. ..50.), + // ); - let idx = self.g.add_node_with_location((), location); + // let idx = self.g.add_node_with_location((), location); - let mut sim_node = fdg_sim::Node::new(idx.index().to_string().as_str(), ()); - sim_node.location = Vec3::new(location.x, location.y, 0.); - self.sim.get_graph_mut().add_node(sim_node); - } + // let mut sim_node = fdg_sim::Node::new(idx.index().to_string().as_str(), ()); + // sim_node.location = Vec3::new(location.x, location.y, 0.); + // self.sim.get_graph_mut().add_node(sim_node); + // } - fn remove_node(&mut self, idx: NodeIndex) { - self.g.remove_node(idx); + // fn remove_node(&mut self, idx: NodeIndex) { + // self.g.remove_node(idx); - self.sim.get_graph_mut().remove_node(idx).unwrap(); + // self.sim.get_graph_mut().remove_node(idx).unwrap(); - // update edges count - self.settings_graph.count_edge = self.g.edge_count(); - } + // // update edges count + // self.settings_graph.count_edge = self.g.edge_count(); + // } - fn add_random_edge(&mut self) { - let random_start = self.random_node_idx().unwrap(); - let random_end = self.random_node_idx().unwrap(); + // fn add_random_edge(&mut self) { + // let random_start = self.random_node_idx().unwrap(); + // let random_end = self.random_node_idx().unwrap(); - self.add_edge(random_start, random_end); - } + // self.add_edge(random_start, random_end); + // } - fn add_edge(&mut self, start: NodeIndex, end: NodeIndex) { - self.g.add_edge(start, end, ()); + // fn add_edge(&mut self, start: NodeIndex, end: NodeIndex) { + // self.g.add_edge(start, end, ()); - self.sim.get_graph_mut().add_edge(start, end, 1.); - } + // self.sim.get_graph_mut().add_edge(start, end, 1.); + // } - fn remove_random_edge(&mut self) { - let random_e_idx = self.random_edge_idx(); - if random_e_idx.is_none() { - return; - } - let endpoints = self.g.edge_endpoints(random_e_idx.unwrap()).unwrap(); + // fn remove_random_edge(&mut self) { + // let random_e_idx = self.random_edge_idx(); + // if random_e_idx.is_none() { + // return; + // } + // let endpoints = self.g.edge_endpoints(random_e_idx.unwrap()).unwrap(); - self.remove_edge(endpoints.0, endpoints.1); - } + // self.remove_edge(endpoints.0, endpoints.1); + // } - fn remove_edge(&mut self, start: NodeIndex, end: NodeIndex) { - let (g_idx, _) = self.g.edges_connecting(start, end).next().unwrap(); - self.g.remove_edge(g_idx); + // fn remove_edge(&mut self, start: NodeIndex, end: NodeIndex) { + // let (g_idx, _) = self.g.edges_connecting(start, end).next().unwrap(); + // self.g.remove_edge(g_idx); - let sim_idx = self.sim.get_graph_mut().find_edge(start, end).unwrap(); - self.sim.get_graph_mut().remove_edge(sim_idx).unwrap(); - } + // let sim_idx = self.sim.get_graph_mut().find_edge(start, end).unwrap(); + // self.sim.get_graph_mut().remove_edge(sim_idx).unwrap(); + // } fn draw_section_app(&mut self, ui: &mut Ui) { CollapsingHeader::new("App Config") @@ -444,35 +447,35 @@ impl ConfigurableApp { } fn draw_counts_sliders(&mut self, ui: &mut Ui) { - ui.horizontal(|ui| { - let before = self.settings_graph.count_node as i32; - - ui.add(Slider::new(&mut self.settings_graph.count_node, 1..=2500).text("nodes")); - - let delta = self.settings_graph.count_node as i32 - before; - (0..delta.abs()).for_each(|_| { - if delta > 0 { - self.add_random_node(); - return; - }; - self.remove_random_node(); - }); - }); - - ui.horizontal(|ui| { - let before = self.settings_graph.count_edge as i32; - - ui.add(Slider::new(&mut self.settings_graph.count_edge, 0..=5000).text("edges")); - - let delta = self.settings_graph.count_edge as i32 - before; - (0..delta.abs()).for_each(|_| { - if delta > 0 { - self.add_random_edge(); - return; - }; - self.remove_random_edge(); - }); - }); + // ui.horizontal(|ui| { + // let before = self.settings_graph.count_node as i32; + + // ui.add(Slider::new(&mut self.settings_graph.count_node, 1..=2500).text("nodes")); + + // let delta = self.settings_graph.count_node as i32 - before; + // (0..delta.abs()).for_each(|_| { + // if delta > 0 { + // self.add_random_node(); + // return; + // }; + // self.remove_random_node(); + // }); + // }); + + // ui.horizontal(|ui| { + // let before = self.settings_graph.count_edge as i32; + + // ui.add(Slider::new(&mut self.settings_graph.count_edge, 0..=5000).text("edges")); + + // let delta = self.settings_graph.count_edge as i32 - before; + // (0..delta.abs()).for_each(|_| { + // if delta > 0 { + // self.add_random_edge(); + // return; + // }; + // self.remove_random_edge(); + // }); + // }); } } @@ -526,14 +529,53 @@ impl App for ConfigurableApp { } } -fn generate(settings: &SettingsGraph) -> (Graph<(), (), Directed, DefaultIx>, Simulation<(), f32>) { - let g = generate_random_graph(settings.count_node, settings.count_edge); +fn generate() -> ( + Graph<(String, Orientation), (), Directed, DefaultIx>, + Simulation<(), f32>, +) { + let mut g: StableGraph<(String, Orientation), ()> = StableGraph::new(); + + let file = std::fs::File::open(env::args().nth(1).expect("missing gfa file argument")).unwrap(); + let entries = parser::parse_source(file).unwrap(); + + let mut index_map = HashMap::new(); + + for entry in entries { + // println!("{:?}", entry); + + if let Entry::Link { + from, + from_orient, + to, + to_orient, + } = entry + { + // add first node if not present + let a = index_map + .entry(from.clone()) + .or_insert_with(|| g.add_node((from.clone(), from_orient))) + .to_owned(); + + // add second node if not present + let b = index_map + .entry(to.clone()) + .or_insert_with(|| g.add_node((to.clone(), to_orient))) + .to_owned(); + + g.add_edge(a, b, ()); + } + } + + let g = Graph::from(&g); + let sim = construct_simulation(&g); (g, sim) } -fn construct_simulation(g: &Graph<(), (), Directed, DefaultIx>) -> Simulation<(), f32> { +fn construct_simulation( + g: &Graph<(String, Orientation), (), Directed, DefaultIx>, +) -> Simulation<(), f32> { // create force graph let mut force_graph = ForceGraph::with_capacity(g.g.node_count(), g.g.edge_count()); g.g.node_indices().for_each(|idx| { @@ -547,31 +589,31 @@ fn construct_simulation(g: &Graph<(), (), Directed, DefaultIx>) -> Simulation<() // initialize simulation let mut params = SimulationParameters::default(); - let force = fdg_sim::force::fruchterman_reingold_weighted(100., 0.5); + let force = fdg_sim::force::fruchterman_reingold_weighted(100., 0.75); params.set_force(force); Simulation::from_graph(force_graph, params) } -fn generate_random_graph(node_count: usize, edge_count: usize) -> Graph<(), ()> { - let mut rng = rand::thread_rng(); - let mut graph = StableGraph::new(); +// fn generate_random_graph(node_count: usize, edge_count: usize) -> Graph<(), ()> { +// let mut rng = rand::thread_rng(); +// let mut graph = StableGraph::new(); - // add nodes - for _ in 0..node_count { - graph.add_node(()); - } +// // add nodes +// for _ in 0..node_count { +// graph.add_node(()); +// } - // add random edges - for _ in 0..edge_count { - let source = rng.gen_range(0..node_count); - let target = rng.gen_range(0..node_count); +// // add random edges +// for _ in 0..edge_count { +// let source = rng.gen_range(0..node_count); +// let target = rng.gen_range(0..node_count); - graph.add_edge(NodeIndex::new(source), NodeIndex::new(target), ()); - } +// graph.add_edge(NodeIndex::new(source), NodeIndex::new(target), ()); +// } - to_graph(&graph) -} +// to_graph(&graph) +// } fn main() { let native_options = eframe::NativeOptions::default(); diff --git a/examples/configurable/src/settings.rs b/examples/configurable/src/settings.rs index 863ee0a..5a95730 100644 --- a/examples/configurable/src/settings.rs +++ b/examples/configurable/src/settings.rs @@ -1,16 +1,16 @@ -pub struct SettingsGraph { - pub count_node: usize, - pub count_edge: usize, -} +// pub struct SettingsGraph { +// pub count_node: usize, +// pub count_edge: usize, +// } -impl Default for SettingsGraph { - fn default() -> Self { - Self { - count_node: 300, - count_edge: 500, - } - } -} +// impl Default for SettingsGraph { +// fn default() -> Self { +// Self { +// count_node: 300, +// count_edge: 500, +// } +// } +// } #[derive(Default)] pub struct SettingsInteraction { diff --git a/examples/egui-graph-viz/Cargo.toml b/examples/egui-graph-viz/Cargo.toml index fc0aaf5..2741d51 100644 --- a/examples/egui-graph-viz/Cargo.toml +++ b/examples/egui-graph-viz/Cargo.toml @@ -9,3 +9,4 @@ egui = "0.27" eframe = "0.27" petgraph = "0.6" egui_graphs = "0.20.0" +asd = { path = "../../" } diff --git a/examples/egui-graph-viz/src/main.rs b/examples/egui-graph-viz/src/main.rs index 637c4f7..a329bf7 100644 --- a/examples/egui-graph-viz/src/main.rs +++ b/examples/egui-graph-viz/src/main.rs @@ -1,3 +1,9 @@ +use std::collections::HashMap; + +use asd::{ + gfa::{Entry, Orientation}, + parser, +}; use eframe::{run_native, App, CreationContext}; use egui::Context; use egui_graphs::{ @@ -6,7 +12,7 @@ use egui_graphs::{ use petgraph::stable_graph::StableGraph; pub struct InteractiveApp { - g: Graph<(), ()>, + g: Graph<(String, Orientation), ()>, } impl InteractiveApp { @@ -37,18 +43,39 @@ impl App for InteractiveApp { } } -fn generate_graph() -> Graph<(), ()> { - let mut g = StableGraph::new(); +fn generate_graph() -> Graph<(String, Orientation), ()> { + let mut g: StableGraph<(String, Orientation), ()> = StableGraph::new(); + + let file = std::fs::File::open("../../dataset/example.gfa").unwrap(); + let entries = parser::parse_source(file).unwrap(); + + let mut index_map = HashMap::new(); - let a = g.add_node(()); - let b = g.add_node(()); - let c = g.add_node(()); + for entry in entries { + println!("{:?}", entry); - g.add_edge(a, a, ()); - g.add_edge(a, b, ()); - g.add_edge(a, b, ()); - g.add_edge(b, c, ()); - g.add_edge(c, a, ()); + if let Entry::Link { + from, + from_orient, + to, + to_orient, + } = entry + { + // add first node if not present + let a = index_map + .entry(from.clone()) + .or_insert_with(|| g.add_node((from.clone(), from_orient))) + .to_owned(); + + // add second node if not present + let b = index_map + .entry(to.clone()) + .or_insert_with(|| g.add_node((to.clone(), to_orient))) + .to_owned(); + + g.add_edge(a, b, ()); + } + } Graph::from(&g) } diff --git a/src/gfa.rs b/src/gfa.rs index 490f8e6..81c2813 100644 --- a/src/gfa.rs +++ b/src/gfa.rs @@ -1,9 +1,20 @@ -#[derive(Debug)] +use std::fmt::Display; + +#[derive(Debug, Hash, PartialEq, Eq, Clone)] pub enum Orientation { Forward, Reverse, } +impl Display for Orientation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Orientation::Forward => write!(f, "+"), + Orientation::Reverse => write!(f, "-"), + } + } +} + #[derive(Debug)] pub enum Entry { Header { diff --git a/src/graph.rs b/src/graph.rs index 27f088f..876de02 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -1,100 +1,120 @@ use std::{ cell::RefCell, collections::{HashMap, HashSet}, + fmt::Debug, + hash::Hash, rc::Rc, }; #[derive(Debug)] -pub struct AdjacencyGraph { - nodes: HashMap, - adjacencies: HashMap>, +pub struct AdjacencyGraph +where + V: Hash + Eq + Clone, +{ + nodes: HashSet, + adjacencies: HashMap>, } #[allow(dead_code)] -impl AdjacencyGraph { +impl AdjacencyGraph +where + V: Hash + Eq + Clone + Debug, +{ pub fn new() -> Self { AdjacencyGraph { - nodes: HashMap::new(), + nodes: HashSet::new(), adjacencies: HashMap::new(), } } - pub fn add_node(&mut self, key: String, value: String) { - self.nodes.insert(key, value); + pub fn add_node(&mut self, node: V) { + // O(1) + self.nodes.insert(node); } - pub fn add_edge(&mut self, from: String, to: String) { + pub fn add_edge(&mut self, from: V, to: V) { + // O(1) + self.add_node(from.clone()); + self.add_node(to.clone()); + + // O(1) self.adjacencies .entry(from) - .or_insert(HashSet::new()) + .or_insert_with(HashSet::new) .insert(to); } - pub fn get_adjacencies(&self, node: &str) -> Option<&HashSet> { + pub fn get_adjacencies(&self, node: &V) -> Option<&HashSet> { self.adjacencies.get(node) } - pub fn adjacencies(&self) -> &HashMap> { + pub fn adjacencies(&self) -> &HashMap> { &self.adjacencies } - pub fn opposite(&self) -> AdjacencyGraph { + pub fn edges(&self) -> impl Iterator { + self.adjacencies + .iter() + .flat_map(|(from, tos)| tos.iter().map(move |to| (from, to))) + } + + pub fn opposite(&self) -> AdjacencyGraph<&V> { let mut opposite = AdjacencyGraph::new(); - for (from, adjacencies) in self.adjacencies.iter() { - for to in adjacencies { - opposite.add_edge(to.clone(), from.clone()); - } + // O(|E|) + for (from, to) in self.edges() { + opposite.add_edge(to, from); } opposite } - pub fn has_edge(&self, from: &str, to: &str) -> bool { + pub fn has_edge(&self, from: &V, to: &V) -> bool { + // O(1) if let Some(adjacencies) = self.get_adjacencies(from) { - adjacencies.contains(&to.to_string()) + // O(1) + adjacencies.contains(&to.to_owned()) } else { false } } - // pub fn dfs(&self, node: String) -> HashSet { - // let mut visited = HashSet::new(); - // let mut stack = vec![node]; - - // while let Some(node) = stack.pop() { - // if visited.contains(&node) { - // continue; - // } + pub fn dfs(&self, node: V) -> HashSet { + let mut visited: HashSet = HashSet::new(); + let mut stack = vec![&node]; - // visited.insert(node.clone()); + // O(|V| + |E|) + while let Some(node) = stack.pop() { + visited.insert(node.clone()); - // if let Some(adjacencies) = self.get_adjacencies(&node) { - // for adj in adjacencies { - // stack.push(adj.clone()); - // } - // } - // } + if let Some(adjacencies) = self.get_adjacencies(&node) { + for adj in adjacencies { + if !visited.contains(adj) { + stack.push(adj); + } + } + } + } - // visited - // } + visited + } - pub fn compute_ccs(&self) -> Vec> { + pub fn compute_ccs(&self) -> Vec> { let mut visited = HashSet::new(); let mut result = Vec::new(); let op = self.opposite(); - for node in self.nodes.keys() { + for node in self.nodes.iter() { if visited.contains(node) { continue; } - let mut cc = HashSet::new(); - let mut stack = vec![node.to_string()]; + let mut cc: HashSet = HashSet::new(); + let mut stack: Vec<&V> = vec![node]; while let Some(node) = stack.pop() { - if cc.contains(&node) { + if cc.contains(node) { continue; } @@ -102,17 +122,19 @@ impl AdjacencyGraph { if let Some(adjacencies) = self.get_adjacencies(&node) { for adj in adjacencies { - stack.push(adj.clone()); + stack.push(adj); } } if let Some(adjacencies) = op.get_adjacencies(&node) { for adj in adjacencies { - stack.push(adj.clone()); + stack.push(adj); } } } + // println!("CC: {:?}", cc); + visited.extend(cc.iter().map(|x| x.to_owned())); result.push(cc.iter().map(|x| x.to_owned()).collect()); } @@ -120,11 +142,11 @@ impl AdjacencyGraph { result } - pub fn compute_ccs_2(&self) -> Vec> { - let mut cc = HashMap::>>>::new(); + pub fn compute_ccs_2(&self) -> Vec> { + let mut cc: HashMap>>> = HashMap::new(); - for node in self.nodes.keys() { - if cc.contains_key(node) { + for node in self.nodes.iter() { + if cc.contains_key(&node) { continue; } @@ -132,7 +154,7 @@ impl AdjacencyGraph { let new_cc = Rc::new(RefCell::new(HashSet::new())); - let mut stack = vec![node.to_string()]; + let mut stack: Vec<&V> = vec![node]; while let Some(node) = stack.pop() { println!("New CC: {:?}", new_cc.borrow()); @@ -140,7 +162,7 @@ impl AdjacencyGraph { if cc.contains_key(&node) { // merge the two connected components and go to the next node - let old_cc = cc.get(&node).unwrap(); + let old_cc: &Rc>> = cc.get(&node).unwrap(); println!( "Merging {:?} with {:?} due to link to {:?}", @@ -164,7 +186,7 @@ impl AdjacencyGraph { if let Some(adjacencies) = self.get_adjacencies(&node) { for adj in adjacencies { - stack.push(adj.clone()); + stack.push(adj); } } } @@ -178,7 +200,7 @@ impl AdjacencyGraph { let mut result = Vec::new(); let mut seen = HashSet::new(); - for node in self.nodes.keys() { + for node in self.nodes.iter() { if seen.contains(node) { continue; } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..0193161 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +pub mod gfa; +pub mod graph; +pub mod parser; diff --git a/src/main.rs b/src/main.rs index d640ecc..e00d40e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use argh::FromArgs; use gfa::{Entry, Orientation}; use graph::AdjacencyGraph; @@ -36,48 +38,45 @@ fn main() -> std::io::Result<()> { let file = std::fs::File::open(show.input)?; let entries = parser::parse_source(file)?; - let mut graph = AdjacencyGraph::new(); + let mut sequence_map = HashMap::new(); + let mut graph: AdjacencyGraph<(String, Orientation)> = AdjacencyGraph::new(); for entry in entries { println!("{:?}", entry); match entry { Entry::Segment { id, sequence } => { - graph.add_node(id, sequence); + sequence_map.insert(id.clone(), sequence); } Entry::Link { from, from_orient, to, to_orient, - } => match (from_orient, to_orient) { - (Orientation::Forward, Orientation::Forward) - | (Orientation::Reverse, Orientation::Reverse) => { - graph.add_edge(from, to); - } - (Orientation::Forward, Orientation::Reverse) - | (Orientation::Reverse, Orientation::Forward) => { - graph.add_edge(to, from); - } - }, + } => { + graph.add_edge((from.clone(), from_orient), (to.clone(), to_orient)); + } _ => {} } } - for (from, adjacencies) in graph.adjacencies().iter() { - println!( - "{} -> {}", - from, - adjacencies - .iter() - .map(|to| to.to_owned()) - .collect::>() - .join(", ") - ); - } + // Print the graph + // for ((from, orient), adjacencies) in graph.adjacencies().iter() { + // println!( + // "{}{} -> {}", + // from, + // orient, + // adjacencies + // .iter() + // .map(|(to, orient)| format!("{}{}", to, orient)) + // .collect::>() + // .join(", ") + // ); + // } + + let cc = graph.compute_ccs(); - let cc = graph.compute_ccs_2(); - println!("CCs: {:?}", cc); + // println!("CCs: {:?}", cc); println!("Number of connected components: {}", cc.len()); } } diff --git a/src/parser.rs b/src/parser.rs index 3d4ae54..9d0f1cf 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -84,7 +84,7 @@ fn parse_path_segments(s: &str) -> Vec<(String, Orientation)> { let mut rest = s; loop { - println!("Rest: {}", rest); + // println!("Rest: {}", rest); let r = rest; @@ -132,7 +132,7 @@ pub fn parse_source(reader: R) -> io::Result> { continue; } - println!("Parsing: {}", line); + // println!("Parsing: {}", line); let first_char = line.chars().next().unwrap(); let entry = match first_char {