pub use self::{cmp::*, directed::*, errors::*, specs::*, undirected::*};
pub(crate) mod cmp;
pub(crate) mod directed;
mod errors;
mod specs;
pub(crate) mod undirected;
pub mod graph;
pub mod search;
pub mod store;
use errors::GraphError;
use std::{collections::HashSet, ops::IndexMut};
use store::AdjacencyTable;
pub trait Graph<N = String, V = i64>:
Clone + Contain<N> + Contain<Edge<N, V>> + IndexMut<N, Output = Vec<(N, V)>>
where
N: Node,
V: Weight,
{
fn add_edge(&mut self, edge: Edge<N, V>) {
let pair = edge.pair();
self.add_node(pair.0.clone());
self.add_node(pair.1.clone());
self.store_mut().entry(pair.0.clone()).and_modify(|e| {
e.push((pair.1, edge.value().clone()));
});
}
fn add_edges(&mut self, iter: impl IntoIterator<Item = Edge<N, V>>) {
for i in iter {
self.add_edge(i)
}
}
fn add_node(&mut self, node: N) -> bool {
match self.store().get(&node) {
None => {
self.store_mut().insert(node, Vec::new());
true
}
_ => false,
}
}
fn add_nodes(&mut self, iter: impl IntoIterator<Item = N>) {
for i in iter {
self.add_node(i);
}
}
fn contains_edge(&self, edge: &Edge<N, V>) -> bool {
match self.store().get(&edge.pair().0) {
Some(edges) => edges.contains(&(edge.pair().1, edge.value().clone())),
None => false,
}
}
fn contains_node(&self, node: &N) -> bool {
self.store().contains_key(node)
}
fn degree(&self, node: &N) -> Result<usize, GraphError> {
match self.store().get(node) {
Some(edges) => Ok(edges.len()),
None => Err(GraphError::NodeNotInGraph),
}
}
fn edges(&self) -> Vec<Edge<N, V>> {
let mut edges = Vec::new();
for (from_node, from_node_neighbours) in self.store().clone() {
for (to_node, weight) in from_node_neighbours {
edges.push((from_node.clone(), to_node, weight).into());
}
}
edges
}
fn edges_from(&self, node: &N) -> Result<Vec<Edge<N, V>>, GraphError> {
match self.store().get(node) {
Some(edges) => Ok(edges
.iter()
.cloned()
.map(|(n, v)| Edge::new(node.clone(), n, v))
.collect()),
None => Err(GraphError::NodeNotInGraph),
}
}
fn edges_to(&self, node: &N) -> Result<Vec<Edge<N, V>>, GraphError> {
let mut edges = Vec::new();
for (origin, neighbours) in self.store().clone() {
for (dest, weight) in neighbours {
if &dest == node {
edges.push((origin.clone(), dest, weight).into());
}
}
}
Ok(edges)
}
fn is_connected(&self) -> bool {
let mut visited = HashSet::new();
let mut stack = self.nodes().iter().cloned().collect::<Vec<_>>();
while let Some(node) = stack.pop() {
if !visited.contains(&node) {
visited.insert(node.clone());
stack.extend(
self.neighbors(node)
.unwrap()
.iter()
.map(|(n, _)| n)
.cloned(),
);
}
}
visited.len() == self.nodes().len()
}
fn store_mut(&mut self) -> &mut AdjacencyTable<N, V>;
fn store(&self) -> &AdjacencyTable<N, V>;
fn neighbors(&self, node: N) -> Result<&Vec<(N, V)>, GraphError> {
if self.nodes().contains(&node) {
Ok(&self[node])
} else {
Err(GraphError::NodeNotInGraph)
}
}
fn nodes(&self) -> HashSet<N> {
self.store().keys().cloned().collect()
}
}
pub trait GraphExt<N = String, V = i64>: Graph<N, V>
where
N: Node,
V: Weight,
{
}
pub trait Subgraph<N = String, V = i64>: Graph<N, V>
where
N: Node,
V: Weight,
{
fn is_subgraph(&self, graph: impl Graph<N, V>) -> bool {
self.nodes().is_subset(&graph.nodes())
}
}