mirror of
https://github.com/aziis98/asd-2024.git
synced 2026-10-06 14:44:59 +00:00
generic graph code and visualization
This commit is contained in:
Generated
+3
-1
@@ -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",
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "asd-2024"
|
||||
name = "asd"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -13,3 +13,4 @@ serde_json = "1.0"
|
||||
fdg-sim = "0.9"
|
||||
rand = "0.8"
|
||||
crossbeam = "0.8"
|
||||
asd = { path = "../../" }
|
||||
|
||||
+161
-119
@@ -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<NodeIndex> {
|
||||
let nodes_cnt = self.g.node_count();
|
||||
if nodes_cnt == 0 {
|
||||
return None;
|
||||
}
|
||||
// fn random_node_idx(&self) -> Option<NodeIndex> {
|
||||
// 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<EdgeIndex> {
|
||||
let edges_cnt = self.g.edge_count();
|
||||
if edges_cnt == 0 {
|
||||
return None;
|
||||
}
|
||||
// fn random_edge_idx(&self) -> Option<EdgeIndex> {
|
||||
// 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.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"));
|
||||
// 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();
|
||||
});
|
||||
});
|
||||
// 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.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"));
|
||||
// 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();
|
||||
});
|
||||
});
|
||||
// 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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -9,3 +9,4 @@ egui = "0.27"
|
||||
eframe = "0.27"
|
||||
petgraph = "0.6"
|
||||
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 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 a = g.add_node(());
|
||||
let b = g.add_node(());
|
||||
let c = g.add_node(());
|
||||
let file = std::fs::File::open("../../dataset/example.gfa").unwrap();
|
||||
let entries = parser::parse_source(file).unwrap();
|
||||
|
||||
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, ());
|
||||
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, ());
|
||||
}
|
||||
}
|
||||
|
||||
Graph::from(&g)
|
||||
}
|
||||
|
||||
+12
-1
@@ -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 {
|
||||
|
||||
+72
-50
@@ -1,100 +1,120 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{HashMap, HashSet},
|
||||
fmt::Debug,
|
||||
hash::Hash,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AdjacencyGraph {
|
||||
nodes: HashMap<String, String>,
|
||||
adjacencies: HashMap<String, HashSet<String>>,
|
||||
pub struct AdjacencyGraph<V>
|
||||
where
|
||||
V: Hash + Eq + Clone,
|
||||
{
|
||||
nodes: HashSet<V>,
|
||||
adjacencies: HashMap<V, HashSet<V>>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl AdjacencyGraph {
|
||||
impl<V> AdjacencyGraph<V>
|
||||
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<String>> {
|
||||
pub fn get_adjacencies(&self, node: &V) -> Option<&HashSet<V>> {
|
||||
self.adjacencies.get(node)
|
||||
}
|
||||
|
||||
pub fn adjacencies(&self) -> &HashMap<String, HashSet<String>> {
|
||||
pub fn adjacencies(&self) -> &HashMap<V, HashSet<V>> {
|
||||
&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();
|
||||
|
||||
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<String> {
|
||||
// let mut visited = HashSet::new();
|
||||
// let mut stack = vec![node];
|
||||
pub fn dfs(&self, node: V) -> HashSet<V> {
|
||||
let mut visited: HashSet<V> = HashSet::new();
|
||||
let mut stack = vec![&node];
|
||||
|
||||
// while let Some(node) = stack.pop() {
|
||||
// if visited.contains(&node) {
|
||||
// continue;
|
||||
// }
|
||||
// O(|V| + |E|)
|
||||
while let Some(node) = stack.pop() {
|
||||
visited.insert(node.clone());
|
||||
|
||||
// visited.insert(node.clone());
|
||||
if let Some(adjacencies) = self.get_adjacencies(&node) {
|
||||
for adj in adjacencies {
|
||||
if !visited.contains(adj) {
|
||||
stack.push(adj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if let Some(adjacencies) = self.get_adjacencies(&node) {
|
||||
// for adj in adjacencies {
|
||||
// stack.push(adj.clone());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
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 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<V> = 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<Vec<String>> {
|
||||
let mut cc = HashMap::<String, Rc<RefCell<HashSet<String>>>>::new();
|
||||
pub fn compute_ccs_2(&self) -> Vec<Vec<V>> {
|
||||
let mut cc: HashMap<V, Rc<RefCell<HashSet<V>>>> = 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<RefCell<HashSet<V>>> = 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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod gfa;
|
||||
pub mod graph;
|
||||
pub mod parser;
|
||||
+24
-25
@@ -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::<Vec<String>>()
|
||||
.join(", ")
|
||||
);
|
||||
}
|
||||
// Print the graph
|
||||
// for ((from, orient), adjacencies) in graph.adjacencies().iter() {
|
||||
// println!(
|
||||
// "{}{} -> {}",
|
||||
// from,
|
||||
// orient,
|
||||
// adjacencies
|
||||
// .iter()
|
||||
// .map(|(to, orient)| format!("{}{}", to, orient))
|
||||
// .collect::<Vec<String>>()
|
||||
// .join(", ")
|
||||
// );
|
||||
// }
|
||||
|
||||
let cc = graph.compute_ccs_2();
|
||||
println!("CCs: {:?}", cc);
|
||||
let cc = graph.compute_ccs();
|
||||
|
||||
// println!("CCs: {:?}", cc);
|
||||
println!("Number of connected components: {}", cc.len());
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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<R: Read>(reader: R) -> io::Result<Vec<Entry>> {
|
||||
continue;
|
||||
}
|
||||
|
||||
println!("Parsing: {}", line);
|
||||
// println!("Parsing: {}", line);
|
||||
|
||||
let first_char = line.chars().next().unwrap();
|
||||
let entry = match first_char {
|
||||
|
||||
Reference in New Issue
Block a user