generic graph code and visualization

main
Antonio De Lucreziis 6 months ago
parent e654535280
commit ce6dcb0551

4
Cargo.lock generated

@ -224,7 +224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
[[package]] [[package]]
name = "asd-2024" name = "asd"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"argh", "argh",
@ -788,6 +788,7 @@ dependencies = [
name = "configurable" name = "configurable"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"asd",
"crossbeam", "crossbeam",
"eframe", "eframe",
"egui", "egui",
@ -1039,6 +1040,7 @@ dependencies = [
name = "egui-graph-viz" name = "egui-graph-viz"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"asd",
"eframe", "eframe",
"egui", "egui",
"egui_graphs", "egui_graphs",

@ -1,5 +1,5 @@
[package] [package]
name = "asd-2024" name = "asd"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"

@ -13,3 +13,4 @@ serde_json = "1.0"
fdg-sim = "0.9" fdg-sim = "0.9"
rand = "0.8" rand = "0.8"
crossbeam = "0.8" crossbeam = "0.8"
asd = { path = "../../" }

@ -1,5 +1,9 @@
use std::collections::HashMap;
use std::env;
use std::time::Instant; use std::time::Instant;
use asd::gfa::{Entry, Orientation};
use asd::parser;
use crossbeam::channel::{unbounded, Receiver, Sender}; use crossbeam::channel::{unbounded, Receiver, Sender};
use eframe::{run_native, App, CreationContext}; use eframe::{run_native, App, CreationContext};
use egui::{CollapsingHeader, Context, Pos2, ScrollArea, Slider, Ui}; 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::stable_graph::{DefaultIx, EdgeIndex, NodeIndex, StableGraph};
use petgraph::Directed; use petgraph::Directed;
use rand::Rng; use rand::Rng;
use settings::{SettingsGraph, SettingsInteraction, SettingsNavigation, SettingsStyle}; use settings::{SettingsInteraction, SettingsNavigation, SettingsStyle};
mod settings; mod settings;
@ -18,10 +22,10 @@ const SIMULATION_DT: f32 = 0.035;
const EVENTS_LIMIT: usize = 100; const EVENTS_LIMIT: usize = 100;
pub struct ConfigurableApp { pub struct ConfigurableApp {
g: Graph<(), (), Directed, DefaultIx>, g: Graph<(String, Orientation), (), Directed, DefaultIx>,
sim: Simulation<(), f32>, sim: Simulation<(), f32>,
settings_graph: SettingsGraph, // settings_graph: SettingsGraph,
settings_interaction: SettingsInteraction, settings_interaction: SettingsInteraction,
settings_navigation: SettingsNavigation, settings_navigation: SettingsNavigation,
settings_style: SettingsStyle, settings_style: SettingsStyle,
@ -43,8 +47,8 @@ pub struct ConfigurableApp {
impl ConfigurableApp { impl ConfigurableApp {
fn new(_: &CreationContext<'_>) -> Self { fn new(_: &CreationContext<'_>) -> Self {
let settings_graph = SettingsGraph::default(); // let settings_graph = SettingsGraph::default();
let (g, sim) = generate(&settings_graph); let (g, sim) = generate();
let (event_publisher, event_consumer) = unbounded(); let (event_publisher, event_consumer) = unbounded();
Self { Self {
g, g,
@ -53,8 +57,7 @@ impl ConfigurableApp {
event_consumer, event_consumer,
event_publisher, event_publisher,
settings_graph, // settings_graph,
settings_interaction: SettingsInteraction::default(), settings_interaction: SettingsInteraction::default(),
settings_navigation: SettingsNavigation::default(), settings_navigation: SettingsNavigation::default(),
settings_style: SettingsStyle::default(), settings_style: SettingsStyle::default(),
@ -149,12 +152,12 @@ impl ConfigurableApp {
} }
fn reset_graph(&mut self, ui: &mut Ui) { fn reset_graph(&mut self, ui: &mut Ui) {
let settings_graph = SettingsGraph::default(); // let settings_graph = SettingsGraph::default();
let (g, sim) = generate(&settings_graph); let (g, sim) = generate();
self.g = g; self.g = g;
self.sim = sim; self.sim = sim;
self.settings_graph = settings_graph; // self.settings_graph = settings_graph;
self.last_events = Vec::default(); self.last_events = Vec::default();
GraphView::<(), (), Directed, DefaultIx>::reset_metadata(ui); GraphView::<(), (), Directed, DefaultIx>::reset_metadata(ui);
@ -198,92 +201,92 @@ impl ConfigurableApp {
}); });
} }
fn random_node_idx(&self) -> Option<NodeIndex> { // fn random_node_idx(&self) -> Option<NodeIndex> {
let nodes_cnt = self.g.node_count(); // let nodes_cnt = self.g.node_count();
if nodes_cnt == 0 { // if nodes_cnt == 0 {
return None; // return None;
} // }
let random_n_idx = rand::thread_rng().gen_range(0..nodes_cnt); // let random_n_idx = rand::thread_rng().gen_range(0..nodes_cnt);
self.g.g.node_indices().nth(random_n_idx) // self.g.g.node_indices().nth(random_n_idx)
} // }
fn random_edge_idx(&self) -> Option<EdgeIndex> { // fn random_edge_idx(&self) -> Option<EdgeIndex> {
let edges_cnt = self.g.edge_count(); // let edges_cnt = self.g.edge_count();
if edges_cnt == 0 { // if edges_cnt == 0 {
return None; // return None;
} // }
let random_e_idx = rand::thread_rng().gen_range(0..edges_cnt); // let random_e_idx = rand::thread_rng().gen_range(0..edges_cnt);
self.g.g.edge_indices().nth(random_e_idx) // self.g.g.edge_indices().nth(random_e_idx)
} // }
fn remove_random_node(&mut self) { // fn remove_random_node(&mut self) {
let idx = self.random_node_idx().unwrap(); // let idx = self.random_node_idx().unwrap();
self.remove_node(idx); // self.remove_node(idx);
} // }
fn add_random_node(&mut self) { // fn add_random_node(&mut self) {
let random_n_idx = self.random_node_idx(); // let random_n_idx = self.random_node_idx();
if random_n_idx.is_none() { // if random_n_idx.is_none() {
return; // 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 // // location of new node is in surrounging of random existing node
let mut rng = rand::thread_rng(); // let mut rng = rand::thread_rng();
let location = Pos2::new( // let location = Pos2::new(
random_n.location().x + 10. + rng.gen_range(0. ..50.), // random_n.location().x + 10. + rng.gen_range(0. ..50.),
random_n.location().y + 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(), ()); // let mut sim_node = fdg_sim::Node::new(idx.index().to_string().as_str(), ());
sim_node.location = Vec3::new(location.x, location.y, 0.); // sim_node.location = Vec3::new(location.x, location.y, 0.);
self.sim.get_graph_mut().add_node(sim_node); // self.sim.get_graph_mut().add_node(sim_node);
} // }
fn remove_node(&mut self, idx: NodeIndex) { // fn remove_node(&mut self, idx: NodeIndex) {
self.g.remove_node(idx); // 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 // // update edges count
self.settings_graph.count_edge = self.g.edge_count(); // self.settings_graph.count_edge = self.g.edge_count();
} // }
fn add_random_edge(&mut self) { // fn add_random_edge(&mut self) {
let random_start = self.random_node_idx().unwrap(); // let random_start = self.random_node_idx().unwrap();
let random_end = 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) { // fn add_edge(&mut self, start: NodeIndex, end: NodeIndex) {
self.g.add_edge(start, end, ()); // 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) { // fn remove_random_edge(&mut self) {
let random_e_idx = self.random_edge_idx(); // let random_e_idx = self.random_edge_idx();
if random_e_idx.is_none() { // if random_e_idx.is_none() {
return; // return;
} // }
let endpoints = self.g.edge_endpoints(random_e_idx.unwrap()).unwrap(); // 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) { // fn remove_edge(&mut self, start: NodeIndex, end: NodeIndex) {
let (g_idx, _) = self.g.edges_connecting(start, end).next().unwrap(); // let (g_idx, _) = self.g.edges_connecting(start, end).next().unwrap();
self.g.remove_edge(g_idx); // self.g.remove_edge(g_idx);
let sim_idx = self.sim.get_graph_mut().find_edge(start, end).unwrap(); // let sim_idx = self.sim.get_graph_mut().find_edge(start, end).unwrap();
self.sim.get_graph_mut().remove_edge(sim_idx).unwrap(); // self.sim.get_graph_mut().remove_edge(sim_idx).unwrap();
} // }
fn draw_section_app(&mut self, ui: &mut Ui) { fn draw_section_app(&mut self, ui: &mut Ui) {
CollapsingHeader::new("App Config") CollapsingHeader::new("App Config")
@ -444,35 +447,35 @@ impl ConfigurableApp {
} }
fn draw_counts_sliders(&mut self, ui: &mut Ui) { fn draw_counts_sliders(&mut self, ui: &mut Ui) {
ui.horizontal(|ui| { // ui.horizontal(|ui| {
let before = self.settings_graph.count_node as i32; // let before = self.settings_graph.count_node as i32;
ui.add(Slider::new(&mut self.settings_graph.count_node, 1..=2500).text("nodes")); // ui.add(Slider::new(&mut self.settings_graph.count_node, 1..=2500).text("nodes"));
let delta = self.settings_graph.count_node as i32 - before; // let delta = self.settings_graph.count_node as i32 - before;
(0..delta.abs()).for_each(|_| { // (0..delta.abs()).for_each(|_| {
if delta > 0 { // if delta > 0 {
self.add_random_node(); // self.add_random_node();
return; // return;
}; // };
self.remove_random_node(); // self.remove_random_node();
}); // });
}); // });
ui.horizontal(|ui| { // ui.horizontal(|ui| {
let before = self.settings_graph.count_edge as i32; // let before = self.settings_graph.count_edge as i32;
ui.add(Slider::new(&mut self.settings_graph.count_edge, 0..=5000).text("edges")); // ui.add(Slider::new(&mut self.settings_graph.count_edge, 0..=5000).text("edges"));
let delta = self.settings_graph.count_edge as i32 - before; // let delta = self.settings_graph.count_edge as i32 - before;
(0..delta.abs()).for_each(|_| { // (0..delta.abs()).for_each(|_| {
if delta > 0 { // if delta > 0 {
self.add_random_edge(); // self.add_random_edge();
return; // return;
}; // };
self.remove_random_edge(); // self.remove_random_edge();
}); // });
}); // });
} }
} }
@ -526,14 +529,53 @@ impl App for ConfigurableApp {
} }
} }
fn generate(settings: &SettingsGraph) -> (Graph<(), (), Directed, DefaultIx>, Simulation<(), f32>) { fn generate() -> (
let g = generate_random_graph(settings.count_node, settings.count_edge); 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); let sim = construct_simulation(&g);
(g, sim) (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 // create force graph
let mut force_graph = ForceGraph::with_capacity(g.g.node_count(), g.g.edge_count()); let mut force_graph = ForceGraph::with_capacity(g.g.node_count(), g.g.edge_count());
g.g.node_indices().for_each(|idx| { g.g.node_indices().for_each(|idx| {
@ -547,31 +589,31 @@ fn construct_simulation(g: &Graph<(), (), Directed, DefaultIx>) -> Simulation<()
// initialize simulation // initialize simulation
let mut params = SimulationParameters::default(); 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); params.set_force(force);
Simulation::from_graph(force_graph, params) Simulation::from_graph(force_graph, params)
} }
fn generate_random_graph(node_count: usize, edge_count: usize) -> Graph<(), ()> { // fn generate_random_graph(node_count: usize, edge_count: usize) -> Graph<(), ()> {
let mut rng = rand::thread_rng(); // let mut rng = rand::thread_rng();
let mut graph = StableGraph::new(); // let mut graph = StableGraph::new();
// add nodes // // add nodes
for _ in 0..node_count { // for _ in 0..node_count {
graph.add_node(()); // graph.add_node(());
} // }
// add random edges // // add random edges
for _ in 0..edge_count { // for _ in 0..edge_count {
let source = rng.gen_range(0..node_count); // let source = rng.gen_range(0..node_count);
let target = 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() { fn main() {
let native_options = eframe::NativeOptions::default(); let native_options = eframe::NativeOptions::default();

@ -1,16 +1,16 @@
pub struct SettingsGraph { // pub struct SettingsGraph {
pub count_node: usize, // pub count_node: usize,
pub count_edge: usize, // pub count_edge: usize,
} // }
impl Default for SettingsGraph { // impl Default for SettingsGraph {
fn default() -> Self { // fn default() -> Self {
Self { // Self {
count_node: 300, // count_node: 300,
count_edge: 500, // count_edge: 500,
} // }
} // }
} // }
#[derive(Default)] #[derive(Default)]
pub struct SettingsInteraction { pub struct SettingsInteraction {

@ -9,3 +9,4 @@ egui = "0.27"
eframe = "0.27" eframe = "0.27"
petgraph = "0.6" petgraph = "0.6"
egui_graphs = "0.20.0" egui_graphs = "0.20.0"
asd = { path = "../../" }

@ -1,3 +1,9 @@
use std::collections::HashMap;
use asd::{
gfa::{Entry, Orientation},
parser,
};
use eframe::{run_native, App, CreationContext}; use eframe::{run_native, App, CreationContext};
use egui::Context; use egui::Context;
use egui_graphs::{ use egui_graphs::{
@ -6,7 +12,7 @@ use egui_graphs::{
use petgraph::stable_graph::StableGraph; use petgraph::stable_graph::StableGraph;
pub struct InteractiveApp { pub struct InteractiveApp {
g: Graph<(), ()>, g: Graph<(String, Orientation), ()>,
} }
impl InteractiveApp { impl InteractiveApp {
@ -37,18 +43,39 @@ impl App for InteractiveApp {
} }
} }
fn generate_graph() -> Graph<(), ()> { fn generate_graph() -> Graph<(String, Orientation), ()> {
let mut g = StableGraph::new(); let mut g: StableGraph<(String, Orientation), ()> = StableGraph::new();
let a = g.add_node(()); let file = std::fs::File::open("../../dataset/example.gfa").unwrap();
let b = g.add_node(()); let entries = parser::parse_source(file).unwrap();
let c = g.add_node(());
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, a, ());
g.add_edge(a, b, ());
g.add_edge(a, b, ()); g.add_edge(a, b, ());
g.add_edge(b, c, ()); }
g.add_edge(c, a, ()); }
Graph::from(&g) Graph::from(&g)
} }

@ -1,9 +1,20 @@
#[derive(Debug)] use std::fmt::Display;
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub enum Orientation { pub enum Orientation {
Forward, Forward,
Reverse, 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)] #[derive(Debug)]
pub enum Entry { pub enum Entry {
Header { Header {

@ -1,100 +1,120 @@
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fmt::Debug,
hash::Hash,
rc::Rc, rc::Rc,
}; };
#[derive(Debug)] #[derive(Debug)]
pub struct AdjacencyGraph { pub struct AdjacencyGraph<V>
nodes: HashMap<String, String>, where
adjacencies: HashMap<String, HashSet<String>>, V: Hash + Eq + Clone,
{
nodes: HashSet<V>,
adjacencies: HashMap<V, HashSet<V>>,
} }
#[allow(dead_code)] #[allow(dead_code)]
impl AdjacencyGraph { impl<V> AdjacencyGraph<V>
where
V: Hash + Eq + Clone + Debug,
{
pub fn new() -> Self { pub fn new() -> Self {
AdjacencyGraph { AdjacencyGraph {
nodes: HashMap::new(), nodes: HashSet::new(),
adjacencies: HashMap::new(), adjacencies: HashMap::new(),
} }
} }
pub fn add_node(&mut self, key: String, value: String) { pub fn add_node(&mut self, node: V) {
self.nodes.insert(key, value); // 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 self.adjacencies
.entry(from) .entry(from)
.or_insert(HashSet::new()) .or_insert_with(HashSet::new)
.insert(to); .insert(to);
} }
pub fn get_adjacencies(&self, node: &str) -> Option<&HashSet<String>> { pub fn get_adjacencies(&self, node: &V) -> Option<&HashSet<V>> {
self.adjacencies.get(node) self.adjacencies.get(node)
} }
pub fn adjacencies(&self) -> &HashMap<String, HashSet<String>> { pub fn adjacencies(&self) -> &HashMap<V, HashSet<V>> {
&self.adjacencies &self.adjacencies
} }
pub fn opposite(&self) -> AdjacencyGraph { pub fn edges(&self) -> impl Iterator<Item = (&V, &V)> {
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(); let mut opposite = AdjacencyGraph::new();
for (from, adjacencies) in self.adjacencies.iter() { // O(|E|)
for to in adjacencies { for (from, to) in self.edges() {
opposite.add_edge(to.clone(), from.clone()); opposite.add_edge(to, from);
}
} }
opposite 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) { if let Some(adjacencies) = self.get_adjacencies(from) {
adjacencies.contains(&to.to_string()) // O(1)
adjacencies.contains(&to.to_owned())
} else { } else {
false false
} }
} }
// pub fn dfs(&self, node: String) -> HashSet<String> { pub fn dfs(&self, node: V) -> HashSet<V> {
// let mut visited = HashSet::new(); let mut visited: HashSet<V> = HashSet::new();
// let mut stack = vec![node]; let mut stack = vec![&node];
// while let Some(node) = stack.pop() {
// if visited.contains(&node) {
// continue;
// }
// 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) { if let Some(adjacencies) = self.get_adjacencies(&node) {
// for adj in adjacencies { for adj in adjacencies {
// stack.push(adj.clone()); if !visited.contains(adj) {
// } stack.push(adj);
// } }
// } }
}
}
// visited visited
// } }
pub fn compute_ccs(&self) -> Vec<Vec<String>> { pub fn compute_ccs(&self) -> Vec<Vec<V>> {
let mut visited = HashSet::new(); let mut visited = HashSet::new();
let mut result = Vec::new(); let mut result = Vec::new();
let op = self.opposite(); let op = self.opposite();
for node in self.nodes.keys() { for node in self.nodes.iter() {
if visited.contains(node) { if visited.contains(node) {
continue; continue;
} }
let mut cc = HashSet::new(); let mut cc: HashSet<V> = HashSet::new();
let mut stack = vec![node.to_string()]; let mut stack: Vec<&V> = vec![node];
while let Some(node) = stack.pop() { while let Some(node) = stack.pop() {
if cc.contains(&node) { if cc.contains(node) {
continue; continue;
} }
@ -102,17 +122,19 @@ impl AdjacencyGraph {
if let Some(adjacencies) = self.get_adjacencies(&node) { if let Some(adjacencies) = self.get_adjacencies(&node) {
for adj in adjacencies { for adj in adjacencies {
stack.push(adj.clone()); stack.push(adj);
} }
} }
if let Some(adjacencies) = op.get_adjacencies(&node) { if let Some(adjacencies) = op.get_adjacencies(&node) {
for adj in adjacencies { for adj in adjacencies {
stack.push(adj.clone()); stack.push(adj);
} }
} }
} }
// println!("CC: {:?}", cc);
visited.extend(cc.iter().map(|x| x.to_owned())); visited.extend(cc.iter().map(|x| x.to_owned()));
result.push(cc.iter().map(|x| x.to_owned()).collect()); result.push(cc.iter().map(|x| x.to_owned()).collect());
} }
@ -120,11 +142,11 @@ impl AdjacencyGraph {
result result
} }
pub fn compute_ccs_2(&self) -> Vec<Vec<String>> { pub fn compute_ccs_2(&self) -> Vec<Vec<V>> {
let mut cc = HashMap::<String, Rc<RefCell<HashSet<String>>>>::new(); let mut cc: HashMap<V, Rc<RefCell<HashSet<V>>>> = HashMap::new();
for node in self.nodes.keys() { for node in self.nodes.iter() {
if cc.contains_key(node) { if cc.contains_key(&node) {
continue; continue;
} }
@ -132,7 +154,7 @@ impl AdjacencyGraph {
let new_cc = Rc::new(RefCell::new(HashSet::new())); 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() { while let Some(node) = stack.pop() {
println!("New CC: {:?}", new_cc.borrow()); println!("New CC: {:?}", new_cc.borrow());
@ -140,7 +162,7 @@ impl AdjacencyGraph {
if cc.contains_key(&node) { if cc.contains_key(&node) {
// merge the two connected components and go to the next node // merge the two connected components and go to the next node
let old_cc = cc.get(&node).unwrap(); let old_cc: &Rc<RefCell<HashSet<V>>> = cc.get(&node).unwrap();
println!( println!(
"Merging {:?} with {:?} due to link to {:?}", "Merging {:?} with {:?} due to link to {:?}",
@ -164,7 +186,7 @@ impl AdjacencyGraph {
if let Some(adjacencies) = self.get_adjacencies(&node) { if let Some(adjacencies) = self.get_adjacencies(&node) {
for adj in adjacencies { for adj in adjacencies {
stack.push(adj.clone()); stack.push(adj);
} }
} }
} }
@ -178,7 +200,7 @@ impl AdjacencyGraph {
let mut result = Vec::new(); let mut result = Vec::new();
let mut seen = HashSet::new(); let mut seen = HashSet::new();
for node in self.nodes.keys() { for node in self.nodes.iter() {
if seen.contains(node) { if seen.contains(node) {
continue; continue;
} }

@ -0,0 +1,3 @@
pub mod gfa;
pub mod graph;
pub mod parser;

@ -1,3 +1,5 @@
use std::collections::HashMap;
use argh::FromArgs; use argh::FromArgs;
use gfa::{Entry, Orientation}; use gfa::{Entry, Orientation};
use graph::AdjacencyGraph; use graph::AdjacencyGraph;
@ -36,48 +38,45 @@ fn main() -> std::io::Result<()> {
let file = std::fs::File::open(show.input)?; let file = std::fs::File::open(show.input)?;
let entries = parser::parse_source(file)?; 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 { for entry in entries {
println!("{:?}", entry); println!("{:?}", entry);
match entry { match entry {
Entry::Segment { id, sequence } => { Entry::Segment { id, sequence } => {
graph.add_node(id, sequence); sequence_map.insert(id.clone(), sequence);
} }
Entry::Link { Entry::Link {
from, from,
from_orient, from_orient,
to, to,
to_orient, to_orient,
} => match (from_orient, to_orient) { } => {
(Orientation::Forward, Orientation::Forward) graph.add_edge((from.clone(), from_orient), (to.clone(), to_orient));
| (Orientation::Reverse, Orientation::Reverse) => {
graph.add_edge(from, to);
}
(Orientation::Forward, Orientation::Reverse)
| (Orientation::Reverse, Orientation::Forward) => {
graph.add_edge(to, from);
} }
},
_ => {} _ => {}
} }
} }
for (from, adjacencies) in graph.adjacencies().iter() { // Print the graph
println!( // for ((from, orient), adjacencies) in graph.adjacencies().iter() {
"{} -> {}", // println!(
from, // "{}{} -> {}",
adjacencies // from,
.iter() // orient,
.map(|to| to.to_owned()) // adjacencies
.collect::<Vec<String>>() // .iter()
.join(", ") // .map(|(to, orient)| format!("{}{}", to, orient))
); // .collect::<Vec<String>>()
} // .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()); println!("Number of connected components: {}", cc.len());
} }
} }

@ -84,7 +84,7 @@ fn parse_path_segments(s: &str) -> Vec<(String, Orientation)> {
let mut rest = s; let mut rest = s;
loop { loop {
println!("Rest: {}", rest); // println!("Rest: {}", rest);
let r = rest; let r = rest;
@ -132,7 +132,7 @@ pub fn parse_source<R: Read>(reader: R) -> io::Result<Vec<Entry>> {
continue; continue;
} }
println!("Parsing: {}", line); // println!("Parsing: {}", line);
let first_char = line.chars().next().unwrap(); let first_char = line.chars().next().unwrap();
let entry = match first_char { let entry = match first_char {

Loading…
Cancel
Save