#![warn(missing_docs)] //! This file implements a data type that implements the trait //! [`Graph`][super::Graph]. This data type represents graphs using //! adjacency lists internally. use super::{ExtGraph, Graph}; use crate::error::Error; // #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] // struct ALEdge { // to: usize, // } // impl ALEdge { // fn new(to: usize) -> Self { // Self { to } // } // } #[derive(Debug, Clone, Default)] struct ALNode { children: Vec, } impl ALNode { fn new(children: Vec) -> Self { Self { children } } } /// The graph implemented using adjacency lists. #[derive(Debug, Clone, Default)] pub struct ALGraph { nodes: Vec, } impl Graph for ALGraph { type Iter<'a> = std::iter::Copied>; #[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, Error> { match self.nodes.get(node_id) { Some(node) => Ok(node.children.iter().copied()), None => Err(Error::IndexOutOfBounds(node_id, self.nodes_len())), } } #[inline] fn degree(&self, node_id: usize) -> Result { match self.nodes.get(node_id) { Some(node) => Ok(node.children.len()), None => Err(Error::IndexOutOfBounds(node_id, self.nodes_len())), } } #[inline] fn is_empty_node(&self, node_id: usize) -> Result { match self.nodes.get(node_id) { Some(node) => Ok(node.children.is_empty()), None => Err(Error::IndexOutOfBounds(node_id, self.nodes_len())), } } fn has_edge(&self, source: usize, target: usize) -> Result { if !self.has_node(source) { Err(Error::IndexOutOfBounds(source, self.nodes_len())) } else if !self.has_node(target) { Err(Error::IndexOutOfBounds(target, self.nodes_len())) } else { Ok(self.nodes.get(source).unwrap().children.contains(&target)) } } } impl ExtGraph for ALGraph { fn extend(&mut self, edges: impl IntoIterator) -> Result { let mut new_node_children = Vec::new(); for edge_to in edges.into_iter() { if !self.has_node(edge_to) { return Err(Error::IndexOutOfBounds(edge_to, self.nodes_len())); } new_node_children.push(edge_to); } let new_node = ALNode::new(new_node_children); self.nodes.push(new_node); Ok(self.nodes.len() - 1) } } // TODO: Add a way to build a graph by its raw adjacency list representation. impl From>> for ALGraph { fn from(adlist: Vec>) -> Self { let nodes: Vec = adlist.iter().cloned().map(ALNode::new).collect(); Self { nodes } } } #[cfg(test)] mod algraph_test { use super::*; #[test] fn test_graph_apis() -> Result<(), Error> { let mut graph = ALGraph::default(); assert!(graph.is_empty()); graph.extend(std::iter::empty())?; graph.extend([0].iter().copied())?; graph.extend([0, 1].iter().copied())?; graph.extend([0, 2].iter().copied())?; graph.extend([1, 2].iter().copied())?; graph.extend([1, 2, 3].iter().copied())?; let graph = graph; assert_eq!(graph.nodes_len(), 6); assert_eq!(graph.children_of(5)?.collect::>(), vec![1, 2, 3]); assert_eq!(graph.degree(4)?, 2); assert!(graph.is_empty_node(0)?); assert!(!graph.is_empty_node(1)?); assert!(graph.has_edge(3, 2)?); assert!(!graph.has_edge(3, 1)?); assert_eq!(graph.has_edge(3, 6), Err(Error::IndexOutOfBounds(6, 6))); Ok(()) } #[test] fn test_extending_algraph_normal() -> Result<(), Error> { let mut graph = ALGraph::default(); let new = graph.extend(std::iter::empty())?; println!("new index = {new}"); println!("new graph = {graph:?}"); let new = graph.extend([0].iter().copied())?; println!("new index = {new}"); println!("new graph = {graph:?}"); let new = graph.extend([0, 1].iter().copied())?; println!("new index = {new}"); println!("new graph = {graph:?}"); Ok(()) } #[test] fn test_extending_algraph_error() -> Result<(), Error> { let mut graph = ALGraph::default(); graph.extend(std::iter::empty())?; graph.extend([0].iter().copied())?; assert_eq!( graph.extend([2].iter().copied()), Err(Error::IndexOutOfBounds(2, 2)) ); Ok(()) } }