use std::borrow::Cow;
use crate::{
utils::graph::{
edge::EdgeId,
node::NodeId,
traits::{GraphBase, Predecessors, Successors},
},
Error, Result,
};
#[derive(Debug, Clone)]
struct EdgeData<E> {
source: NodeId,
target: NodeId,
data: E,
}
#[derive(Debug, Clone)]
pub struct DirectedGraph<'a, N: Clone, E> {
nodes: Cow<'a, [N]>,
edges: Vec<EdgeData<E>>,
outgoing: Vec<Vec<EdgeId>>,
incoming: Vec<Vec<EdgeId>>,
}
impl<N: Clone, E> Default for DirectedGraph<'static, N, E> {
fn default() -> Self {
Self::new()
}
}
impl<N: Clone, E> DirectedGraph<'static, N, E> {
#[must_use]
pub fn new() -> Self {
DirectedGraph {
nodes: Cow::Owned(Vec::new()),
edges: Vec::new(),
outgoing: Vec::new(),
incoming: Vec::new(),
}
}
#[must_use]
pub fn with_capacity(node_capacity: usize, edge_capacity: usize) -> Self {
DirectedGraph {
nodes: Cow::Owned(Vec::with_capacity(node_capacity)),
edges: Vec::with_capacity(edge_capacity),
outgoing: Vec::with_capacity(node_capacity),
incoming: Vec::with_capacity(node_capacity),
}
}
pub fn add_node(&mut self, data: N) -> NodeId {
let id = NodeId::new(self.nodes.len());
self.nodes.to_mut().push(data);
self.outgoing.push(Vec::new());
self.incoming.push(Vec::new());
id
}
pub fn node_mut(&mut self, node: NodeId) -> Option<&mut N> {
self.nodes.to_mut().get_mut(node.index())
}
}
impl<'a, N: Clone, E> DirectedGraph<'a, N, E> {
#[must_use]
pub fn from_nodes_borrowed(nodes: &'a [N]) -> Self {
let node_count = nodes.len();
DirectedGraph {
nodes: Cow::Borrowed(nodes),
edges: Vec::new(),
outgoing: vec![Vec::new(); node_count],
incoming: vec![Vec::new(); node_count],
}
}
#[must_use]
pub fn into_owned(self) -> DirectedGraph<'static, N, E> {
DirectedGraph {
nodes: Cow::Owned(self.nodes.into_owned()),
edges: self.edges,
outgoing: self.outgoing,
incoming: self.incoming,
}
}
#[must_use]
pub fn is_owned(&self) -> bool {
matches!(self.nodes, Cow::Owned(_))
}
#[must_use]
pub fn node(&self, node: NodeId) -> Option<&N> {
self.nodes.get(node.index())
}
#[must_use]
pub fn node_count(&self) -> usize {
self.nodes.len()
}
pub fn node_ids(&self) -> impl Iterator<Item = NodeId> + '_ {
(0..self.nodes.len()).map(NodeId::new)
}
pub fn nodes(&self) -> impl Iterator<Item = (NodeId, &N)> + '_ {
self.nodes
.iter()
.enumerate()
.map(|(i, data)| (NodeId::new(i), data))
}
pub fn add_edge(&mut self, source: NodeId, target: NodeId, data: E) -> Result<EdgeId> {
if source.index() >= self.nodes.len() {
return Err(Error::GraphError(format!(
"source node {} does not exist in graph with {} nodes",
source,
self.nodes.len()
)));
}
if target.index() >= self.nodes.len() {
return Err(Error::GraphError(format!(
"target node {} does not exist in graph with {} nodes",
target,
self.nodes.len()
)));
}
let id = EdgeId::new(self.edges.len());
self.edges.push(EdgeData {
source,
target,
data,
});
self.outgoing[source.index()].push(id);
self.incoming[target.index()].push(id);
Ok(id)
}
#[must_use]
pub fn edge(&self, edge: EdgeId) -> Option<&E> {
self.edges.get(edge.index()).map(|e| &e.data)
}
pub fn edge_mut(&mut self, edge: EdgeId) -> Option<&mut E> {
self.edges.get_mut(edge.index()).map(|e| &mut e.data)
}
#[must_use]
pub fn edge_endpoints(&self, edge: EdgeId) -> Option<(NodeId, NodeId)> {
self.edges.get(edge.index()).map(|e| (e.source, e.target))
}
#[must_use]
pub fn edge_count(&self) -> usize {
self.edges.len()
}
pub fn edge_ids(&self) -> impl Iterator<Item = EdgeId> + '_ {
(0..self.edges.len()).map(EdgeId::new)
}
pub fn edges(&self) -> impl Iterator<Item = (EdgeId, &E)> + '_ {
self.edges
.iter()
.enumerate()
.map(|(i, e)| (EdgeId::new(i), &e.data))
}
pub fn successors(&self, node: NodeId) -> impl Iterator<Item = NodeId> + '_ {
self.outgoing[node.index()]
.iter()
.map(|&edge_id| self.edges[edge_id.index()].target)
}
pub fn predecessors(&self, node: NodeId) -> impl Iterator<Item = NodeId> + '_ {
self.incoming[node.index()]
.iter()
.map(|&edge_id| self.edges[edge_id.index()].source)
}
pub fn outgoing_edges(&self, node: NodeId) -> impl Iterator<Item = (EdgeId, &E)> + '_ {
self.outgoing[node.index()]
.iter()
.map(|&edge_id| (edge_id, &self.edges[edge_id.index()].data))
}
pub fn incoming_edges(&self, node: NodeId) -> impl Iterator<Item = (EdgeId, &E)> + '_ {
self.incoming[node.index()]
.iter()
.map(|&edge_id| (edge_id, &self.edges[edge_id.index()].data))
}
#[must_use]
pub fn out_degree(&self, node: NodeId) -> usize {
self.outgoing[node.index()].len()
}
#[must_use]
pub fn in_degree(&self, node: NodeId) -> usize {
self.incoming[node.index()].len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn entry_nodes(&self) -> impl Iterator<Item = NodeId> + '_ {
self.node_ids().filter(|&node| self.in_degree(node) == 0)
}
pub fn exit_nodes(&self) -> impl Iterator<Item = NodeId> + '_ {
self.node_ids().filter(|&node| self.out_degree(node) == 0)
}
#[must_use]
pub fn contains_node(&self, node: NodeId) -> bool {
node.index() < self.nodes.len()
}
#[must_use]
pub fn contains_edge(&self, edge: EdgeId) -> bool {
edge.index() < self.edges.len()
}
}
impl<N: Clone, E> GraphBase for DirectedGraph<'_, N, E> {
fn node_count(&self) -> usize {
self.nodes.len()
}
fn node_ids(&self) -> impl Iterator<Item = NodeId> {
(0..self.nodes.len()).map(NodeId::new)
}
}
impl<N: Clone, E> Successors for DirectedGraph<'_, N, E> {
fn successors(&self, node: NodeId) -> impl Iterator<Item = NodeId> {
self.outgoing[node.index()]
.iter()
.map(|&edge_id| self.edges[edge_id.index()].target)
}
}
impl<N: Clone, E> Predecessors for DirectedGraph<'_, N, E> {
fn predecessors(&self, node: NodeId) -> impl Iterator<Item = NodeId> {
self.incoming[node.index()]
.iter()
.map(|&edge_id| self.edges[edge_id.index()].source)
}
}
#[cfg(test)]
mod tests {
use crate::utils::graph::{
directed::DirectedGraph,
edge::EdgeId,
node::NodeId,
traits::{GraphBase, Predecessors, Successors},
};
fn create_linear_graph() -> DirectedGraph<'static, &'static str, ()> {
let mut graph = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
graph.add_edge(a, b, ()).unwrap();
graph.add_edge(b, c, ()).unwrap();
graph
}
fn create_diamond_graph() -> DirectedGraph<'static, &'static str, ()> {
let mut graph = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
let d = graph.add_node("D");
graph.add_edge(a, b, ()).unwrap();
graph.add_edge(a, c, ()).unwrap();
graph.add_edge(b, d, ()).unwrap();
graph.add_edge(c, d, ()).unwrap();
graph
}
fn create_cycle_graph() -> DirectedGraph<'static, &'static str, ()> {
let mut graph = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
graph.add_edge(a, b, ()).unwrap();
graph.add_edge(b, c, ()).unwrap();
graph.add_edge(c, a, ()).unwrap();
graph
}
#[test]
fn test_new_graph_is_empty() {
let graph: DirectedGraph<(), ()> = DirectedGraph::new();
assert!(graph.is_empty());
assert_eq!(graph.node_count(), 0);
assert_eq!(graph.edge_count(), 0);
}
#[test]
fn test_with_capacity() {
let graph: DirectedGraph<i32, i32> = DirectedGraph::with_capacity(100, 200);
assert!(graph.is_empty());
}
#[test]
fn test_default() {
let graph: DirectedGraph<(), ()> = DirectedGraph::default();
assert!(graph.is_empty());
}
#[test]
fn test_add_node() {
let mut graph: DirectedGraph<&str, ()> = DirectedGraph::new();
let a = graph.add_node("A");
assert_eq!(a, NodeId::new(0));
assert_eq!(graph.node_count(), 1);
let b = graph.add_node("B");
assert_eq!(b, NodeId::new(1));
assert_eq!(graph.node_count(), 2);
}
#[test]
fn test_node_access() {
let mut graph: DirectedGraph<&str, ()> = DirectedGraph::new();
let a = graph.add_node("hello");
assert_eq!(graph.node(a), Some(&"hello"));
assert_eq!(graph.node(NodeId::new(999)), None);
}
#[test]
fn test_node_mut() {
let mut graph: DirectedGraph<String, ()> = DirectedGraph::new();
let a = graph.add_node(String::from("hello"));
if let Some(data) = graph.node_mut(a) {
data.push_str(" world");
}
assert_eq!(graph.node(a), Some(&String::from("hello world")));
}
#[test]
fn test_node_ids_iterator() {
let mut graph: DirectedGraph<char, ()> = DirectedGraph::new();
graph.add_node('A');
graph.add_node('B');
graph.add_node('C');
let ids: Vec<NodeId> = graph.node_ids().collect();
assert_eq!(ids, vec![NodeId::new(0), NodeId::new(1), NodeId::new(2)]);
}
#[test]
fn test_nodes_iterator() {
let mut graph: DirectedGraph<&str, ()> = DirectedGraph::new();
graph.add_node("A");
graph.add_node("B");
let nodes: Vec<(NodeId, &&str)> = graph.nodes().collect();
assert_eq!(nodes.len(), 2);
assert_eq!(nodes[0], (NodeId::new(0), &"A"));
assert_eq!(nodes[1], (NodeId::new(1), &"B"));
}
#[test]
fn test_add_edge() {
let mut graph: DirectedGraph<&str, &str> = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let edge = graph.add_edge(a, b, "A->B").unwrap();
assert_eq!(edge, EdgeId::new(0));
assert_eq!(graph.edge_count(), 1);
}
#[test]
fn test_edge_access() {
let mut graph: DirectedGraph<(), &str> = DirectedGraph::new();
let a = graph.add_node(());
let b = graph.add_node(());
let edge = graph.add_edge(a, b, "label").unwrap();
assert_eq!(graph.edge(edge), Some(&"label"));
assert_eq!(graph.edge(EdgeId::new(999)), None);
}
#[test]
fn test_edge_endpoints() {
let mut graph: DirectedGraph<&str, ()> = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let edge = graph.add_edge(a, b, ()).unwrap();
assert_eq!(graph.edge_endpoints(edge), Some((a, b)));
assert_eq!(graph.edge_endpoints(EdgeId::new(999)), None);
}
#[test]
fn test_multiple_edges() {
let mut graph: DirectedGraph<&str, i32> = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let e1 = graph.add_edge(a, b, 1).unwrap();
let e2 = graph.add_edge(a, b, 2).unwrap();
assert_eq!(graph.edge_count(), 2);
assert_eq!(graph.edge(e1), Some(&1));
assert_eq!(graph.edge(e2), Some(&2));
}
#[test]
fn test_self_loop() {
let mut graph: DirectedGraph<&str, ()> = DirectedGraph::new();
let a = graph.add_node("A");
let edge = graph.add_edge(a, a, ()).unwrap();
assert_eq!(graph.edge_endpoints(edge), Some((a, a)));
assert_eq!(graph.out_degree(a), 1);
assert_eq!(graph.in_degree(a), 1);
}
#[test]
fn test_add_edge_invalid_source() {
let mut graph: DirectedGraph<(), ()> = DirectedGraph::new();
let a = graph.add_node(());
let result = graph.add_edge(NodeId::new(999), a, ());
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("source node"));
}
#[test]
fn test_add_edge_invalid_target() {
let mut graph: DirectedGraph<(), ()> = DirectedGraph::new();
let a = graph.add_node(());
let result = graph.add_edge(a, NodeId::new(999), ());
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("target node"));
}
#[test]
fn test_successors() {
let graph = create_diamond_graph();
let a = NodeId::new(0);
let successors: Vec<NodeId> = graph.successors(a).collect();
assert_eq!(successors.len(), 2);
assert!(successors.contains(&NodeId::new(1))); assert!(successors.contains(&NodeId::new(2))); }
#[test]
fn test_predecessors() {
let graph = create_diamond_graph();
let d = NodeId::new(3);
let predecessors: Vec<NodeId> = graph.predecessors(d).collect();
assert_eq!(predecessors.len(), 2);
assert!(predecessors.contains(&NodeId::new(1))); assert!(predecessors.contains(&NodeId::new(2))); }
#[test]
fn test_outgoing_edges() {
let mut graph: DirectedGraph<&str, i32> = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
graph.add_edge(a, b, 10).unwrap();
graph.add_edge(a, c, 20).unwrap();
let outgoing: Vec<(EdgeId, &i32)> = graph.outgoing_edges(a).collect();
assert_eq!(outgoing.len(), 2);
let weights: Vec<i32> = outgoing.iter().map(|(_, &w)| w).collect();
assert!(weights.contains(&10));
assert!(weights.contains(&20));
}
#[test]
fn test_incoming_edges() {
let mut graph: DirectedGraph<&str, i32> = DirectedGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
graph.add_edge(a, c, 10).unwrap();
graph.add_edge(b, c, 20).unwrap();
let incoming: Vec<(EdgeId, &i32)> = graph.incoming_edges(c).collect();
assert_eq!(incoming.len(), 2);
}
#[test]
fn test_out_degree() {
let graph = create_diamond_graph();
assert_eq!(graph.out_degree(NodeId::new(0)), 2); assert_eq!(graph.out_degree(NodeId::new(1)), 1); assert_eq!(graph.out_degree(NodeId::new(3)), 0); }
#[test]
fn test_in_degree() {
let graph = create_diamond_graph();
assert_eq!(graph.in_degree(NodeId::new(0)), 0); assert_eq!(graph.in_degree(NodeId::new(1)), 1); assert_eq!(graph.in_degree(NodeId::new(3)), 2); }
#[test]
fn test_entry_nodes() {
let graph = create_diamond_graph();
let entries: Vec<NodeId> = graph.entry_nodes().collect();
assert_eq!(entries.len(), 1);
assert_eq!(entries[0], NodeId::new(0)); }
#[test]
fn test_exit_nodes() {
let graph = create_diamond_graph();
let exits: Vec<NodeId> = graph.exit_nodes().collect();
assert_eq!(exits.len(), 1);
assert_eq!(exits[0], NodeId::new(3)); }
#[test]
fn test_entry_nodes_with_cycle() {
let graph = create_cycle_graph();
let entries: Vec<NodeId> = graph.entry_nodes().collect();
assert!(entries.is_empty());
}
#[test]
fn test_contains_node() {
let mut graph: DirectedGraph<(), ()> = DirectedGraph::new();
let a = graph.add_node(());
assert!(graph.contains_node(a));
assert!(!graph.contains_node(NodeId::new(999)));
}
#[test]
fn test_contains_edge() {
let mut graph: DirectedGraph<(), ()> = DirectedGraph::new();
let a = graph.add_node(());
let b = graph.add_node(());
let edge = graph.add_edge(a, b, ()).unwrap();
assert!(graph.contains_edge(edge));
assert!(!graph.contains_edge(EdgeId::new(999)));
}
#[test]
fn test_graph_clone() {
let original = create_diamond_graph();
let cloned = original.clone();
assert_eq!(original.node_count(), cloned.node_count());
assert_eq!(original.edge_count(), cloned.edge_count());
for node_id in original.node_ids() {
assert_eq!(original.node(node_id), cloned.node(node_id));
}
}
#[test]
fn test_graph_base_trait() {
fn use_graph_base<G: GraphBase>(g: &G) -> usize {
g.node_count()
}
let graph = create_linear_graph();
assert_eq!(use_graph_base(&graph), 3);
}
#[test]
fn test_successors_trait() {
fn use_successors<G: Successors>(g: &G, node: NodeId) -> Vec<NodeId> {
g.successors(node).collect()
}
let graph = create_linear_graph();
let successors = use_successors(&graph, NodeId::new(0));
assert_eq!(successors, vec![NodeId::new(1)]);
}
#[test]
fn test_predecessors_trait() {
fn use_predecessors<G: Predecessors>(g: &G, node: NodeId) -> Vec<NodeId> {
g.predecessors(node).collect()
}
let graph = create_linear_graph();
let predecessors = use_predecessors(&graph, NodeId::new(2));
assert_eq!(predecessors, vec![NodeId::new(1)]);
}
#[test]
fn test_large_graph() {
let mut graph: DirectedGraph<usize, ()> = DirectedGraph::with_capacity(1000, 2000);
for i in 0..1000 {
graph.add_node(i);
}
for i in 0..999 {
graph
.add_edge(NodeId::new(i), NodeId::new(i + 1), ())
.unwrap();
}
assert_eq!(graph.node_count(), 1000);
assert_eq!(graph.edge_count(), 999);
assert_eq!(graph.out_degree(NodeId::new(0)), 1);
assert_eq!(graph.out_degree(NodeId::new(999)), 0);
assert_eq!(graph.in_degree(NodeId::new(0)), 0);
assert_eq!(graph.in_degree(NodeId::new(999)), 1);
}
}