more refactoring

main
Antonio De Lucreziis 2 months ago
parent 37bc313f20
commit e3b5d1f7da

@ -2,8 +2,6 @@ use std::collections::HashMap;
use std::env; 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, Ui}; use egui::{CollapsingHeader, Context, Pos2, ScrollArea, Ui};
@ -11,6 +9,8 @@ use egui_graphs::events::Event;
use egui_graphs::{DefaultEdgeShape, DefaultNodeShape, Graph, GraphView}; use egui_graphs::{DefaultEdgeShape, DefaultNodeShape, Graph, GraphView};
use fdg_sim::glam::Vec3; use fdg_sim::glam::Vec3;
use fdg_sim::{ForceGraph, ForceGraphHelper, Simulation, SimulationParameters}; use fdg_sim::{ForceGraph, ForceGraphHelper, Simulation, SimulationParameters};
// use gfa::parser;
// use gfa::{Entry, Orientation};
use petgraph::stable_graph::{DefaultIx, NodeIndex, StableGraph}; use petgraph::stable_graph::{DefaultIx, NodeIndex, StableGraph};
use petgraph::Directed; use petgraph::Directed;
use settings::{SettingsInteraction, SettingsNavigation, SettingsStyle}; use settings::{SettingsInteraction, SettingsNavigation, SettingsStyle};

@ -46,3 +46,5 @@ pub enum Entry {
segments: Vec<(String, Orientation)>, segments: Vec<(String, Orientation)>,
}, },
} }
pub mod parser;

@ -1,4 +1,4 @@
#![allow(dead_code)] // #![allow(dead_code)]
use std::{ use std::{
io::{self, BufRead, BufReader, Read}, io::{self, BufRead, BufReader, Read},
@ -126,13 +126,13 @@ fn parse_walk(line: &str) -> Entry {
} }
} }
pub fn parse_file<R: AsRef<str>>(file: R) -> io::Result<Vec<Entry>> { pub fn parse_file(file: &str) -> io::Result<Vec<Entry>> {
let file_lines_count = BufReader::new(std::fs::File::open(file.as_ref())?) let file_lines_count = BufReader::new(std::fs::File::open(file)?)
.lines() .lines()
.progress_count(0) .progress_count(0)
.count() as u64; .count() as u64;
let file = std::fs::File::open(file.as_ref())?; let file = std::fs::File::open(file)?;
parse_source(file, file_lines_count) parse_source(file, file_lines_count)
} }

