Documentation updates #6
+209
@@ -2,35 +2,244 @@ use crate::maps::{EdgeMap, VertexMap};
|
|||||||
|
|
||||||
// TODO: Add functions to reserve memory for vertices and edges.
|
// TODO: Add functions to reserve memory for vertices and edges.
|
||||||
// TODO: Split out GraphTopologyAddition trait.
|
// TODO: Split out GraphTopologyAddition trait.
|
||||||
|
/// 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 {
|
pub trait GraphTopology {
|
||||||
|
/// An opaque, stable handle identifying a vertex.
|
||||||
type Vertex: Copy + Eq;
|
type Vertex: Copy + Eq;
|
||||||
|
|
||||||
|
/// An opaque, stable handle identifying an edge.
|
||||||
type Edge: Copy + Eq;
|
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<Self> + Copy;
|
type IncidenceCursor: IncidenceCursor<Self> + Copy;
|
||||||
|
|
||||||
|
/// Returns the number of vertices in the graph.
|
||||||
fn vertex_count(&self) -> usize;
|
fn vertex_count(&self) -> usize;
|
||||||
|
|
||||||
|
/// Returns the total number of vertices the graph can hold without reallocating.
|
||||||
fn vertex_capacity(&self) -> usize;
|
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<T: Clone>(&self, default: T) -> VertexMap<Self::Vertex, T>;
|
fn vertex_map<T: Clone>(&self, default: T) -> VertexMap<Self::Vertex, T>;
|
||||||
|
|
||||||
|
/// Returns the number of edges in the graph.
|
||||||
fn edge_count(&self) -> usize;
|
fn edge_count(&self) -> usize;
|
||||||
|
|
||||||
|
/// Returns the total number of edges the graph can hold without reallocating.
|
||||||
fn edge_capacity(&self) -> usize;
|
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<T: Clone>(&self, default: T) -> EdgeMap<Self::Edge, T>;
|
fn edge_map<T: Clone>(&self, default: T) -> EdgeMap<Self::Edge, T>;
|
||||||
|
|
||||||
|
/// 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;
|
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;
|
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<Item = Self::Vertex>;
|
fn vertices(&self) -> impl Iterator<Item = Self::Vertex>;
|
||||||
|
|
||||||
|
/// 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<Item = Self::Vertex>;
|
fn adjacent_vertices(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Vertex>;
|
||||||
|
|
||||||
|
/// 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);
|
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<Item = Self::Edge>;
|
fn edges(&self) -> impl Iterator<Item = Self::Edge>;
|
||||||
|
|
||||||
|
/// 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<Item = Self::Edge>;
|
fn incident_edges(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Edge>;
|
||||||
|
|
||||||
|
/// 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<Item = (Self::Vertex, Self::Edge)>;
|
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)>;
|
||||||
|
|
||||||
|
/// 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;
|
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;
|
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;
|
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 {
|
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);
|
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);
|
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<G: GraphTopology + ?Sized> {
|
pub trait IncidenceCursor<G: GraphTopology + ?Sized> {
|
||||||
|
/// 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;
|
||||||
|
/// // 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)>;
|
fn next(&mut self, graph: &G) -> Option<(G::Vertex, G::Edge)>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user