mirror of https://github.com/aziis98/asd-2024.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
5.9 KiB
Rust
222 lines
5.9 KiB
Rust
use std::{
|
|
collections::{BTreeMap, BTreeSet},
|
|
fmt::Debug,
|
|
};
|
|
|
|
pub trait Graph<V>
|
|
where
|
|
V: Ord + Clone,
|
|
{
|
|
fn new() -> Self
|
|
where
|
|
Self: Sized;
|
|
|
|
fn from_edges(edges: &[(V, V)]) -> Self
|
|
where
|
|
Self: Sized,
|
|
{
|
|
let mut graph = Self::new();
|
|
|
|
for (from, to) in edges {
|
|
graph.add_edge(from.clone(), to.clone());
|
|
}
|
|
|
|
graph
|
|
}
|
|
|
|
fn to_adjecency_graph(&self) -> AdjacencyGraph<V>;
|
|
|
|
fn nodes(&self) -> BTreeSet<V>;
|
|
fn adjacencies(&self) -> BTreeMap<V, BTreeSet<V>>;
|
|
fn edges(&self) -> BTreeSet<(V, V)>;
|
|
fn neighbors(&self, from: &V) -> BTreeSet<V>;
|
|
|
|
fn add_node(&mut self, node: V);
|
|
fn add_edge(&mut self, from: V, to: V);
|
|
|
|
fn remove_node(&mut self, node: &V);
|
|
fn remove_edge(&mut self, from: &V, to: &V);
|
|
|
|
fn restricted(&self, nodes: &Vec<V>) -> Self
|
|
where
|
|
Self: Sized,
|
|
{
|
|
let nodes_index = nodes.iter().collect::<BTreeSet<_>>();
|
|
let mut restricted = Self::new();
|
|
|
|
for node in nodes {
|
|
for adj in self.neighbors(&node) {
|
|
if nodes_index.contains(&adj) {
|
|
restricted.add_edge(node.clone(), adj.clone());
|
|
}
|
|
}
|
|
}
|
|
|
|
restricted
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct AdjacencyGraph<V>
|
|
where
|
|
V: Clone,
|
|
{
|
|
nodes: BTreeSet<V>,
|
|
adjacencies: BTreeMap<V, BTreeSet<V>>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct UndirectedGraph<V>
|
|
where
|
|
V: Clone,
|
|
{
|
|
pub directed: AdjacencyGraph<V>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct DirectedAcyclicGraph<V>(pub AdjacencyGraph<V>)
|
|
where
|
|
V: Clone;
|
|
|
|
pub mod algorithms;
|
|
pub mod dag;
|
|
pub mod directed;
|
|
pub mod edge_types;
|
|
pub mod undirected;
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use std::collections::BTreeMap;
|
|
|
|
use super::*;
|
|
|
|
fn print_edge_types<T>(edge_types: &BTreeMap<(T, T), edge_types::EdgeType>)
|
|
where
|
|
T: Debug,
|
|
{
|
|
println!("");
|
|
println!("Edge types:");
|
|
|
|
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();
|
|
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();
|
|
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();
|
|
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();
|
|
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);
|
|
}
|
|
|
|
#[test]
|
|
fn test_compact_chains() {
|
|
let mut g = AdjacencyGraph::from_edges(&[(0, 1), (1, 2), (2, 3), (3, 4)]).undirected();
|
|
|
|
println!("Compacting chains...");
|
|
println!("{:?}", g);
|
|
g.compact_chains();
|
|
println!("{:?}", g);
|
|
}
|
|
|
|
#[test]
|
|
fn test_all_paths() {
|
|
let g = AdjacencyGraph::from_edges(&[
|
|
//
|
|
("u", "v"),
|
|
("u", "x"),
|
|
("v", "y"),
|
|
("y", "x"),
|
|
("y", "w"),
|
|
("w", "z"),
|
|
("z", "x"),
|
|
("x", "h"),
|
|
("x", "g"),
|
|
("h", "i"),
|
|
("g", "i"),
|
|
]);
|
|
|
|
let g = g.dag();
|
|
|
|
g.all_paths(&"u", |path| {
|
|
println!("{:?}", path);
|
|
false
|
|
});
|
|
}
|
|
}
|