@ -1,104 +1,104 @@
use std::{collections::HashMap, io::Read}; // use std::{collections::HashMap, io::Read};
use crate::{gfa::Entry, parser}; // use crate::{gfa::Entry, parser};
pub struct Graph { // pub struct Graph {
nodes: HashMap<String, usize>, // nodes: HashMap<String, usize>,
edges_from: Vec<usize>, // edges_from: Vec<usize>,
edges_to: Vec<usize>, // edges_to: Vec<usize>,
} // }
#[derive(Debug)] // #[derive(Debug)]
pub enum GraphError { // pub enum GraphError {
NodeNotFound(String), // NodeNotFound(String),
} // }
impl Graph { // impl Graph {
pub fn new() -> Self { // pub fn new() -> Self {
Self { // Self {
nodes: HashMap::new(), // nodes: HashMap::new(),
edges_from: Vec::new(), // edges_from: Vec::new(),
edges_to: Vec::new(), // edges_to: Vec::new(),
} // }
} // }
pub fn add_node(&mut self, id: String) { // pub fn add_node(&mut self, id: String) {
if self.nodes.contains_key(&id) { // if self.nodes.contains_key(&id) {
return; // return;
} // }
self.nodes.insert(id, self.nodes.len()); // self.nodes.insert(id, self.nodes.len());
} // }
pub fn add_edge(&mut self, from_id: &String, to_id: &String) -> Result<(), GraphError> { // pub fn add_edge(&mut self, from_id: &String, to_id: &String) -> Result<(), GraphError> {
let from = self // let from = self
.nodes // .nodes
.get(from_id) // .get(from_id)
.ok_or(GraphError::NodeNotFound(from_id.clone()))?; // .ok_or(GraphError::NodeNotFound(from_id.clone()))?;
let to = self // let to = self
.nodes // .nodes
.get(to_id) // .get(to_id)
.ok_or(GraphError::NodeNotFound(to_id.clone()))?; // .ok_or(GraphError::NodeNotFound(to_id.clone()))?;
self.edges_from.push(*from); // self.edges_from.push(*from);
self.edges_to.push(*to); // self.edges_to.push(*to);
Ok(()) // Ok(())
} // }
} // }
#[derive(Debug)] // #[derive(Debug)]
pub enum LoadGraphError { // pub enum LoadGraphError {
IoError(std::io::Error), // IoError(std::io::Error),
GraphError(GraphError), // GraphError(GraphError),
} // }
pub fn load_graph<R: Read>(reader: R, len: u64) -> Result<Graph, LoadGraphError> { // pub fn load_graph<R: Read>(reader: R, len: u64) -> Result<Graph, LoadGraphError> {
println!("Loading graph"); // println!("Loading graph");
let mut graph = Graph::new(); // let mut graph = Graph::new();
let entries = parser::parse_source(reader, len).map_err(|e| LoadGraphError::IoError(e))?; // let entries = parser::parse_source(reader, len).map_err(|e| LoadGraphError::IoError(e))?;
let node_count = entries // let node_count = entries
.iter() // .iter()
.filter_map(|entry| match entry { // .filter_map(|entry| match entry {
Entry::Segment { id, .. } => Some(id), // Entry::Segment { id, .. } => Some(id),
_ => None, // _ => None,
}) // })
.count(); // .count();
println!("Node count: {}", node_count); // println!("Node count: {}", node_count);
for entry in entries // for entry in entries
.iter() // .iter()
.filter(|entry| matches!(entry, Entry::Link { .. })) // .filter(|entry| matches!(entry, Entry::Link { .. }))
{ // {
if let Entry::Link { // if let Entry::Link {
from, // from,
from_orient, // from_orient,
to, // to,
to_orient, // to_orient,
} = entry // } = entry
{ // {
let node_from = format!("{}{}", from, from_orient); // let node_from = format!("{}{}", from, from_orient);
let node_to = format!("{}{}", to, to_orient); // let node_to = format!("{}{}", to, to_orient);
graph.add_node(node_from.clone()); // graph.add_node(node_from.clone());
graph.add_node(node_to.clone()); // graph.add_node(node_to.clone());
graph // graph
.add_edge(&node_from, &node_to) // .add_edge(&node_from, &node_to)
.expect("Error adding edge"); // .expect("Error adding edge");
graph // graph
.add_edge(&node_to, &node_from) // .add_edge(&node_to, &node_from)
.expect("Error adding edge"); // .expect("Error adding edge");
} // }
} // }
println!("Loading completed"); // println!("Loading completed");
Ok(graph) // Ok(graph)
} // }

