chore: cleaned up graphs

main
Antonio De Lucreziis 3 weeks ago
parent d5065151f1
commit 0417ad55e0

@ -5,7 +5,7 @@ use std::{
fmt::Debug, fmt::Debug,
}; };
use indicatif::{ProgressBar, ProgressIterator}; use indicatif::ProgressIterator;
use super::{AdjacencyGraph, Graph, UndirectedGraph}; use super::{AdjacencyGraph, Graph, UndirectedGraph};
@ -14,51 +14,6 @@ impl<V> AdjacencyGraph<V>
where where
V: Ord + Eq + Clone + Debug, 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<V>> {
// self.adjacencies.get(node)
// }
// pub fn adjacencies(&self) -> &BTreeMap<V, BTreeSet<V>> {
// &self.adjacencies
// }
// pub fn nodes(&self) -> &BTreeSet<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> { pub fn opposite(&self) -> AdjacencyGraph<V> {
let mut opposite = AdjacencyGraph::new(); let mut opposite = AdjacencyGraph::new();
@ -103,25 +58,6 @@ where
self.neighbors(from).contains(to) self.neighbors(from).contains(to)
} }
// pub fn dfs<'a>(&'a self, node: &'a V) -> impl Iterator<Item = V> + '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<V, BTreeMap<V, usize>> { pub fn shortest_path_matrix(&self) -> BTreeMap<V, BTreeMap<V, usize>> {
let mut result = BTreeMap::new(); let mut result = BTreeMap::new();
@ -161,17 +97,9 @@ where
let op = self.opposite(); let op = self.opposite();
for node in self println!("Computing connected components...");
.nodes
.iter() for node in self.nodes.iter().progress() {
.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) { if visited.contains(node) {
continue; continue;
} }
@ -202,7 +130,7 @@ where
result result
} }
fn gc(&mut self) { pub fn gc(&mut self) {
let mut to_remove = Vec::new(); let mut to_remove = Vec::new();
for node in self.nodes.iter() { for node in self.nodes.iter() {
@ -217,130 +145,3 @@ where
} }
} }
} }
impl<V> UndirectedGraph<V>
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<Vec<V>> {
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<V> = BTreeSet::new();
let mut stack: Vec<V> = 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::<Vec<_>>();
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();
}
}

@ -1,4 +1,9 @@
use std::collections::{BTreeMap, BTreeSet}; use std::{
collections::{BTreeMap, BTreeSet},
fmt::Debug,
};
use indicatif::ProgressBar;
use super::{AdjacencyGraph, Graph, UndirectedGraph}; use super::{AdjacencyGraph, Graph, UndirectedGraph};
@ -53,3 +58,130 @@ where
self.directed.remove_edge(to, from); self.directed.remove_edge(to, from);
} }
} }
impl<V> UndirectedGraph<V>
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<Vec<V>> {
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<V> = BTreeSet::new();
let mut stack: Vec<V> = 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::<Vec<_>>();
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();
}
}

Loading…
Cancel
Save