//! Core traits for undirected graph topologies. use crate::maps::{EdgeMap, VertexMap}; // TODO: Add functions to reserve memory for vertices and edges. // TODO: Split out GraphTopologyAddition trait. // TODO: Introduce an Incidence struct. /// A trait representing an undirected graph topology. /// /// An undirected graph is a set of vertices and undirected edges, where each edge connects either /// exactly two vertices or one vertex with itself (loop edge). This trait provides methods for /// querying a graph topology, iterating over vertices and edges, and adding new vertices and edges. /// /// # Vertices and edges /// /// Vertices and edges are identified by opaque handles ([`Vertex`] and [`Edge`]) that implement /// [`Copy`] and [`Eq`]. Handles remain valid for the lifetime of the graph unless the graph also /// implements [`GraphTopologyDeletion`] and the item identified by the handle is explicitly /// deleted. /// /// Methods accepting vertices or edges as parameters panic if the handle was invalidated by a /// deletion, and return incorrect results if the handle was not produced by this graph instance. /// /// # Deletion /// /// This trait covers graph construction and querying only. To delete vertices and edges, see /// [`GraphTopologyDeletion`]. /// /// [`Edge`]: GraphTopology::Edge /// [`Vertex`]: GraphTopology::Vertex pub trait GraphTopology { /// An opaque, stable handle identifying a vertex. type Vertex: Copy + Eq; /// An opaque, stable handle identifying an edge. type Edge: Copy + Eq; /// A resumable position in the incidence list of a vertex. /// /// Prefer [`incidences`](Self::incidences) for straightforward iteration. A cursor is useful /// when an algorithm needs to pause traversal, perform other graph queries or mutations, and /// then continue from where it left off. This cursor type can be obtained via /// [`incidence_cursor`](Self::incidence_cursor). type IncidenceCursor: IncidenceCursor + Copy; /// Returns the number of vertices in the graph. fn vertex_count(&self) -> usize; /// Returns the total number of vertices the graph can hold without reallocating. fn vertex_capacity(&self) -> usize; /// Creates and returns a [`VertexMap`] with every slot initialised to `default`. /// /// # Examples /// /// ``` /// # use grapherity::prelude::*; /// # use grapherity::models::Graph; /// let mut graph = Graph::new(); /// let v1 = graph.add_vertex(); /// let mut labels = graph.vertex_map("z"); /// assert_eq!(labels[v1], "z"); /// labels[v1] = "a"; /// assert_eq!(labels[v1], "a"); /// /// // A new vertex is immediately available for read and write. /// let v2 = graph.add_vertex(); /// assert_eq!(labels[v2], "z"); /// labels[v2] = "b"; /// assert_eq!(labels[v2], "b"); /// ``` fn vertex_map(&self, default: T) -> VertexMap; /// Returns the number of edges in the graph. fn edge_count(&self) -> usize; /// Returns the total number of edges the graph can hold without reallocating. fn edge_capacity(&self) -> usize; /// Creates and returns an [`EdgeMap`] with every slot initialised to `default`. /// /// # Examples /// /// ``` /// # use grapherity::prelude::*; /// # use grapherity::models::Graph; /// let mut graph = Graph::new(); /// let v1 = graph.add_vertex(); /// let v2 = graph.add_vertex(); /// let e1 = graph.add_edge(v1, v2); /// let mut weights = graph.edge_map(5); /// assert_eq!(weights[e1], 5); /// weights[e1] = 1; /// assert_eq!(weights[e1], 1); /// /// // A new edge is immediately available for read and write. /// let e2 = graph.add_edge(v1, v2); /// assert_eq!(weights[e2], 5); /// weights[e2] = 2; /// assert_eq!(weights[e2], 2); /// ``` fn edge_map(&self, default: T) -> EdgeMap; /// Returns the degree of `v`, i.e. the number of incident edges, where each loop contributes 2. /// /// # Panics /// /// Panics if `v` is not a valid vertex of this graph. fn degree(&self, v: Self::Vertex) -> usize; /// Returns `true` if there is at least one edge between `v1` and `v2`, and `false` otherwise. /// /// A vertex is adjacent to itself if and only if it has a loop edge. /// /// # Panics /// /// Panics if `v1` or `v2` is not a valid vertex of this graph. fn are_adjacent(&self, v1: Self::Vertex, v2: Self::Vertex) -> bool; /// Returns an iterator over all vertices in the graph. fn vertices(&self) -> impl Iterator; /// Returns an iterator over all vertices adjacent to `v`. /// /// Algorithms may prefer this over [`incidences`](Self::incidences) if the edges are not /// required, since implementors may be able to provide an iterator faster than the trivial /// mapping. The complexity of this method must not exceed that of /// [`incidences`](Self::incidences). /// /// # Panics /// /// Panics if `v` is not a valid vertex of this graph. fn adjacent_vertices(&self, v: Self::Vertex) -> impl Iterator; /// Returns the two endpoints of edge `e`, which are identical if and only if `e` is a loop /// edge. /// /// # Panics /// /// Panics if `e` is not a valid edge of this graph. fn incident_vertices(&self, e: Self::Edge) -> (Self::Vertex, Self::Vertex); /// Returns an iterator over all edges in the graph. fn edges(&self) -> impl Iterator; /// Returns an iterator over all edges incident to `v`. /// /// Algorithms may prefer this over [`incidences`](Self::incidences) if the vertices are not /// required, since implementors may be able to provide an iterator faster than the trivial /// mapping. The complexity of this method must not exceed that of /// [`incidences`](Self::incidences). /// /// # Panics /// /// Panics if `v` is not a valid vertex of this graph. fn incident_edges(&self, v: Self::Vertex) -> impl Iterator; /// Returns an iterator over all incidences of `v`, i.e. vertex-edge pairs `(u, e)` such that /// `u` is adjacent to `v` and `e` is an edge between them. /// /// Use [`incidence_cursor`](Self::incidence_cursor) instead for a traversal that needs to /// suspend and resume across other state updates. /// /// # Panics /// /// Panics if `v` is not a valid vertex of this graph. fn incidences(&self, v: Self::Vertex) -> impl Iterator; /// Returns a cursor over all incidences of `v`, analogously to /// [`incidences`](Self::incidences), initially positioned before the first one. /// /// See [`IncidenceCursor`](Self::IncidenceCursor) for when to prefer a cursor over /// [`incidences`](Self::incidences). /// /// # Panics /// /// Panics if `v` is not a valid vertex of this graph. fn incidence_cursor(&self, v: Self::Vertex) -> Self::IncidenceCursor; /// Adds a new isolated vertex and returns its handle. fn add_vertex(&mut self) -> Self::Vertex; /// Adds a new edge between `v1` and `v2` and returns its handle. /// /// # Panics /// /// Panics if `v1` or `v2` is not a valid vertex of this graph. fn add_edge(&mut self, v1: Self::Vertex, v2: Self::Vertex) -> Self::Edge; } /// A trait that adds deletion operations to an undirected graph topology. /// /// This trait provides methods for deletion of vertices and edges in an undirected graph. These /// operations will invalidate handles to all deleted vertices and edges. Methods accepting invalid /// vertices or edges as parameters panic. pub trait GraphTopologyDeletion: GraphTopology { /// Deletes the vertex `v` and all its incident edges from the graph. Note that this also /// invalidates the handles of all edges incident to `v`. /// /// # Panics /// /// Panics if `v` is not a valid vertex of this graph. fn delete_vertex(&mut self, v: Self::Vertex); /// Deletes the edge `e` from the graph. This operation only invalidates `e` and no other vertex /// or edge handles. /// /// # Panics /// /// Panics if `e` is not a valid edge of this graph. fn delete_edge(&mut self, e: Self::Edge); } /// A cursor for traversing the incidences of a vertex one step at a time. /// /// Cursors are obtained via [`GraphTopology::incidence_cursor`]. See /// [`GraphTopology::IncidenceCursor`] for guidance on when to prefer a cursor over /// [`GraphTopology::incidences`]. pub trait IncidenceCursor { /// Advances the cursor and returns the next incidence as `Some((u, e))`, or `None` if the /// traversal is exhausted. /// /// # Examples /// /// ``` /// # use grapherity::prelude::*; /// # use grapherity::models::Graph; /// # use grapherity::traits::IncidenceCursor; /// // Constructs a graph with two vertices connected to `v`. /// let mut graph = Graph::new(); /// let v = graph.add_vertex(); /// for _ in 0..2 { /// let u = graph.add_vertex(); /// graph.add_edge(u, v); /// } /// /// // Iterates over the incidences of `v` with a cursor. /// let mut c1 = graph.incidence_cursor(v); /// assert!(c1.next(&graph).is_some()); /// let mut c2 = c1; /// // Continues iteration with original cursor. /// assert!(c1.next(&graph).is_some()); /// assert!(c1.next(&graph).is_none()); /// // Iterates over the last incidence again with the copied cursor. /// assert!(c2.next(&graph).is_some()); /// assert!(c2.next(&graph).is_none()); /// ``` fn next(&mut self, graph: &G) -> Option<(G::Vertex, G::Edge)>; }