diff --git a/src/graph/algorithms.rs b/src/graph/algorithms.rs index 518b26f..1df0187 100644 --- a/src/graph/algorithms.rs +++ b/src/graph/algorithms.rs @@ -5,7 +5,7 @@ use std::{ fmt::Debug, }; -use indicatif::{ProgressBar, ProgressIterator}; +use indicatif::ProgressIterator; use super::{AdjacencyGraph, Graph, UndirectedGraph}; @@ -14,51 +14,6 @@ impl AdjacencyGraph where V: Ord + Eq + Clone + Debug, { - // pub fn new() -> Self { - // AdjacencyGraph { - // nodes: BTreeSet::new(), - // adjacencies: BTreeMap::new(), - // } - // } - - // pub fn add_node(&mut self, node: V) { - // self.nodes.insert(node); - // } - - // pub fn add_edge(&mut self, from: V, to: V) { - // self.add_node(from.clone()); - // self.add_node(to.clone()); - - // self.adjacencies - // .entry(from) - // .or_insert_with(BTreeSet::new) - // .insert(to); - // } - - // pub fn remove_edge(&mut self, from: &V, to: &V) { - // if let Some(adjacencies) = self.adjacencies.get_mut(from) { - // adjacencies.remove(to); - // } - // } - - // pub fn get_adjacencies(&self, node: &V) -> Option<&BTreeSet> { - // self.adjacencies.get(node) - // } - - // pub fn adjacencies(&self) -> &BTreeMap> { - // &self.adjacencies - // } - - // pub fn nodes(&self) -> &BTreeSet { - // &self.nodes - // } - - // 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 { let mut opposite = AdjacencyGraph::new(); @@ -103,25 +58,6 @@ where self.neighbors(from).contains(to) } - // pub fn dfs<'a>(&'a self, node: &'a V) -> impl Iterator + 'a { - // let mut visited = BTreeSet::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; - // } - - // stack.extend(self.neighbors(node).iter()); - - // return Some(node.clone()); - // } - - // None - // }) - // } - pub fn shortest_path_matrix(&self) -> BTreeMap> { let mut result = BTreeMap::new(); @@ -161,17 +97,9 @@ where 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") - { + println!("Computing connected components..."); + + for node in self.nodes.iter().progress() { if visited.contains(node) { continue; } @@ -202,7 +130,7 @@ where result } - fn gc(&mut self) { + pub fn gc(&mut self) { let mut to_remove = Vec::new(); for node in self.nodes.iter() { @@ -217,130 +145,3 @@ where } } } - -impl UndirectedGraph -where - V: Ord + Eq + Clone + Debug, -{ - pub fn add_edge(&mut self, from: V, to: V) { - self.directed.add_edge(from.clone(), to.clone()); - self.directed.add_edge(to.clone(), from.clone()); - } - - pub fn remove_edge(&mut self, from: &V, to: &V) { - self.directed.remove_edge(from, to); - self.directed.remove_edge(to, from); - } - - pub fn connected_components(&self) -> Vec> { - let mut visited = BTreeSet::new(); - let mut result = Vec::new(); - - let pb = ProgressBar::new(self.directed.nodes.len() as u64); - - for node in self.directed.nodes.iter() { - if visited.contains(node) { - continue; - } - - let mut cc: BTreeSet = BTreeSet::new(); - let mut stack: Vec = vec![node.clone()]; - - while let Some(node) = stack.pop() { - if cc.contains(&node) { - continue; - } - - pb.inc(1); - cc.insert(node.clone()); - - for adj in self.neighbors(&node) { - stack.push(adj); - } - } - - visited.extend(cc.iter().map(|x| x.to_owned())); - result.push(cc.iter().map(|x| x.to_owned()).collect()); - } - - pb.finish(); - - result - } - - // This runs a depth-first search on the graph searching for o--o--o paths and removes the middle node - // recursively until no more o--o--o paths are found. - pub fn compact_chains(&mut self) { - let mut visited = BTreeSet::new(); - - let nodes = self.directed.nodes.clone(); - - let pb = ProgressBar::new(nodes.len() as u64); - - let mut compacted_count = 0; - - for node in nodes { - if visited.contains(&node) { - continue; - } - - let mut stack = vec![node]; - - while let Some(node) = stack.pop() { - if visited.contains(&node) { - continue; - } - - pb.inc(1); - visited.insert(node.clone()); - - // while adj has only one neighbor - let mut curr = node; - let mut path = vec![curr.clone()]; - - loop { - let adjacencies = self.neighbors(&curr); - if adjacencies.is_empty() { - break; - } - - let probes = adjacencies - .iter() - .filter(|&x| !path.contains(x)) - .collect::>(); - - if probes.len() != 1 { - break; - } - - curr = probes[0].clone(); - - visited.insert(curr.clone()); - path.push(curr.clone()); - } - - if path.len() < 3 { - continue; - } - - path.windows(2).for_each(|x| { - self.remove_edge(&x[0], &x[1]); - }); - - self.add_edge(path[0].clone(), path[path.len() - 1].clone()); - - compacted_count += path.len() - 2; - - for adj in self.neighbors(&curr) { - stack.push(adj); - } - } - } - - println!("Compacted {} nodes", compacted_count); - - self.directed.gc(); - - pb.finish(); - } -} diff --git a/src/graph/undirected.rs b/src/graph/undirected.rs index 1eb3271..fda9a4e 100644 --- a/src/graph/undirected.rs +++ b/src/graph/undirected.rs @@ -1,4 +1,9 @@ -use std::collections::{BTreeMap, BTreeSet}; +use std::{ + collections::{BTreeMap, BTreeSet}, + fmt::Debug, +}; + +use indicatif::ProgressBar; use super::{AdjacencyGraph, Graph, UndirectedGraph}; @@ -53,3 +58,130 @@ where self.directed.remove_edge(to, from); } } + +impl UndirectedGraph +where + V: Ord + Eq + Clone + Debug, +{ + pub fn add_edge(&mut self, from: V, to: V) { + self.directed.add_edge(from.clone(), to.clone()); + self.directed.add_edge(to.clone(), from.clone()); + } + + pub fn remove_edge(&mut self, from: &V, to: &V) { + self.directed.remove_edge(from, to); + self.directed.remove_edge(to, from); + } + + pub fn connected_components(&self) -> Vec> { + let mut visited = BTreeSet::new(); + let mut result = Vec::new(); + + let pb = ProgressBar::new(self.directed.nodes.len() as u64); + + for node in self.directed.nodes.iter() { + if visited.contains(node) { + continue; + } + + let mut cc: BTreeSet = BTreeSet::new(); + let mut stack: Vec = vec![node.clone()]; + + while let Some(node) = stack.pop() { + if cc.contains(&node) { + continue; + } + + pb.inc(1); + cc.insert(node.clone()); + + for adj in self.neighbors(&node) { + stack.push(adj); + } + } + + visited.extend(cc.iter().map(|x| x.to_owned())); + result.push(cc.iter().map(|x| x.to_owned()).collect()); + } + + pb.finish(); + + result + } + + // This runs a depth-first search on the graph searching for o--o--o paths and removes the middle node + // recursively until no more o--o--o paths are found. + pub fn compact_chains(&mut self) { + let mut visited = BTreeSet::new(); + + let nodes = self.directed.nodes.clone(); + + let pb = ProgressBar::new(nodes.len() as u64); + + let mut compacted_count = 0; + + for node in nodes { + if visited.contains(&node) { + continue; + } + + let mut stack = vec![node]; + + while let Some(node) = stack.pop() { + if visited.contains(&node) { + continue; + } + + pb.inc(1); + visited.insert(node.clone()); + + // while adj has only one neighbor + let mut curr = node; + let mut path = vec![curr.clone()]; + + loop { + let adjacencies = self.neighbors(&curr); + if adjacencies.is_empty() { + break; + } + + let probes = adjacencies + .iter() + .filter(|&x| !path.contains(x)) + .collect::>(); + + if probes.len() != 1 { + break; + } + + curr = probes[0].clone(); + + visited.insert(curr.clone()); + path.push(curr.clone()); + } + + if path.len() < 3 { + continue; + } + + path.windows(2).for_each(|x| { + self.remove_edge(&x[0], &x[1]); + }); + + self.add_edge(path[0].clone(), path[path.len() - 1].clone()); + + compacted_count += path.len() - 2; + + for adj in self.neighbors(&curr) { + stack.push(adj); + } + } + } + + println!("Compacted {} nodes", compacted_count); + + self.directed.gc(); + + pb.finish(); + } +}