diff options
Diffstat (limited to 'graph')
| -rw-r--r-- | graph/src/dfs.rs | 88 | ||||
| -rw-r--r-- | graph/src/labelled/binary.rs | 78 | ||||
| -rw-r--r-- | graph/src/labelled/double.rs | 16 | ||||
| -rw-r--r-- | graph/src/labelled/mod.rs | 5 | ||||
| -rw-r--r-- | graph/src/labelled/simple.rs | 612 | ||||
| -rw-r--r-- | graph/src/lib.rs | 52 |
6 files changed, 748 insertions, 103 deletions
diff --git a/graph/src/dfs.rs b/graph/src/dfs.rs new file mode 100644 index 0000000..e9af3de --- /dev/null +++ b/graph/src/dfs.rs @@ -0,0 +1,88 @@ +//! This module implements a function to produce the depth-first order +//! for a graph. + +use super::*; + +use error::Error; + +/// Return a list of indices that are ordered according to a depth-first search. +/// +/// A node is only recorded at most once. And the search starts from +/// the `root`, so this in fact only includes the connected component +/// of the `root`. +pub fn dfs(g: &impl Graph, root: usize) -> Result<Vec<usize>, Error> { + // let g = g.borrow(); + + let nodes_len = g.nodes_len(); + + let mut result: Vec<usize> = Vec::with_capacity(nodes_len); + + let mut stack: Vec<usize> = Vec::with_capacity(nodes_len); + + stack.push(root); + + let mut seen_nodes: Vec<bool> = std::iter::repeat(false).take(nodes_len).collect(); + + while let Some(top) = stack.pop() { + match seen_nodes.get_mut(top) { + Some(reference) if !*reference => { + *reference = true; + + result.push(top); + + // REVIEW: Maybe I shall add a method + // `children_of_rev`. + + stack.extend(g.children_of(top)?.collect::<Vec<_>>().into_iter().rev()); + } + None => { + return Err(Error::IndexOutOfBounds(top, nodes_len)); + } + _ => {} + } + } + + Ok(result) +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::labelled::simple::SLGBuilder; + + #[test] + fn test_dfs() -> Result<(), Box<dyn std::error::Error>> { + let mut builder = SLGBuilder::<usize, usize>::default(); + + // Add five nodes + builder.add_vertex(0); + builder.add_vertex(1); + builder.add_vertex(2); + builder.add_vertex(3); + builder.add_vertex(4); + + let dummy_label = 0usize; + + builder.add_edge(0, 1, dummy_label)?; + builder.add_edge(0, 4, dummy_label)?; + builder.add_edge(1, 4, dummy_label)?; + builder.add_edge(1, 2, dummy_label)?; + builder.add_edge(2, 3, dummy_label)?; + builder.add_edge(3, 4, dummy_label)?; + + // build a graph + + let graph = builder.build(); + + let dfs = dfs(&graph, 0)?; + + println!("dfs = {dfs:?}"); + + let answer = vec![0, 1, 4, 2, 3]; + + assert_eq!(answer, dfs); + + Ok(()) + } +} diff --git a/graph/src/labelled/binary.rs b/graph/src/labelled/binary.rs index 862f25b..fecc295 100644 --- a/graph/src/labelled/binary.rs +++ b/graph/src/labelled/binary.rs @@ -2,7 +2,7 @@ //! labels and each node knows about its parents. use super::*; -use crate::{Parent, ParentsGraph, RedirectGraph}; +use crate::{Parent, ParentsGraph, RedirectGraph, VLabelGraph}; use std::{ collections::{hash_map::Iter as MapIter, HashMap as Map}, @@ -223,7 +223,7 @@ impl<T: GraphLabel> Graph for PLGraph<T> { for node in self.nodes() { post.push_str(&format!( " {node} [label = \"{node}:{}\"]\n", - match self.vertex_label(node) { + match VLabelGraph::vertex_label(self, node) { Ok(Some(label)) => { format!("{label}") } @@ -249,6 +249,7 @@ impl<T: GraphLabel> Graph for PLGraph<T> { let mut file = std::fs::File::options() .write(true) .create(true) + .truncate(true) .open(&filename)?; use std::io::Write; @@ -405,6 +406,79 @@ impl<T: GraphLabel> RedirectGraph for PLGraph<T> { } } +/// A delegation of iterators. +/// +/// This is used to avoid a boxed pointer to an iterator. +#[derive(Debug, Clone)] +pub struct PLVIter<'a, T: GraphLabel> { + iter: Iter<'a, usize>, + graph: &'a PLGraph<T>, +} + +impl<'a, T: GraphLabel> PLVIter<'a, T> { + /// Return an iterator from a graph and a node. + pub fn try_new(graph: &'a PLGraph<T>, node: usize) -> Result<Self, Error> { + let iter = graph + .nodes + .get(node) + .ok_or(Error::IndexOutOfBounds(node, graph.nodes.len()))? + .children + .iter(); + + Ok(Self { iter, graph }) + } +} + +impl<'a, T: GraphLabel> Iterator for PLVIter<'a, T> { + type Item = (T, usize); + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().and_then(|child| { + VLabelGraph::vertex_label(self.graph, *child) + .ok() + .flatten() + .map(|label| (label, *child)) + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let len = self.iter.len(); + + (len, Some(len)) + } +} + +impl<'a, T: GraphLabel> ExactSizeIterator for PLVIter<'a, T> { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } +} + +impl<T: GraphLabel> VLabelGraph<T> for PLGraph<T> { + type TupleIter<'a> = PLVIter<'a,T> + where + Self: 'a, + T: 'a; + + fn vertex_label(&self, node_id: usize) -> Result<Option<T>, Error> { + self.nodes + .get(node_id) + .ok_or(Error::IndexOutOfBounds(node_id, self.nodes.len())) + .map(|node| Some(node.label)) + } + + fn query_label(&self, label: T) -> Option<usize> { + self.label_index_map.get(&label).copied() + } + + fn verlabren_of(&self, node_id: usize) -> Result<Self::TupleIter<'_>, Error> { + PLVIter::try_new(self, node_id) + } +} + impl<T: GraphLabel> LabelGraph<T> for PLGraph<T> { type Iter<'a> = std::iter::Empty<usize> where diff --git a/graph/src/labelled/double.rs b/graph/src/labelled/double.rs index b01a13b..12d0e54 100644 --- a/graph/src/labelled/double.rs +++ b/graph/src/labelled/double.rs @@ -158,6 +158,7 @@ impl<T: GraphLabel> Graph for DLGraph<T> { let mut file = std::fs::File::options() .write(true) .create(true) + .truncate(true) .open(&filename)?; use std::io::Write; @@ -408,21 +409,12 @@ impl<T: GraphLabel> LabelExtGraph<T> for DLGraph<T> { if !set.contains(&label) { flat.push((label, to)); by_target.get_mut(&to).unwrap().insert(label); - by_label - .entry(label) - .or_insert_with(Default::default) - .insert(to); + by_label.entry(label).or_default().insert(to); } } else { flat.push((label, to)); - by_target - .entry(to) - .or_insert_with(Default::default) - .insert(label); - by_label - .entry(label) - .or_insert_with(Default::default) - .insert(to); + by_target.entry(to).or_default().insert(label); + by_label.entry(label).or_default().insert(to); } } diff --git a/graph/src/labelled/mod.rs b/graph/src/labelled/mod.rs index 13fd8c1..f0704e0 100644 --- a/graph/src/labelled/mod.rs +++ b/graph/src/labelled/mod.rs @@ -19,4 +19,7 @@ pub mod binary; pub use binary::{PLGBuilderMut, PLGraph}; pub mod simple; -pub use simple::{SLGBuilder, SLGraph}; +pub use simple::{ + // SLGBuilder , + SLGraph, +}; diff --git a/graph/src/labelled/simple.rs b/graph/src/labelled/simple.rs index b5388a9..5fb7641 100644 --- a/graph/src/labelled/simple.rs +++ b/graph/src/labelled/simple.rs @@ -8,49 +8,74 @@ use super::*; +use crate::VLabelGraph; + #[derive(Debug, Clone)] -struct SLNode<T: GraphLabel> { - children: Vec<(T, usize)>, +struct SLNode<S: GraphLabel, T: GraphLabel> { + children: Box<[(T, usize)]>, + label: S, } -impl<T: GraphLabel> Default for SLNode<T> { +impl<S: GraphLabel + Default, T: GraphLabel> Default for SLNode<S, T> { fn default() -> Self { Self { - children: Vec::new(), + children: Box::new([]), + label: Default::default(), } } } -impl<T: GraphLabel> SLNode<T> { - fn new(children: Vec<(T, usize)>) -> Self { - Self { children } +impl<S: GraphLabel, T: GraphLabel> SLNode<S, T> { + #[allow(dead_code)] + fn new(children: Box<[(T, usize)]>, label: S) -> Self { + Self { children, label } + } + + fn into_builder(self) -> SLBNode<S, T> { + let label = self.label; + let children = self.children.into_vec(); + + SLBNode { children, label } + } + + fn to_builder(&self) -> SLBNode<S, T> { + let label = self.label; + let children = self.children.to_vec(); + + SLBNode { children, label } } } /// Simple Labelled Graph. #[derive(Debug, Clone)] -pub struct SLGraph<T: GraphLabel> { - nodes: Vec<SLNode<T>>, +pub struct SLGraph<S: GraphLabel, T: GraphLabel> { + nodes: Box<[SLNode<S, T>]>, } -impl<T: GraphLabel> SLGraph<T> { +impl<S: GraphLabel, T: GraphLabel> SLGraph<S, T> { /// Return a builder. #[inline] - pub fn builder(self) -> SLGBuilder<T> { - SLGBuilder(self) + pub fn builder(self) -> SLGBuilder<S, T> { + SLGBuilder { + nodes: <Box<[_]> as IntoIterator>::into_iter(self.nodes) + .map(SLNode::into_builder) + .collect(), + } } /// Return a builder from a reference. #[inline] - pub fn builder_ref(&self) -> SLGBuilder<T> { - SLGBuilder(self.clone()) + pub fn builder_ref(&self) -> SLGBuilder<S, T> { + SLGBuilder { + nodes: self.nodes.iter().map(SLNode::to_builder).collect(), + } } } -impl<T: GraphLabel> Default for SLGraph<T> { +impl<S: GraphLabel, T: GraphLabel> Default for SLGraph<S, T> { #[inline] fn default() -> Self { - let nodes = Vec::new(); + let nodes = Box::new([]); Self { nodes } } @@ -89,9 +114,12 @@ impl<'a, T: GraphLabel> ExactSizeIterator for ChildrenIter<'a, T> { } } -impl<T: GraphLabel> Graph for SLGraph<T> { +impl<S: GraphLabel, T: GraphLabel> Graph for SLGraph<S, T> { // Not using a boxed pointer is supposed to save some allocations. - type Iter<'a> = ChildrenIter<'a, T> where T: 'a; + type Iter<'a> = ChildrenIter<'a, T> + where + T: 'a, + S:'a; #[inline] fn is_empty(&self) -> bool { @@ -161,6 +189,10 @@ impl<T: GraphLabel> Graph for SLGraph<T> { let mut post = String::new(); + for (node_id, node_label) in self.nodes.iter().map(|node| &node.label).enumerate() { + post.push_str(&format!(" {node_id} [label = \"{node_label}\"]\n")); + } + for (source, target) in self.edges() { for label in self.edge_label(source, target).unwrap() { post.push_str(&format!(" {source} -> {target} [label = \"{label}\"]\n")); @@ -178,6 +210,7 @@ impl<T: GraphLabel> Graph for SLGraph<T> { let mut file = std::fs::File::options() .write(true) .create(true) + .truncate(true) .open(&filename)?; use std::io::Write; @@ -193,7 +226,112 @@ impl<T: GraphLabel> Graph for SLGraph<T> { } } -impl<T: GraphLabel> LabelGraph<T> for SLGraph<T> { +/// An iterator delegation for children, and labels of children, of +/// nodes of `SLGraph`. +#[derive(Debug, Clone)] +pub struct VLChildrenIter<'a, S: GraphLabel, T: GraphLabel> { + iter: std::iter::Copied<std::slice::Iter<'a, (T, usize)>>, + graph: &'a SLGraph<S, T>, +} + +impl<'a, S: GraphLabel, T: GraphLabel> VLChildrenIter<'a, S, T> { + fn new( + iter: std::iter::Copied<std::slice::Iter<'a, (T, usize)>>, + graph: &'a SLGraph<S, T>, + ) -> Self { + Self { iter, graph } + } +} + +impl<'a, S: GraphLabel, T: GraphLabel> Iterator for VLChildrenIter<'a, S, T> { + type Item = (S, usize); + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().and_then(|(_, to)| { + let label = self.graph.nodes.get(to)?.label; + Some((label, to)) + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +impl<'a, S: GraphLabel, T: GraphLabel> ExactSizeIterator for VLChildrenIter<'a, S, T> { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } +} + +impl<S: GraphLabel, T: GraphLabel> VLabelGraph<S> for SLGraph<S, T> { + type TupleIter<'a> = VLChildrenIter<'a, S, T> + where + Self: 'a, + T:'a, + S: 'a; + + fn vertex_label(&self, node_id: usize) -> Result<Option<S>, Error> { + Ok(Some( + self.nodes + .get(node_id) + .ok_or(Error::IndexOutOfBounds(node_id, self.nodes_len()))? + .label, + )) + } + + fn verlabren_of(&self, node_id: usize) -> Result<Self::TupleIter<'_>, Error> { + let iter = self + .nodes + .get(node_id) + .ok_or(Error::IndexOutOfBounds(node_id, self.nodes.len()))? + .children + .iter() + .copied(); + + Ok(Self::TupleIter::new(iter, self)) + } +} + +/// An iterator delegation for children of nodes of `SLGraph`. +/// +/// This iterates through labels and targets of edges simultaneously. +#[derive(Debug, Clone)] +pub struct ELChildrenIter<'a, T: GraphLabel> { + iter: std::iter::Copied<std::slice::Iter<'a, (T, usize)>>, +} + +impl<'a, T: GraphLabel> ELChildrenIter<'a, T> { + fn new(iter: std::iter::Copied<std::slice::Iter<'a, (T, usize)>>) -> Self { + Self { iter } + } +} + +impl<'a, T: GraphLabel> Iterator for ELChildrenIter<'a, T> { + type Item = (T, usize); + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +impl<'a, T: GraphLabel> ExactSizeIterator for ELChildrenIter<'a, T> { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } +} + +impl<S: GraphLabel, T: GraphLabel> LabelGraph<T> for SLGraph<S, T> { type Iter<'a> = std::iter::Empty<usize> where Self:'a, @@ -204,7 +342,7 @@ impl<T: GraphLabel> LabelGraph<T> for SLGraph<T> { Self: 'a, T: 'a; - type TupleIter<'a> = std::iter::Copied<std::slice::Iter<'a, (T, usize)>> + type TupleIter<'a> = ELChildrenIter<'a, T> where Self: 'a, T: 'a; @@ -218,7 +356,7 @@ impl<T: GraphLabel> LabelGraph<T> for SLGraph<T> { self.nodes .get(node_id) .ok_or(Error::IndexOutOfBounds(node_id, self.nodes.len())) - .map(|node| node.children.iter().copied()) + .map(|node| ELChildrenIter::new(node.children.iter().copied())) } fn edge_label(&self, source: usize, target: usize) -> Result<Self::EdgeLabelIter<'_>, Error> { @@ -276,9 +414,16 @@ impl<T: GraphLabel> LabelGraph<T> for SLGraph<T> { } } -impl<T: GraphLabel> LabelExtGraph<T> for SLGraph<T> { - #[inline] - fn extend(&mut self, edges: impl IntoIterator<Item = (T, usize)>) -> Result<usize, Error> { +impl<S: GraphLabel, T: GraphLabel> SLGBuilder<S, T> { + /// Add a new node with `edges` and `label`. + /// + /// If an edge from `edges` points to a non-existent node, return + /// an error. + pub fn extend( + &mut self, + label: S, + edges: impl IntoIterator<Item = (T, usize)>, + ) -> Result<usize, Error> { let mut children = Vec::new(); for (label, to) in edges { @@ -289,7 +434,7 @@ impl<T: GraphLabel> LabelExtGraph<T> for SLGraph<T> { children.push((label, to)); } - let new_node = SLNode::new(children); + let new_node = SLBNode::new(children, label); let new_index = self.nodes_len(); self.nodes.push(new_node); @@ -300,55 +445,326 @@ impl<T: GraphLabel> LabelExtGraph<T> for SLGraph<T> { // Builder for this implementation of graph +/// The type of nodes for builders. +#[derive(Debug, Clone)] +struct SLBNode<S: GraphLabel, T: GraphLabel> { + children: Vec<(T, usize)>, + label: S, +} + +impl<S: GraphLabel, T: GraphLabel> SLBNode<S, T> { + fn new(children: Vec<(T, usize)>, label: S) -> Self { + Self { children, label } + } + + fn into_boxed(self) -> SLNode<S, T> { + let label = self.label; + + let children = self.children.into_boxed_slice(); + SLNode { children, label } + } +} + /// A builder for simple labelled graphs. #[derive(Debug, Clone)] -pub struct SLGBuilder<T: GraphLabel>(SLGraph<T>); +pub struct SLGBuilder<S: GraphLabel, T: GraphLabel> { + nodes: Vec<SLBNode<S, T>>, +} -impl<T: GraphLabel> Default for SLGBuilder<T> { +impl<S: GraphLabel, T: GraphLabel> Default for SLGBuilder<S, T> { fn default() -> Self { - Self(Default::default()) + Self { nodes: Vec::new() } + } +} + +impl<S: GraphLabel, T: GraphLabel> Graph for SLGBuilder<S, T> { + // Not using a boxed pointer is supposed to save some allocations. + type Iter<'a> = ChildrenIter<'a, T> + where + T: 'a, + S:'a; + + #[inline] + fn is_empty(&self) -> bool { + self.nodes.is_empty() + } + + #[inline] + fn nodes_len(&self) -> usize { + self.nodes.len() + } + + #[inline] + fn children_of(&self, node_id: usize) -> Result<Self::Iter<'_>, Error> { + match self.nodes.get(node_id) { + Some(node) => Ok(ChildrenIter::new(node.children.iter().copied())), + None => Err(Error::IndexOutOfBounds(node_id, self.nodes.len())), + } + } + + #[inline] + /// Return the number of "children" of a node, or an error if the + /// node is not a member of the graph. + /// + /// This counts edges with different labels as different edges. + fn degree(&self, node_id: usize) -> Result<usize, Error> { + self.nodes + .get(node_id) + .ok_or(Error::IndexOutOfBounds(node_id, self.nodes.len())) + .map(|node| node.children.len()) + } + + #[inline] + fn is_empty_node(&self, node_id: usize) -> Result<bool, Error> { + self.nodes + .get(node_id) + .ok_or(Error::IndexOutOfBounds(node_id, self.nodes.len())) + .map(|node| node.children.is_empty()) + } + + fn has_edge(&self, source: usize, target: usize) -> Result<bool, Error> { + match self.nodes.get(source) { + Some(source_node) => { + if self.nodes.get(target).is_none() { + Err(Error::IndexOutOfBounds(target, self.nodes.len())) + } else { + for (_, to) in source_node.children.iter() { + if *to == target { + return Ok(true); + } + } + + Ok(false) + } + } + None => Err(Error::IndexOutOfBounds(source, self.nodes.len())), + } + } + + fn print_viz(&self, filename: &str) -> Result<(), std::io::Error> { + let filename = format!("output/{filename}"); + + let preamble = "digraph nfa { + fontname=\"Helvetica,Arial,sans-serif\" + node [fontname=\"Helvetica,Arial,sans-serif\", ordering=out] + edge [fontname=\"Helvetica,Arial,sans-serif\"] + rankdir=LR;\n"; + + let mut post = String::new(); + + for (node_id, node_label) in self.nodes.iter().map(|node| &node.label).enumerate() { + post.push_str(&format!(" {node_id} [label = \"{node_label}\"]\n")); + } + + for (source, target) in self.edges() { + for label in self.edge_label(source, target).unwrap() { + post.push_str(&format!(" {source} -> {target} [label = \"{label}\"]\n")); + } + } + + post.push_str("}\n"); + + let result = format!("{preamble}{post}"); + + if std::fs::metadata(&filename).is_ok() { + std::fs::remove_file(&filename)?; + } + + let mut file = std::fs::File::options() + .write(true) + .create(true) + .truncate(true) + .open(&filename)?; + + use std::io::Write; + + file.write_all(result.as_bytes()) + } + + #[inline] + fn replace_by_builder(&mut self, _builder: impl Builder<Result = Self>) { + unimplemented!() } } -impl<T: GraphLabel> Deref for SLGBuilder<T> { - type Target = SLGraph<T>; +/// An iterator delegation for children, and labels of children, of +/// nodes of `SLGBuilder`. +#[derive(Debug, Clone)] +pub struct VLBChildrenIter<'a, S: GraphLabel, T: GraphLabel> { + iter: std::iter::Copied<std::slice::Iter<'a, (T, usize)>>, + builder: &'a SLGBuilder<S, T>, +} - fn deref(&self) -> &Self::Target { - &self.0 +impl<'a, S: GraphLabel, T: GraphLabel> VLBChildrenIter<'a, S, T> { + fn new( + iter: std::iter::Copied<std::slice::Iter<'a, (T, usize)>>, + builder: &'a SLGBuilder<S, T>, + ) -> Self { + Self { iter, builder } } } -impl<T: GraphLabel> DerefMut for SLGBuilder<T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 +impl<'a, S: GraphLabel, T: GraphLabel> Iterator for VLBChildrenIter<'a, S, T> { + type Item = (S, usize); + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().and_then(|(_, to)| { + let label = self.builder.nodes.get(to)?.label; + Some((label, to)) + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +impl<'a, S: GraphLabel, T: GraphLabel> ExactSizeIterator for VLBChildrenIter<'a, S, T> { + #[inline] + fn len(&self) -> usize { + self.iter.len() } } -impl<T: GraphLabel> Builder for SLGBuilder<T> { - type Label = T; +impl<S: GraphLabel, T: GraphLabel> VLabelGraph<S> for SLGBuilder<S, T> { + type TupleIter<'a> = VLBChildrenIter<'a, S,T> + where + Self: 'a, + T:'a, + S: 'a; + + fn vertex_label(&self, node_id: usize) -> Result<Option<S>, Error> { + Ok(Some( + self.nodes + .get(node_id) + .ok_or(Error::IndexOutOfBounds(node_id, self.nodes_len()))? + .label, + )) + } - type Result = SLGraph<T>; + fn verlabren_of(&self, node_id: usize) -> Result<Self::TupleIter<'_>, Error> { + let iter = self + .nodes + .get(node_id) + .ok_or(Error::IndexOutOfBounds(node_id, self.nodes.len()))? + .children + .iter() + .copied(); + + Ok(Self::TupleIter::new(iter, self)) + } +} + +impl<S: GraphLabel, T: GraphLabel> LabelGraph<T> for SLGBuilder<S, T> { + type Iter<'a> = std::iter::Empty<usize> + where + Self:'a, + T:'a; + + type LabelIter<'a> = std::iter::Empty<(&'a T, <Self as LabelGraph<T>>::Iter<'a>)> + where + Self: 'a, + T: 'a; + + type TupleIter<'a> = ELChildrenIter<'a,T> + where + Self: 'a, + T: 'a; + + type EdgeLabelIter<'a> = std::option::IntoIter<T> + where + Self: 'a, + T: 'a; + + fn tuples_of(&self, node_id: usize) -> Result<Self::TupleIter<'_>, Error> { + self.nodes + .get(node_id) + .ok_or(Error::IndexOutOfBounds(node_id, self.nodes.len())) + .map(|node| ELChildrenIter::new(node.children.iter().copied())) + } + + fn edge_label(&self, source: usize, target: usize) -> Result<Self::EdgeLabelIter<'_>, Error> { + let nodes_len = self.nodes.len(); + + if let Some(source_node) = self.nodes.get(source) { + if !(0..nodes_len).contains(&target) { + return Err(Error::IndexOutOfBounds(target, nodes_len)); + } + + for (label, end) in source_node.children.iter() { + if *end == target { + return Ok(Some(*label).into_iter()); + } + } + + Ok(None.into_iter()) + } else { + Err(Error::IndexOutOfBounds(source, nodes_len)) + } + } + + fn find_children_with_label( + &self, + _node_id: usize, + _label: &T, + ) -> Result<<Self as LabelGraph<T>>::Iter<'_>, Error> { + unimplemented!("Unsupported operation") + } + + fn labels_of(&self, _node_id: usize) -> Result<Self::LabelIter<'_>, Error> { + unimplemented!("Unsupported operation") + } #[inline] - fn with_capacity(size: usize) -> Self { - Self(SLGraph { + fn has_edge_label(&self, node_id: usize, label: &T, target: usize) -> Result<bool, Error> { + let nodes_len = self.nodes.len(); + + match self.nodes.get(node_id) { + Some(node) => { + if target >= nodes_len { + return Err(Error::IndexOutOfBounds(target, nodes_len)); + } + + for (edge_label, end) in node.children.iter() { + if *edge_label == *label && *end == target { + return Ok(true); + } + } + + Ok(false) + } + None => Err(Error::IndexOutOfBounds(node_id, nodes_len)), + } + } +} + +impl<S: GraphLabel, T: GraphLabel> SLGBuilder<S, T> { + /// Return a builder with a fixed capacity. + #[inline] + pub fn with_capacity(size: usize) -> Self { + SLGBuilder { nodes: Vec::with_capacity(size), - }) + } } + /// Add a vertex with a given label. #[inline] - fn add_vertex(&mut self) -> usize { - self.nodes.push(SLNode::default()); + pub fn add_vertex(&mut self, label: S) -> usize { + self.nodes.push(SLBNode::new(Vec::new(), label)); self.nodes.len() - 1 } + /// Add vertices with an iterator of labels. #[inline] - fn add_vertices(&mut self, n: usize) { + pub fn add_vertices(&mut self, labels: impl Iterator<Item = S>) { self.nodes - .extend(std::iter::repeat_with(Default::default).take(n)); + .extend(labels.map(|label| SLBNode::new(Vec::new(), label))); } - fn add_edge(&mut self, source: usize, target: usize, label: Self::Label) -> Result<(), Error> { + /// Add an edge from the source to the target. + pub fn add_edge(&mut self, source: usize, target: usize, label: T) -> Result<(), Error> { let nodes_len = self.nodes.len(); let source_node = self @@ -365,14 +781,19 @@ impl<T: GraphLabel> Builder for SLGBuilder<T> { Ok(()) } - fn remove_edge<F>( + /// Remove an edge from the source to the target. + /// + /// Since some graphs are labelled, the users are allowed to pass + /// a predicate to determine if an edge from the source to the + /// target should be removed. + pub fn remove_edge<F>( &mut self, source: usize, target: usize, mut predicate: F, ) -> Result<(), Error> where - F: FnMut(Self::Label) -> bool, + F: FnMut(T) -> bool, { let nodes_len = self.nodes.len(); @@ -392,12 +813,35 @@ impl<T: GraphLabel> Builder for SLGBuilder<T> { Ok(()) } - fn build_ref(&self) -> Self::Result { - self.0.clone() + /// Convert the builder into a graph using a reference. + /// + /// This is similar to [`build`][Builder::build], but takes an + /// immutable reference of the builder, so that the builder can + /// still be used later on. + pub fn build_ref(&self) -> SLGraph<S, T> { + let nodes = self + .nodes + .clone() + .into_iter() + .map(SLBNode::into_boxed) + .collect::<Vec<_>>() + .into_boxed_slice(); + + SLGraph { nodes } } - fn build(self) -> Self::Result { - self.0 + /// Convert the builder into a graph. + /// + /// This is the purpose of having a builder. + pub fn build(self) -> SLGraph<S, T> { + let nodes = self + .nodes + .into_iter() + .map(SLBNode::into_boxed) + .collect::<Vec<_>>() + .into_boxed_slice(); + + SLGraph { nodes } } } @@ -408,15 +852,15 @@ mod simple_test { use std::collections::BTreeSet as Set; macro_rules! set { - () => { Set::<usize>::default() }; - ($($num:literal),*) => { - { - let mut set: Set<usize> = Set::default(); - $(set.insert($num);)* - set - } - }; - } + () => { Set::<usize>::default() }; + ($($num:literal),*) => { + { + let mut set: Set<usize> = Set::default(); + $(set.insert($num);)* + set + } + }; +} // macro_rules! map { // () => { Map::<usize, Set<usize>>::default() }; @@ -431,30 +875,36 @@ mod simple_test { #[test] fn test_graph_apis() -> Result<(), Error> { - let mut graph: SLGraph<usize> = Default::default(); + let mut builder: SLGBuilder<usize, usize> = Default::default(); // testing empty graph - assert!(graph.is_empty()); + assert!(builder.is_empty()); // testing adding an empty node - assert_eq!(graph.extend(std::iter::empty())?, 0); + assert_eq!(builder.extend(0, std::iter::empty())?, 0); // testing nodes_len - assert_eq!(graph.nodes_len(), 1); + assert_eq!(builder.nodes_len(), 1); // testing extension - assert_eq!(graph.extend([(0, 0)].iter().copied())?, 1); - assert_eq!(graph.extend([(1, 0), (1, 1)].iter().copied())?, 2); - assert_eq!(graph.extend([(3, 0), (3, 2)].iter().copied())?, 3); - assert_eq!(graph.extend([(1, 1), (1, 2)].iter().copied())?, 4); - assert_eq!(graph.extend([(2, 1), (3, 2), (2, 3)].iter().copied())?, 5); + assert_eq!(builder.extend(1, [(0, 0)].iter().copied())?, 1); + assert_eq!(builder.extend(2, [(1, 0), (1, 1)].iter().copied())?, 2); + assert_eq!(builder.extend(3, [(3, 0), (3, 2)].iter().copied())?, 3); + assert_eq!(builder.extend(4, [(1, 1), (1, 2)].iter().copied())?, 4); + assert_eq!( + builder.extend(5, [(2, 1), (3, 2), (2, 3)].iter().copied())?, + 5 + ); // testing adding a duplicated edge set - assert_eq!(graph.extend([(2, 1), (2, 3), (3, 2)].iter().copied())?, 6); - assert_eq!(graph.extend([(3, 2), (3, 0)].iter().copied())?, 7); + assert_eq!( + builder.extend(6, [(2, 1), (2, 3), (3, 2)].iter().copied())?, + 6 + ); + assert_eq!(builder.extend(7, [(3, 2), (3, 0)].iter().copied())?, 7); - let graph = graph; + let graph = builder.build(); // ensuring the correct length assert_eq!(graph.nodes_len(), 8); @@ -500,14 +950,10 @@ mod test_slgraph_builder { #[test] fn test_builder() -> Result<(), Box<dyn std::error::Error>> { - let mut builder = SLGBuilder::<usize>::default(); + let mut builder = SLGBuilder::<usize, usize>::default(); // Add five nodes - builder.add_vertex(); - builder.add_vertex(); - builder.add_vertex(); - builder.add_vertex(); - builder.add_vertex(); + builder.add_vertices(0..5); // Link each node to its successor and link the last node with // the first one to form a cycle. @@ -529,14 +975,10 @@ mod test_slgraph_builder { #[test] fn test_errors() -> Result<(), Box<dyn std::error::Error>> { - let mut builder = SLGBuilder::default(); + let mut builder = SLGBuilder::<usize, usize>::default(); // Add five nodes - builder.add_vertex(); - builder.add_vertex(); - builder.add_vertex(); - builder.add_vertex(); - builder.add_vertex(); + builder.add_vertices(0..5); // Errors in add_edge diff --git a/graph/src/lib.rs b/graph/src/lib.rs index 058d62c..36fc545 100644 --- a/graph/src/lib.rs +++ b/graph/src/lib.rs @@ -22,6 +22,7 @@ pub use adlist::ALGraph; pub mod labelled; +pub use labelled::simple::{SLGBuilder, SLGraph}; pub use labelled::DLGraph; pub use labelled::PLGraph; @@ -29,6 +30,8 @@ pub mod builder; pub use builder::Builder; +pub mod dfs; + use error::Error; /// The expected behaviour of an immutable graph. @@ -138,6 +141,7 @@ pub trait Graph: Default { let mut file = std::fs::File::options() .write(true) .create(true) + .truncate(true) .open(filename)?; use std::io::Write; @@ -290,8 +294,8 @@ pub trait RedirectGraph: Graph { /// This trait defines some convenient methods for accessing the /// labels of vertices. pub trait VLabelGraph<T: GraphLabel>: Graph { - /// A type that iterates through tuples of labels and targets of - /// edges. + /// A type that iterates through tuples of target labels and + /// target indices of edges. type TupleIter<'a>: Iterator<Item = (T, usize)> + 'a where Self: 'a, @@ -321,13 +325,55 @@ pub trait VLabelGraph<T: GraphLabel>: Graph { } /// Return an iterator of tuples of vertex labels and indices of - /// targets edges out of a node. + /// targets for edges out of a node. /// /// The name is a weird new word created to stand as a /// simplification of the phrase "vertex label and children of". fn verlabren_of(&self, node_id: usize) -> Result<Self::TupleIter<'_>, Error>; } +/// A graph whose edges are associated with labels. +/// +/// This trait defines some convenient methods for accessing the +/// labels of edges. +pub trait ELabelGraph<T: GraphLabel>: Graph { + /// A type that iterates through tuples of edge labels and target + /// indices of edges. + type TupleIter<'a>: Iterator<Item = (T, usize)> + 'a + where + Self: 'a, + T: 'a; + + #[inline] + /// Return the label of an edge or an error if the node is + /// invalid. + /// + /// The default implementation always returns `None` after + /// checking the validity of the edge. + fn edge_label(&self, from: usize, to: usize) -> Result<Option<T>, Error> { + self.has_edge(from, to).map(|_| None) + } + + /// Return an iterator of tuples of edge labels and indices of + /// targets for edges out of a node. + /// + /// The name is a weird new word created to stand as a + /// simplification of the phrase "edge label and children of". + fn edlabren_of(&self, node_id: usize) -> Result<Self::TupleIter<'_>, Error>; +} + +impl<T: GraphLabel, G: LabelGraph<T>> ELabelGraph<T> for G { + type TupleIter<'a> = <G as LabelGraph<T>>::TupleIter<'a> + where + Self: 'a, + T: 'a; + + #[inline] + fn edlabren_of(&self, node_id: usize) -> Result<Self::TupleIter<'_>, Error> { + LabelGraph::tuples_of(self, node_id) + } +} + /// A labelled graph is just a graph with labels associated to /// vertices and / or edges. /// |
