blob: 0e0c26c24cda8c1d93745f63ccb5eba8ca669d1b [file] [log] [blame]
//! `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, GetAdjacencyMatrix, GraphBase, GraphProp, IntoEdgeReferences, IntoEdges, IntoNeighbors,
IntoNeighborsDirected, IntoNodeIdentifiers, IntoNodeReferences, NodeCompactIndexable,
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> {
type Wrapped = T;
fn new(value: T) -> Self {
assert!(!value.is_zero());
NotZero(value)
}
// implemented here for optimization purposes
fn is_null(&self) -> bool {
self.0.is_zero()
}
fn as_ref(&self) -> Option<&Self::Wrapped> {
if !self.is_null() {
Some(&self.0)
} else {
None
}
}
fn as_mut(&mut self) -> Option<&mut Self::Wrapped> {
if !self.is_null() {
Some(&mut self.0)
} else {
None
}
}
}
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`](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
}
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());
m.extend_capacity_for_node(NodeIndex::new(node_capacity));
m
}
#[inline]
fn to_edge_position(&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));
self.node_adjacencies[position] = Default::default();
if Ty::is_directed() {
let position = self.to_edge_position(NodeIndex::new(id), a);
self.node_adjacencies[position] = Default::default();
}
}
self.nodes.remove(a.index())
}
#[inline]
fn extend_capacity_for_node(&mut self, min_node: NodeIndex<Ix>) {
self.node_capacity = extend_linearized_matrix::<Ty, _>(
&mut self.node_adjacencies,
self.node_capacity,
min_node.index(),
);
}
#[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);
}
}
/// 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(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`.
///
/// Return the index of the new edge.
///
/// 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);
let old_weight = mem::replace(&mut self.node_adjacencies[p], Default::default())
.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 {
let p = self.to_edge_position(a, b);
!self.node_adjacencies[p].is_null()
}
/// 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);
self.node_adjacencies[p].as_ref().unwrap()
}
/// 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);
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<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 [`Edges<E, Ix>`](../graph/struct.Edges.html).
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 [`EdgeReference<E, Ix>`](../graph/struct.EdgeReference.html).
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
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<'a, Ix: IndexType> Iterator for NodeIdentifiers<'a, Ix> {
type Item = NodeIndex<Ix>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(NodeIndex::new)
}
}
/// 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, 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]))
}
}
/// 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, 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
pub struct Neighbors<'a, Ty: EdgeType, Null: 'a + Nullable, Ix>(Edges<'a, Ty, Null, Ix>);
impl<'a, Ty: EdgeType, Null: Nullable, Ix: IndexType> Iterator for Neighbors<'a, Ty, Null, Ix> {
type Item = NodeIndex<Ix>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|(_, b, _)| b)
}
}
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
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,
min_node_capacity: usize,
) -> usize {
if Ty::is_directed() {
extend_flat_square_matrix(node_adjacencies, old_node_capacity, min_node_capacity)
} else {
extend_lower_triangular_matrix(node_adjacencies, min_node_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,
min_node_capacity: usize,
) -> usize {
let min_node_capacity = (min_node_capacity + 1).next_power_of_two();
// Optimization: when resizing the matrix this way we skip the first few grows to make
// small matrices a bit faster to work with.
const MIN_CAPACITY: usize = 4;
let new_node_capacity = cmp::max(min_node_capacity, MIN_CAPACITY);
let mut new_node_adjacencies = vec![];
ensure_len(&mut new_node_adjacencies, new_node_capacity.pow(2));
for c in 0..old_node_capacity {
let pos = c * old_node_capacity;
let new_pos = c * new_node_capacity;
let mut old = &mut node_adjacencies[pos..pos + old_node_capacity];
let mut new = &mut new_node_adjacencies[new_pos..new_pos + old_node_capacity];
mem::swap(&mut old, &mut new);
}
mem::swap(node_adjacencies, &mut new_node_adjacencies);
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_node_capacity: usize,
) -> usize {
let max_pos = to_lower_triangular_matrix_position(new_node_capacity, new_node_capacity);
ensure_len(node_adjacencies, max_pos + 1);
new_node_capacity + 1
}
/// Grow a Vec by appending the type's default value the `size` is reached.
fn ensure_len<T: Default>(v: &mut Vec<T>, size: usize) {
if let Some(n) = size.checked_sub(v.len()) {
v.reserve(n);
for _ in 0..n {
v.push(T::default());
}
}
}
#[derive(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()
}
}
struct IdIterator<'a> {
upper_bound: usize,
removed_ids: &'a IndexSet<usize>,
current: Option<usize>,
}
impl<'a> Iterator for IdIterator<'a> {
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)
}
}
/// 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_count())
}
fn reset_map(&self, map: &mut Self::Map) {
map.clear();
map.grow(self.node_count());
}
}
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<N, E, Ty: EdgeType, Null: Nullable<Wrapped = E>, Ix: IndexType> NodeIndexable
for MatrixGraph<N, E, Ty, Null, Ix>
{
fn node_bound(&self) -> usize {
self.node_count()
}
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> NodeCompactIndexable
for MatrixGraph<N, E, Ty, Null, 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]
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_eq!(*g.edge_weight(a, b), true);
assert_eq!(*g.edge_weight(b, c), false);
}
#[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);
}
}