aboutsummaryrefslogtreecommitdiff
path: root/graph/src/labelled/simple.rs
diff options
context:
space:
mode:
authorJSDurand <mmemmew@gmail.com>2026-10-16 14:01:01 +0800
committerJSDurand <mmemmew@gmail.com>2026-10-16 14:02:10 +0800
commitfba9a90cfc6aca2a26cce72f55fb261789139781 (patch)
treeb4b121791ad639e745df689c0d5a8ed7a9e5dcc4 /graph/src/labelled/simple.rs
parent3ae0cf9898485a2ec35df7d23cd274e7dea5796d (diff)
new startHEADmaster
Now I tested and discussed with claude, and had a working version of this project. The rest is to port the claude version to my own writings. So this serves as the starting point before that attempt. In the new attempt the design is better, and a number of bugs were found and supposedly fixed, so let us see how this goes at the end.
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