MatrixGraph: add missing docs
diff --git a/src/lib.rs b/src/lib.rs
index 6c3f937..4a76111 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,6 +10,9 @@
//! - [`GraphMap`](./graphmap/struct.GraphMap.html) is an adjacency list graph
//! which is backed by a hash table and the node identifiers are the keys
//! into the table.
+//!
+//! - [`MatrixGraph`](./matrix_graph/struct.MatrixGraph.html) is an adjacency matrix graph.
+//!
//! - [`CSR`](./csr/struct.Csr.html) is a sparse adjacency matrix graph with
//! arbitrary associated data.
//!
diff --git a/src/matrix_graph.rs b/src/matrix_graph.rs
index a4f6eaf..e3624e0 100644
--- a/src/matrix_graph.rs
+++ b/src/matrix_graph.rs
@@ -1,3 +1,5 @@
+//! `MatrixGraph<N, E, Ty, Null>` is a graph datastructure backed by an adjacency matrix.
+
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
@@ -45,19 +47,20 @@
// should be reasonably picked.
type Ix = u16;
+/// Node identifier.
pub type NodeIndex = GraphNodeIndex<Ix>;
mod private {
pub trait Sealed {}
- impl<N> Sealed for super::NotZero<N> {}
- impl<N> Sealed for Option<N> {}
+ impl<T> Sealed for super::NotZero<T> {}
+ impl<T> Sealed for Option<T> {}
}
/// Wrapper trait for an `Option`, allowing user-defined structs to be input as containers when
/// defining a null element.
///
-/// Note: this trait currently is sealed and cannot be implemented for types outside this crate.
+/// Note: this trait is currently *sealed* and cannot be implemented for types outside this crate.
pub trait Nullable: Default + Into<Option<<Self as Nullable>::Wrapped>> + private::Sealed {
#[doc(hidden)]
type Wrapped;
@@ -93,22 +96,23 @@
}
}
-/// Struct used to optimize the memory usage of edge weights `E` in a
-/// [`MatrixGraph`](struct.MatrixGraph.html), by using a sentinel value (such as 0 for numeric
-/// types) instead of the default `Option<E>`.
+/// `NotZero` is used to optimize the memory usage of edge weights `E` in a
+/// [`MatrixGraph`](struct.MatrixGraph.html), replacing the default `Option<E>` sentinel.
+///
+/// Pre-requisite: edge weight should implement [`Zero`](trait.Zero.html).
///
/// Note that if you're already using the standard non-zero types (such as `NonZeroU32`), you don't
-/// have to use this wrapper and can leave the default Null type argument.
-pub struct NotZero<N>(N);
+/// have to use this wrapper and can leave the default `Null` type argument.
+pub struct NotZero<T>(T);
-impl<N: Zero> Default for NotZero<N> {
+impl<T: Zero> Default for NotZero<T> {
fn default() -> Self {
- NotZero(N::zero())
+ NotZero(T::zero())
}
}
-impl<N: Zero> Nullable for NotZero<N> {
- type Wrapped = N;
+impl<T: Zero> Nullable for NotZero<T> {
+ type Wrapped = T;
fn new(value: T) -> Self {
assert!(!value.is_zero());
@@ -131,14 +135,14 @@
}
}
-impl<N: Zero> Into<Option<N>> for NotZero<N> {
- fn into(self) -> Option<N> {
+impl<T: Zero> Into<Option<T>> for NotZero<T> {
+ fn into(self) -> Option<T> {
if !self.is_null() { Some(self.0) }
else { None }
}
}
-/// Base trait for types that can be wrapped in a [`NotZero`](trait.NotZero.html).
+/// Base trait for types that can be wrapped in a [`NotZero`](struct.NotZero.html).
///
/// Implementors must provide a singleton object that will be used to mark empty edges in a
/// [`MatrixGraph`](struct.MatrixGraph.html).
@@ -178,12 +182,31 @@
not_zero_impls!(i8, i16, i32, i64, isize);
not_zero_impls!(f32, f64);
+/// Short version of `NodeIndex::new`
#[inline]
pub fn node_index(ax: usize) -> NodeIndex {
debug_assert!(ax.index() <= Ix::max_value() as usize);
NodeIndex::new(ax)
}
+/// `MatrixGraph<N, E, Ty, Null>` is a graph datastructure using an adjacency matrix
+/// representation.
+///
+/// `MatrixGraph` is parameterized over:
+///
+/// - Associated data `N` for nodes and `E` for edges, called *weights*.
+/// The associated data can be of arbitrary type.
+/// - Edge type `Ty` that determines whether the graph edges are directed or undirected.
+/// - Nullable type `Null`, which denotes the edges' presence (defaults to `Option<E>`). You may
+/// specify [`NotZero<E>`](struct.NotZero.html) if you want to use a sentinel value (such as 0)
+/// to mark the absence of an edge.
+///
+/// The graph uses **O(|V^2|)** space, with fast edge insertion & amortized node insertion, as well
+/// as efficient graph search and graph algorithms on dense graphs.
+///
+/// This graph is backed by a flattened 2D array. For undirected graphs, only the lower triangular
+/// matrix is stored. Since the backing array stores edge weights, it is recommended to box large
+/// edge weights.
#[derive(Clone)]
pub struct MatrixGraph<N, E, Ty = Directed, Null: Nullable<Wrapped=E> = Option<E>> {
node_adjacencies: Vec<Null>,
@@ -193,8 +216,11 @@
ty: PhantomData<Ty>,
}
-pub type DiMatrix<N, E, Null: Nullable<Wrapped=E> = Option<E>> = MatrixGraph<N, E, Directed, Null>;
-pub type UnMatrix<N, E, Null: Nullable<Wrapped=E> = Option<E>> = MatrixGraph<N, E, Undirected, Null>;
+/// A `MatrixGraph` with directed edges.
+pub type DiMatrix<N, E, Null = Option<E>> = MatrixGraph<N, E, Directed, Null>;
+
+/// A `MatrixGraph` with undirected edges.
+pub type UnMatrix<N, E, Null = Option<E>> = MatrixGraph<N, E, Undirected, Null>;
impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped=E>> MatrixGraph<N, E, Ty, Null> {
/// Create a new `MatrixGraph` with estimated capacity for nodes.
@@ -248,7 +274,7 @@
self.nb_edges
}
- /// Whether the graph has directed edges or not.
+ /// Return whether the graph has directed edges or not.
#[inline]
pub fn is_directed(&self) -> bool {
Ty::is_directed()
@@ -260,8 +286,7 @@
///
/// Return the index of the new node.
///
- /// **Panics** if the Graph is at the maximum number of nodes for its index
- /// type.
+ /// **Panics** if the MatrixGraph is at the maximum number of nodes for its index type.
pub fn add_node(&mut self, weight: N) -> NodeIndex {
node_index(self.nodes.add(weight))
}
@@ -343,10 +368,7 @@
/// Remove the edge from `a` to `b` to the graph.
///
/// **Panics** if any of the nodes don't exist.
- /// **Panics** if an edge already exists from `a` to `b`.
- ///
- /// **Note:** `MatrixGraph` does not allow adding parallel (“duplicate”) edges. If you want to avoid
- /// this, use [`.update_edge(a, b, weight)`](#method.update_edge) instead.
+ /// **Panics** if no edge exists between `a` and `b`.
pub fn remove_edge(&mut self, a: NodeIndex, b: NodeIndex) -> E {
let p = self.to_edge_position(a, b);
let old_weight = mem::replace(&mut self.node_adjacencies[p], Default::default()).into().unwrap();
@@ -385,7 +407,7 @@
///
/// Also available with indexing syntax: `&graph[e]`.
///
- /// **Panics** if the edge doesn't exist.
+ /// **Panics** if no edge exists between `a` and `b`.
pub fn edge_weight(&self, a: NodeIndex, b: NodeIndex) -> &E {
let p = self.to_edge_position(a, b);
self.node_adjacencies[p].as_ref().unwrap()
@@ -395,32 +417,51 @@
///
/// Also available with indexing syntax: `&mut graph[e]`.
///
- /// **Panics** if the edge doesn't exist.
+ /// **Panics** if no edge exists between `a` and `b`.
pub fn edge_weight_mut(&mut self, a: NodeIndex, b: NodeIndex) -> &mut E {
let p = self.to_edge_position(a, b);
self.node_adjacencies[p].as_mut().unwrap()
}
+ /// Return an iterator of all nodes with an edge starting from `a`.
+ ///
+ /// - `Directed`: Outgoing edges from `a`.
+ /// - `Undirected`: All edges from or to `a`.
+ ///
+ /// Produces an empty iterator if the node doesn't exist.<br>
+ /// Iterator element type is [`NodeIndex<Ix>`](../graph/struct.NodeIndex.html).
pub fn neighbors(&self, a: NodeIndex) -> Neighbors<Ty, Null> {
Neighbors(Edges::on_columns(a.index(), &self.node_adjacencies, self.node_capacity))
}
+ /// Return an iterator of all edges of `a`.
+ ///
+ /// - `Directed`: Outgoing edges from `a`.
+ /// - `Undirected`: All edges connected to `a`.
+ ///
+ /// Produces an empty iterator if the node doesn't exist.<br>
+ /// Iterator element type is [`Edges<E, Ix>`](../graph/struct.Edges.html).
pub fn edges(&self, a: NodeIndex) -> Edges<Ty, Null> {
Edges::on_columns(a.index(), &self.node_adjacencies, self.node_capacity)
}
- pub fn node_identifiers(&self) -> NodeIdentifiers {
- NodeIdentifiers(self.nodes.iter_ids())
- }
-
- pub fn node_references(&self) -> NodeReferences<N> {
- NodeReferences::new(&self.nodes)
- }
-
- pub fn edge_references(&self) -> EdgeReferences<Ty, Null> {
- EdgeReferences::new(&self.node_adjacencies, self.node_capacity)
- }
-
+ /// Create a new `MatrixGraph` from an iterable of edges.
+ ///
+ /// Node weights `N` are set to default values.
+ /// Edge weights `E` may either be specified in the list,
+ /// or they are filled with default values.
+ ///
+ /// Nodes are inserted automatically to match the edges.
+ ///
+ /// ```
+ /// use petgraph::matrix_graph::MatrixGraph;
+ ///
+ /// let gr = MatrixGraph::<(), i32>::from_edges(&[
+ /// (0, 1), (0, 2), (0, 3),
+ /// (1, 2), (1, 3),
+ /// (2, 3),
+ /// ]);
+ /// ```
pub fn from_edges<I>(iterable: I) -> Self
where I: IntoIterator,
I::Item: IntoWeightedEdge<E>,
@@ -458,6 +499,16 @@
}
impl<N, E, Null: Nullable<Wrapped=E>> MatrixGraph<N, E, Directed, Null> {
+ /// Return an iterator of all neighbors that have an edge between them and
+ /// `a`, in the specified direction.
+ /// If the graph's edges are undirected, this is equivalent to *.neighbors(a)*.
+ ///
+ /// - `Directed`, `Outgoing`: All edges from `a`.
+ /// - `Directed`, `Incoming`: All edges to `a`.
+ /// - `Undirected`: All edges from or to `a`.
+ ///
+ /// Produces an empty iterator if the node doesn't exist.<br>
+ /// Iterator element type is [`NodeIndex<Ix>`](../graph/struct.NodeIndex.html).
pub fn neighbors_directed(&self, a: NodeIndex, d: Direction) -> Neighbors<Directed, Null> {
if d == Outgoing {
self.neighbors(a)
@@ -466,6 +517,14 @@
}
}
+ /// Return an iterator of all edges of `a`, in the specified direction.
+ ///
+ /// - `Directed`, `Outgoing`: All edges from `a`.
+ /// - `Directed`, `Incoming`: All edges to `a`.
+ /// - `Undirected`: All edges connected to `a`.
+ ///
+ /// Produces an empty iterator if the node `a` doesn't exist.<br>
+ /// Iterator element type is [`EdgeReference<E, Ix>`](../graph/struct.EdgeReference.html).
pub fn edges_directed(&self, a: NodeIndex, d: Direction) -> Edges<Directed, Null> {
if d == Outgoing {
self.edges(a)
@@ -475,6 +534,12 @@
}
}
+/// Iterator over the node identifiers of a graph.
+///
+/// Created from a call to [`.node_identifiers()`][1] on a [`MatrixGraph`][2].
+///
+/// [1]: ../visit/trait.IntoNodeIdentifiers.html#tymethod.node_identifiers
+/// [2]: struct.MatrixGraph.html
pub struct NodeIdentifiers<'a>(IdIterator<'a>);
impl<'a> Iterator for NodeIdentifiers<'a> {
@@ -485,6 +550,12 @@
}
}
+/// Iterator over all nodes of a graph.
+///
+/// Created from a call to [`.node_references()`][1] on a [`MatrixGraph`][2].
+///
+/// [1]: ../visit/trait.IntoNodeReferences.html#tymethod.node_references
+/// [2]: struct.MatrixGraph.html
pub struct NodeReferences<'a, N: 'a> {
nodes: &'a IdStorage<N>,
iter: IdIterator<'a>,
@@ -508,6 +579,12 @@
}
}
+/// Iterator over all edges of a graph.
+///
+/// Created from a call to [`.edge_references()`][1] on a [`MatrixGraph`][2].
+///
+/// [1]: ../visit/trait.IntoEdgeReferences.html#tymethod.edge_references
+/// [2]: struct.MatrixGraph.html
pub struct EdgeReferences<'a, Ty: EdgeType, Null: 'a + Nullable> {
row: usize,
column: usize,
@@ -556,6 +633,14 @@
}
}
+/// Iterator over the neighbors of a node.
+///
+/// Iterator element type is `NodeIndex<Ix>`.
+///
+/// Created with [`.neighbors()`][1], [`.neighbors_directed()`][2].
+///
+/// [1]: struct.MatrixGraph.html#method.neighbors
+/// [2]: struct.MatrixGraph.html#method.neighbors_directed
pub struct Neighbors<'a, Ty: EdgeType, Null: 'a + Nullable>(Edges<'a, Ty, Null>);
impl<'a, Ty: EdgeType, Null: Nullable> Iterator for Neighbors<'a, Ty, Null> {
@@ -571,6 +656,12 @@
Columns,
}
+/// Iterator over the edges of from or to a node
+///
+/// Created with [`.edges()`][1], [`.edges_directed()`][2].
+///
+/// [1]: struct.MatrixGraph.html#method.edges
+/// [2]: struct.MatrixGraph.html#method.edges_directed
pub struct Edges<'a, Ty: EdgeType, Null: 'a + Nullable> {
iter_direction: NeighborIterDirection,
node_adjacencies: &'a [Null],
@@ -783,7 +874,7 @@
}
}
-pub struct IdIterator<'a> {
+struct IdIterator<'a> {
upper_bound: usize,
removed_ids: &'a IndexSet<usize>,
current: Option<usize>,
@@ -937,7 +1028,7 @@
type NodeIdentifiers = NodeIdentifiers<'a>;
fn node_identifiers(self) -> Self::NodeIdentifiers {
- MatrixGraph::node_identifiers(self)
+ NodeIdentifiers(self.nodes.iter_ids())
}
}
@@ -961,7 +1052,7 @@
type NodeRef = (NodeIndex, &'a N);
type NodeReferences = NodeReferences<'a, N>;
fn node_references(self) -> Self::NodeReferences {
- MatrixGraph::node_references(self)
+ NodeReferences::new(&self.nodes)
}
}
@@ -969,7 +1060,7 @@
type EdgeRef = (NodeIndex, NodeIndex, &'a E);
type EdgeReferences = EdgeReferences<'a, Ty, Null>;
fn edge_references(self) -> Self::EdgeReferences {
- MatrixGraph::edge_references(self)
+ EdgeReferences::new(&self.node_adjacencies, self.node_capacity)
}
}
@@ -1347,6 +1438,18 @@
}
#[test]
+ fn test_edges_of_absent_node_is_empty_iterator() {
+ let g: MatrixGraph<char, bool> = MatrixGraph::new();
+ assert_eq!(g.edges(node_index(0)).count(), 0);
+ }
+
+ #[test]
+ fn test_neighbors_of_absent_node_is_empty_iterator() {
+ let g: MatrixGraph<char, bool> = MatrixGraph::new();
+ assert_eq!(g.neighbors(node_index(0)).count(), 0);
+ }
+
+ #[test]
fn test_edge_references() {
let g: MatrixGraph<char, bool> = MatrixGraph::from_edges(&[
(0, 5), (0, 2), (0, 3), (0, 1),