#![warn(clippy::pedantic)]
#![deny(missing_docs)]
pub mod algorithms;
pub mod arc_storage;
pub mod datasets;
pub mod node_storage;
pub mod search;
mod arc_info;
use std::{
collections::{HashMap, HashSet},
fmt::Display,
hash::Hash,
marker::PhantomData,
ops::Index,
};
pub use arc_storage::{ArcStorage, HashMapStorage};
use search::{BfsIter, DfsIter, Direction};
use crate::{
algorithms::{Cyclic, topological_sorting},
node_storage::NodeStorage,
};
pub use self::arc_info::ArcInfo;
pub struct Network<
I,
NodeAttr,
ArcAttr,
NodeStore = HashMap<I, NodeAttr>,
ArcStore = HashMapStorage<I, ArcAttr>,
> where
NodeStore: NodeStorage<I, NodeAttr>,
ArcStore: ArcStorage<I, ArcAttr>,
{
_phantom_aa: PhantomData<ArcAttr>,
_phantom_na: PhantomData<NodeAttr>,
_phantom_i: PhantomData<I>,
nodes: NodeStore,
arc_store: ArcStore,
}
impl<I, NodeAttr, ArcAttr, NodeStore, ArcStore> Clone
for Network<I, NodeAttr, ArcAttr, NodeStore, ArcStore>
where
NodeStore: NodeStorage<I, NodeAttr> + Clone,
ArcStore: ArcStorage<I, ArcAttr> + Clone,
ArcAttr: Clone,
NodeAttr: Clone,
{
fn clone(&self) -> Self {
Self {
_phantom_aa: self._phantom_aa,
_phantom_na: self._phantom_na,
_phantom_i: PhantomData,
nodes: self.nodes.clone(),
arc_store: self.arc_store.clone(),
}
}
}
impl<I, NodeAttr, ArcAttr, NodeStore, ArcStore> PartialEq
for Network<I, NodeAttr, ArcAttr, NodeStore, ArcStore>
where
NodeStore: NodeStorage<I, NodeAttr> + PartialEq,
ArcStore: ArcStorage<I, ArcAttr> + PartialEq,
ArcAttr: PartialEq,
NodeAttr: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.nodes == other.nodes && self.arc_store == other.arc_store
}
}
impl<I, NA, AA, NodeStore, ArcStore> Default for Network<I, NA, AA, NodeStore, ArcStore>
where
NodeStore: NodeStorage<I, NA> + Default,
ArcStore: ArcStorage<I, AA> + Default,
{
fn default() -> Self {
Self {
_phantom_aa: PhantomData,
_phantom_na: PhantomData,
_phantom_i: PhantomData,
nodes: Default::default(),
arc_store: Default::default(),
}
}
}
impl<I, NA, AA, NodeStore, ArcStore> std::fmt::Debug for Network<I, NA, AA, NodeStore, ArcStore>
where
NodeStore: NodeStorage<I, NA> + std::fmt::Debug,
ArcStore: ArcStorage<I, AA> + std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Network")
.field("nodes", &self.nodes)
.field("arc_store", &self.arc_store)
.finish()
}
}
impl<I, NA, AA, NodeStore, ArcStore> Network<I, NA, AA, NodeStore, ArcStore>
where
NodeStore: NodeStorage<I, NA> + Default,
ArcStore: ArcStorage<I, AA> + Default,
{
#[must_use]
pub fn new() -> Self {
Self::default()
}
}
impl<I, NodeAttr, ArcAttr, NodeStore, ArcStore> Network<I, NodeAttr, ArcAttr, NodeStore, ArcStore>
where
NodeStore: NodeStorage<I, NodeAttr>,
ArcStore: ArcStorage<I, ArcAttr>,
{
}
impl<I, NodeAttr, ArcAttr, NodeStore, ArcStore> Network<I, NodeAttr, ArcAttr, NodeStore, ArcStore>
where
NodeStore: NodeStorage<I, NodeAttr>,
ArcStore: ArcStorage<I, ArcAttr>,
{
#[must_use]
pub fn arc_store(&self) -> &ArcStore {
&self.arc_store
}
pub fn n_nodes(&self) -> usize {
self.nodes.n_nodes()
}
pub fn add_node(&mut self, id: I, attributes: NodeAttr) -> Option<NodeAttr> {
self.nodes.add_node(id, attributes)
}
pub fn into_parts(self) -> (NodeStore, ArcStore) {
(self.nodes, self.arc_store)
}
pub fn from_parts(nodes: NodeStore, arc_store: ArcStore) -> Self {
Self {
_phantom_na: PhantomData,
_phantom_aa: PhantomData,
_phantom_i: PhantomData,
nodes,
arc_store,
}
}
pub fn add_nodes<T: IntoIterator<Item = (I, NodeAttr)>>(&mut self, from: T) {
from.into_iter().for_each(|(id, attr)| {
self.add_node(id, attr);
});
}
pub fn remove_node(&mut self, id: &I) -> Option<NodeAttr> {
self.arc_store.remove_arcs_with_node(id);
self.nodes.remove_node(id)
}
pub fn contains_node(&self, id: &I) -> bool {
self.nodes.contains_node(id)
}
pub fn node(&self, id: &I) -> Option<&NodeAttr> {
self.nodes.node(id)
}
pub fn node_mut(&mut self, id: &I) -> Option<&mut NodeAttr> {
self.nodes.node_mut(id)
}
pub fn iter_nodes(&self) -> impl Iterator<Item = (&I, &NodeAttr)> {
self.nodes.iter_nodes()
}
pub fn bfs<'a>(
&'a self,
start_id: &'a I,
direction: Direction,
) -> BfsIter<'a, I, ArcAttr, ArcStore> {
BfsIter::new(&self.arc_store, start_id, direction)
}
pub fn dfs<'a>(
&'a self,
start_id: &'a I,
direction: Direction,
) -> DfsIter<'a, I, ArcAttr, ArcStore> {
DfsIter::new(&self.arc_store, start_id, direction)
}
pub fn map_nodes<F, NewNodeAttr, NewNodeStore>(
self,
f: F,
) -> Network<I, NewNodeAttr, ArcAttr, NewNodeStore, ArcStore>
where
F: Fn((I, NodeAttr)) -> (I, NewNodeAttr),
NewNodeStore: NodeStorage<I, NewNodeAttr> + std::iter::FromIterator<(I, NewNodeAttr)>,
NodeStore: IntoIterator<Item = (I, NodeAttr)>,
{
Network::from_parts(self.nodes.into_iter().map(f).collect(), self.arc_store)
}
pub fn map_arcs<F, NewArcAttr, NewArcStore>(
self,
f: F,
) -> Network<I, NodeAttr, NewArcAttr, NodeStore, NewArcStore>
where
F: Fn(ArcInfo<I, ArcAttr>) -> ArcInfo<I, NewArcAttr>,
NewArcStore: ArcStorage<I, NewArcAttr> + FromIterator<ArcInfo<I, NewArcAttr>>,
ArcStore: IntoIterator<Item = ArcInfo<I, ArcAttr>>,
{
Network::from_parts(self.nodes, self.arc_store.into_iter().map(f).collect())
}
pub fn map_nodes_and_arcs<FN, FA, NewNodeAttr, NewArcAttr, NewNodeStore, NewArcStore>(
self,
f_nodes: FN,
f_arcs: FA,
) -> Network<I, NewNodeAttr, NewArcAttr, NewNodeStore, NewArcStore>
where
FN: Fn((I, NodeAttr)) -> (I, NewNodeAttr),
FA: Fn(ArcInfo<I, ArcAttr>) -> ArcInfo<I, NewArcAttr>,
NodeStore: IntoIterator<Item = (I, NodeAttr)>,
ArcStore: IntoIterator<Item = ArcInfo<I, ArcAttr>>,
NewNodeStore: NodeStorage<I, NewNodeAttr> + std::iter::FromIterator<(I, NewNodeAttr)>,
NewArcStore: ArcStorage<I, NewArcAttr> + FromIterator<ArcInfo<I, NewArcAttr>>,
{
Network::from_parts(
self.nodes.into_iter().map(f_nodes).collect(),
self.arc_store.into_iter().map(f_arcs).collect(),
)
}
pub fn topological_sorting(&self) -> Result<Vec<I>, Cyclic>
where
I: Eq + Hash + Clone,
{
topological_sorting(self)
}
pub fn generations(&self) -> Result<Vec<HashSet<&I>>, Cyclic>
where
I: Eq + Hash,
{
let mut generations: Vec<HashSet<&I>> = vec![];
let mut indegrees = HashMap::new();
let mut zero_indegrees = HashSet::new();
self.nodes.iter_nodes().for_each(|(i, _attributes)| {
let indegree = self.reverse_arcs(i).count();
if indegree > 0 {
indegrees.insert(i, indegree);
} else {
zero_indegrees.insert(i);
}
});
while !zero_indegrees.is_empty() {
let this_generation = std::mem::take(&mut zero_indegrees);
for node in &this_generation {
self.forward_arcs(node).for_each(|arc| {
let child_indegrees = indegrees
.get_mut(arc.head())
.expect("Child should be in the indegrees map");
*child_indegrees -= 1;
if *child_indegrees == 0 {
zero_indegrees.insert(arc.head());
indegrees.remove(arc.head());
}
});
}
generations.push(this_generation);
}
if indegrees.is_empty() {
Ok(generations)
} else {
Err(Cyclic)
}
}
pub fn m_arcs(&self) -> usize {
self.arc_store.m_arcs()
}
pub fn add_arc<T: Into<ArcInfo<I, ArcAttr>>>(&mut self, arc: T) -> Result<(), NoSuchNode<I>> {
let arc = arc.into();
if !self.contains_node(&arc.tail) {
Err(NoSuchNode(arc.tail))
} else if !self.contains_node(&arc.head) {
Err(NoSuchNode(arc.head))
} else {
self.arc_store.add_arc(arc);
Ok(())
}
}
pub fn add_arcs<T: Into<ArcInfo<I, ArcAttr>>, It: IntoIterator<Item = T>>(
&mut self,
iter: It,
) -> Result<(), NoSuchNode<I>> {
for arc in iter {
self.add_arc(arc)?;
}
Ok(())
}
pub fn remove_arc(&mut self, tail: &I, head: &I) -> Option<ArcAttr> {
self.arc_store.remove_arc(tail, head)
}
pub fn remove_arcs<'a, It>(&'a mut self, iter: It)
where
It: IntoIterator<Item = (&'a I, &'a I)>,
{
for (tail, head) in iter {
self.arc_store.remove_arc(tail, head);
}
}
pub fn arc_iter<'a>(&'a self) -> impl Iterator<Item = &'a ArcInfo<I, ArcAttr>> + 'a
where
ArcAttr: 'a,
I: 'a,
{
self.arc_store.arc_iter()
}
pub fn arc_iter_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut ArcInfo<I, ArcAttr>> + 'a
where
ArcAttr: 'a,
I: 'a,
{
self.arc_store.arc_iter_mut()
}
pub fn forward_arcs<'a>(
&'a self,
node: &'a I,
) -> impl Iterator<Item = &'a ArcInfo<I, ArcAttr>> + 'a
where
ArcAttr: 'a,
I: 'a,
{
self.arc_store.forward_arcs(node)
}
pub fn reverse_arcs<'a>(
&'a self,
node: &'a I,
) -> impl Iterator<Item = &'a ArcInfo<I, ArcAttr>> + 'a
where
ArcAttr: 'a,
I: 'a,
{
self.arc_store.reverse_arcs(node)
}
pub fn arc(&self, tail: I, head: I) -> Option<&ArcAttr> {
self.arc_store.arc(tail, head)
}
pub fn arc_mut(&mut self, tail: I, head: I) -> Option<&mut ArcAttr> {
self.arc_store.arc_mut(tail, head)
}
pub fn contains_arc(&self, tail: I, head: I) -> bool {
self.arc_store.contains_arc(tail, head)
}
pub fn has_forward_arcs(&self, node: &I) -> bool {
self.arc_store.has_forward_arcs(node)
}
pub fn has_reverse_arcs(&self, node: &I) -> bool {
self.arc_store.has_reverse_arcs(node)
}
}
#[derive(Debug)]
pub struct NoSuchNode<I>(I);
impl<I> Display for NoSuchNode<I>
where
I: Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "No node corresponds to id '{0}'", self.0)
}
}
pub struct NodeAccessor<'a, I, NodeAttr, ArcAttr, NodeStore, ArcStore>
where
ArcStore: ArcStorage<I, ArcAttr>,
NodeStore: NodeStorage<I, NodeAttr>,
{
network: &'a Network<I, NodeAttr, ArcAttr, NodeStore, ArcStore>,
}
impl<I, NodeAttr, ArcAttr, NodeStore, ArcStore> Index<&I>
for NodeAccessor<'_, I, NodeAttr, ArcAttr, NodeStore, ArcStore>
where
ArcStore: ArcStorage<I, ArcAttr>,
NodeStore: NodeStorage<I, NodeAttr>,
{
type Output = NodeAttr;
fn index(&self, index: &I) -> &Self::Output {
self.network.nodes.node(index).unwrap()
}
}