mod graph_macros;
mod graph_serde;
mod node;
pub use crate::digraph::node::*;
use ahash::{AHashMap as HashMap, AHashSet as HashSet};
use std::{
fmt::{Display, Write},
hash::Hash,
};
pub struct Graph<K, N, E>
where
K: Clone + Hash + Display + PartialEq + Eq,
N: Clone,
E: Clone,
{
nodes: HashMap<K, Node<K, N, E>>,
}
impl<K, N, E> Graph<K, N, E>
where
K: Clone + Hash + Display + PartialEq + Eq,
N: Clone,
E: Clone,
{
pub fn new() -> Self {
Self {
nodes: HashMap::default(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
nodes: HashMap::with_capacity(capacity),
}
}
pub fn contains(&self, key: &K) -> bool {
self.nodes.contains_key(key)
}
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn get(&self, key: &K) -> Option<Node<K, N, E>> {
self.nodes.get(key).cloned()
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn insert(&mut self, node: Node<K, N, E>) -> bool {
if self.nodes.contains_key(node.key()) {
false
} else {
self.nodes.insert(node.key().clone(), node.clone());
true
}
}
pub fn remove(&mut self, node: &K) -> Option<Node<K, N, E>> {
self.nodes.remove(node)
}
pub fn to_vec(&self) -> Vec<Node<K, N, E>> {
self.nodes.values().cloned().collect()
}
pub fn roots(&self) -> Vec<Node<K, N, E>> {
self.nodes
.values()
.filter(|node| node.is_root())
.cloned()
.collect()
}
pub fn leaves(&self) -> Vec<Node<K, N, E>> {
self.nodes
.values()
.filter(|node| node.is_leaf())
.cloned()
.collect()
}
pub fn orphans(&self) -> Vec<Node<K, N, E>> {
self.nodes
.values()
.filter(|node| node.is_orphan())
.cloned()
.collect()
}
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, K, Node<K, N, E>> {
self.nodes.iter()
}
pub fn scc(&self) -> Vec<Vec<Node<K, N, E>>> {
let mut invariant = HashSet::new();
let mut components = Vec::new();
let mut ordering = self.scc_ordering();
while let Some(node) = ordering.pop() {
if !invariant.contains(node.key()) {
let cycle = node
.dfs()
.transpose()
.filter(&mut |Edge(_, v, _)| !invariant.contains(v.key()))
.search_cycle();
match cycle {
Some(cycle) => {
let mut cycle = cycle.to_vec_nodes();
cycle.pop();
for node in &cycle {
invariant.insert(node.key().clone());
}
components.push(cycle);
}
None => {
invariant.insert(node.key().clone());
components.push(vec![node.clone()]);
}
}
}
}
components
}
fn scc_ordering(&self) -> Vec<Node<K, N, E>> {
let mut visited = HashSet::new();
let mut ordering = Vec::new();
for (_, next) in self.iter() {
if !visited.contains(next.key()) {
let partition = next
.postorder()
.filter(&mut |Edge(_, v, _)| !visited.contains(v.key()))
.search_nodes();
for node in &partition {
visited.insert(node.key().clone());
ordering.push(node.clone());
}
}
}
ordering
}
pub fn to_dot(&self) -> String {
let mut s = String::new();
s.push_str("digraph {\n");
for (u_key, node) in self.iter() {
write!(&mut s, " {}", u_key.clone()).unwrap();
for Edge(_, v, _) in node {
write!(&mut s, "\n {} -> {}", u_key, v.key()).unwrap();
}
s.push('\n');
}
s.push('}');
s
}
fn fmt_attr(attrs: Vec<(String, String)>) -> String {
let mut s = String::new();
for (k, v) in attrs {
write!(&mut s, "[{}=\"{}\"]", k, v).unwrap();
}
s
}
pub fn to_dot_with_attr(
&self,
gattr: &dyn Fn(&Self) -> Option<Vec<(String, String)>>,
nattr: &dyn Fn(&Node<K, N, E>) -> Option<Vec<(String, String)>>,
eattr: &dyn Fn(&Node<K, N, E>, &Node<K, N, E>, &E) -> Option<Vec<(String, String)>>,
) -> String {
let mut s = String::new();
s.push_str("digraph {\n");
if let Some(gattrs) = gattr(self) {
for (k, v) in gattrs {
s.push_str(&format!("\t{}=\"{}\"\n", k, v));
}
}
for (u_key, node) in self.iter() {
s.push_str(&format!("\t{}", u_key.clone()));
if let Some(nattr) = nattr(node) {
s.push_str(&format!(" {}", Self::fmt_attr(nattr)));
}
s.push('\n');
}
for (_, node) in self.iter() {
for Edge(u, v, e) in node {
s.push_str(&format!("\t{} -> {}", u.key(), v.key()));
if let Some(eattrs) = eattr(&u, &v, &e) {
s.push_str(&format!(" {}", Self::fmt_attr(eattrs)));
}
s.push('\n');
}
}
s.push('}');
s
}
pub fn sizeof(&self) -> usize {
let mut size = 0;
for (k, node) in self.iter() {
size += node.sizeof() + std::mem::size_of_val(k);
}
size
}
}
impl<K, N, E> std::ops::Index<K> for Graph<K, N, E>
where
K: Clone + Hash + Display + Eq,
N: Clone,
E: Clone,
{
type Output = Node<K, N, E>;
fn index(&self, key: K) -> &Self::Output {
&self.nodes[&key]
}
}
impl<'a, K, N, E> std::ops::Index<&'a K> for Graph<K, N, E>
where
K: Clone + Hash + Display + Eq,
N: Clone,
E: Clone,
{
type Output = Node<K, N, E>;
fn index(&self, key: &'a K) -> &Self::Output {
&self.nodes[key]
}
}
impl<K, N, E> Default for Graph<K, N, E>
where
K: Clone + Hash + Display + Eq,
N: Clone,
E: Clone,
{
fn default() -> Self {
Self::new()
}
}