mirror of
https://github.com/aziis98/asd-2024.git
synced 2026-10-06 06:35:00 +00:00
disperazione 1
This commit is contained in:
@@ -46,6 +46,7 @@ class Graph:
|
||||
def add_edge(self, u, v):
|
||||
if u not in self.adjacency_list:
|
||||
self.adjacency_list[u] = []
|
||||
|
||||
self.adjacency_list[u].append(v)
|
||||
|
||||
def vertices(self):
|
||||
@@ -56,10 +57,18 @@ class Graph:
|
||||
|
||||
# Example usage:
|
||||
g = Graph()
|
||||
# g.add_edge(0, 1)
|
||||
# g.add_edge(1, 2)
|
||||
# g.add_edge(2, 3)
|
||||
# g.add_edge(3, 0)
|
||||
# g.add_edge(3, 4)
|
||||
# g.add_edge(4, 5)
|
||||
# g.add_edge(5, 0)
|
||||
# g.add_edge(4, 2)
|
||||
|
||||
g.add_edge(0, 1)
|
||||
g.add_edge(1, 2)
|
||||
g.add_edge(2, 3)
|
||||
g.add_edge(3, 0) # Creating the cycle 0 -> 1 -> 2 -> 3 -> 0
|
||||
g.add_edge(0, 2)
|
||||
|
||||
# Running DFS
|
||||
results = dfs(g)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
|
||||
#[derive(Debug, Hash, PartialEq, PartialOrd, Ord, Eq, Copy, Clone)]
|
||||
pub enum Orientation {
|
||||
Forward,
|
||||
Reverse,
|
||||
|
||||
+83
-76
@@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{BTreeMap, HashMap, HashSet, VecDeque},
|
||||
collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque},
|
||||
fmt::Debug,
|
||||
hash::Hash,
|
||||
rc::Rc,
|
||||
@@ -13,41 +13,48 @@ use super::{AdjacencyGraph, UndirectedGraph};
|
||||
#[allow(dead_code)]
|
||||
impl<V> AdjacencyGraph<V>
|
||||
where
|
||||
V: Hash + Eq + Clone + Debug,
|
||||
V: Ord + Clone + Debug,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
AdjacencyGraph {
|
||||
nodes: HashSet::new(),
|
||||
adjacencies: HashMap::new(),
|
||||
nodes: BTreeSet::new(),
|
||||
adjacencies: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_edges(edges: &[(V, V)]) -> Self {
|
||||
let mut graph = AdjacencyGraph::new();
|
||||
|
||||
for (from, to) in edges {
|
||||
graph.add_edge(from.clone(), to.clone());
|
||||
}
|
||||
|
||||
graph
|
||||
}
|
||||
|
||||
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)
|
||||
.or_insert_with(BTreeSet::new)
|
||||
.insert(to);
|
||||
}
|
||||
|
||||
pub fn get_adjacencies(&self, node: &V) -> Option<&HashSet<V>> {
|
||||
pub fn get_adjacencies(&self, node: &V) -> Option<&BTreeSet<V>> {
|
||||
self.adjacencies.get(node)
|
||||
}
|
||||
|
||||
pub fn adjacencies(&self) -> &HashMap<V, HashSet<V>> {
|
||||
pub fn adjacencies(&self) -> &BTreeMap<V, BTreeSet<V>> {
|
||||
&self.adjacencies
|
||||
}
|
||||
|
||||
pub fn nodes(&self) -> &HashSet<V> {
|
||||
pub fn nodes(&self) -> &BTreeSet<V> {
|
||||
&self.nodes
|
||||
}
|
||||
|
||||
@@ -91,7 +98,7 @@ where
|
||||
}
|
||||
|
||||
pub fn dfs<'a>(&'a self, node: &'a V) -> impl Iterator<Item = V> + 'a {
|
||||
let mut visited = HashSet::new();
|
||||
let mut visited = BTreeSet::new();
|
||||
let mut stack = VecDeque::from([node]);
|
||||
|
||||
std::iter::from_fn(move || {
|
||||
@@ -113,7 +120,7 @@ where
|
||||
|
||||
/// 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 mut remaining_nodes = self.nodes.iter().collect::<BTreeSet<_>>();
|
||||
|
||||
// let progress_bar = ProgressBar::new(self.nodes.len() as u64);
|
||||
// let mut visited_count = 0;
|
||||
@@ -125,7 +132,7 @@ where
|
||||
remaining_nodes.remove(start);
|
||||
// progress_bar.inc(1);
|
||||
|
||||
let mut dfs_visited = HashSet::new();
|
||||
let mut dfs_visited = BTreeSet::new();
|
||||
let mut stack = VecDeque::new();
|
||||
stack.push_back(start);
|
||||
|
||||
@@ -154,12 +161,12 @@ where
|
||||
false
|
||||
}
|
||||
|
||||
pub fn shortest_path_matrix(&self) -> HashMap<&V, HashMap<&V, usize>> {
|
||||
let mut result = HashMap::new();
|
||||
pub fn shortest_path_matrix(&self) -> BTreeMap<&V, BTreeMap<&V, usize>> {
|
||||
let mut result = BTreeMap::new();
|
||||
|
||||
for node in self.nodes.iter() {
|
||||
let mut distances = HashMap::new();
|
||||
let mut visited = HashSet::new();
|
||||
let mut distances = BTreeMap::new();
|
||||
let mut visited = BTreeSet::new();
|
||||
let mut queue = VecDeque::from([node]);
|
||||
|
||||
distances.insert(node, 0);
|
||||
@@ -190,7 +197,7 @@ where
|
||||
}
|
||||
|
||||
pub fn compute_ccs(&self) -> Vec<Vec<V>> {
|
||||
let mut visited = HashSet::new();
|
||||
let mut visited = BTreeSet::new();
|
||||
let mut result = Vec::new();
|
||||
|
||||
let op = self.opposite();
|
||||
@@ -210,7 +217,7 @@ where
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut cc: HashSet<V> = HashSet::new();
|
||||
let mut cc: BTreeSet<V> = BTreeSet::new();
|
||||
let mut stack: Vec<&V> = vec![node];
|
||||
|
||||
while let Some(node) = stack.pop() {
|
||||
@@ -240,82 +247,82 @@ where
|
||||
result
|
||||
}
|
||||
|
||||
pub fn compute_ccs_2(&self) -> Vec<Vec<V>> {
|
||||
let mut cc: HashMap<V, Rc<RefCell<HashSet<V>>>> = HashMap::new();
|
||||
// pub fn compute_ccs_2(&self) -> Vec<Vec<V>> {
|
||||
// let mut cc: BTreeMap<V, Rc<RefCell<BTreeSet<V>>>> = BTreeMap::new();
|
||||
|
||||
for node in self.nodes.iter() {
|
||||
if cc.contains_key(&node) {
|
||||
continue;
|
||||
}
|
||||
// for node in self.nodes.iter() {
|
||||
// if cc.contains_key(&node) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// println!("All CC: {:?}", cc);
|
||||
// // println!("All CC: {:?}", cc);
|
||||
|
||||
let new_cc = Rc::new(RefCell::new(HashSet::new()));
|
||||
// let new_cc = Rc::new(RefCell::new(HashSet::new()));
|
||||
|
||||
let mut stack: Vec<&V> = vec![node];
|
||||
// let mut stack: Vec<&V> = vec![node];
|
||||
|
||||
while let Some(node) = stack.pop() {
|
||||
// println!("New CC: {:?}", new_cc.borrow());
|
||||
// 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
|
||||
// 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();
|
||||
// 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
|
||||
// );
|
||||
// // 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()));
|
||||
// new_cc
|
||||
// .borrow_mut()
|
||||
// .extend(old_cc.borrow().iter().map(|x| x.to_owned()));
|
||||
|
||||
break;
|
||||
}
|
||||
// break;
|
||||
// }
|
||||
|
||||
if new_cc.borrow().contains(&node) {
|
||||
continue;
|
||||
}
|
||||
// if new_cc.borrow().contains(&node) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
new_cc.borrow_mut().insert(node.clone());
|
||||
// new_cc.borrow_mut().insert(node.clone());
|
||||
|
||||
if let Some(adjacencies) = self.get_adjacencies(&node) {
|
||||
for adj in adjacencies {
|
||||
stack.push(adj);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
// 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();
|
||||
// // 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;
|
||||
}
|
||||
// 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()));
|
||||
// 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.push(cc.borrow().iter().map(|x| x.to_owned()).collect());
|
||||
// }
|
||||
|
||||
result
|
||||
}
|
||||
// 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();
|
||||
let mut vertices_degrees = BTreeMap::new();
|
||||
|
||||
for (from, tos) in self
|
||||
.adjacencies
|
||||
@@ -356,10 +363,10 @@ where
|
||||
|
||||
impl<V> UndirectedGraph<V>
|
||||
where
|
||||
V: Hash + Eq + Clone + Debug,
|
||||
V: Ord + Eq + Clone + Debug,
|
||||
{
|
||||
pub fn connected_components(&self) -> Vec<Vec<V>> {
|
||||
let mut visited = HashSet::new();
|
||||
let mut visited = BTreeSet::new();
|
||||
let mut result = Vec::new();
|
||||
|
||||
for node in self.graph.nodes.iter() {
|
||||
@@ -367,7 +374,7 @@ where
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut cc: HashSet<V> = HashSet::new();
|
||||
let mut cc: BTreeSet<V> = BTreeSet::new();
|
||||
let mut stack: Vec<&V> = vec![node];
|
||||
|
||||
while let Some(node) = stack.pop() {
|
||||
|
||||
+165
-69
@@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::{HashMap, HashSet},
|
||||
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
||||
fmt::Debug,
|
||||
hash::Hash,
|
||||
};
|
||||
@@ -17,106 +17,202 @@ pub enum EdgeType {
|
||||
CrossEdge,
|
||||
}
|
||||
|
||||
impl<V> AdjacencyGraph<V>
|
||||
struct ClassifyState<V> {
|
||||
progress_bar: ProgressBar,
|
||||
|
||||
edge_types: BTreeMap<(V, V), EdgeType>,
|
||||
|
||||
visited: BTreeSet<V>,
|
||||
|
||||
start_times: BTreeMap<V, i32>,
|
||||
finished_nodes: BTreeSet<V>,
|
||||
|
||||
time: i32,
|
||||
}
|
||||
|
||||
impl<V> ClassifyState<V>
|
||||
where
|
||||
V: Hash + Eq + Clone + Debug,
|
||||
V: Ord + Eq + Clone + Debug,
|
||||
{
|
||||
pub fn compute_edge_types(&self) -> HashMap<(&V, &V), EdgeType> {
|
||||
let mut edge_types = HashMap::new();
|
||||
pub fn classify_edges_rec(mut self, graph: &AdjacencyGraph<V>) -> BTreeMap<(V, V), EdgeType> {
|
||||
for start in graph.nodes().iter() {
|
||||
if self.visited.contains(start) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: ...
|
||||
self.dfs(graph, start, None);
|
||||
}
|
||||
|
||||
return edge_types;
|
||||
self.progress_bar.finish();
|
||||
return self.edge_types;
|
||||
}
|
||||
|
||||
// pub fn compute_edge_types(&self) -> HashMap<(&V, &V), EdgeType> {
|
||||
// /// To correctly compute the start and end times of the nodes in the
|
||||
// /// graph, we need to keep do work before and after the recursion call
|
||||
// enum RecurseState<'a, V> {
|
||||
// Before(&'a V),
|
||||
// BeforeNeighbor(&'a V, &'a V),
|
||||
// AfterNeighbor(&'a V),
|
||||
pub fn dfs(&mut self, graph: &AdjacencyGraph<V>, node: &V, parent: Option<&V>) {
|
||||
if self.visited.contains(node) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.progress_bar.inc(1);
|
||||
self.visited.insert(node.clone());
|
||||
self.time += 1;
|
||||
self.start_times.insert(node.clone(), self.time);
|
||||
|
||||
if let Some(parent) = parent {
|
||||
self.edge_types
|
||||
.insert((parent.clone(), node.clone()), EdgeType::TreeEdge);
|
||||
}
|
||||
|
||||
if let Some(adjacencies) = graph.get_adjacencies(node) {
|
||||
for adj in adjacencies.iter() {
|
||||
if !self.visited.contains(adj) {
|
||||
self.dfs(graph, adj, Some(node));
|
||||
} else {
|
||||
if !self.finished_nodes.contains(adj) {
|
||||
self.edge_types
|
||||
.insert((node.clone(), adj.clone()), EdgeType::BackEdge);
|
||||
} else if self.start_times.get(node) < self.start_times.get(adj) {
|
||||
self.edge_types
|
||||
.insert((node.clone(), adj.clone()), EdgeType::ForwardEdge);
|
||||
} else {
|
||||
self.edge_types
|
||||
.insert((node.clone(), adj.clone()), EdgeType::CrossEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.time += 1;
|
||||
self.finished_nodes.insert(node.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> AdjacencyGraph<V>
|
||||
where
|
||||
V: Ord + Eq + Clone + Debug,
|
||||
{
|
||||
pub fn compute_edge_types_rec(&self) -> BTreeMap<(V, V), EdgeType> {
|
||||
return ClassifyState {
|
||||
progress_bar: ProgressBar::new(self.nodes().len() as u64),
|
||||
|
||||
edge_types: BTreeMap::new(),
|
||||
visited: BTreeSet::new(),
|
||||
start_times: BTreeMap::new(),
|
||||
finished_nodes: BTreeSet::new(),
|
||||
time: 0,
|
||||
}
|
||||
.classify_edges_rec(self);
|
||||
}
|
||||
|
||||
// pub fn compute_edge_types(&self) -> BTreeMap<(V, V), EdgeType> {
|
||||
// println!("{:?}", self);
|
||||
|
||||
// let mut edge_types: BTreeMap<(V, V), EdgeType> = BTreeMap::new();
|
||||
// let mut visited: BTreeSet<V> = BTreeSet::new();
|
||||
|
||||
// let mut start_times: BTreeMap<V, i32> = BTreeMap::new();
|
||||
// let mut finished_nodes: BTreeSet<V> = BTreeSet::new();
|
||||
|
||||
// #[derive(Debug)]
|
||||
// enum RecurseState<V> {
|
||||
// Visit { node: V, parent: Option<V> },
|
||||
// End { node: V },
|
||||
// }
|
||||
|
||||
// let mut edge_types = HashMap::new();
|
||||
|
||||
// let mut visited = HashSet::new();
|
||||
// let mut start_times = HashMap::new();
|
||||
// let mut finished_nodes = HashSet::new();
|
||||
|
||||
// let mut time = 0;
|
||||
|
||||
// let progress_bar = ProgressBar::new(self.nodes().len() as u64);
|
||||
// // let progress_bar = ProgressBar::new(self.nodes().len() as u64);
|
||||
|
||||
// for node in self.nodes().iter() {
|
||||
// if visited.contains(node) {
|
||||
// for start in self.nodes().iter() {
|
||||
// if visited.contains(start) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// let mut stack = Vec::new();
|
||||
// let mut stack: Vec<RecurseState<V>> = Vec::new();
|
||||
|
||||
// stack.push(RecurseState::Before(node));
|
||||
// // The first node does not have a parent
|
||||
// stack.push(RecurseState::End {
|
||||
// node: start.clone(),
|
||||
// });
|
||||
// stack.push(RecurseState::Visit {
|
||||
// node: start.clone(),
|
||||
// parent: None,
|
||||
// });
|
||||
|
||||
// println!("Starting DFS from {:?}", start);
|
||||
|
||||
// while let Some(state) = stack.pop() {
|
||||
// println!("Current: {:?}", state);
|
||||
// println!("Finished Nodes: {:?}", finished_nodes);
|
||||
|
||||
// match state {
|
||||
// RecurseState::Before(node) => {
|
||||
// progress_bar.inc(1);
|
||||
// visited.insert(node.clone());
|
||||
// start_times.insert(node, time);
|
||||
// RecurseState::Visit { node, parent } => {
|
||||
// if visited.contains(&node) {
|
||||
// // progress_bar.inc(1);
|
||||
// }
|
||||
|
||||
// if let Some(parent) = parent.clone() {
|
||||
// if !visited.contains(&node) {
|
||||
// println!("{:?} => TreeEdge", (parent.clone(), node.clone()));
|
||||
// edge_types
|
||||
// .insert((parent.clone(), node.clone()), EdgeType::TreeEdge);
|
||||
// } else {
|
||||
// if !finished_nodes.contains(&parent) {
|
||||
// println!("{:?} => BackEdge", (parent.clone(), node.clone()));
|
||||
// edge_types
|
||||
// .insert((node.clone(), parent.clone()), EdgeType::BackEdge);
|
||||
// } else if start_times.get(&node) < start_times.get(&parent) {
|
||||
// println!("{:?} => ForwardEdge", (parent.clone(), node.clone()));
|
||||
// edge_types.insert(
|
||||
// (node.clone(), parent.clone()),
|
||||
// EdgeType::ForwardEdge,
|
||||
// );
|
||||
// } else {
|
||||
// println!("{:?} => CrossEdge", (parent.clone(), node.clone()));
|
||||
// edge_types.insert(
|
||||
// (node.clone(), parent.clone()),
|
||||
// EdgeType::CrossEdge,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// time += 1;
|
||||
// start_times.insert(node.clone(), time);
|
||||
|
||||
// visited.insert(node.clone());
|
||||
|
||||
// // it is extremely important that this before the adjacencies to correctly
|
||||
// // iterate over the graph
|
||||
// // stack.push(RecurseState::AfterNeighbors { node });
|
||||
|
||||
// if let Some(adjacencies) = self.get_adjacencies(node) {
|
||||
// for adj in adjacencies {
|
||||
// println!("Node: {:?} Adj: {:?}", node, adj,);
|
||||
|
||||
// stack.push(RecurseState::AfterNeighbor(node));
|
||||
|
||||
// if !visited.contains(adj) {
|
||||
// edge_types.insert((node, adj), EdgeType::TreeEdge);
|
||||
// stack.push(RecurseState::Before(adj));
|
||||
// } else {
|
||||
// stack.push(RecurseState::BeforeNeighbor(node, adj));
|
||||
// if let Some(adjacencies) = self.get_adjacencies(&node) {
|
||||
// println!("adjacencies: {:?}", adjacencies);
|
||||
// for adj in adjacencies.iter().rev() {
|
||||
// if !visited.contains(&adj) {
|
||||
// stack.push(RecurseState::End { node: adj.clone() });
|
||||
// stack.push(RecurseState::Visit {
|
||||
// node: adj.clone(),
|
||||
// parent: Some(node.clone()),
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// RecurseState::AfterNeighbor(node) => {
|
||||
// finished_nodes.insert(node);
|
||||
// RecurseState::End { node } => {
|
||||
// time += 1;
|
||||
// }
|
||||
// RecurseState::BeforeNeighbor(node, adj) => {
|
||||
// let start_time_node = start_times.get(node).unwrap();
|
||||
// let start_time_adj = start_times.get(adj).unwrap();
|
||||
// let end_time_node = finished_nodes.get(node).unwrap_or(&0);
|
||||
// let end_time_adj = finished_nodes.get(adj).unwrap_or(&0);
|
||||
|
||||
// println!(
|
||||
// "Times: ({:?}, {:?}) ({:?}, {:?})",
|
||||
// start_time_node, end_time_node, start_time_adj, end_time_adj
|
||||
// );
|
||||
|
||||
// match (
|
||||
// start_time_node.cmp(start_time_adj),
|
||||
// end_time_node.cmp(end_time_adj),
|
||||
// ) {
|
||||
// (Ordering::Less, Ordering::Greater) => {
|
||||
// edge_types.insert((node, adj), EdgeType::ForwardEdge);
|
||||
// }
|
||||
// (Ordering::Greater, Ordering::Less) => {
|
||||
// edge_types.insert((node, adj), EdgeType::BackEdge);
|
||||
// }
|
||||
// _ => {
|
||||
// edge_types.insert((node, adj), EdgeType::CrossEdge);
|
||||
// }
|
||||
// }
|
||||
// finished_nodes.insert(node.clone());
|
||||
// }
|
||||
// }
|
||||
|
||||
// println!();
|
||||
|
||||
// // println!("after:");
|
||||
// // println!("~> {:?}", stack);
|
||||
// }
|
||||
// }
|
||||
|
||||
// edge_types
|
||||
// // progress_bar.finish();
|
||||
|
||||
// return edge_types;
|
||||
// }
|
||||
}
|
||||
|
||||
+95
-27
@@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
collections::{BTreeMap, BTreeSet, HashSet},
|
||||
fmt::Debug,
|
||||
hash::Hash,
|
||||
};
|
||||
@@ -7,15 +7,15 @@ use std::{
|
||||
#[derive(Debug)]
|
||||
pub struct AdjacencyGraph<V>
|
||||
where
|
||||
V: Hash + Eq + Clone,
|
||||
V: Clone,
|
||||
{
|
||||
nodes: HashSet<V>,
|
||||
adjacencies: HashMap<V, HashSet<V>>,
|
||||
nodes: BTreeSet<V>,
|
||||
adjacencies: BTreeMap<V, BTreeSet<V>>,
|
||||
}
|
||||
|
||||
pub struct UndirectedGraph<V>
|
||||
where
|
||||
V: Hash + Eq + Clone,
|
||||
V: Clone,
|
||||
{
|
||||
graph: AdjacencyGraph<V>,
|
||||
}
|
||||
@@ -29,29 +29,97 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_compute_edge_types() {
|
||||
let mut g = AdjacencyGraph::new();
|
||||
fn print_edge_types<T>(edge_types: &BTreeMap<(T, T), edge_types::EdgeType>)
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
println!("");
|
||||
println!("Edge types:");
|
||||
|
||||
g.add_edge(1, 2);
|
||||
g.add_edge(2, 3);
|
||||
g.add_edge(3, 4);
|
||||
g.add_edge(4, 1);
|
||||
|
||||
let edge_types = g.compute_edge_types();
|
||||
let edge_type_dict =
|
||||
edge_types
|
||||
.iter()
|
||||
.fold(BTreeMap::new(), |mut acc, (edge, edge_type)| {
|
||||
acc.entry(edge_type).or_insert_with(Vec::new).push(edge);
|
||||
acc
|
||||
});
|
||||
|
||||
for (edge_type, edges) in edge_type_dict.iter() {
|
||||
println!("- {:?}", edge_type);
|
||||
for edge in edges {
|
||||
println!("Edge: {:?}", edge);
|
||||
}
|
||||
for (edge, edge_type) in edge_types {
|
||||
println!("{:?} -> {:?}: {:?}", edge.0, edge.1, edge_type);
|
||||
}
|
||||
|
||||
// for (edge_type, edges) in edge_types
|
||||
// .iter()
|
||||
// .fold(BTreeMap::new(), |mut acc, (edge, edge_type)| {
|
||||
// acc.entry(edge_type).or_insert_with(Vec::new).push(edge);
|
||||
// acc
|
||||
// })
|
||||
// .iter()
|
||||
// {
|
||||
// println!("- {:?}", edge_type);
|
||||
// for edge in edges {
|
||||
// println!("{:?}", edge);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_edge_types_cycle() {
|
||||
let g = AdjacencyGraph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 0)]);
|
||||
|
||||
let edge_types = g.compute_edge_types_rec();
|
||||
print_edge_types(&edge_types);
|
||||
|
||||
assert_eq!(edge_types.len(), 4);
|
||||
assert_eq!(edge_types[&(0, 1)], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&(1, 2)], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&(2, 3)], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&(3, 0)], edge_types::EdgeType::BackEdge);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_edge_types_forward() {
|
||||
let g = AdjacencyGraph::from_edges(&[(0, 1), (1, 2), (0, 2)]);
|
||||
|
||||
let edge_types = g.compute_edge_types_rec();
|
||||
print_edge_types(&edge_types);
|
||||
|
||||
assert_eq!(edge_types.len(), 3);
|
||||
assert_eq!(edge_types[&(0, 1)], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&(1, 2)], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&(0, 2)], edge_types::EdgeType::ForwardEdge);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_edge_types_cross() {
|
||||
let g = AdjacencyGraph::from_edges(&[(0, 1), (1, 2), (0, 3), (3, 4), (2, 4)]);
|
||||
|
||||
let edge_types = g.compute_edge_types_rec();
|
||||
print_edge_types(&edge_types);
|
||||
|
||||
assert_eq!(edge_types.len(), 5);
|
||||
assert_eq!(edge_types[&(0, 1)], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&(1, 2)], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&(0, 3)], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&(2, 4)], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&(3, 4)], edge_types::EdgeType::CrossEdge);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_edge_types_all() {
|
||||
let g = AdjacencyGraph::from_edges(&[
|
||||
//
|
||||
("u", "v"),
|
||||
("u", "x"),
|
||||
("v", "y"),
|
||||
("y", "x"),
|
||||
("x", "v"),
|
||||
("w", "y"),
|
||||
("w", "z"),
|
||||
]);
|
||||
|
||||
let edge_types = g.compute_edge_types_rec();
|
||||
print_edge_types(&edge_types);
|
||||
|
||||
assert_eq!(edge_types.len(), 7);
|
||||
assert_eq!(edge_types[&("u", "v")], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&("u", "x")], edge_types::EdgeType::ForwardEdge);
|
||||
assert_eq!(edge_types[&("v", "y")], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&("y", "x")], edge_types::EdgeType::TreeEdge);
|
||||
assert_eq!(edge_types[&("x", "v")], edge_types::EdgeType::BackEdge);
|
||||
assert_eq!(edge_types[&("w", "y")], edge_types::EdgeType::CrossEdge);
|
||||
assert_eq!(edge_types[&("w", "z")], edge_types::EdgeType::TreeEdge);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ fn main() -> std::io::Result<()> {
|
||||
|
||||
// println!("Graph has cycles: {}", graph.is_cyclic());
|
||||
|
||||
let edge_types = graph.compute_edge_types();
|
||||
let edge_types = graph.compute_edge_types_rec();
|
||||
|
||||
let edge_type_histogram: BTreeMap<_, _> = edge_types
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user