diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
| commit | 8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch) | |
| tree | 22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/petgraph/src/matrix_graph.rs | |
| parent | 4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff) | |
chore: add vendor directory
Diffstat (limited to 'vendor/petgraph/src/matrix_graph.rs')
| -rw-r--r-- | vendor/petgraph/src/matrix_graph.rs | 1814 |
1 files changed, 1814 insertions, 0 deletions
diff --git a/vendor/petgraph/src/matrix_graph.rs b/vendor/petgraph/src/matrix_graph.rs new file mode 100644 index 00000000..2ae7c8d0 --- /dev/null +++ b/vendor/petgraph/src/matrix_graph.rs @@ -0,0 +1,1814 @@ +//! `MatrixGraph<N, E, Ty, NullN, NullE, Ix>` is a graph datastructure backed by an adjacency matrix. + +use std::marker::PhantomData; +use std::ops::{Index, IndexMut}; + +use std::cmp; +use std::mem; + +use indexmap::IndexSet; + +use fixedbitset::FixedBitSet; + +use crate::{Directed, Direction, EdgeType, IntoWeightedEdge, Outgoing, Undirected}; + +use crate::graph::NodeIndex as GraphNodeIndex; + +use crate::visit::{ + Data, EdgeCount, GetAdjacencyMatrix, GraphBase, GraphProp, IntoEdgeReferences, IntoEdges, + IntoEdgesDirected, IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, + IntoNodeReferences, NodeCount, NodeIndexable, Visitable, +}; + +use crate::data::Build; + +pub use crate::graph::IndexType; + +// The following types are used to control the max size of the adjacency matrix. Since the maximum +// size of the matrix vector's is the square of the maximum number of nodes, the number of nodes +// should be reasonably picked. +type DefaultIx = u16; + +/// Node identifier. +pub type NodeIndex<Ix = DefaultIx> = GraphNodeIndex<Ix>; + +mod private { + pub trait Sealed {} + + 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 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; + + #[doc(hidden)] + fn new(value: Self::Wrapped) -> Self; + + #[doc(hidden)] + fn as_ref(&self) -> Option<&Self::Wrapped>; + + #[doc(hidden)] + fn as_mut(&mut self) -> Option<&mut Self::Wrapped>; + + #[doc(hidden)] + fn is_null(&self) -> bool { + self.as_ref().is_none() + } +} + +impl<T> Nullable for Option<T> { + type Wrapped = T; + + fn new(value: T) -> Self { + Some(value) + } + + fn as_ref(&self) -> Option<&Self::Wrapped> { + self.as_ref() + } + + fn as_mut(&mut self) -> Option<&mut Self::Wrapped> { + self.as_mut() + } +} + +/// `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<T>(T); + +impl<T: Zero> Default for NotZero<T> { + fn default() -> Self { + NotZero(T::zero()) + } +} + +impl<T: Zero> Nullable for NotZero<T> { + #[doc(hidden)] + type Wrapped = T; + + #[doc(hidden)] + fn new(value: T) -> Self { + assert!(!value.is_zero()); + NotZero(value) + } + + // implemented here for optimization purposes + #[doc(hidden)] + fn is_null(&self) -> bool { + self.0.is_zero() + } + + #[doc(hidden)] + fn as_ref(&self) -> Option<&Self::Wrapped> { + if !self.is_null() { + Some(&self.0) + } else { + None + } + } + + #[doc(hidden)] + fn as_mut(&mut self) -> Option<&mut Self::Wrapped> { + if !self.is_null() { + Some(&mut self.0) + } else { + None + } + } +} + +impl<T: Zero> From<NotZero<T>> for Option<T> { + fn from(not_zero: NotZero<T>) -> Self { + if !not_zero.is_null() { + Some(not_zero.0) + } else { + None + } + } +} + +/// 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). +/// +/// Note that this trait is already implemented for the base numeric types. +pub trait Zero { + /// Return the singleton object which can be used as a sentinel value. + fn zero() -> Self; + + /// Return true if `self` is equal to the sentinel value. + fn is_zero(&self) -> bool; +} + +macro_rules! not_zero_impl { + ($t:ty,$z:expr) => { + impl Zero for $t { + fn zero() -> Self { + $z as $t + } + + #[allow(clippy::float_cmp)] + fn is_zero(&self) -> bool { + self == &Self::zero() + } + } + }; +} + +macro_rules! not_zero_impls { + ($($t:ty),*) => { + $( + not_zero_impl!($t, 0); + )* + } +} + +not_zero_impls!(u8, u16, u32, u64, usize); +not_zero_impls!(i8, i16, i32, i64, isize); +not_zero_impls!(f32, f64); + +/// Short version of `NodeIndex::new` (with Ix = `DefaultIx`) +#[inline] +pub fn node_index(ax: usize) -> NodeIndex { + 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. +/// - Index type `Ix` that sets the maximum size for the graph (defaults to `DefaultIx`). +/// +/// 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>, Ix = DefaultIx> +{ + node_adjacencies: Vec<Null>, + node_capacity: usize, + nodes: IdStorage<N>, + nb_edges: usize, + ty: PhantomData<Ty>, + ix: PhantomData<Ix>, +} + +/// A `MatrixGraph` with directed edges. +pub type DiMatrix<N, E, Null = Option<E>, Ix = DefaultIx> = MatrixGraph<N, E, Directed, Null, Ix>; + +/// A `MatrixGraph` with undirected edges. +pub type UnMatrix<N, E, Null = Option<E>, Ix = DefaultIx> = MatrixGraph<N, E, Undirected, Null, Ix>; + +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> + MatrixGraph<N, E, Ty, Null, Ix> +{ + /// Create a new `MatrixGraph` with estimated capacity for nodes. + pub fn with_capacity(node_capacity: usize) -> Self { + let mut m = Self { + node_adjacencies: vec![], + node_capacity: 0, + nodes: IdStorage::with_capacity(node_capacity), + nb_edges: 0, + ty: PhantomData, + ix: PhantomData, + }; + + debug_assert!(node_capacity <= <Ix as IndexType>::max().index()); + if node_capacity > 0 { + m.extend_capacity_for_node(NodeIndex::new(node_capacity - 1), true); + } + + m + } + + #[inline] + fn to_edge_position(&self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> Option<usize> { + if cmp::max(a.index(), b.index()) >= self.node_capacity { + return None; + } + Some(self.to_edge_position_unchecked(a, b)) + } + + #[inline] + fn to_edge_position_unchecked(&self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> usize { + to_linearized_matrix_position::<Ty>(a.index(), b.index(), self.node_capacity) + } + + /// Remove all nodes and edges. + pub fn clear(&mut self) { + for edge in self.node_adjacencies.iter_mut() { + *edge = Default::default(); + } + self.nodes.clear(); + self.nb_edges = 0; + } + + /// Return the number of nodes (vertices) in the graph. + /// + /// Computes in **O(1)** time. + #[inline] + pub fn node_count(&self) -> usize { + self.nodes.len() + } + + /// Return the number of edges in the graph. + /// + /// Computes in **O(1)** time. + #[inline] + pub fn edge_count(&self) -> usize { + self.nb_edges + } + + /// Return whether the graph has directed edges or not. + #[inline] + pub fn is_directed(&self) -> bool { + Ty::is_directed() + } + + /// Add a node (also called vertex) with associated data `weight` to the graph. + /// + /// Computes in **O(1)** time. + /// + /// Return the index of the new node. + /// + /// **Panics** if the MatrixGraph is at the maximum number of nodes for its index type. + pub fn add_node(&mut self, weight: N) -> NodeIndex<Ix> { + NodeIndex::new(self.nodes.add(weight)) + } + + /// Remove `a` from the graph. + /// + /// Computes in **O(V)** time, due to the removal of edges with other nodes. + /// + /// **Panics** if the node `a` does not exist. + pub fn remove_node(&mut self, a: NodeIndex<Ix>) -> N { + for id in self.nodes.iter_ids() { + let position = self.to_edge_position(a, NodeIndex::new(id)); + if let Some(pos) = position { + self.node_adjacencies[pos] = Default::default(); + } + + if Ty::is_directed() { + let position = self.to_edge_position(NodeIndex::new(id), a); + if let Some(pos) = position { + self.node_adjacencies[pos] = Default::default(); + } + } + } + + self.nodes.remove(a.index()) + } + + #[inline] + fn extend_capacity_for_node(&mut self, min_node: NodeIndex<Ix>, exact: bool) { + self.node_capacity = extend_linearized_matrix::<Ty, _>( + &mut self.node_adjacencies, + self.node_capacity, + min_node.index() + 1, + exact, + ); + } + + #[inline] + fn extend_capacity_for_edge(&mut self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) { + let min_node = cmp::max(a, b); + if min_node.index() >= self.node_capacity { + self.extend_capacity_for_node(min_node, false); + } + } + + /// Update the edge from `a` to `b` to the graph, with its associated data `weight`. + /// + /// Return the previous data, if any. + /// + /// Computes in **O(1)** time, best case. + /// Computes in **O(|V|^2)** time, worst case (matrix needs to be re-allocated). + /// + /// **Panics** if any of the nodes don't exist. + pub fn update_edge(&mut self, a: NodeIndex<Ix>, b: NodeIndex<Ix>, weight: E) -> Option<E> { + self.extend_capacity_for_edge(a, b); + let p = self.to_edge_position_unchecked(a, b); + let old_weight = mem::replace(&mut self.node_adjacencies[p], Null::new(weight)); + if old_weight.is_null() { + self.nb_edges += 1; + } + old_weight.into() + } + + /// Add an edge from `a` to `b` to the graph, with its associated + /// data `weight`. + /// + /// Computes in **O(1)** time, best case. + /// Computes in **O(|V|^2)** time, worst case (matrix needs to be re-allocated). + /// + /// **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. + pub fn add_edge(&mut self, a: NodeIndex<Ix>, b: NodeIndex<Ix>, weight: E) { + let old_edge_id = self.update_edge(a, b, weight); + assert!(old_edge_id.is_none()); + } + + /// Remove the edge from `a` to `b` to the graph. + /// + /// **Panics** if any of the nodes don't exist. + /// **Panics** if no edge exists between `a` and `b`. + pub fn remove_edge(&mut self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> E { + let p = self + .to_edge_position(a, b) + .expect("No edge found between the nodes."); + let old_weight = mem::take(&mut self.node_adjacencies[p]).into().unwrap(); + let old_weight: Option<_> = old_weight.into(); + self.nb_edges -= 1; + old_weight.unwrap() + } + + /// Return true if there is an edge between `a` and `b`. + /// + /// **Panics** if any of the nodes don't exist. + pub fn has_edge(&self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool { + if let Some(p) = self.to_edge_position(a, b) { + return !self.node_adjacencies[p].is_null(); + } + false + } + + /// Access the weight for node `a`. + /// + /// Also available with indexing syntax: `&graph[a]`. + /// + /// **Panics** if the node doesn't exist. + pub fn node_weight(&self, a: NodeIndex<Ix>) -> &N { + &self.nodes[a.index()] + } + + /// Access the weight for node `a`, mutably. + /// + /// Also available with indexing syntax: `&mut graph[a]`. + /// + /// **Panics** if the node doesn't exist. + pub fn node_weight_mut(&mut self, a: NodeIndex<Ix>) -> &mut N { + &mut self.nodes[a.index()] + } + + /// Access the weight for edge `e`. + /// + /// Also available with indexing syntax: `&graph[e]`. + /// + /// **Panics** if no edge exists between `a` and `b`. + pub fn edge_weight(&self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> &E { + let p = self + .to_edge_position(a, b) + .expect("No edge found between the nodes."); + self.node_adjacencies[p] + .as_ref() + .expect("No edge found between the nodes.") + } + + /// Access the weight for edge `e`, mutably. + /// + /// Also available with indexing syntax: `&mut graph[e]`. + /// + /// **Panics** if no edge exists between `a` and `b`. + pub fn edge_weight_mut(&mut self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> &mut E { + let p = self + .to_edge_position(a, b) + .expect("No edge found between the nodes."); + self.node_adjacencies[p] + .as_mut() + .expect("No edge found between the nodes.") + } + + /// 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<Ix>) -> Neighbors<Ty, Null, Ix> { + 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 `(NodeIndex<Ix>, NodeIndex<Ix>, &E)`. + pub fn edges(&self, a: NodeIndex<Ix>) -> Edges<Ty, Null, Ix> { + Edges::on_columns(a.index(), &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>, + <I::Item as IntoWeightedEdge<E>>::NodeId: Into<NodeIndex<Ix>>, + N: Default, + { + let mut g = Self::default(); + g.extend_with_edges(iterable); + g + } + + /// Extend the graph 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. + pub fn extend_with_edges<I>(&mut self, iterable: I) + where + I: IntoIterator, + I::Item: IntoWeightedEdge<E>, + <I::Item as IntoWeightedEdge<E>>::NodeId: Into<NodeIndex<Ix>>, + N: Default, + { + for elt in iterable { + let (source, target, weight) = elt.into_weighted_edge(); + let (source, target) = (source.into(), target.into()); + let nx = cmp::max(source, target); + while nx.index() >= self.node_count() { + self.add_node(N::default()); + } + self.add_edge(source, target, weight); + } + } +} + +impl<N, E, Null: Nullable<Wrapped = E>, Ix: IndexType> MatrixGraph<N, E, Directed, Null, Ix> { + /// 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)*. + /// + /// - `Outgoing`: All edges from `a`. + /// - `Incoming`: All edges 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<Ix>, + d: Direction, + ) -> Neighbors<Directed, Null, Ix> { + if d == Outgoing { + self.neighbors(a) + } else { + Neighbors(Edges::on_rows( + a.index(), + &self.node_adjacencies, + self.node_capacity, + )) + } + } + + /// Return an iterator of all edges of `a`, in the specified direction. + /// + /// - `Outgoing`: All edges from `a`. + /// - `Incoming`: All edges to `a`. + /// + /// Produces an empty iterator if the node `a` doesn't exist.<br> + /// Iterator element type is `(NodeIndex<Ix>, NodeIndex<Ix>, &E)`. + pub fn edges_directed(&self, a: NodeIndex<Ix>, d: Direction) -> Edges<Directed, Null, Ix> { + if d == Outgoing { + self.edges(a) + } else { + Edges::on_rows(a.index(), &self.node_adjacencies, self.node_capacity) + } + } +} + +/// 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 +#[derive(Debug, Clone)] +pub struct NodeIdentifiers<'a, Ix> { + iter: IdIterator<'a>, + ix: PhantomData<Ix>, +} + +impl<'a, Ix: IndexType> NodeIdentifiers<'a, Ix> { + fn new(iter: IdIterator<'a>) -> Self { + Self { + iter, + ix: PhantomData, + } + } +} + +impl<Ix: IndexType> Iterator for NodeIdentifiers<'_, Ix> { + type Item = NodeIndex<Ix>; + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().map(NodeIndex::new) + } + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +/// 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 +#[derive(Debug, Clone)] +pub struct NodeReferences<'a, N: 'a, Ix> { + nodes: &'a IdStorage<N>, + iter: IdIterator<'a>, + ix: PhantomData<Ix>, +} + +impl<'a, N: 'a, Ix> NodeReferences<'a, N, Ix> { + fn new(nodes: &'a IdStorage<N>) -> Self { + NodeReferences { + nodes, + iter: nodes.iter_ids(), + ix: PhantomData, + } + } +} + +impl<'a, N: 'a, Ix: IndexType> Iterator for NodeReferences<'a, N, Ix> { + type Item = (NodeIndex<Ix>, &'a N); + + fn next(&mut self) -> Option<Self::Item> { + self.iter + .next() + .map(|i| (NodeIndex::new(i), &self.nodes[i])) + } + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +/// 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 +#[derive(Debug, Clone)] +pub struct EdgeReferences<'a, Ty: EdgeType, Null: 'a + Nullable, Ix> { + row: usize, + column: usize, + node_adjacencies: &'a [Null], + node_capacity: usize, + ty: PhantomData<Ty>, + ix: PhantomData<Ix>, +} + +impl<'a, Ty: EdgeType, Null: 'a + Nullable, Ix> EdgeReferences<'a, Ty, Null, Ix> { + fn new(node_adjacencies: &'a [Null], node_capacity: usize) -> Self { + EdgeReferences { + row: 0, + column: 0, + node_adjacencies, + node_capacity, + ty: PhantomData, + ix: PhantomData, + } + } +} + +impl<'a, Ty: EdgeType, Null: Nullable, Ix: IndexType> Iterator + for EdgeReferences<'a, Ty, Null, Ix> +{ + type Item = (NodeIndex<Ix>, NodeIndex<Ix>, &'a Null::Wrapped); + + fn next(&mut self) -> Option<Self::Item> { + loop { + let (row, column) = (self.row, self.column); + if row >= self.node_capacity { + return None; + } + + // By default, advance the column. Reset and advance the row if the column overflows. + // + // Note that for undirected graphs, we don't want to yield the same edge twice, + // therefore the maximum column length should be the index new after the row index. + self.column += 1; + let max_column_len = if !Ty::is_directed() { + row + 1 + } else { + self.node_capacity + }; + if self.column >= max_column_len { + self.column = 0; + self.row += 1; + } + + let p = to_linearized_matrix_position::<Ty>(row, column, self.node_capacity); + if let Some(e) = self.node_adjacencies[p].as_ref() { + return Some((NodeIndex::new(row), NodeIndex::new(column), e)); + } + } + } +} + +/// 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 +#[derive(Debug, Clone)] +pub struct Neighbors<'a, Ty: EdgeType, Null: 'a + Nullable, Ix>(Edges<'a, Ty, Null, Ix>); + +impl<Ty: EdgeType, Null: Nullable, Ix: IndexType> Iterator for Neighbors<'_, Ty, Null, Ix> { + type Item = NodeIndex<Ix>; + + fn next(&mut self) -> Option<Self::Item> { + self.0.next().map(|(_, b, _)| b) + } + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.size_hint() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum NeighborIterDirection { + Rows, + 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 +#[derive(Debug, Clone)] +pub struct Edges<'a, Ty: EdgeType, Null: 'a + Nullable, Ix> { + iter_direction: NeighborIterDirection, + node_adjacencies: &'a [Null], + node_capacity: usize, + row: usize, + column: usize, + ty: PhantomData<Ty>, + ix: PhantomData<Ix>, +} + +impl<'a, Ty: EdgeType, Null: 'a + Nullable, Ix> Edges<'a, Ty, Null, Ix> { + fn on_columns(row: usize, node_adjacencies: &'a [Null], node_capacity: usize) -> Self { + Edges { + iter_direction: NeighborIterDirection::Columns, + node_adjacencies, + node_capacity, + row, + column: 0, + ty: PhantomData, + ix: PhantomData, + } + } + + fn on_rows(column: usize, node_adjacencies: &'a [Null], node_capacity: usize) -> Self { + Edges { + iter_direction: NeighborIterDirection::Rows, + node_adjacencies, + node_capacity, + row: 0, + column, + ty: PhantomData, + ix: PhantomData, + } + } +} + +impl<'a, Ty: EdgeType, Null: Nullable, Ix: IndexType> Iterator for Edges<'a, Ty, Null, Ix> { + type Item = (NodeIndex<Ix>, NodeIndex<Ix>, &'a Null::Wrapped); + + fn next(&mut self) -> Option<Self::Item> { + use self::NeighborIterDirection::*; + + loop { + let (row, column) = (self.row, self.column); + if row >= self.node_capacity || column >= self.node_capacity { + return None; + } + + match self.iter_direction { + Rows => self.row += 1, + Columns => self.column += 1, + } + + let p = to_linearized_matrix_position::<Ty>(row, column, self.node_capacity); + if let Some(e) = self.node_adjacencies[p].as_ref() { + let (a, b) = match self.iter_direction { + Rows => (column, row), + Columns => (row, column), + }; + + return Some((NodeIndex::new(a), NodeIndex::new(b), e)); + } + } + } +} + +#[inline] +fn to_linearized_matrix_position<Ty: EdgeType>(row: usize, column: usize, width: usize) -> usize { + if Ty::is_directed() { + to_flat_square_matrix_position(row, column, width) + } else { + to_lower_triangular_matrix_position(row, column) + } +} + +#[inline] +fn extend_linearized_matrix<Ty: EdgeType, T: Default>( + node_adjacencies: &mut Vec<T>, + old_node_capacity: usize, + new_capacity: usize, + exact: bool, +) -> usize { + if old_node_capacity >= new_capacity { + return old_node_capacity; + } + if Ty::is_directed() { + extend_flat_square_matrix(node_adjacencies, old_node_capacity, new_capacity, exact) + } else { + extend_lower_triangular_matrix(node_adjacencies, new_capacity) + } +} + +#[inline] +fn to_flat_square_matrix_position(row: usize, column: usize, width: usize) -> usize { + row * width + column +} + +#[inline] +fn extend_flat_square_matrix<T: Default>( + node_adjacencies: &mut Vec<T>, + old_node_capacity: usize, + new_node_capacity: usize, + exact: bool, +) -> usize { + // Grow the capacity by exponential steps to avoid repeated allocations. + // Disabled for the with_capacity constructor. + let new_node_capacity = if exact { + new_node_capacity + } else { + const MIN_CAPACITY: usize = 4; + cmp::max(new_node_capacity.next_power_of_two(), MIN_CAPACITY) + }; + + // Optimization: when resizing the matrix this way we skip the first few grows to make + // small matrices a bit faster to work with. + + ensure_len(node_adjacencies, new_node_capacity.pow(2)); + for c in (1..old_node_capacity).rev() { + let pos = c * old_node_capacity; + let new_pos = c * new_node_capacity; + // Move the slices directly if they do not overlap with their new position + if pos + old_node_capacity <= new_pos { + debug_assert!(pos + old_node_capacity < node_adjacencies.len()); + debug_assert!(new_pos + old_node_capacity < node_adjacencies.len()); + let ptr = node_adjacencies.as_mut_ptr(); + // SAFETY: pos + old_node_capacity <= new_pos, so this won't overlap + unsafe { + let old = ptr.add(pos); + let new = ptr.add(new_pos); + core::ptr::swap_nonoverlapping(old, new, old_node_capacity); + } + } else { + for i in (0..old_node_capacity).rev() { + node_adjacencies.as_mut_slice().swap(pos + i, new_pos + i); + } + } + } + + new_node_capacity +} + +#[inline] +fn to_lower_triangular_matrix_position(row: usize, column: usize) -> usize { + let (row, column) = if row > column { + (row, column) + } else { + (column, row) + }; + (row * (row + 1)) / 2 + column +} + +#[inline] +fn extend_lower_triangular_matrix<T: Default>( + node_adjacencies: &mut Vec<T>, + new_capacity: usize, +) -> usize { + let max_node = new_capacity - 1; + let max_pos = to_lower_triangular_matrix_position(max_node, max_node); + ensure_len(node_adjacencies, max_pos + 1); + new_capacity +} + +/// Grow a Vec by appending the type's default value until the `size` is reached. +fn ensure_len<T: Default>(v: &mut Vec<T>, size: usize) { + v.resize_with(size, T::default); +} + +#[derive(Debug, Clone)] +struct IdStorage<T> { + elements: Vec<Option<T>>, + upper_bound: usize, + removed_ids: IndexSet<usize>, +} + +impl<T> IdStorage<T> { + fn with_capacity(capacity: usize) -> Self { + IdStorage { + elements: Vec::with_capacity(capacity), + upper_bound: 0, + removed_ids: IndexSet::new(), + } + } + + fn add(&mut self, element: T) -> usize { + let id = if let Some(id) = self.removed_ids.pop() { + id + } else { + let id = self.upper_bound; + self.upper_bound += 1; + + ensure_len(&mut self.elements, id + 1); + + id + }; + + self.elements[id] = Some(element); + + id + } + + fn remove(&mut self, id: usize) -> T { + let data = self.elements[id].take().unwrap(); + if self.upper_bound - id == 1 { + self.upper_bound -= 1; + } else { + self.removed_ids.insert(id); + } + data + } + + fn clear(&mut self) { + self.upper_bound = 0; + self.elements.clear(); + self.removed_ids.clear(); + } + + #[inline] + fn len(&self) -> usize { + self.upper_bound - self.removed_ids.len() + } + + fn iter_ids(&self) -> IdIterator { + IdIterator { + upper_bound: self.upper_bound, + removed_ids: &self.removed_ids, + current: None, + } + } +} + +impl<T> Index<usize> for IdStorage<T> { + type Output = T; + fn index(&self, index: usize) -> &T { + self.elements[index].as_ref().unwrap() + } +} + +impl<T> IndexMut<usize> for IdStorage<T> { + fn index_mut(&mut self, index: usize) -> &mut T { + self.elements[index].as_mut().unwrap() + } +} + +#[derive(Debug, Clone)] +struct IdIterator<'a> { + upper_bound: usize, + removed_ids: &'a IndexSet<usize>, + current: Option<usize>, +} + +impl Iterator for IdIterator<'_> { + type Item = usize; + + fn next(&mut self) -> Option<Self::Item> { + // initialize / advance + let current = { + if self.current.is_none() { + self.current = Some(0); + self.current.as_mut().unwrap() + } else { + let current = self.current.as_mut().unwrap(); + *current += 1; + current + } + }; + + // skip removed ids + while self.removed_ids.contains(current) && *current < self.upper_bound { + *current += 1; + } + + if *current < self.upper_bound { + Some(*current) + } else { + None + } + } +} + +/// Create a new empty `MatrixGraph`. +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> Default + for MatrixGraph<N, E, Ty, Null, Ix> +{ + fn default() -> Self { + Self::with_capacity(0) + } +} + +impl<N, E> MatrixGraph<N, E, Directed> { + /// Create a new `MatrixGraph` with directed edges. + /// + /// This is a convenience method. Use `MatrixGraph::with_capacity` or `MatrixGraph::default` for + /// a constructor that is generic in all the type parameters of `MatrixGraph`. + pub fn new() -> Self { + MatrixGraph::default() + } +} + +impl<N, E> MatrixGraph<N, E, Undirected> { + /// Create a new `MatrixGraph` with undirected edges. + /// + /// This is a convenience method. Use `MatrixGraph::with_capacity` or `MatrixGraph::default` for + /// a constructor that is generic in all the type parameters of `MatrixGraph`. + pub fn new_undirected() -> Self { + MatrixGraph::default() + } +} + +/// Index the `MatrixGraph` by `NodeIndex` to access node weights. +/// +/// **Panics** if the node doesn't exist. +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> Index<NodeIndex<Ix>> + for MatrixGraph<N, E, Ty, Null, Ix> +{ + type Output = N; + + fn index(&self, ax: NodeIndex<Ix>) -> &N { + self.node_weight(ax) + } +} + +/// Index the `MatrixGraph` by `NodeIndex` to access node weights. +/// +/// **Panics** if the node doesn't exist. +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> IndexMut<NodeIndex<Ix>> + for MatrixGraph<N, E, Ty, Null, Ix> +{ + fn index_mut(&mut self, ax: NodeIndex<Ix>) -> &mut N { + self.node_weight_mut(ax) + } +} + +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> NodeCount + for MatrixGraph<N, E, Ty, Null, Ix> +{ + fn node_count(&self) -> usize { + MatrixGraph::node_count(self) + } +} + +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> EdgeCount + for MatrixGraph<N, E, Ty, Null, Ix> +{ + #[inline] + fn edge_count(&self) -> usize { + self.edge_count() + } +} + +/// Index the `MatrixGraph` by `NodeIndex` pair to access edge weights. +/// +/// Also available with indexing syntax: `&graph[e]`. +/// +/// **Panics** if no edge exists between `a` and `b`. +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> + Index<(NodeIndex<Ix>, NodeIndex<Ix>)> for MatrixGraph<N, E, Ty, Null, Ix> +{ + type Output = E; + + fn index(&self, (ax, bx): (NodeIndex<Ix>, NodeIndex<Ix>)) -> &E { + self.edge_weight(ax, bx) + } +} + +/// Index the `MatrixGraph` by `NodeIndex` pair to access edge weights. +/// +/// Also available with indexing syntax: `&mut graph[e]`. +/// +/// **Panics** if no edge exists between `a` and `b`. +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> + IndexMut<(NodeIndex<Ix>, NodeIndex<Ix>)> for MatrixGraph<N, E, Ty, Null, Ix> +{ + fn index_mut(&mut self, (ax, bx): (NodeIndex<Ix>, NodeIndex<Ix>)) -> &mut E { + self.edge_weight_mut(ax, bx) + } +} + +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> GetAdjacencyMatrix + for MatrixGraph<N, E, Ty, Null, Ix> +{ + type AdjMatrix = (); + + fn adjacency_matrix(&self) -> Self::AdjMatrix {} + + fn is_adjacent(&self, _: &Self::AdjMatrix, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool { + MatrixGraph::has_edge(self, a, b) + } +} + +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> Visitable + for MatrixGraph<N, E, Ty, Null, Ix> +{ + type Map = FixedBitSet; + + fn visit_map(&self) -> FixedBitSet { + FixedBitSet::with_capacity(self.node_bound()) + } + + fn reset_map(&self, map: &mut Self::Map) { + map.clear(); + map.grow(self.node_bound()); + } +} + +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> GraphBase + for MatrixGraph<N, E, Ty, Null, Ix> +{ + type NodeId = NodeIndex<Ix>; + type EdgeId = (NodeIndex<Ix>, NodeIndex<Ix>); +} + +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> GraphProp + for MatrixGraph<N, E, Ty, Null, Ix> +{ + type EdgeType = Ty; +} + +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> Data + for MatrixGraph<N, E, Ty, Null, Ix> +{ + type NodeWeight = N; + type EdgeWeight = E; +} + +impl<'a, N, E: 'a, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> IntoNodeIdentifiers + for &'a MatrixGraph<N, E, Ty, Null, Ix> +{ + type NodeIdentifiers = NodeIdentifiers<'a, Ix>; + + fn node_identifiers(self) -> Self::NodeIdentifiers { + NodeIdentifiers::new(self.nodes.iter_ids()) + } +} + +impl<'a, N, E: 'a, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> IntoNeighbors + for &'a MatrixGraph<N, E, Ty, Null, Ix> +{ + type Neighbors = Neighbors<'a, Ty, Null, Ix>; + + fn neighbors(self, a: NodeIndex<Ix>) -> Self::Neighbors { + MatrixGraph::neighbors(self, a) + } +} + +impl<'a, N, E: 'a, Null: Nullable<Wrapped = E>, Ix: IndexType> IntoNeighborsDirected + for &'a MatrixGraph<N, E, Directed, Null, Ix> +{ + type NeighborsDirected = Neighbors<'a, Directed, Null, Ix>; + + fn neighbors_directed(self, a: NodeIndex<Ix>, d: Direction) -> Self::NeighborsDirected { + MatrixGraph::neighbors_directed(self, a, d) + } +} + +impl<'a, N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> IntoNodeReferences + for &'a MatrixGraph<N, E, Ty, Null, Ix> +{ + type NodeRef = (NodeIndex<Ix>, &'a N); + type NodeReferences = NodeReferences<'a, N, Ix>; + fn node_references(self) -> Self::NodeReferences { + NodeReferences::new(&self.nodes) + } +} + +impl<'a, N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> IntoEdgeReferences + for &'a MatrixGraph<N, E, Ty, Null, Ix> +{ + type EdgeRef = (NodeIndex<Ix>, NodeIndex<Ix>, &'a E); + type EdgeReferences = EdgeReferences<'a, Ty, Null, Ix>; + fn edge_references(self) -> Self::EdgeReferences { + EdgeReferences::new(&self.node_adjacencies, self.node_capacity) + } +} + +impl<'a, N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> IntoEdges + for &'a MatrixGraph<N, E, Ty, Null, Ix> +{ + type Edges = Edges<'a, Ty, Null, Ix>; + fn edges(self, a: Self::NodeId) -> Self::Edges { + MatrixGraph::edges(self, a) + } +} + +impl<'a, N, E, Null: Nullable<Wrapped = E>, Ix: IndexType> IntoEdgesDirected + for &'a MatrixGraph<N, E, Directed, Null, Ix> +{ + type EdgesDirected = Edges<'a, Directed, Null, Ix>; + + fn edges_directed(self, a: Self::NodeId, dir: Direction) -> Self::EdgesDirected { + MatrixGraph::edges_directed(self, a, dir) + } +} + +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> NodeIndexable + for MatrixGraph<N, E, Ty, Null, Ix> +{ + fn node_bound(&self) -> usize { + self.nodes.upper_bound + } + + fn to_index(&self, ix: NodeIndex<Ix>) -> usize { + ix.index() + } + + fn from_index(&self, ix: usize) -> Self::NodeId { + NodeIndex::new(ix) + } +} + +impl<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> Build + for MatrixGraph<N, E, Ty, Null, Ix> +{ + fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId { + self.add_node(weight) + } + + fn add_edge( + &mut self, + a: Self::NodeId, + b: Self::NodeId, + weight: Self::EdgeWeight, + ) -> Option<Self::EdgeId> { + if !self.has_edge(a, b) { + MatrixGraph::update_edge(self, a, b, weight); + Some((a, b)) + } else { + None + } + } + + fn update_edge( + &mut self, + a: Self::NodeId, + b: Self::NodeId, + weight: Self::EdgeWeight, + ) -> Self::EdgeId { + MatrixGraph::update_edge(self, a, b, weight); + (a, b) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{Incoming, Outgoing}; + + #[test] + fn test_new() { + let g = MatrixGraph::<i32, i32>::new(); + assert_eq!(g.node_count(), 0); + assert_eq!(g.edge_count(), 0); + } + + #[test] + fn test_default() { + let g = MatrixGraph::<i32, i32>::default(); + assert_eq!(g.node_count(), 0); + assert_eq!(g.edge_count(), 0); + } + + #[test] + fn test_with_capacity() { + let g = MatrixGraph::<i32, i32>::with_capacity(10); + assert_eq!(g.node_count(), 0); + assert_eq!(g.edge_count(), 0); + } + + #[test] + fn test_node_indexing() { + let mut g: MatrixGraph<char, ()> = MatrixGraph::new(); + let a = g.add_node('a'); + let b = g.add_node('b'); + assert_eq!(g.node_count(), 2); + assert_eq!(g.edge_count(), 0); + assert_eq!(g[a], 'a'); + assert_eq!(g[b], 'b'); + } + + #[test] + fn test_remove_node() { + let mut g: MatrixGraph<char, ()> = MatrixGraph::new(); + let a = g.add_node('a'); + + g.remove_node(a); + + assert_eq!(g.node_count(), 0); + assert_eq!(g.edge_count(), 0); + } + + #[test] + fn test_add_edge() { + let mut g = MatrixGraph::new(); + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + g.add_edge(a, b, ()); + g.add_edge(b, c, ()); + assert_eq!(g.node_count(), 3); + assert_eq!(g.edge_count(), 2); + } + + #[test] + /// Adds an edge that triggers a second extension of the matrix. + /// From #425 + fn test_add_edge_with_extension() { + let mut g = DiMatrix::<u8, ()>::new(); + let _n0 = g.add_node(0); + let n1 = g.add_node(1); + let n2 = g.add_node(2); + let n3 = g.add_node(3); + let n4 = g.add_node(4); + let _n5 = g.add_node(5); + g.add_edge(n2, n1, ()); + g.add_edge(n2, n3, ()); + g.add_edge(n2, n4, ()); + assert_eq!(g.node_count(), 6); + assert_eq!(g.edge_count(), 3); + assert!(g.has_edge(n2, n1)); + assert!(g.has_edge(n2, n3)); + assert!(g.has_edge(n2, n4)); + } + + #[test] + fn test_matrix_resize() { + let mut g = DiMatrix::<u8, ()>::with_capacity(3); + let n0 = g.add_node(0); + let n1 = g.add_node(1); + let n2 = g.add_node(2); + let n3 = g.add_node(3); + g.add_edge(n1, n0, ()); + g.add_edge(n1, n1, ()); + // Triggers a resize from capacity 3 to 4 + g.add_edge(n2, n3, ()); + assert_eq!(g.node_count(), 4); + assert_eq!(g.edge_count(), 3); + assert!(g.has_edge(n1, n0)); + assert!(g.has_edge(n1, n1)); + assert!(g.has_edge(n2, n3)); + } + + #[test] + fn test_add_edge_with_weights() { + let mut g = MatrixGraph::new(); + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + g.add_edge(a, b, true); + g.add_edge(b, c, false); + assert!(*g.edge_weight(a, b)); + assert!(!*g.edge_weight(b, c)); + } + + #[test] + fn test_add_edge_with_weights_undirected() { + let mut g = MatrixGraph::new_undirected(); + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + let d = g.add_node('d'); + g.add_edge(a, b, "ab"); + g.add_edge(a, a, "aa"); + g.add_edge(b, c, "bc"); + g.add_edge(d, d, "dd"); + assert_eq!(*g.edge_weight(a, b), "ab"); + assert_eq!(*g.edge_weight(b, c), "bc"); + } + + /// Shorthand for `.collect::<Vec<_>>()` + trait IntoVec<T> { + fn into_vec(self) -> Vec<T>; + } + + impl<It, T> IntoVec<T> for It + where + It: Iterator<Item = T>, + { + fn into_vec(self) -> Vec<T> { + self.collect() + } + } + + #[test] + fn test_clear() { + let mut g = MatrixGraph::new(); + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + assert_eq!(g.node_count(), 3); + + g.add_edge(a, b, ()); + g.add_edge(b, c, ()); + g.add_edge(c, a, ()); + assert_eq!(g.edge_count(), 3); + + g.clear(); + + assert_eq!(g.node_count(), 0); + assert_eq!(g.edge_count(), 0); + + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + assert_eq!(g.node_count(), 3); + assert_eq!(g.edge_count(), 0); + + assert_eq!(g.neighbors_directed(a, Incoming).into_vec(), vec![]); + assert_eq!(g.neighbors_directed(b, Incoming).into_vec(), vec![]); + assert_eq!(g.neighbors_directed(c, Incoming).into_vec(), vec![]); + + assert_eq!(g.neighbors_directed(a, Outgoing).into_vec(), vec![]); + assert_eq!(g.neighbors_directed(b, Outgoing).into_vec(), vec![]); + assert_eq!(g.neighbors_directed(c, Outgoing).into_vec(), vec![]); + } + + #[test] + fn test_clear_undirected() { + let mut g = MatrixGraph::new_undirected(); + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + assert_eq!(g.node_count(), 3); + + g.add_edge(a, b, ()); + g.add_edge(b, c, ()); + g.add_edge(c, a, ()); + assert_eq!(g.edge_count(), 3); + + g.clear(); + + assert_eq!(g.node_count(), 0); + assert_eq!(g.edge_count(), 0); + + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + assert_eq!(g.node_count(), 3); + assert_eq!(g.edge_count(), 0); + + assert_eq!(g.neighbors(a).into_vec(), vec![]); + assert_eq!(g.neighbors(b).into_vec(), vec![]); + assert_eq!(g.neighbors(c).into_vec(), vec![]); + } + + /// Helper trait for always sorting before testing. + trait IntoSortedVec<T> { + fn into_sorted_vec(self) -> Vec<T>; + } + + impl<It, T> IntoSortedVec<T> for It + where + It: Iterator<Item = T>, + T: Ord, + { + fn into_sorted_vec(self) -> Vec<T> { + let mut v: Vec<T> = self.collect(); + v.sort(); + v + } + } + + /// Helper macro for always sorting before testing. + macro_rules! sorted_vec { + ($($x:expr),*) => { + { + let mut v = vec![$($x,)*]; + v.sort(); + v + } + } + } + + #[test] + fn test_neighbors() { + let mut g = MatrixGraph::new(); + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + g.add_edge(a, b, ()); + g.add_edge(a, c, ()); + + let a_neighbors = g.neighbors(a).into_sorted_vec(); + assert_eq!(a_neighbors, sorted_vec![b, c]); + + let b_neighbors = g.neighbors(b).into_sorted_vec(); + assert_eq!(b_neighbors, vec![]); + + let c_neighbors = g.neighbors(c).into_sorted_vec(); + assert_eq!(c_neighbors, vec![]); + } + + #[test] + fn test_neighbors_undirected() { + let mut g = MatrixGraph::new_undirected(); + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + g.add_edge(a, b, ()); + g.add_edge(a, c, ()); + + let a_neighbors = g.neighbors(a).into_sorted_vec(); + assert_eq!(a_neighbors, sorted_vec![b, c]); + + let b_neighbors = g.neighbors(b).into_sorted_vec(); + assert_eq!(b_neighbors, sorted_vec![a]); + + let c_neighbors = g.neighbors(c).into_sorted_vec(); + assert_eq!(c_neighbors, sorted_vec![a]); + } + + #[test] + fn test_remove_node_and_edges() { + let mut g = MatrixGraph::new(); + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + g.add_edge(a, b, ()); + g.add_edge(b, c, ()); + g.add_edge(c, a, ()); + + // removing b should break the `a -> b` and `b -> c` edges + g.remove_node(b); + + assert_eq!(g.node_count(), 2); + + let a_neighbors = g.neighbors(a).into_sorted_vec(); + assert_eq!(a_neighbors, vec![]); + + let c_neighbors = g.neighbors(c).into_sorted_vec(); + assert_eq!(c_neighbors, vec![a]); + } + + #[test] + fn test_remove_node_and_edges_undirected() { + let mut g = UnMatrix::new_undirected(); + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + g.add_edge(a, b, ()); + g.add_edge(b, c, ()); + g.add_edge(c, a, ()); + + // removing a should break the `a - b` and `a - c` edges + g.remove_node(a); + + assert_eq!(g.node_count(), 2); + + let b_neighbors = g.neighbors(b).into_sorted_vec(); + assert_eq!(b_neighbors, vec![c]); + + let c_neighbors = g.neighbors(c).into_sorted_vec(); + assert_eq!(c_neighbors, vec![b]); + } + + #[test] + fn test_node_identifiers() { + let mut g = MatrixGraph::new(); + let a = g.add_node('a'); + let b = g.add_node('b'); + let c = g.add_node('c'); + let d = g.add_node('c'); + g.add_edge(a, b, ()); + g.add_edge(a, c, ()); + + let node_ids = g.node_identifiers().into_sorted_vec(); + assert_eq!(node_ids, sorted_vec![a, b, c, d]); + } + + #[test] + fn test_edges_directed() { + let g: MatrixGraph<char, bool> = MatrixGraph::from_edges(&[ + (0, 5), + (0, 2), + (0, 3), + (0, 1), + (1, 3), + (2, 3), + (2, 4), + (4, 0), + (6, 6), + ]); + + assert_eq!(g.edges_directed(node_index(0), Outgoing).count(), 4); + assert_eq!(g.edges_directed(node_index(1), Outgoing).count(), 1); + assert_eq!(g.edges_directed(node_index(2), Outgoing).count(), 2); + assert_eq!(g.edges_directed(node_index(3), Outgoing).count(), 0); + assert_eq!(g.edges_directed(node_index(4), Outgoing).count(), 1); + assert_eq!(g.edges_directed(node_index(5), Outgoing).count(), 0); + assert_eq!(g.edges_directed(node_index(6), Outgoing).count(), 1); + + assert_eq!(g.edges_directed(node_index(0), Incoming).count(), 1); + assert_eq!(g.edges_directed(node_index(1), Incoming).count(), 1); + assert_eq!(g.edges_directed(node_index(2), Incoming).count(), 1); + assert_eq!(g.edges_directed(node_index(3), Incoming).count(), 3); + assert_eq!(g.edges_directed(node_index(4), Incoming).count(), 1); + assert_eq!(g.edges_directed(node_index(5), Incoming).count(), 1); + assert_eq!(g.edges_directed(node_index(6), Incoming).count(), 1); + } + + #[test] + fn test_edges_undirected() { + let g: UnMatrix<char, bool> = UnMatrix::from_edges(&[ + (0, 5), + (0, 2), + (0, 3), + (0, 1), + (1, 3), + (2, 3), + (2, 4), + (4, 0), + (6, 6), + ]); + + assert_eq!(g.edges(node_index(0)).count(), 5); + assert_eq!(g.edges(node_index(1)).count(), 2); + assert_eq!(g.edges(node_index(2)).count(), 3); + assert_eq!(g.edges(node_index(3)).count(), 3); + assert_eq!(g.edges(node_index(4)).count(), 2); + assert_eq!(g.edges(node_index(5)).count(), 1); + assert_eq!(g.edges(node_index(6)).count(), 1); + } + + #[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), + (1, 3), + (2, 3), + (2, 4), + (4, 0), + (6, 6), + ]); + + assert_eq!(g.edge_references().count(), 9); + } + + #[test] + fn test_edge_references_undirected() { + let g: UnMatrix<char, bool> = UnMatrix::from_edges(&[ + (0, 5), + (0, 2), + (0, 3), + (0, 1), + (1, 3), + (2, 3), + (2, 4), + (4, 0), + (6, 6), + ]); + + assert_eq!(g.edge_references().count(), 9); + } + + #[test] + fn test_id_storage() { + use super::IdStorage; + + let mut storage: IdStorage<char> = IdStorage::with_capacity(0); + let a = storage.add('a'); + let b = storage.add('b'); + let c = storage.add('c'); + + assert!(a < b && b < c); + + // list IDs + assert_eq!(storage.iter_ids().into_vec(), vec![a, b, c]); + + storage.remove(b); + + // re-use of IDs + let bb = storage.add('B'); + assert_eq!(b, bb); + + // list IDs + assert_eq!(storage.iter_ids().into_vec(), vec![a, b, c]); + } + + #[test] + fn test_not_zero() { + let mut g: MatrixGraph<(), i32, Directed, NotZero<i32>> = MatrixGraph::default(); + + let a = g.add_node(()); + let b = g.add_node(()); + + assert!(!g.has_edge(a, b)); + assert_eq!(g.edge_count(), 0); + + g.add_edge(a, b, 12); + + assert!(g.has_edge(a, b)); + assert_eq!(g.edge_count(), 1); + assert_eq!(g.edge_weight(a, b), &12); + + g.remove_edge(a, b); + + assert!(!g.has_edge(a, b)); + assert_eq!(g.edge_count(), 0); + } + + #[test] + #[should_panic] + fn test_not_zero_asserted() { + let mut g: MatrixGraph<(), i32, Directed, NotZero<i32>> = MatrixGraph::default(); + + let a = g.add_node(()); + let b = g.add_node(()); + + g.add_edge(a, b, 0); // this should trigger an assertion + } + + #[test] + fn test_not_zero_float() { + let mut g: MatrixGraph<(), f32, Directed, NotZero<f32>> = MatrixGraph::default(); + + let a = g.add_node(()); + let b = g.add_node(()); + + assert!(!g.has_edge(a, b)); + assert_eq!(g.edge_count(), 0); + + g.add_edge(a, b, 12.); + + assert!(g.has_edge(a, b)); + assert_eq!(g.edge_count(), 1); + assert_eq!(g.edge_weight(a, b), &12.); + + g.remove_edge(a, b); + + assert!(!g.has_edge(a, b)); + assert_eq!(g.edge_count(), 0); + } + #[test] + // From https://github.com/petgraph/petgraph/issues/523 + fn test_tarjan_scc_with_removed_node() { + let mut g: MatrixGraph<(), ()> = MatrixGraph::new(); + + g.add_node(()); + let b = g.add_node(()); + g.add_node(()); + + g.remove_node(b); + + assert_eq!( + crate::algo::tarjan_scc(&g), + [[node_index(0)], [node_index(2)]] + ); + } + + #[test] + // From https://github.com/petgraph/petgraph/issues/523 + fn test_kosaraju_scc_with_removed_node() { + let mut g: MatrixGraph<(), ()> = MatrixGraph::new(); + + g.add_node(()); + let b = g.add_node(()); + g.add_node(()); + + g.remove_node(b); + + assert_eq!( + crate::algo::kosaraju_scc(&g), + [[node_index(2)], [node_index(0)]] + ); + } +} |
