aboutsummaryrefslogtreecommitdiff
path: root/graph/src/labelled/simple.rs
diff options
context:
space:
mode:
Diffstat (limited to 'graph/src/labelled/simple.rs')
-rw-r--r--graph/src/labelled/simple.rs612
1 files changed, 527 insertions, 85 deletions
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