@ -1,416 +0,0 @@
use std::{
cell::RefCell,
cmp::Ordering,
collections::{BTreeMap, HashMap, HashSet, VecDeque},
fmt::Debug,
hash::Hash,
rc::Rc,
};
use indicatif::{ProgressBar, ProgressIterator};
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum EdgeType {
TreeEdge,
BackEdge,
ForwardEdge,
CrossEdge,
}
#[derive(Debug)]
pub struct AdjacencyGraph<V>
where
V: Hash + Eq + Clone,
{
nodes: HashSet<V>,
adjacencies: HashMap<V, HashSet<V>>,
}
pub struct UndirectedGraph<V>
where
V: Hash + Eq + Clone,
{
graph: AdjacencyGraph<V>,
}
#[allow(dead_code)]
impl<V> AdjacencyGraph<V>
where
V: Hash + Eq + Clone + Debug,
{
pub fn new() -> Self {
AdjacencyGraph {
nodes: HashSet::new(),
adjacencies: HashMap::new(),
}
}
pub fn add_node(&mut self, node: V) {
// O(1)
self.nodes.insert(node);
}
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_with(HashSet::new)
.insert(to);
}
pub fn get_adjacencies(&self, node: &V) -> Option<&HashSet<V>> {
self.adjacencies.get(node)
}
pub fn adjacencies(&self) -> &HashMap<V, HashSet<V>> {
&self.adjacencies
}
pub fn nodes(&self) -> &HashSet<V> {
&self.nodes
}
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();
// O(|E|)
for (from, to) in self.edges() {
opposite.add_edge(to, from);
}
opposite
}
pub fn undirected(&self) -> UndirectedGraph<&V> {
let mut undirected = AdjacencyGraph::new();
// O(|E|)
for (from, to) in self.edges() {
undirected.add_edge(from, to);
undirected.add_edge(to, from);
}
UndirectedGraph { graph: undirected }
}
pub fn has_edge(&self, from: &V, to: &V) -> bool {
// O(1)
if let Some(adjacencies) = self.get_adjacencies(from) {
// O(1)
adjacencies.contains(&to.to_owned())
} else {
false
}
}
pub fn dfs<'a>(&'a self, node: &'a V) -> impl Iterator<Item = V> + 'a {
let mut visited = HashSet::new();
let mut stack = VecDeque::from([node]);
std::iter::from_fn(move || {
while let Some(node) = stack.pop_back() {
if !visited.insert(node.clone()) {
continue;
}
if let Some(adjacencies) = self.get_adjacencies(node) {
stack.extend(adjacencies);
}
return Some(node.clone());
}
None
})
}
/// This computes if this undirected graph is cyclic or not by searching for an oriented cycle in the graph
pub fn is_cyclic(&self) -> bool {
let mut remaining_nodes = self.nodes.iter().collect::<HashSet<_>>();
// let progress_bar = ProgressBar::new(self.nodes.len() as u64);
// let mut visited_count = 0;
while !remaining_nodes.is_empty() {
let start: &V = remaining_nodes.iter().next().unwrap();
// visited_count += 1;
remaining_nodes.remove(start);
// progress_bar.inc(1);
let mut dfs_visited = HashSet::new();
let mut stack = VecDeque::new();
stack.push_back(start);
// start a new dfs from the current node
while let Some(node) = stack.pop_back() {
if dfs_visited.contains(node) {
// println!("Found cycle after {} nodes", visited_count);
// progress_bar.finish();
return true;
}
// visited_count += 1;
remaining_nodes.remove(node);
// progress_bar.inc(1);
dfs_visited.insert(node.clone());
if let Some(adjacencies) = self.get_adjacencies(node) {
stack.extend(adjacencies);
}
}
}
// println!("Found cycle after {} nodes", visited_count);
// progress_bar.finish();
false
}
pub fn shortest_path_matrix(&self) -> HashMap<&V, HashMap<&V, usize>> {
let mut result = HashMap::new();
for node in self.nodes.iter() {
let mut distances = HashMap::new();
let mut visited = HashSet::new();
let mut queue = VecDeque::from([node]);
distances.insert(node, 0);
while let Some(node) = queue.pop_front() {
if visited.contains(node) {
continue;
}
visited.insert(node.clone());
let distance = *distances.get(node).unwrap();
if let Some(adjacencies) = self.get_adjacencies(node) {
for adj in adjacencies {
if !distances.contains_key(adj) {
distances.insert(adj, distance + 1);
queue.push_back(adj);
}
}
}
}
result.insert(node, distances);
}
result
}
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
.iter()
.progress()
.with_style(
indicatif::ProgressStyle::default_bar()
.template("{prefix} {spinner} [{elapsed_precise}] [{wide_bar}] {pos}/{len}")
.unwrap(),
)
.with_prefix("computing connected components")
{
if visited.contains(node) {
continue;
}
let mut cc: HashSet<V> = HashSet::new();
let mut stack: Vec<&V> = vec![node];
while let Some(node) = stack.pop() {
if cc.contains(node) {
continue;
}
cc.insert(node.clone());
if let Some(adjacencies) = self.get_adjacencies(&node) {
for adj in adjacencies {
stack.push(adj);
}
}
if let Some(adjacencies) = op.get_adjacencies(&node) {
for adj in adjacencies {
stack.push(adj);
}
}
}
visited.extend(cc.iter().map(|x| x.to_owned()));
result.push(cc.iter().map(|x| x.to_owned()).collect());
}
result
}
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.iter() {
if cc.contains_key(&node) {
continue;
}
// println!("All CC: {:?}", cc);
let new_cc = Rc::new(RefCell::new(HashSet::new()));
let mut stack: Vec<&V> = vec![node];
while let Some(node) = stack.pop() {
// println!("New CC: {:?}", new_cc.borrow());
if cc.contains_key(&node) {
// merge the two connected components and go to the next node
let old_cc: &Rc<RefCell<HashSet<V>>> = cc.get(&node).unwrap();
// println!(
// "Merging {:?} with {:?} due to link to {:?}",
// new_cc.borrow(),
// old_cc.borrow(),
// node
// );
new_cc
.borrow_mut()
.extend(old_cc.borrow().iter().map(|x| x.to_owned()));
break;
}
if new_cc.borrow().contains(&node) {
continue;
}
new_cc.borrow_mut().insert(node.clone());
if let Some(adjacencies) = self.get_adjacencies(&node) {
for adj in adjacencies {
stack.push(adj);
}
}
}
for n in new_cc.borrow().iter() {
cc.insert(n.to_owned(), new_cc.clone());
}
}
// extract the unique connected components by pointers
let mut result = Vec::new();
let mut seen = HashSet::new();
for node in self.nodes.iter() {
if seen.contains(node) {
continue;
}
let cc = cc.get(node).unwrap();
seen.extend(cc.borrow().iter().map(|x| x.to_owned()));
result.push(cc.borrow().iter().map(|x| x.to_owned()).collect());
}
result
}
/// This function prints the number of nodes, edges and a histogram of the degrees of the nodes
/// in the graph (computing the degrees might take a long time)
pub fn print_stats(&self) {
let mut vertices_degrees = HashMap::new();
for (from, tos) in self
.adjacencies
.iter()
.progress()
.with_style(
indicatif::ProgressStyle::default_bar()
.template("{prefix} {spinner} [{elapsed_precise}] [{wide_bar}] {pos}/{len}")
.unwrap(),
)
.with_prefix("computing nodes degrees")
{
*vertices_degrees.entry(from).or_insert(0) += tos.len();
for to in tos {
*vertices_degrees.entry(to).or_insert(0) += 1;
}
}
let histogram: BTreeMap<usize, usize> = vertices_degrees
.iter()
.map(|(_, degree)| *degree)
.fold(BTreeMap::new(), |mut acc, degree| {
*acc.entry(degree).or_insert(0) += 1;
acc
});
println!("Stats:");
println!("Nodes: {}", self.nodes.len());
println!("Edges: {}", self.edges().count());
println!("Histogram:");
for (degree, count) in histogram.iter() {
println!("{}: {}", degree, count);
}
}
}
impl<V> UndirectedGraph<V>
where
V: Hash + Eq + Clone + Debug,
{
pub fn connected_components(&self) -> Vec<Vec<V>> {
let mut visited = HashSet::new();
let mut result = Vec::new();
for node in self.graph.nodes.iter() {
if visited.contains(node) {
continue;
}
let mut cc: HashSet<V> = HashSet::new();
let mut stack: Vec<&V> = vec![node];
while let Some(node) = stack.pop() {
if cc.contains(node) {
continue;
}
cc.insert(node.clone());
if let Some(adjacencies) = self.graph.get_adjacencies(&node) {
for adj in adjacencies {
stack.push(adj);
}
}
}
visited.extend(cc.iter().map(|x| x.to_owned()));
result.push(cc.iter().map(|x| x.to_owned()).collect());
}
result
}
}

@ -1,6 +1,4 @@
pub mod gfa; // pub mod gfa;
pub mod graph; // pub mod graph;
pub mod graph_2; // pub mod graph_2;
pub mod parser; // pub mod parser;
mod utils;

@ -1,3 +1,6 @@
mod gfa;
mod graph;
use std::{ use std::{
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
io::{BufRead, BufReader}, io::{BufRead, BufReader},
@ -8,10 +11,6 @@ use gfa::{Entry, Orientation};
use graph::AdjacencyGraph; use graph::AdjacencyGraph;
use indicatif::ProgressIterator; use indicatif::ProgressIterator;
mod gfa;
mod graph;
mod parser;
#[derive(FromArgs, PartialEq, Debug)] #[derive(FromArgs, PartialEq, Debug)]
/// Strumento CLI per il progetto di Algoritmi e Strutture Dati 2024 /// Strumento CLI per il progetto di Algoritmi e Strutture Dati 2024
struct CliTool { struct CliTool {
@ -48,7 +47,7 @@ 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, file_lines_count)?; let entries = gfa::parser::parse_source(file, file_lines_count)?;
println!("Number of entries: {}", entries.len()); println!("Number of entries: {}", entries.len());

Loading…
Cancel
Save