Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

867
vendor/petgraph/src/acyclic.rs vendored Normal file
View File

@@ -0,0 +1,867 @@
//! A wrapper around graph types that enforces an acyclicity invariant.
use std::{
cell::RefCell,
cmp::Ordering,
collections::{BTreeMap, BTreeSet},
convert::TryFrom,
ops::{Deref, RangeBounds},
};
use crate::{
adj::IndexType,
algo::Cycle,
data::{Build, Create, DataMap, DataMapMut},
graph::NodeIndex,
prelude::DiGraph,
visit::{
dfs_visitor, Control, Data, DfsEvent, EdgeCount, EdgeIndexable, GetAdjacencyMatrix,
GraphBase, GraphProp, IntoEdgeReferences, IntoEdges, IntoEdgesDirected, IntoNeighbors,
IntoNeighborsDirected, IntoNodeIdentifiers, IntoNodeReferences, NodeCompactIndexable,
NodeCount, NodeIndexable, Reversed, Time, Visitable,
},
Direction,
};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::StableDiGraph;
mod order_map;
use fixedbitset::FixedBitSet;
use order_map::OrderMap;
pub use order_map::TopologicalPosition;
/// A directed acyclic graph.
///
/// Wrap directed acyclic graphs and expose an API that ensures the invariant
/// is maintained, i.e. no cycles can be created. This uses a topological order
/// that is dynamically updated when edges are added. In the worst case, the
/// runtime may be linear in the number of vertices, but it has been shown to
/// be fast in practice, particularly on sparse graphs (Pierce and Kelly, 2004).
///
/// To be modifiable (and hence to be useful), the graphs of generic type `G`
/// should implement the [`Build`] trait. Good candidates for `G` are thus
/// [`crate::graph::DiGraph`] and [`crate::stable_graph::StableDiGraph`].
///
/// ## Algorithm
/// This implements the PK algorithm for dynamic topological sort described in
/// "A Dynamic Topological Sort Algorithm for Directed Acyclic Graphs" by
/// D. Pierce and P. Kelly, JEA, 2004. It maintains a topological order of the
/// nodes that can be efficiently updated when edges are added. Achieves a good
/// balance between simplicity and performance in practice, see the paper for
/// discussions of the running time.
///
/// ## Graph traits
/// All graph traits are delegated to the inner graph, with the exception of
/// the graph construction trait [`Build`]. The wrapped graph can thus only
/// be modified through the wrapped API that ensures no cycles are created.
///
/// ## Behaviour on cycles
/// By design, edge additions to this datatype may fail. It is recommended to
/// prefer the dedicated [`Acyclic::try_add_edge`] and
/// [`Acyclic::try_update_edge`] methods whenever possible. The
/// [`Build::update_edge`] methods will panic if it is attempted to add an edge
/// that would create a cycle. The [`Build::add_edge`] on the other hand method
/// will return `None` if the edge cannot be added (either it already exists on
/// a graph type that does not support it or would create a cycle).
#[derive(Clone, Debug)]
pub struct Acyclic<G: Visitable> {
/// The underlying graph, accessible through the `inner` method.
graph: G,
/// The current topological order of the nodes.
order_map: OrderMap<G::NodeId>,
// We fix the internal DFS maps to FixedBitSet instead of G::VisitMap to do
// faster resets (by just setting bits to false)
/// Helper map for DFS tracking discovered nodes.
discovered: RefCell<FixedBitSet>,
/// Helper map for DFS tracking finished nodes.
finished: RefCell<FixedBitSet>,
}
/// An error that can occur during edge addition for acyclic graphs.
#[derive(Clone, Debug, PartialEq)]
pub enum AcyclicEdgeError<N> {
/// The edge would create a cycle.
Cycle(Cycle<N>),
/// The edge would create a self-loop.
SelfLoop,
/// Could not successfully add the edge to the underlying graph.
InvalidEdge,
}
impl<N> From<Cycle<N>> for AcyclicEdgeError<N> {
fn from(cycle: Cycle<N>) -> Self {
AcyclicEdgeError::Cycle(cycle)
}
}
impl<G: Visitable> Acyclic<G> {
/// Create a new empty acyclic graph.
pub fn new() -> Self
where
G: Default,
{
Default::default()
}
/// Get an iterator over the nodes, ordered by their position.
pub fn nodes_iter(&self) -> impl Iterator<Item = G::NodeId> + '_ {
self.order_map.nodes_iter()
}
/// Get an iterator over the nodes within the range of positions.
///
/// The nodes are ordered by their position in the topological sort.
pub fn range<'r>(
&'r self,
range: impl RangeBounds<TopologicalPosition> + 'r,
) -> impl Iterator<Item = G::NodeId> + 'r {
self.order_map.range(range)
}
/// Get the underlying graph.
pub fn inner(&self) -> &G {
&self.graph
}
/// Get the underlying graph mutably.
///
/// This cannot be public because it might break the acyclicity invariant.
fn inner_mut(&mut self) -> &mut G {
&mut self.graph
}
/// Consume the `Acyclic` wrapper and return the underlying graph.
pub fn into_inner(self) -> G {
self.graph
}
}
impl<G: Visitable + NodeIndexable> Acyclic<G>
where
for<'a> &'a G: IntoNeighborsDirected + IntoNodeIdentifiers + GraphBase<NodeId = G::NodeId>,
{
/// Wrap a graph into an acyclic graph.
///
/// The graph types [`DiGraph`] and [`StableDiGraph`] also implement
/// [`TryFrom`], which can be used instead of this method and have looser
/// type bounds.
pub fn try_from_graph(graph: G) -> Result<Self, Cycle<G::NodeId>> {
let order_map = OrderMap::try_from_graph(&graph)?;
let discovered = RefCell::new(FixedBitSet::with_capacity(graph.node_bound()));
let finished = RefCell::new(FixedBitSet::with_capacity(graph.node_bound()));
Ok(Self {
graph,
order_map,
discovered,
finished,
})
}
/// Add an edge to the graph using [`Build::add_edge`].
///
/// Returns the id of the added edge, or an [`AcyclicEdgeError`] if the edge
/// would create a cycle, a self-loop or if the edge addition failed in
/// the underlying graph.
///
/// In cases where edge addition cannot fail in the underlying graph (e.g.
/// when multi-edges are allowed, as in [`DiGraph`] and [`StableDiGraph`]),
/// this will return an error if and only if [`Self::is_valid_edge`]
/// returns `false`.
pub fn try_add_edge(
&mut self,
a: G::NodeId,
b: G::NodeId,
weight: G::EdgeWeight,
) -> Result<G::EdgeId, AcyclicEdgeError<G::NodeId>>
where
G: Build,
G::NodeId: IndexType,
{
if a == b {
// No self-loops allowed
return Err(AcyclicEdgeError::SelfLoop);
}
self.update_ordering(a, b)?;
self.graph
.add_edge(a, b, weight)
.ok_or(AcyclicEdgeError::InvalidEdge)
}
/// Update an edge in a graph using [`Build::update_edge`].
///
/// Returns the id of the updated edge, or an [`AcyclicEdgeError`] if the edge
/// would create a cycle or a self-loop. If the edge does not exist, the
/// edge is created.
///
/// This will return an error if and only if [`Self::is_valid_edge`] returns
/// `false`.
pub fn try_update_edge(
&mut self,
a: G::NodeId,
b: G::NodeId,
weight: G::EdgeWeight,
) -> Result<G::EdgeId, AcyclicEdgeError<G::NodeId>>
where
G: Build,
G::NodeId: IndexType,
{
if a == b {
// No self-loops allowed
return Err(AcyclicEdgeError::SelfLoop);
}
self.update_ordering(a, b)?;
Ok(self.graph.update_edge(a, b, weight))
}
/// Check if an edge would be valid, i.e. adding it would not create a cycle.
pub fn is_valid_edge(&self, a: G::NodeId, b: G::NodeId) -> bool
where
G::NodeId: IndexType,
{
if a == b {
false // No self-loops
} else if self.get_position(a) < self.get_position(b) {
true // valid edge in the current topological order
} else {
// Check if the future of `b` is disjoint from the past of `a`
// (in which case the topological order could be adjusted)
self.causal_cones(b, a).is_ok()
}
}
/// Update the ordering of the nodes in the order map resulting from adding an
/// edge a -> b.
///
/// If a cycle is detected, an error is returned and `self` remains unchanged.
///
/// Implements the core update logic of the PK algorithm.
fn update_ordering(&mut self, a: G::NodeId, b: G::NodeId) -> Result<(), Cycle<G::NodeId>>
where
G::NodeId: IndexType,
{
let min_order = self.get_position(b);
let max_order = self.get_position(a);
if min_order >= max_order {
// Order is already correct
return Ok(());
}
// Get the nodes reachable from `b` and the nodes that can reach `a`
// between `min_order` and `max_order`
let (b_fut, a_past) = self.causal_cones(b, a)?;
// Now reorder of nodes in a_past and b_fut such that
// i) within each vec, the nodes are in topological order,
// ii) all elements of b_fut come before all elements of a_past in the new order.
let all_positions: BTreeSet<_> = b_fut.keys().chain(a_past.keys()).copied().collect();
let all_nodes = a_past.values().chain(b_fut.values()).copied();
debug_assert_eq!(all_positions.len(), b_fut.len() + a_past.len());
for (pos, node) in all_positions.into_iter().zip(all_nodes) {
self.order_map.set_position(node, pos, &self.graph);
}
Ok(())
}
/// Use DFS to find the future causal cone of `min_node` and the past causal
/// cone of `max_node`.
///
/// The cones are trimmed to the range `[min_order, max_order]`. The cones
/// are returned if they are disjoint. Otherwise, a [`Cycle`] error is returned.
///
/// If `return_result` is false, then the cones are not constructed and the
/// method only checks for disjointness.
#[allow(clippy::type_complexity)]
fn causal_cones(
&self,
min_node: G::NodeId,
max_node: G::NodeId,
) -> Result<
(
BTreeMap<TopologicalPosition, G::NodeId>,
BTreeMap<TopologicalPosition, G::NodeId>,
),
Cycle<G::NodeId>,
>
where
G::NodeId: IndexType,
{
debug_assert!(self.discovered.borrow().is_clear());
debug_assert!(self.finished.borrow().is_clear());
let min_order = self.get_position(min_node);
let max_order = self.get_position(max_node);
// Prepare DFS scratch space: make sure the maps have enough capacity
if self.discovered.borrow().len() < self.graph.node_bound() {
self.discovered.borrow_mut().grow(self.graph.node_bound());
self.finished.borrow_mut().grow(self.graph.node_bound());
}
// Get all nodes reachable from b with min_order <= order < max_order
let mut forward_cone = BTreeMap::new();
let mut backward_cone = BTreeMap::new();
// The main logic: run DFS twice. We run this in a closure to catch
// errors and reset the maps properly at the end.
let mut run_dfs = || {
// Get all nodes reachable from min_node with min_order < order <= max_order
self.future_cone(min_node, min_order, max_order, &mut forward_cone)?;
// Get all nodes that can reach a with min_order < order <= max_order
// These are disjoint from the nodes in the forward cone, otherwise
// we would have a cycle.
self.past_cone(max_node, min_order, max_order, &mut backward_cone)
.expect("cycles already detected in future_cone");
Ok(())
};
let success = run_dfs();
// Cleanup: reset map to 0. This is faster than a full reset, especially
// on large sparse graphs.
for &v in forward_cone.values().chain(backward_cone.values()) {
self.discovered.borrow_mut().set(v.index(), false);
self.finished.borrow_mut().set(v.index(), false);
}
debug_assert!(self.discovered.borrow().is_clear());
debug_assert!(self.finished.borrow().is_clear());
match success {
Ok(()) => Ok((forward_cone, backward_cone)),
Err(cycle) => Err(cycle),
}
}
fn future_cone(
&self,
start: G::NodeId,
min_position: TopologicalPosition,
max_position: TopologicalPosition,
res: &mut BTreeMap<TopologicalPosition, G::NodeId>,
) -> Result<(), Cycle<G::NodeId>>
where
G::NodeId: IndexType,
{
dfs(
&self.graph,
start,
&self.order_map,
|order| {
debug_assert!(order >= min_position, "invalid topological order");
match order.cmp(&max_position) {
Ordering::Less => Ok(true), // node within [min_node, max_node]
Ordering::Equal => Err(Cycle(start)), // cycle!
Ordering::Greater => Ok(false), // node beyond [min_node, max_node]
}
},
res,
&mut self.discovered.borrow_mut(),
&mut self.finished.borrow_mut(),
)
}
fn past_cone(
&self,
start: G::NodeId,
min_position: TopologicalPosition,
max_position: TopologicalPosition,
res: &mut BTreeMap<TopologicalPosition, G::NodeId>,
) -> Result<(), Cycle<G::NodeId>>
where
G::NodeId: IndexType,
{
dfs(
Reversed(&self.graph),
start,
&self.order_map,
|order| {
debug_assert!(order <= max_position, "invalid topological order");
match order.cmp(&min_position) {
Ordering::Less => Ok(false), // node beyond [min_node, max_node]
Ordering::Equal => panic!("found by future_cone"), // cycle!
Ordering::Greater => Ok(true), // node within [min_node, max_node]
}
},
res,
&mut self.discovered.borrow_mut(),
&mut self.finished.borrow_mut(),
)
}
}
impl<G: Visitable> GraphBase for Acyclic<G> {
type NodeId = G::NodeId;
type EdgeId = G::EdgeId;
}
impl<G: Default + Visitable> Default for Acyclic<G> {
fn default() -> Self {
let graph: G = Default::default();
let order_map = Default::default();
let discovered = RefCell::new(FixedBitSet::default());
let finished = RefCell::new(FixedBitSet::default());
Self {
graph,
order_map,
discovered,
finished,
}
}
}
impl<G: Build + Visitable + NodeIndexable> Build for Acyclic<G>
where
for<'a> &'a G: IntoNeighborsDirected
+ IntoNodeIdentifiers
+ Visitable<Map = G::Map>
+ GraphBase<NodeId = G::NodeId>,
G::NodeId: IndexType,
{
fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
let n = self.graph.add_node(weight);
self.order_map.add_node(n, &self.graph);
n
}
fn add_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Option<Self::EdgeId> {
self.try_add_edge(a, b, weight).ok()
}
fn update_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Self::EdgeId {
self.try_update_edge(a, b, weight).unwrap()
}
}
impl<G: Create + Visitable + NodeIndexable> Create for Acyclic<G>
where
for<'a> &'a G: IntoNeighborsDirected
+ IntoNodeIdentifiers
+ Visitable<Map = G::Map>
+ GraphBase<NodeId = G::NodeId>,
G::NodeId: IndexType,
{
fn with_capacity(nodes: usize, edges: usize) -> Self {
let graph = G::with_capacity(nodes, edges);
let order_map = OrderMap::with_capacity(nodes);
let discovered = FixedBitSet::with_capacity(nodes);
let finished = FixedBitSet::with_capacity(nodes);
Self {
graph,
order_map,
discovered: RefCell::new(discovered),
finished: RefCell::new(finished),
}
}
}
impl<G: Visitable> Deref for Acyclic<G> {
type Target = G;
fn deref(&self) -> &Self::Target {
&self.graph
}
}
/// Traverse nodes in `graph` in DFS order, starting from `start`, for as long
/// as the predicate `valid_order` returns `true` on the current node's order.
fn dfs<G: NodeIndexable + IntoNeighborsDirected + IntoNodeIdentifiers + Visitable>(
graph: G,
start: G::NodeId,
order_map: &OrderMap<G::NodeId>,
// A predicate that returns whether to continue the search from a node,
// or an error to stop and shortcircuit the search.
mut valid_order: impl FnMut(TopologicalPosition) -> Result<bool, Cycle<G::NodeId>>,
res: &mut BTreeMap<TopologicalPosition, G::NodeId>,
discovered: &mut FixedBitSet,
finished: &mut FixedBitSet,
) -> Result<(), Cycle<G::NodeId>>
where
G::NodeId: IndexType,
{
dfs_visitor(
graph,
start,
&mut |ev| -> Result<Control<()>, Cycle<G::NodeId>> {
match ev {
DfsEvent::Discover(u, _) => {
// We are visiting u
let order = order_map.get_position(u, &graph);
res.insert(order, u);
Ok(Control::Continue)
}
DfsEvent::TreeEdge(_, u) => {
// Should we visit u?
let order = order_map.get_position(u, &graph);
match valid_order(order) {
Ok(true) => Ok(Control::Continue),
Ok(false) => Ok(Control::Prune),
Err(cycle) => Err(cycle),
}
}
_ => Ok(Control::Continue),
}
},
discovered,
finished,
&mut Time::default(),
)?;
Ok(())
}
/////////////////////// Pass-through graph traits ///////////////////////
// We implement all the following traits by delegating to the inner graph:
// - Data
// - DataMap
// - DataMapMut
// - EdgeCount
// - EdgeIndexable
// - GetAdjacencyMatrix
// - GraphProp
// - NodeCompactIndexable
// - NodeCount
// - NodeIndexable
// - Visitable
//
// Furthermore, we also implement the `remove_node` and `remove_edge` methods,
// as well as the following traits for `DiGraph` and `StableDiGraph` (these
// are hard/impossible to implement generically):
// - TryFrom
// - IntoEdgeReferences
// - IntoEdges
// - IntoEdgesDirected
// - IntoNeighbors
// - IntoNeighborsDirected
// - IntoNodeIdentifiers
// - IntoNodeReferences
impl<G: Visitable + Data> Data for Acyclic<G> {
type NodeWeight = G::NodeWeight;
type EdgeWeight = G::EdgeWeight;
}
impl<G: Visitable + DataMap> DataMap for Acyclic<G> {
fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
self.inner().node_weight(id)
}
fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
self.inner().edge_weight(id)
}
}
impl<G: Visitable + DataMapMut> DataMapMut for Acyclic<G> {
fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
self.inner_mut().node_weight_mut(id)
}
fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
self.inner_mut().edge_weight_mut(id)
}
}
impl<G: Visitable + EdgeCount> EdgeCount for Acyclic<G> {
fn edge_count(&self) -> usize {
self.inner().edge_count()
}
}
impl<G: Visitable + EdgeIndexable> EdgeIndexable for Acyclic<G> {
fn edge_bound(&self) -> usize {
self.inner().edge_bound()
}
fn to_index(&self, a: Self::EdgeId) -> usize {
self.inner().to_index(a)
}
fn from_index(&self, i: usize) -> Self::EdgeId {
self.inner().from_index(i)
}
}
impl<G: Visitable + GetAdjacencyMatrix> GetAdjacencyMatrix for Acyclic<G> {
type AdjMatrix = G::AdjMatrix;
fn adjacency_matrix(&self) -> Self::AdjMatrix {
self.inner().adjacency_matrix()
}
fn is_adjacent(&self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool {
self.inner().is_adjacent(matrix, a, b)
}
}
impl<G: Visitable + GraphProp> GraphProp for Acyclic<G> {
type EdgeType = G::EdgeType;
}
impl<G: Visitable + NodeCompactIndexable> NodeCompactIndexable for Acyclic<G> {}
impl<G: Visitable + NodeCount> NodeCount for Acyclic<G> {
fn node_count(&self) -> usize {
self.inner().node_count()
}
}
impl<G: Visitable + NodeIndexable> NodeIndexable for Acyclic<G> {
fn node_bound(&self) -> usize {
self.inner().node_bound()
}
fn to_index(&self, a: Self::NodeId) -> usize {
self.inner().to_index(a)
}
fn from_index(&self, i: usize) -> Self::NodeId {
self.inner().from_index(i)
}
}
impl<G: Visitable> Visitable for Acyclic<G> {
type Map = G::Map;
fn visit_map(&self) -> Self::Map {
self.inner().visit_map()
}
fn reset_map(&self, map: &mut Self::Map) {
self.inner().reset_map(map)
}
}
macro_rules! impl_graph_traits {
($graph_type:ident) => {
// Remove edge and node methods (not available through traits)
impl<N, E, Ix: IndexType> Acyclic<$graph_type<N, E, Ix>> {
/// Remove an edge and return its edge weight, or None if it didn't exist.
///
/// Pass through to underlying graph.
pub fn remove_edge(
&mut self,
e: <$graph_type<N, E, Ix> as GraphBase>::EdgeId,
) -> Option<E> {
self.graph.remove_edge(e)
}
/// Remove a node from the graph if it exists, and return its
/// weight. If it doesn't exist in the graph, return None.
///
/// This updates the order in O(v) runtime and removes the node in
/// the underlying graph.
pub fn remove_node(
&mut self,
n: <$graph_type<N, E, Ix> as GraphBase>::NodeId,
) -> Option<N> {
self.order_map.remove_node(n, &self.graph);
self.graph.remove_node(n)
}
}
impl<N, E, Ix: IndexType> TryFrom<$graph_type<N, E, Ix>>
for Acyclic<$graph_type<N, E, Ix>>
{
type Error = Cycle<NodeIndex<Ix>>;
fn try_from(graph: $graph_type<N, E, Ix>) -> Result<Self, Self::Error> {
let order_map = OrderMap::try_from_graph(&graph)?;
let discovered = RefCell::new(FixedBitSet::with_capacity(graph.node_bound()));
let finished = RefCell::new(FixedBitSet::with_capacity(graph.node_bound()));
Ok(Self {
graph,
order_map,
discovered,
finished,
})
}
}
impl<'a, N, E, Ix: IndexType> IntoEdgeReferences for &'a Acyclic<$graph_type<N, E, Ix>> {
type EdgeRef = <&'a $graph_type<N, E, Ix> as IntoEdgeReferences>::EdgeRef;
type EdgeReferences = <&'a $graph_type<N, E, Ix> as IntoEdgeReferences>::EdgeReferences;
fn edge_references(self) -> Self::EdgeReferences {
self.inner().edge_references()
}
}
impl<'a, N, E, Ix: IndexType> IntoEdges for &'a Acyclic<$graph_type<N, E, Ix>> {
type Edges = <&'a $graph_type<N, E, Ix> as IntoEdges>::Edges;
fn edges(self, a: Self::NodeId) -> Self::Edges {
self.inner().edges(a)
}
}
impl<'a, N, E, Ix: IndexType> IntoEdgesDirected for &'a Acyclic<$graph_type<N, E, Ix>> {
type EdgesDirected = <&'a $graph_type<N, E, Ix> as IntoEdgesDirected>::EdgesDirected;
fn edges_directed(self, a: Self::NodeId, dir: Direction) -> Self::EdgesDirected {
self.inner().edges_directed(a, dir)
}
}
impl<'a, N, E, Ix: IndexType> IntoNeighbors for &'a Acyclic<$graph_type<N, E, Ix>> {
type Neighbors = <&'a $graph_type<N, E, Ix> as IntoNeighbors>::Neighbors;
fn neighbors(self, a: Self::NodeId) -> Self::Neighbors {
self.inner().neighbors(a)
}
}
impl<'a, N, E, Ix: IndexType> IntoNeighborsDirected for &'a Acyclic<$graph_type<N, E, Ix>> {
type NeighborsDirected =
<&'a $graph_type<N, E, Ix> as IntoNeighborsDirected>::NeighborsDirected;
fn neighbors_directed(self, n: Self::NodeId, d: Direction) -> Self::NeighborsDirected {
self.inner().neighbors_directed(n, d)
}
}
impl<'a, N, E, Ix: IndexType> IntoNodeIdentifiers for &'a Acyclic<$graph_type<N, E, Ix>> {
type NodeIdentifiers =
<&'a $graph_type<N, E, Ix> as IntoNodeIdentifiers>::NodeIdentifiers;
fn node_identifiers(self) -> Self::NodeIdentifiers {
self.inner().node_identifiers()
}
}
impl<'a, N, E, Ix: IndexType> IntoNodeReferences for &'a Acyclic<$graph_type<N, E, Ix>> {
type NodeRef = <&'a $graph_type<N, E, Ix> as IntoNodeReferences>::NodeRef;
type NodeReferences = <&'a $graph_type<N, E, Ix> as IntoNodeReferences>::NodeReferences;
fn node_references(self) -> Self::NodeReferences {
self.inner().node_references()
}
}
};
}
impl_graph_traits!(DiGraph);
#[cfg(feature = "stable_graph")]
impl_graph_traits!(StableDiGraph);
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::DiGraph;
#[cfg(feature = "stable_graph")]
use crate::prelude::StableDiGraph;
use crate::visit::IntoNodeReferences;
#[test]
fn test_acyclic_graph() {
// Create an acyclic DiGraph
let mut graph = DiGraph::<(), ()>::new();
let a = graph.add_node(());
let c = graph.add_node(());
let b = graph.add_node(());
graph.add_edge(a, b, ());
graph.add_edge(b, c, ());
// Create an Acyclic object
let mut acyclic = Acyclic::try_from_graph(graph).unwrap();
// Test initial topological order
assert_valid_topological_order(&acyclic);
// Add a valid edge
assert!(acyclic.try_add_edge(a, c, ()).is_ok());
assert_valid_topological_order(&acyclic);
// Try to add an edge that would create a cycle
assert!(acyclic.try_add_edge(c, a, ()).is_err());
// Add another valid edge
let d = acyclic.add_node(());
assert!(acyclic.try_add_edge(c, d, ()).is_ok());
assert_valid_topological_order(&acyclic);
// Try to add an edge that would create a cycle (using the Build trait)
assert!(acyclic.add_edge(d, a, ()).is_none());
}
#[cfg(feature = "stable_graph")]
#[test]
fn test_acyclic_graph_add_remove() {
// Create an initial Acyclic graph with two nodes and one edge
let mut acyclic = Acyclic::<StableDiGraph<(), ()>>::new();
let a = acyclic.add_node(());
let b = acyclic.add_node(());
assert!(acyclic.try_add_edge(a, b, ()).is_ok());
// Check initial topological order
assert_valid_topological_order(&acyclic);
// Add a new node and an edge
let c = acyclic.add_node(());
assert!(acyclic.try_add_edge(b, c, ()).is_ok());
// Check topological order after addition
assert_valid_topological_order(&acyclic);
// Remove the node connected to two edges (node b)
acyclic.remove_node(b);
// Check topological order after removal
assert_valid_topological_order(&acyclic);
// Verify the remaining structure
let remaining_nodes: Vec<_> = acyclic
.inner()
.node_references()
.map(|(id, _)| id)
.collect();
assert_eq!(remaining_nodes.len(), 2);
assert!(remaining_nodes.contains(&a));
assert!(remaining_nodes.contains(&c));
assert!(!acyclic.inner().contains_edge(a, c));
}
fn assert_valid_topological_order<'a, G>(acyclic: &'a Acyclic<G>)
where
G: Visitable + NodeCount + NodeIndexable,
&'a G: NodeIndexable
+ IntoNodeReferences
+ IntoNeighborsDirected
+ GraphBase<NodeId = G::NodeId>,
G::NodeId: std::fmt::Debug,
{
let ordered_nodes: Vec<_> = acyclic.nodes_iter().collect();
assert_eq!(ordered_nodes.len(), acyclic.node_count());
let nodes: Vec<_> = acyclic.inner().node_identifiers().collect();
// Check that the nodes are in topological order
let mut last_position = None;
for (idx, &node) in ordered_nodes.iter().enumerate() {
assert!(nodes.contains(&node));
// Check that the node positions are monotonically increasing
let pos = acyclic.get_position(node);
assert!(Some(pos) > last_position);
last_position = Some(pos);
// Check that the neighbors are in the future of the current node
for neighbor in acyclic.inner().neighbors(node) {
let neighbour_idx = ordered_nodes.iter().position(|&n| n == neighbor).unwrap();
assert!(neighbour_idx > idx);
}
}
}
}

193
vendor/petgraph/src/acyclic/order_map.rs vendored Normal file
View File

@@ -0,0 +1,193 @@
//! A bijective map between node indices and a `TopologicalPosition`, to store
//! the total topological order of the graph.
//!
//! This data structure is an implementation detail and is not exposed in the
//! public API.
use std::{collections::BTreeMap, fmt, ops::RangeBounds};
use crate::{
algo::{toposort, Cycle},
visit::{GraphBase, IntoNeighborsDirected, IntoNodeIdentifiers, NodeIndexable, Visitable},
};
/// A position in the topological order of the graph.
///
/// This defines a total order over the set of nodes in the graph.
///
/// Note that the positions of all nodes in a graph may not form a contiguous
/// interval.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
#[repr(transparent)]
pub struct TopologicalPosition(pub(super) usize);
/// A bijective map between node indices and their position in a topological order.
///
/// Note that this map does not check for injectivity or surjectivity, this
/// must be enforced by the user. Map mutations that invalidate these properties
/// are allowed to make it easy to perform batch modifications that temporarily
/// break the invariants.
#[derive(Clone)]
pub(super) struct OrderMap<N> {
/// Map topological position to node index.
pos_to_node: BTreeMap<TopologicalPosition, N>,
/// The inverse of `pos_to_node`, i.e. map node indices to their position.
///
/// This is a Vec, relying on `N: NodeIndexable` for indexing.
node_to_pos: Vec<TopologicalPosition>,
}
impl<N> Default for OrderMap<N> {
fn default() -> Self {
Self {
pos_to_node: Default::default(),
node_to_pos: Default::default(),
}
}
}
impl<N: fmt::Debug> fmt::Debug for OrderMap<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OrderMap")
.field("order", &self.pos_to_node)
.finish()
}
}
impl<N: Copy> OrderMap<N> {
pub(super) fn try_from_graph<G>(graph: G) -> Result<Self, Cycle<G::NodeId>>
where
G: NodeIndexable<NodeId = N> + IntoNeighborsDirected + IntoNodeIdentifiers + Visitable,
{
// Compute the topological order.
let topo_vec = toposort(graph, None)?;
// Create the two map directions.
let mut pos_to_node = BTreeMap::new();
let mut node_to_pos = vec![TopologicalPosition::default(); graph.node_bound()];
// Populate the maps.
for (i, &id) in topo_vec.iter().enumerate() {
let pos = TopologicalPosition(i);
pos_to_node.insert(pos, id);
node_to_pos[graph.to_index(id)] = pos;
}
Ok(Self {
pos_to_node,
node_to_pos,
})
}
pub(super) fn with_capacity(nodes: usize) -> Self {
Self {
pos_to_node: BTreeMap::new(),
node_to_pos: Vec::with_capacity(nodes),
}
}
/// Map a node to its position in the topological order.
///
/// Panics if the node index is out of bounds.
pub(super) fn get_position(
&self,
id: N,
graph: impl NodeIndexable<NodeId = N>,
) -> TopologicalPosition {
let idx = graph.to_index(id);
assert!(idx < self.node_to_pos.len());
self.node_to_pos[idx]
}
/// Map a position in the topological order to a node, if it exists.
pub(super) fn at_position(&self, pos: TopologicalPosition) -> Option<N> {
self.pos_to_node.get(&pos).copied()
}
/// Get an iterator over the nodes, ordered by their position.
pub(super) fn nodes_iter(&self) -> impl Iterator<Item = N> + '_ {
self.pos_to_node.values().copied()
}
/// Get an iterator over the nodes within the range of positions.
pub(super) fn range(
&self,
range: impl RangeBounds<TopologicalPosition>,
) -> impl Iterator<Item = N> + '_ {
self.pos_to_node.range(range).map(|(_, &n)| n)
}
/// Add a node to the order map and assign it an arbitrary position.
///
/// Return the position of the new node.
pub(super) fn add_node(
&mut self,
id: N,
graph: impl NodeIndexable<NodeId = N>,
) -> TopologicalPosition {
// The position and node index
let new_pos = self
.pos_to_node
.iter()
.next_back()
.map(|(TopologicalPosition(idx), _)| TopologicalPosition(idx + 1))
.unwrap_or_default();
let idx = graph.to_index(id);
// Make sure the order_inv is large enough.
if idx >= self.node_to_pos.len() {
self.node_to_pos
.resize(graph.node_bound(), TopologicalPosition::default());
}
// Insert both map directions.
self.pos_to_node.insert(new_pos, id);
self.node_to_pos[idx] = new_pos;
new_pos
}
/// Remove a node from the order map.
///
/// Panics if the node index is out of bounds.
pub(super) fn remove_node(&mut self, id: N, graph: impl NodeIndexable<NodeId = N>) {
let idx = graph.to_index(id);
assert!(idx < self.node_to_pos.len());
let pos = self.node_to_pos[idx];
self.node_to_pos[idx] = TopologicalPosition::default();
self.pos_to_node.remove(&pos);
}
/// Set the position of a node.
///
/// Panics if the node index is out of bounds.
pub(super) fn set_position(
&mut self,
id: N,
pos: TopologicalPosition,
graph: impl NodeIndexable<NodeId = N>,
) {
let idx = graph.to_index(id);
assert!(idx < self.node_to_pos.len());
self.pos_to_node.insert(pos, id);
self.node_to_pos[idx] = pos;
}
}
impl<G: Visitable> super::Acyclic<G> {
/// Get the position of a node in the topological sort.
///
/// Panics if the node index is out of bounds.
pub fn get_position<'a>(&'a self, id: G::NodeId) -> TopologicalPosition
where
&'a G: NodeIndexable + GraphBase<NodeId = G::NodeId>,
{
self.order_map.get_position(id, &self.graph)
}
/// Get the node at a given position in the topological sort, if it exists.
pub fn at_position(&self, pos: TopologicalPosition) -> Option<G::NodeId> {
self.order_map.at_position(pos)
}
}

653
vendor/petgraph/src/adj.rs vendored Normal file
View File

@@ -0,0 +1,653 @@
//! Simple adjacency list.
use crate::data::{Build, DataMap, DataMapMut};
use crate::iter_format::NoPretty;
use crate::visit::{
self, EdgeCount, EdgeRef, GetAdjacencyMatrix, IntoEdgeReferences, IntoNeighbors, NodeCount,
};
use fixedbitset::FixedBitSet;
use std::fmt;
use std::ops::Range;
#[doc(no_inline)]
pub use crate::graph::{DefaultIx, IndexType};
/// Adjacency list node index type, a plain integer.
pub type NodeIndex<Ix = DefaultIx> = Ix;
/// Adjacency list edge index type, a pair of integers.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct EdgeIndex<Ix = DefaultIx>
where
Ix: IndexType,
{
/// Source of the edge.
from: NodeIndex<Ix>,
/// Index of the sucessor in the successor list.
successor_index: usize,
}
iterator_wrap! {
impl (Iterator) for
/// An Iterator over the indices of the outgoing edges from a node.
///
/// It does not borrow the graph during iteration.
#[derive(Debug, Clone)]
struct OutgoingEdgeIndices <Ix> where { Ix: IndexType }
item: EdgeIndex<Ix>,
iter: std::iter::Map<std::iter::Zip<Range<usize>, std::iter::Repeat<NodeIndex<Ix>>>, fn((usize, NodeIndex<Ix>)) -> EdgeIndex<Ix>>,
}
/// Weighted sucessor
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct WSuc<E, Ix: IndexType> {
/// Index of the sucessor.
suc: Ix,
/// Weight of the edge to `suc`.
weight: E,
}
/// One row of the adjacency list.
type Row<E, Ix> = Vec<WSuc<E, Ix>>;
type RowIter<'a, E, Ix> = std::slice::Iter<'a, WSuc<E, Ix>>;
iterator_wrap! {
impl (Iterator DoubleEndedIterator ExactSizeIterator) for
/// An iterator over the indices of the neighbors of a node.
#[derive(Debug, Clone)]
struct Neighbors<'a, E, Ix> where { Ix: IndexType }
item: NodeIndex<Ix>,
iter: std::iter::Map<RowIter<'a, E, Ix>, fn(&WSuc<E, Ix>) -> NodeIndex<Ix>>,
}
/// A reference to an edge of the graph.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct EdgeReference<'a, E, Ix: IndexType> {
/// index of the edge
id: EdgeIndex<Ix>,
/// a reference to the corresponding item in the adjacency list
edge: &'a WSuc<E, Ix>,
}
impl<E, Ix: IndexType> Copy for EdgeReference<'_, E, Ix> {}
impl<E, Ix: IndexType> Clone for EdgeReference<'_, E, Ix> {
fn clone(&self) -> Self {
*self
}
}
impl<E, Ix: IndexType> visit::EdgeRef for EdgeReference<'_, E, Ix> {
type NodeId = NodeIndex<Ix>;
type EdgeId = EdgeIndex<Ix>;
type Weight = E;
fn source(&self) -> Self::NodeId {
self.id.from
}
fn target(&self) -> Self::NodeId {
self.edge.suc
}
fn id(&self) -> Self::EdgeId {
self.id
}
fn weight(&self) -> &Self::Weight {
&self.edge.weight
}
}
#[derive(Debug, Clone)]
pub struct EdgeIndices<'a, E, Ix: IndexType> {
rows: std::iter::Enumerate<std::slice::Iter<'a, Row<E, Ix>>>,
row_index: usize,
row_len: usize,
cur: usize,
}
impl<E, Ix: IndexType> Iterator for EdgeIndices<'_, E, Ix> {
type Item = EdgeIndex<Ix>;
fn next(&mut self) -> Option<EdgeIndex<Ix>> {
loop {
if self.cur < self.row_len {
let res = self.cur;
self.cur += 1;
return Some(EdgeIndex {
from: Ix::new(self.row_index),
successor_index: res,
});
} else {
match self.rows.next() {
Some((index, row)) => {
self.row_index = index;
self.cur = 0;
self.row_len = row.len();
}
None => return None,
}
}
}
}
}
iterator_wrap! {
impl (Iterator DoubleEndedIterator ExactSizeIterator) for
/// An iterator over all node indices in the graph.
#[derive(Debug, Clone)]
struct NodeIndices <Ix> where {}
item: Ix,
iter: std::iter::Map<Range<usize>, fn(usize) -> Ix>,
}
/// An adjacency list with labeled edges.
///
/// Can be interpreted as a directed graph
/// with unweighted nodes.
///
/// This is the most simple adjacency list you can imagine. [`Graph`](../graph/struct.Graph.html), in contrast,
/// maintains both the list of successors and predecessors for each node,
/// which is a different trade-off.
///
/// Allows parallel edges and self-loops.
///
/// This data structure is append-only (except for [`clear`](#method.clear)), so indices
/// returned at some point for a given graph will stay valid with this same
/// graph until it is dropped or [`clear`](#method.clear) is called.
///
/// Space consumption: **O(|E|)**.
#[derive(Clone, Default)]
pub struct List<E, Ix = DefaultIx>
where
Ix: IndexType,
{
suc: Vec<Row<E, Ix>>,
}
impl<E, Ix: IndexType> List<E, Ix> {
/// Creates a new, empty adjacency list.
pub fn new() -> List<E, Ix> {
List { suc: Vec::new() }
}
/// Creates a new, empty adjacency list tailored for `nodes` nodes.
pub fn with_capacity(nodes: usize) -> List<E, Ix> {
List {
suc: Vec::with_capacity(nodes),
}
}
/// Removes all nodes and edges from the list.
pub fn clear(&mut self) {
self.suc.clear()
}
/// Returns the number of edges in the list
///
/// Computes in **O(|V|)** time.
pub fn edge_count(&self) -> usize {
self.suc.iter().map(|x| x.len()).sum()
}
/// Adds a new node to the list. This allocates a new `Vec` and then should
/// run in amortized **O(1)** time.
pub fn add_node(&mut self) -> NodeIndex<Ix> {
let i = self.suc.len();
self.suc.push(Vec::new());
Ix::new(i)
}
/// Adds a new node to the list. This allocates a new `Vec` and then should
/// run in amortized **O(1)** time.
pub fn add_node_with_capacity(&mut self, successors: usize) -> NodeIndex<Ix> {
let i = self.suc.len();
self.suc.push(Vec::with_capacity(successors));
Ix::new(i)
}
/// Adds a new node to the list by giving its list of successors and the corresponding
/// weigths.
pub fn add_node_from_edges<I: Iterator<Item = (NodeIndex<Ix>, E)>>(
&mut self,
edges: I,
) -> NodeIndex<Ix> {
let i = self.suc.len();
self.suc
.push(edges.map(|(suc, weight)| WSuc { suc, weight }).collect());
Ix::new(i)
}
/// 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.
///
/// **Panics** if the source node does not exist.<br>
///
/// **Note:** `List` allows 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) -> EdgeIndex<Ix> {
if b.index() >= self.suc.len() {
panic!(
"{} is not a valid node index for a {} nodes adjacency list",
b.index(),
self.suc.len()
);
}
let row = &mut self.suc[a.index()];
let rank = row.len();
row.push(WSuc { suc: b, weight });
EdgeIndex {
from: a,
successor_index: rank,
}
}
fn get_edge(&self, e: EdgeIndex<Ix>) -> Option<&WSuc<E, Ix>> {
self.suc
.get(e.from.index())
.and_then(|row| row.get(e.successor_index))
}
fn get_edge_mut(&mut self, e: EdgeIndex<Ix>) -> Option<&mut WSuc<E, Ix>> {
self.suc
.get_mut(e.from.index())
.and_then(|row| row.get_mut(e.successor_index))
}
/// Accesses the source and target of edge `e`
///
/// Computes in **O(1)**
pub fn edge_endpoints(&self, e: EdgeIndex<Ix>) -> Option<(NodeIndex<Ix>, NodeIndex<Ix>)> {
self.get_edge(e).map(|x| (e.from, x.suc))
}
pub fn edge_indices_from(&self, a: NodeIndex<Ix>) -> OutgoingEdgeIndices<Ix> {
let proj: fn((usize, NodeIndex<Ix>)) -> EdgeIndex<Ix> =
|(successor_index, from)| EdgeIndex {
from,
successor_index,
};
let iter = (0..(self.suc[a.index()].len()))
.zip(std::iter::repeat(a))
.map(proj);
OutgoingEdgeIndices { iter }
}
/// Lookups whether there is an edge from `a` to `b`.
///
/// Computes in **O(e')** time, where **e'** is the number of successors of `a`.
pub fn contains_edge(&self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool {
match self.suc.get(a.index()) {
None => false,
Some(row) => row.iter().any(|x| x.suc == b),
}
}
/// Lookups whether there is an edge from `a` to `b`.
///
/// Computes in **O(e')** time, where **e'** is the number of successors of `a`.
pub fn find_edge(&self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> Option<EdgeIndex<Ix>> {
self.suc.get(a.index()).and_then(|row| {
row.iter()
.enumerate()
.find(|(_, x)| x.suc == b)
.map(|(i, _)| EdgeIndex {
from: a,
successor_index: i,
})
})
}
/// Returns an iterator over all node indices of the graph.
///
/// Consuming the whole iterator take **O(|V|)**.
pub fn node_indices(&self) -> NodeIndices<Ix> {
NodeIndices {
iter: (0..self.suc.len()).map(Ix::new),
}
}
/// Returns an iterator over all edge indices of the graph.
///
/// Consuming the whole iterator take **O(|V| + |E|)**.
pub fn edge_indices(&self) -> EdgeIndices<E, Ix> {
EdgeIndices {
rows: self.suc.iter().enumerate(),
row_index: 0,
row_len: 0,
cur: 0,
}
}
}
/// A very simple adjacency list with no node or label weights.
pub type UnweightedList<Ix> = List<(), Ix>;
impl<E, Ix: IndexType> Build for List<E, Ix> {
/// Adds a new node to the list. This allocates a new `Vec` and then should
/// run in amortized **O(1)** time.
fn add_node(&mut self, _weight: ()) -> NodeIndex<Ix> {
self.add_node()
}
/// 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.
///
/// **Panics** if the source node does not exist.<br>
///
/// **Note:** `List` allows adding parallel (“duplicate”) edges. If you want
/// to avoid this, use [`.update_edge(a, b, weight)`](#method.update_edge) instead.
fn add_edge(&mut self, a: NodeIndex<Ix>, b: NodeIndex<Ix>, weight: E) -> Option<EdgeIndex<Ix>> {
Some(self.add_edge(a, b, weight))
}
/// Updates or adds an edge from `a` to `b` to the graph, with its associated
/// data `weight`.
///
/// Return the index of the new edge.
///
/// Computes in **O(e')** time, where **e'** is the number of successors of `a`.
///
/// **Panics** if the source node does not exist.<br>
fn update_edge(&mut self, a: NodeIndex<Ix>, b: NodeIndex<Ix>, weight: E) -> EdgeIndex<Ix> {
let row = &mut self.suc[a.index()];
for (i, info) in row.iter_mut().enumerate() {
if info.suc == b {
info.weight = weight;
return EdgeIndex {
from: a,
successor_index: i,
};
}
}
let rank = row.len();
row.push(WSuc { suc: b, weight });
EdgeIndex {
from: a,
successor_index: rank,
}
}
}
impl<E, Ix> fmt::Debug for EdgeReferences<'_, E, Ix>
where
E: fmt::Debug,
Ix: IndexType,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut edge_list = f.debug_list();
let iter: Self = self.clone();
for e in iter {
if std::mem::size_of::<E>() != 0 {
edge_list.entry(&(
NoPretty((e.source().index(), e.target().index())),
e.weight(),
));
} else {
edge_list.entry(&NoPretty((e.source().index(), e.target().index())));
}
}
edge_list.finish()
}
}
impl<E, Ix> fmt::Debug for List<E, Ix>
where
E: fmt::Debug,
Ix: IndexType,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut fmt_struct = f.debug_struct("adj::List");
fmt_struct.field("node_count", &self.node_count());
fmt_struct.field("edge_count", &self.edge_count());
if self.edge_count() > 0 {
fmt_struct.field("edges", &self.edge_references());
}
fmt_struct.finish()
}
}
impl<E, Ix> visit::GraphBase for List<E, Ix>
where
Ix: IndexType,
{
type NodeId = NodeIndex<Ix>;
type EdgeId = EdgeIndex<Ix>;
}
impl<E, Ix> visit::Visitable for List<E, Ix>
where
Ix: IndexType,
{
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<E, Ix: IndexType> visit::IntoNodeIdentifiers for &List<E, Ix> {
type NodeIdentifiers = NodeIndices<Ix>;
fn node_identifiers(self) -> NodeIndices<Ix> {
self.node_indices()
}
}
impl<Ix: IndexType> visit::NodeRef for NodeIndex<Ix> {
type NodeId = NodeIndex<Ix>;
type Weight = ();
fn id(&self) -> Self::NodeId {
*self
}
fn weight(&self) -> &Self::Weight {
&()
}
}
impl<Ix: IndexType, E> visit::IntoNodeReferences for &List<E, Ix> {
type NodeRef = NodeIndex<Ix>;
type NodeReferences = NodeIndices<Ix>;
fn node_references(self) -> Self::NodeReferences {
self.node_indices()
}
}
impl<E, Ix: IndexType> visit::Data for List<E, Ix> {
type NodeWeight = ();
type EdgeWeight = E;
}
impl<'a, E, Ix: IndexType> IntoNeighbors for &'a List<E, Ix> {
type Neighbors = Neighbors<'a, E, Ix>;
/// Returns an iterator of all nodes with an edge starting from `a`.
/// Panics if `a` is out of bounds.
/// Use [`List::edge_indices_from`] instead if you do not want to borrow the adjacency list while
/// iterating.
fn neighbors(self, a: NodeIndex<Ix>) -> Self::Neighbors {
let proj: fn(&WSuc<E, Ix>) -> NodeIndex<Ix> = |x| x.suc;
let iter = self.suc[a.index()].iter().map(proj);
Neighbors { iter }
}
}
type SomeIter<'a, E, Ix> = std::iter::Map<
std::iter::Zip<std::iter::Enumerate<RowIter<'a, E, Ix>>, std::iter::Repeat<Ix>>,
fn(((usize, &'a WSuc<E, Ix>), Ix)) -> EdgeReference<'a, E, Ix>,
>;
iterator_wrap! {
impl (Iterator) for
/// An iterator over the [`EdgeReference`] of all the edges of the graph.
struct EdgeReferences<'a, E, Ix> where { Ix: IndexType }
item: EdgeReference<'a, E, Ix>,
iter: std::iter::FlatMap<
std::iter::Enumerate<
std::slice::Iter<'a, Row<E, Ix>>
>,
SomeIter<'a, E, Ix>,
fn(
(usize, &'a Vec<WSuc<E, Ix>>)
) -> SomeIter<'a, E, Ix>,
>,
}
impl<E, Ix: IndexType> Clone for EdgeReferences<'_, E, Ix> {
fn clone(&self) -> Self {
EdgeReferences {
iter: self.iter.clone(),
}
}
}
fn proj1<E, Ix: IndexType>(
((successor_index, edge), from): ((usize, &WSuc<E, Ix>), Ix),
) -> EdgeReference<E, Ix> {
let id = EdgeIndex {
from,
successor_index,
};
EdgeReference { id, edge }
}
fn proj2<E, Ix: IndexType>((row_index, row): (usize, &Vec<WSuc<E, Ix>>)) -> SomeIter<E, Ix> {
row.iter()
.enumerate()
.zip(std::iter::repeat(Ix::new(row_index)))
.map(proj1 as _)
}
impl<'a, Ix: IndexType, E> visit::IntoEdgeReferences for &'a List<E, Ix> {
type EdgeRef = EdgeReference<'a, E, Ix>;
type EdgeReferences = EdgeReferences<'a, E, Ix>;
fn edge_references(self) -> Self::EdgeReferences {
let iter = self.suc.iter().enumerate().flat_map(proj2 as _);
EdgeReferences { iter }
}
}
iterator_wrap! {
impl (Iterator) for
/// Iterator over the [`EdgeReference`] of the outgoing edges from a node.
#[derive(Debug, Clone)]
struct OutgoingEdgeReferences<'a, E, Ix> where { Ix: IndexType }
item: EdgeReference<'a, E, Ix>,
iter: SomeIter<'a, E, Ix>,
}
impl<'a, Ix: IndexType, E> visit::IntoEdges for &'a List<E, Ix> {
type Edges = OutgoingEdgeReferences<'a, E, Ix>;
fn edges(self, a: Self::NodeId) -> Self::Edges {
let iter = self.suc[a.index()]
.iter()
.enumerate()
.zip(std::iter::repeat(a))
.map(proj1 as _);
OutgoingEdgeReferences { iter }
}
}
impl<E, Ix: IndexType> visit::GraphProp for List<E, Ix> {
type EdgeType = crate::Directed;
fn is_directed(&self) -> bool {
true
}
}
impl<E, Ix: IndexType> NodeCount for List<E, Ix> {
/// Returns the number of nodes in the list
///
/// Computes in **O(1)** time.
fn node_count(&self) -> usize {
self.suc.len()
}
}
impl<E, Ix: IndexType> EdgeCount for List<E, Ix> {
/// Returns the number of edges in the list
///
/// Computes in **O(|V|)** time.
fn edge_count(&self) -> usize {
List::edge_count(self)
}
}
impl<E, Ix: IndexType> visit::NodeIndexable for List<E, Ix> {
fn node_bound(&self) -> usize {
self.node_count()
}
#[inline]
fn to_index(&self, a: Self::NodeId) -> usize {
a.index()
}
#[inline]
fn from_index(&self, i: usize) -> Self::NodeId {
Ix::new(i)
}
}
impl<E, Ix: IndexType> visit::NodeCompactIndexable for List<E, Ix> {}
impl<E, Ix: IndexType> DataMap for List<E, Ix> {
fn node_weight(&self, n: Self::NodeId) -> Option<&()> {
if n.index() < self.suc.len() {
Some(&())
} else {
None
}
}
/// Accesses the weight of edge `e`
///
/// Computes in **O(1)**
fn edge_weight(&self, e: EdgeIndex<Ix>) -> Option<&E> {
self.get_edge(e).map(|x| &x.weight)
}
}
impl<E, Ix: IndexType> DataMapMut for List<E, Ix> {
fn node_weight_mut(&mut self, n: Self::NodeId) -> Option<&mut ()> {
if n.index() < self.suc.len() {
// A hack to produce a &'static mut ()
// It does not actually allocate according to godbolt
let b = Box::new(());
Some(Box::leak(b))
} else {
None
}
}
/// Accesses the weight of edge `e`
///
/// Computes in **O(1)**
fn edge_weight_mut(&mut self, e: EdgeIndex<Ix>) -> Option<&mut E> {
self.get_edge_mut(e).map(|x| &mut x.weight)
}
}
/// The adjacency matrix for **List** is a bitmap that's computed by
/// `.adjacency_matrix()`.
impl<E, Ix> GetAdjacencyMatrix for List<E, Ix>
where
Ix: IndexType,
{
type AdjMatrix = FixedBitSet;
fn adjacency_matrix(&self) -> FixedBitSet {
let n = self.node_count();
let mut matrix = FixedBitSet::with_capacity(n * n);
for edge in self.edge_references() {
let i = edge.source().index() * n + edge.target().index();
matrix.put(i);
}
matrix
}
fn is_adjacent(&self, matrix: &FixedBitSet, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool {
let n = self.node_count();
let index = n * a.index() + b.index();
matrix.contains(index)
}
}

178
vendor/petgraph/src/algo/astar.rs vendored Normal file
View File

@@ -0,0 +1,178 @@
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{BinaryHeap, HashMap};
use std::hash::Hash;
use crate::scored::MinScored;
use crate::visit::{EdgeRef, GraphBase, IntoEdges, Visitable};
use crate::algo::Measure;
/// \[Generic\] A* shortest path algorithm.
///
/// Computes the shortest path from `start` to `finish`, including the total path cost.
///
/// `finish` is implicitly given via the `is_goal` callback, which should return `true` if the
/// given node is the finish node.
///
/// The function `edge_cost` should return the cost for a particular edge. Edge costs must be
/// non-negative.
///
/// The function `estimate_cost` should return the estimated cost to the finish for a particular
/// node. For the algorithm to find the actual shortest path, it should be admissible, meaning that
/// it should never overestimate the actual cost to get to the nearest goal node. Estimate costs
/// must also be non-negative.
///
/// The graph should be `Visitable` and implement `IntoEdges`.
///
/// # Example
/// ```
/// use petgraph::Graph;
/// use petgraph::algo::astar;
///
/// let mut g = Graph::new();
/// let a = g.add_node((0., 0.));
/// let b = g.add_node((2., 0.));
/// let c = g.add_node((1., 1.));
/// let d = g.add_node((0., 2.));
/// let e = g.add_node((3., 3.));
/// let f = g.add_node((4., 2.));
/// g.extend_with_edges(&[
/// (a, b, 2),
/// (a, d, 4),
/// (b, c, 1),
/// (b, f, 7),
/// (c, e, 5),
/// (e, f, 1),
/// (d, e, 1),
/// ]);
///
/// // Graph represented with the weight of each edge
/// // Edges with '*' are part of the optimal path.
/// //
/// // 2 1
/// // a ----- b ----- c
/// // | 4* | 7 |
/// // d f | 5
/// // | 1* | 1* |
/// // \------ e ------/
///
/// let path = astar(&g, a, |finish| finish == f, |e| *e.weight(), |_| 0);
/// assert_eq!(path, Some((6, vec![a, d, e, f])));
/// ```
///
/// Returns the total cost + the path of subsequent `NodeId` from start to finish, if one was
/// found.
pub fn astar<G, F, H, K, IsGoal>(
graph: G,
start: G::NodeId,
mut is_goal: IsGoal,
mut edge_cost: F,
mut estimate_cost: H,
) -> Option<(K, Vec<G::NodeId>)>
where
G: IntoEdges + Visitable,
IsGoal: FnMut(G::NodeId) -> bool,
G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
H: FnMut(G::NodeId) -> K,
K: Measure + Copy,
{
let mut visit_next = BinaryHeap::new();
let mut scores = HashMap::new(); // g-values, cost to reach the node
let mut estimate_scores = HashMap::new(); // f-values, cost to reach + estimate cost to goal
let mut path_tracker = PathTracker::<G>::new();
let zero_score = K::default();
scores.insert(start, zero_score);
visit_next.push(MinScored(estimate_cost(start), start));
while let Some(MinScored(estimate_score, node)) = visit_next.pop() {
if is_goal(node) {
let path = path_tracker.reconstruct_path_to(node);
let cost = scores[&node];
return Some((cost, path));
}
// This lookup can be unwrapped without fear of panic since the node was necessarily scored
// before adding it to `visit_next`.
let node_score = scores[&node];
match estimate_scores.entry(node) {
Occupied(mut entry) => {
// If the node has already been visited with an equal or lower score than now, then
// we do not need to re-visit it.
if *entry.get() <= estimate_score {
continue;
}
entry.insert(estimate_score);
}
Vacant(entry) => {
entry.insert(estimate_score);
}
}
for edge in graph.edges(node) {
let next = edge.target();
let next_score = node_score + edge_cost(edge);
match scores.entry(next) {
Occupied(mut entry) => {
// No need to add neighbors that we have already reached through a shorter path
// than now.
if *entry.get() <= next_score {
continue;
}
entry.insert(next_score);
}
Vacant(entry) => {
entry.insert(next_score);
}
}
path_tracker.set_predecessor(next, node);
let next_estimate_score = next_score + estimate_cost(next);
visit_next.push(MinScored(next_estimate_score, next));
}
}
None
}
struct PathTracker<G>
where
G: GraphBase,
G::NodeId: Eq + Hash,
{
came_from: HashMap<G::NodeId, G::NodeId>,
}
impl<G> PathTracker<G>
where
G: GraphBase,
G::NodeId: Eq + Hash,
{
fn new() -> PathTracker<G> {
PathTracker {
came_from: HashMap::new(),
}
}
fn set_predecessor(&mut self, node: G::NodeId, previous: G::NodeId) {
self.came_from.insert(node, previous);
}
fn reconstruct_path_to(&self, last: G::NodeId) -> Vec<G::NodeId> {
let mut path = vec![last];
let mut current = last;
while let Some(&previous) = self.came_from.get(&current) {
path.push(previous);
current = previous;
}
path.reverse();
path
}
}

244
vendor/petgraph/src/algo/bellman_ford.rs vendored Normal file
View File

@@ -0,0 +1,244 @@
//! Bellman-Ford algorithms.
use crate::prelude::*;
use crate::visit::{IntoEdges, IntoNodeIdentifiers, NodeCount, NodeIndexable, VisitMap, Visitable};
use super::{FloatMeasure, NegativeCycle};
#[derive(Debug, Clone)]
pub struct Paths<NodeId, EdgeWeight> {
pub distances: Vec<EdgeWeight>,
pub predecessors: Vec<Option<NodeId>>,
}
/// \[Generic\] Compute shortest paths from node `source` to all other.
///
/// Using the [BellmanFord algorithm][bf]; negative edge costs are
/// permitted, but the graph must not have a cycle of negative weights
/// (in that case it will return an error).
///
/// On success, return one vec with path costs, and another one which points
/// out the predecessor of a node along a shortest path. The vectors
/// are indexed by the graph's node indices.
///
/// [bf]: https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm
///
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::bellman_ford;
/// use petgraph::prelude::*;
///
/// let mut g = Graph::new();
/// let a = g.add_node(()); // node with no weight
/// let b = g.add_node(());
/// let c = g.add_node(());
/// let d = g.add_node(());
/// let e = g.add_node(());
/// let f = g.add_node(());
/// g.extend_with_edges(&[
/// (0, 1, 2.0),
/// (0, 3, 4.0),
/// (1, 2, 1.0),
/// (1, 5, 7.0),
/// (2, 4, 5.0),
/// (4, 5, 1.0),
/// (3, 4, 1.0),
/// ]);
///
/// // Graph represented with the weight of each edge
/// //
/// // 2 1
/// // a ----- b ----- c
/// // | 4 | 7 |
/// // d f | 5
/// // | 1 | 1 |
/// // \------ e ------/
///
/// let path = bellman_ford(&g, a);
/// assert!(path.is_ok());
/// let path = path.unwrap();
/// assert_eq!(path.distances, vec![ 0.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
/// assert_eq!(path.predecessors, vec![None, Some(a),Some(b),Some(a), Some(d), Some(e)]);
///
/// // Node f (indice 5) can be reach from a with a path costing 6.
/// // Predecessor of f is Some(e) which predecessor is Some(d) which predecessor is Some(a).
/// // Thus the path from a to f is a <-> d <-> e <-> f
///
/// let graph_with_neg_cycle = Graph::<(), f32, Undirected>::from_edges(&[
/// (0, 1, -2.0),
/// (0, 3, -4.0),
/// (1, 2, -1.0),
/// (1, 5, -25.0),
/// (2, 4, -5.0),
/// (4, 5, -25.0),
/// (3, 4, -1.0),
/// ]);
///
/// assert!(bellman_ford(&graph_with_neg_cycle, NodeIndex::new(0)).is_err());
/// ```
pub fn bellman_ford<G>(
g: G,
source: G::NodeId,
) -> Result<Paths<G::NodeId, G::EdgeWeight>, NegativeCycle>
where
G: NodeCount + IntoNodeIdentifiers + IntoEdges + NodeIndexable,
G::EdgeWeight: FloatMeasure,
{
let ix = |i| g.to_index(i);
// Step 1 and Step 2: initialize and relax
let (distances, predecessors) = bellman_ford_initialize_relax(g, source);
// Step 3: check for negative weight cycle
for i in g.node_identifiers() {
for edge in g.edges(i) {
let j = edge.target();
let w = *edge.weight();
if distances[ix(i)] + w < distances[ix(j)] {
return Err(NegativeCycle(()));
}
}
}
Ok(Paths {
distances,
predecessors,
})
}
/// \[Generic\] Find the path of a negative cycle reachable from node `source`.
///
/// Using the [find_negative_cycle][nc]; will search the Graph for negative cycles using
/// [BellmanFord algorithm][bf]. If no negative cycle is found the function will return `None`.
///
/// If a negative cycle is found from source, return one vec with a path of `NodeId`s.
///
/// The time complexity of this algorithm should be the same as the Bellman-Ford (O(|V|·|E|)).
///
/// [nc]: https://blogs.asarkar.com/assets/docs/algorithms-curated/Negative-Weight%20Cycle%20Algorithms%20-%20Huang.pdf
/// [bf]: https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm
///
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::find_negative_cycle;
/// use petgraph::prelude::*;
///
/// let graph_with_neg_cycle = Graph::<(), f32, Directed>::from_edges(&[
/// (0, 1, 1.),
/// (0, 2, 1.),
/// (0, 3, 1.),
/// (1, 3, 1.),
/// (2, 1, 1.),
/// (3, 2, -3.),
/// ]);
///
/// let path = find_negative_cycle(&graph_with_neg_cycle, NodeIndex::new(0));
/// assert_eq!(
/// path,
/// Some([NodeIndex::new(1), NodeIndex::new(3), NodeIndex::new(2)].to_vec())
/// );
/// ```
pub fn find_negative_cycle<G>(g: G, source: G::NodeId) -> Option<Vec<G::NodeId>>
where
G: NodeCount + IntoNodeIdentifiers + IntoEdges + NodeIndexable + Visitable,
G::EdgeWeight: FloatMeasure,
{
let ix = |i| g.to_index(i);
let mut path = Vec::<G::NodeId>::new();
// Step 1: initialize and relax
let (distance, predecessor) = bellman_ford_initialize_relax(g, source);
// Step 2: Check for negative weight cycle
'outer: for i in g.node_identifiers() {
for edge in g.edges(i) {
let j = edge.target();
let w = *edge.weight();
if distance[ix(i)] + w < distance[ix(j)] {
// Step 3: negative cycle found
let start = j;
let mut node = start;
let mut visited = g.visit_map();
// Go backward in the predecessor chain
loop {
let ancestor = match predecessor[ix(node)] {
Some(predecessor_node) => predecessor_node,
None => node, // no predecessor, self cycle
};
// We have only 2 ways to find the cycle and break the loop:
// 1. start is reached
if ancestor == start {
path.push(ancestor);
break;
}
// 2. some node was reached twice
else if visited.is_visited(&ancestor) {
// Drop any node in path that is before the first ancestor
let pos = path
.iter()
.position(|&p| p == ancestor)
.expect("we should always have a position");
path = path[pos..path.len()].to_vec();
break;
}
// None of the above, some middle path node
path.push(ancestor);
visited.visit(ancestor);
node = ancestor;
}
// We are done here
break 'outer;
}
}
}
if !path.is_empty() {
// Users will probably need to follow the path of the negative cycle
// so it should be in the reverse order than it was found by the algorithm.
path.reverse();
Some(path)
} else {
None
}
}
// Perform Step 1 and Step 2 of the Bellman-Ford algorithm.
#[inline(always)]
fn bellman_ford_initialize_relax<G>(
g: G,
source: G::NodeId,
) -> (Vec<G::EdgeWeight>, Vec<Option<G::NodeId>>)
where
G: NodeCount + IntoNodeIdentifiers + IntoEdges + NodeIndexable,
G::EdgeWeight: FloatMeasure,
{
// Step 1: initialize graph
let mut predecessor = vec![None; g.node_bound()];
let mut distance = vec![<_>::infinite(); g.node_bound()];
let ix = |i| g.to_index(i);
distance[ix(source)] = <_>::zero();
// Step 2: relax edges repeatedly
for _ in 1..g.node_count() {
let mut did_update = false;
for i in g.node_identifiers() {
for edge in g.edges(i) {
let j = edge.target();
let w = *edge.weight();
if distance[ix(i)] + w < distance[ix(j)] {
distance[ix(j)] = distance[ix(i)] + w;
predecessor[ix(j)] = Some(i);
did_update = true;
}
}
}
if !did_update {
break;
}
}
(distance, predecessor)
}

96
vendor/petgraph/src/algo/coloring.rs vendored Normal file
View File

@@ -0,0 +1,96 @@
use std::collections::{BinaryHeap, HashMap, HashSet};
use std::hash::Hash;
use crate::scored::MaxScored;
use crate::visit::{IntoEdges, IntoNodeIdentifiers, NodeIndexable, VisitMap, Visitable};
/// \[Generic\] DStatur algorithm to properly color a non weighted undirected graph.
/// https://en.wikipedia.org/wiki/DSatur
///
/// This is a heuristic. So, it does not necessarily return a minimum coloring.
///
/// The graph must be undirected. It should not contain loops.
/// It must implement `IntoEdges`, `IntoNodeIdentifiers` and `Visitable`
/// Returns a tuple composed of a HashMap that associates to each `NodeId` its color and the number of used colors.
///
/// Computes in **O((|V| + |E|)*log(|V|)** time
///
/// # Example
/// ```rust
/// use petgraph::{Graph, Undirected};
/// use petgraph::algo::dsatur_coloring;
///
/// let mut graph: Graph<(), (), Undirected> = Graph::new_undirected();
/// let a = graph.add_node(());
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// (d, e),
/// (e, f),
/// (f, a),
/// ]);
///
/// // a ----- b ----- c
/// // | |
/// // | |
/// // | |
/// // f ----- e------ d
///
/// let (coloring, nb_colors) = dsatur_coloring(&graph);
/// assert_eq!(nb_colors, 2);
/// assert_ne!(coloring[&a], coloring[&b]);
/// ```
pub fn dsatur_coloring<G>(graph: G) -> (HashMap<G::NodeId, usize>, usize)
where
G: IntoEdges + IntoNodeIdentifiers + Visitable + NodeIndexable,
G::NodeId: Eq + Hash,
{
let ix = |v| graph.to_index(v);
let n = graph.node_bound();
let mut degree_map = vec![0; n];
let mut queue = BinaryHeap::with_capacity(n);
let mut colored = HashMap::with_capacity(n);
let mut adj_color_map = vec![HashSet::new(); n];
let mut seen = graph.visit_map();
let mut max_color = 0;
for node in graph.node_identifiers() {
let degree = graph.edges(node).count();
queue.push(MaxScored((0, degree), node));
degree_map[ix(node)] = degree;
}
while let Some(MaxScored(_, node)) = queue.pop() {
if seen.is_visited(&node) {
continue;
}
seen.visit(node);
let adj_color = &adj_color_map[ix(node)];
let mut color = 0;
while adj_color.contains(&color) {
color += 1;
}
colored.insert(node, color);
max_color = max_color.max(color);
for nbor in graph.neighbors(node) {
if let Some(adj_color) = adj_color_map.get_mut(ix(nbor)) {
adj_color.insert(color);
queue.push(MaxScored((adj_color.len(), degree_map[ix(nbor)]), nbor));
}
}
}
(colored, max_color + 1)
}

122
vendor/petgraph/src/algo/dijkstra.rs vendored Normal file
View File

@@ -0,0 +1,122 @@
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{BinaryHeap, HashMap};
use std::hash::Hash;
use crate::algo::Measure;
use crate::scored::MinScored;
use crate::visit::{EdgeRef, IntoEdges, VisitMap, Visitable};
/// \[Generic\] Dijkstra's shortest path algorithm.
///
/// Compute the length of the shortest path from `start` to every reachable
/// node.
///
/// The graph should be `Visitable` and implement `IntoEdges`. The function
/// `edge_cost` should return the cost for a particular edge, which is used
/// to compute path costs. Edge costs must be non-negative.
///
/// If `goal` is not `None`, then the algorithm terminates once the `goal` node's
/// cost is calculated.
///
/// Returns a `HashMap` that maps `NodeId` to path cost.
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::dijkstra;
/// use petgraph::prelude::*;
/// use std::collections::HashMap;
///
/// let mut graph: Graph<(), (), Directed> = Graph::new();
/// let a = graph.add_node(()); // node with no weight
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
/// let g = graph.add_node(());
/// let h = graph.add_node(());
/// // z will be in another connected component
/// let z = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// (d, a),
/// (e, f),
/// (b, e),
/// (f, g),
/// (g, h),
/// (h, e),
/// ]);
/// // a ----> b ----> e ----> f
/// // ^ | ^ |
/// // | v | v
/// // d <---- c h <---- g
///
/// let expected_res: HashMap<NodeIndex, usize> = [
/// (a, 3),
/// (b, 0),
/// (c, 1),
/// (d, 2),
/// (e, 1),
/// (f, 2),
/// (g, 3),
/// (h, 4),
/// ].iter().cloned().collect();
/// let res = dijkstra(&graph, b, None, |_| 1);
/// assert_eq!(res, expected_res);
/// // z is not inside res because there is not path from b to z.
/// ```
pub fn dijkstra<G, F, K>(
graph: G,
start: G::NodeId,
goal: Option<G::NodeId>,
mut edge_cost: F,
) -> HashMap<G::NodeId, K>
where
G: IntoEdges + Visitable,
G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
K: Measure + Copy,
{
let mut visited = graph.visit_map();
let mut scores = HashMap::new();
//let mut predecessor = HashMap::new();
let mut visit_next = BinaryHeap::new();
let zero_score = K::default();
scores.insert(start, zero_score);
visit_next.push(MinScored(zero_score, start));
while let Some(MinScored(node_score, node)) = visit_next.pop() {
if visited.is_visited(&node) {
continue;
}
if goal.as_ref() == Some(&node) {
break;
}
for edge in graph.edges(node) {
let next = edge.target();
if visited.is_visited(&next) {
continue;
}
let next_score = node_score + edge_cost(edge);
match scores.entry(next) {
Occupied(ent) => {
if next_score < *ent.get() {
*ent.into_mut() = next_score;
visit_next.push(MinScored(next_score, next));
//predecessor.insert(next.clone(), node.clone());
}
}
Vacant(ent) => {
ent.insert(next_score);
visit_next.push(MinScored(next_score, next));
//predecessor.insert(next.clone(), node.clone());
}
}
}
visited.visit(node);
}
scores
}

333
vendor/petgraph/src/algo/dominators.rs vendored Normal file
View File

@@ -0,0 +1,333 @@
//! Compute dominators of a control-flow graph.
//!
//! # The Dominance Relation
//!
//! In a directed graph with a root node **R**, a node **A** is said to *dominate* a
//! node **B** iff every path from **R** to **B** contains **A**.
//!
//! The node **A** is said to *strictly dominate* the node **B** iff **A** dominates
//! **B** and **A ≠ B**.
//!
//! The node **A** is said to be the *immediate dominator* of a node **B** iff it
//! strictly dominates **B** and there does not exist any node **C** where **A**
//! dominates **C** and **C** dominates **B**.
use std::cmp::Ordering;
use std::collections::{hash_map::Iter, HashMap, HashSet};
use std::hash::Hash;
use crate::visit::{DfsPostOrder, GraphBase, IntoNeighbors, Visitable, Walker};
/// The dominance relation for some graph and root.
#[derive(Debug, Clone)]
pub struct Dominators<N>
where
N: Copy + Eq + Hash,
{
root: N,
dominators: HashMap<N, N>,
}
impl<N> Dominators<N>
where
N: Copy + Eq + Hash,
{
/// Get the root node used to construct these dominance relations.
pub fn root(&self) -> N {
self.root
}
/// Get the immediate dominator of the given node.
///
/// Returns `None` for any node that is not reachable from the root, and for
/// the root itself.
pub fn immediate_dominator(&self, node: N) -> Option<N> {
if node == self.root {
None
} else {
self.dominators.get(&node).cloned()
}
}
/// Iterate over the given node's strict dominators.
///
/// If the given node is not reachable from the root, then `None` is
/// returned.
pub fn strict_dominators(&self, node: N) -> Option<DominatorsIter<N>> {
if self.dominators.contains_key(&node) {
Some(DominatorsIter {
dominators: self,
node: self.immediate_dominator(node),
})
} else {
None
}
}
/// Iterate over all of the given node's dominators (including the given
/// node itself).
///
/// If the given node is not reachable from the root, then `None` is
/// returned.
pub fn dominators(&self, node: N) -> Option<DominatorsIter<N>> {
if self.dominators.contains_key(&node) {
Some(DominatorsIter {
dominators: self,
node: Some(node),
})
} else {
None
}
}
/// Iterate over all nodes immediately dominated by the given node (not
/// including the given node itself).
pub fn immediately_dominated_by(&self, node: N) -> DominatedByIter<N> {
DominatedByIter {
iter: self.dominators.iter(),
node,
}
}
}
/// Iterator for a node's dominators.
#[derive(Debug, Clone)]
pub struct DominatorsIter<'a, N>
where
N: 'a + Copy + Eq + Hash,
{
dominators: &'a Dominators<N>,
node: Option<N>,
}
impl<'a, N> Iterator for DominatorsIter<'a, N>
where
N: 'a + Copy + Eq + Hash,
{
type Item = N;
fn next(&mut self) -> Option<Self::Item> {
let next = self.node.take();
if let Some(next) = next {
self.node = self.dominators.immediate_dominator(next);
}
next
}
}
/// Iterator for nodes dominated by a given node.
#[derive(Debug, Clone)]
pub struct DominatedByIter<'a, N>
where
N: 'a + Copy + Eq + Hash,
{
iter: Iter<'a, N, N>,
node: N,
}
impl<'a, N> Iterator for DominatedByIter<'a, N>
where
N: 'a + Copy + Eq + Hash,
{
type Item = N;
fn next(&mut self) -> Option<Self::Item> {
for (dominator, dominated) in self.iter.by_ref() {
// The root node dominates itself, but it should not be included in
// the results.
if dominated == &self.node && dominated != dominator {
return Some(*dominator);
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
/// The undefined dominator sentinel, for when we have not yet discovered a
/// node's dominator.
const UNDEFINED: usize = ::std::usize::MAX;
/// This is an implementation of the engineered ["Simple, Fast Dominance
/// Algorithm"][0] discovered by Cooper et al.
///
/// This algorithm is **O(|V|²)**, and therefore has slower theoretical running time
/// than the Lengauer-Tarjan algorithm (which is **O(|E| log |V|)**. However,
/// Cooper et al found it to be faster in practice on control flow graphs of up
/// to ~30,000 vertices.
///
/// [0]: http://www.hipersoft.rice.edu/grads/publications/dom14.pdf
pub fn simple_fast<G>(graph: G, root: G::NodeId) -> Dominators<G::NodeId>
where
G: IntoNeighbors + Visitable,
<G as GraphBase>::NodeId: Eq + Hash,
{
let (post_order, predecessor_sets) = simple_fast_post_order(graph, root);
let length = post_order.len();
debug_assert!(length > 0);
debug_assert!(post_order.last() == Some(&root));
// From here on out we use indices into `post_order` instead of actual
// `NodeId`s wherever possible. This greatly improves the performance of
// this implementation, but we have to pay a little bit of upfront cost to
// convert our data structures to play along first.
// Maps a node to its index into `post_order`.
let node_to_post_order_idx: HashMap<_, _> = post_order
.iter()
.enumerate()
.map(|(idx, &node)| (node, idx))
.collect();
// Maps a node's `post_order` index to its set of predecessors's indices
// into `post_order` (as a vec).
let idx_to_predecessor_vec =
predecessor_sets_to_idx_vecs(&post_order, &node_to_post_order_idx, predecessor_sets);
let mut dominators = vec![UNDEFINED; length];
dominators[length - 1] = length - 1;
let mut changed = true;
while changed {
changed = false;
// Iterate in reverse post order, skipping the root.
for idx in (0..length - 1).rev() {
debug_assert!(post_order[idx] != root);
// Take the intersection of every predecessor's dominator set; that
// is the current best guess at the immediate dominator for this
// node.
let new_idom_idx = {
let mut predecessors = idx_to_predecessor_vec[idx]
.iter()
.filter(|&&p| dominators[p] != UNDEFINED);
let new_idom_idx = predecessors.next().expect(
"Because the root is initialized to dominate itself, and is the \
first node in every path, there must exist a predecessor to this \
node that also has a dominator",
);
predecessors.fold(*new_idom_idx, |new_idom_idx, &predecessor_idx| {
intersect(&dominators, new_idom_idx, predecessor_idx)
})
};
debug_assert!(new_idom_idx < length);
if new_idom_idx != dominators[idx] {
dominators[idx] = new_idom_idx;
changed = true;
}
}
}
// All done! Translate the indices back into proper `G::NodeId`s.
debug_assert!(!dominators.iter().any(|&dom| dom == UNDEFINED));
Dominators {
root,
dominators: dominators
.into_iter()
.enumerate()
.map(|(idx, dom_idx)| (post_order[idx], post_order[dom_idx]))
.collect(),
}
}
fn intersect(dominators: &[usize], mut finger1: usize, mut finger2: usize) -> usize {
loop {
match finger1.cmp(&finger2) {
Ordering::Less => finger1 = dominators[finger1],
Ordering::Greater => finger2 = dominators[finger2],
Ordering::Equal => return finger1,
}
}
}
fn predecessor_sets_to_idx_vecs<N>(
post_order: &[N],
node_to_post_order_idx: &HashMap<N, usize>,
mut predecessor_sets: HashMap<N, HashSet<N>>,
) -> Vec<Vec<usize>>
where
N: Copy + Eq + Hash,
{
post_order
.iter()
.map(|node| {
predecessor_sets
.remove(node)
.map(|predecessors| {
predecessors
.into_iter()
.map(|p| *node_to_post_order_idx.get(&p).unwrap())
.collect()
})
.unwrap_or_default()
})
.collect()
}
type PredecessorSets<NodeId> = HashMap<NodeId, HashSet<NodeId>>;
fn simple_fast_post_order<G>(
graph: G,
root: G::NodeId,
) -> (Vec<G::NodeId>, PredecessorSets<G::NodeId>)
where
G: IntoNeighbors + Visitable,
<G as GraphBase>::NodeId: Eq + Hash,
{
let mut post_order = vec![];
let mut predecessor_sets = HashMap::new();
for node in DfsPostOrder::new(graph, root).iter(graph) {
post_order.push(node);
for successor in graph.neighbors(node) {
predecessor_sets
.entry(successor)
.or_insert_with(HashSet::new)
.insert(node);
}
}
(post_order, predecessor_sets)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_iter_dominators() {
let doms: Dominators<u32> = Dominators {
root: 0,
dominators: [(2, 1), (1, 0), (0, 0)].iter().cloned().collect(),
};
let all_doms: Vec<_> = doms.dominators(2).unwrap().collect();
assert_eq!(vec![2, 1, 0], all_doms);
assert_eq!(None::<()>, doms.dominators(99).map(|_| unreachable!()));
let strict_doms: Vec<_> = doms.strict_dominators(2).unwrap().collect();
assert_eq!(vec![1, 0], strict_doms);
assert_eq!(
None::<()>,
doms.strict_dominators(99).map(|_| unreachable!())
);
let dom_by: Vec<_> = doms.immediately_dominated_by(1).collect();
assert_eq!(vec![2], dom_by);
assert_eq!(None, doms.immediately_dominated_by(99).next());
assert_eq!(1, doms.immediately_dominated_by(0).count());
}
}

View File

@@ -0,0 +1,449 @@
use std::{
collections::{HashMap, VecDeque},
ops::{Index, IndexMut},
};
use crate::{
graph::{GraphIndex, NodeIndex},
visit::{EdgeRef, GraphProp, IntoEdgeReferences},
Directed,
};
use self::linked_list::{LinkedList, LinkedListEntry};
/// \[Generic\] Finds a [feedback arc set]: a set of edges in the given directed graph, which when
/// removed, make the graph acyclic.
///
/// Uses a [greedy heuristic algorithm] to select a small number of edges, but does not necessarily
/// find the minimum feedback arc set. Time complexity is roughly **O(|E|)** for an input graph with
/// edges **E**.
///
/// Does not consider edge/node weights when selecting edges for the feedback arc set.
///
/// Loops (edges to and from the same node) are always included in the returned set.
///
/// # Example
///
/// ```
/// # #[cfg(feature = "stable_graph")] {
/// use petgraph::{
/// algo::{greedy_feedback_arc_set, is_cyclic_directed},
/// graph::EdgeIndex,
/// stable_graph::StableGraph,
/// visit::EdgeRef,
/// };
///
/// let mut g: StableGraph<(), ()> = StableGraph::from_edges(&[
/// (0, 1),
/// (1, 2),
/// (2, 3),
/// (3, 4),
/// (4, 5),
/// (5, 0),
/// (4, 1),
/// (1, 3),
/// ]);
///
/// assert!(is_cyclic_directed(&g));
///
/// let fas: Vec<EdgeIndex> = greedy_feedback_arc_set(&g).map(|e| e.id()).collect();
///
/// // Remove edges in feedback arc set from original graph
/// for edge_id in fas {
/// g.remove_edge(edge_id);
/// }
///
/// assert!(!is_cyclic_directed(&g));
/// # }
/// ```
///
/// [feedback arc set]: https://en.wikipedia.org/wiki/Feedback_arc_set
/// [greedy heuristic algorithm]: https://doi.org/10.1016/0020-0190(93)90079-O
pub fn greedy_feedback_arc_set<G>(g: G) -> impl Iterator<Item = G::EdgeRef>
where
G: IntoEdgeReferences + GraphProp<EdgeType = Directed>,
G::NodeId: GraphIndex,
G: crate::visit::NodeCount,
{
let node_seq = good_node_sequence(g.edge_references().map(|e| {
(
NodeIndex::new(e.source().index()),
NodeIndex::new(e.target().index()),
)
}));
g.edge_references()
.filter(move |e| node_seq[&e.source().index()] >= node_seq[&e.target().index()])
}
fn good_node_sequence(
edge_refs: impl Iterator<Item = (NodeIndex<usize>, NodeIndex<usize>)>,
) -> HashMap<usize, usize> {
let mut nodes = FasNodeContainer { nodes: Vec::new() };
let mut buckets = Buckets {
sinks_or_isolated: NodeLinkedList::new(),
sources: NodeLinkedList::new(),
bidirectional_pve_dd: Vec::new(),
bidirectional_nve_dd: Vec::new(),
};
// Lookup of node indices from input graph to indices into `nodes`
let mut graph_ix_lookup = HashMap::new();
// Build node entries
for (from_g_ix, to_g_ix) in edge_refs {
let mut fas_node_entry = |g_ix: NodeIndex<usize>| -> FasNodeIndex {
match graph_ix_lookup.get(&g_ix) {
Some(fas_ix) => *fas_ix,
None => {
let fas_ix = FasNodeIndex(nodes.nodes.len());
nodes.nodes.push(LinkedListEntry::new(FasNode {
graph_ix: g_ix,
out_edges: Vec::new(),
in_edges: Vec::new(),
out_degree: 0,
in_degree: 0,
}));
graph_ix_lookup.insert(g_ix, fas_ix);
fas_ix
}
}
};
let from_fas_ix = fas_node_entry(from_g_ix);
let to_fas_ix = fas_node_entry(to_g_ix);
nodes[from_fas_ix].data().out_edges.push(to_fas_ix);
nodes[to_fas_ix].data().in_edges.push(from_fas_ix);
}
// Set initial in/out-degrees
for entry in nodes.nodes.iter_mut() {
let node = entry.data();
node.out_degree = node.out_edges.len();
node.in_degree = node.in_edges.len();
}
// Add nodes to initial lists
for i in 0..nodes.nodes.len() {
let fas_ix = FasNodeIndex(i);
buckets
.suitable_bucket(fas_ix, &mut nodes)
.push_front(fas_ix, &mut nodes);
}
let mut s_1 = VecDeque::new();
let mut s_2 = VecDeque::new();
loop {
let mut some_moved = false;
while let Some(sink_fas_ix) = buckets.sinks_or_isolated.pop(&mut nodes) {
some_moved = true;
buckets.update_neighbour_node_buckets(sink_fas_ix, &mut nodes);
s_2.push_front(nodes[sink_fas_ix].data().graph_ix);
}
while let Some(source_fas_ix) = buckets.sources.pop(&mut nodes) {
some_moved = true;
buckets.update_neighbour_node_buckets(source_fas_ix, &mut nodes);
s_1.push_back(nodes[source_fas_ix].data().graph_ix);
}
if let Some(list) = buckets
.bidirectional_pve_dd
.iter_mut()
.rev()
.chain(buckets.bidirectional_nve_dd.iter_mut())
.find(|b| b.start.is_some())
{
let highest_dd_fas_ix = list.pop(&mut nodes).unwrap();
some_moved = true;
buckets.update_neighbour_node_buckets(highest_dd_fas_ix, &mut nodes);
s_1.push_back(nodes[highest_dd_fas_ix].data().graph_ix);
Buckets::trim_bucket_list(&mut buckets.bidirectional_pve_dd);
Buckets::trim_bucket_list(&mut buckets.bidirectional_nve_dd);
}
if !some_moved {
break;
}
}
s_1.into_iter()
.chain(s_2)
.enumerate()
.map(|(seq_order, node_index)| (node_index.index(), seq_order))
.collect()
}
type NodeLinkedList = LinkedList<FasNode, FasNodeContainer, FasNodeIndex>;
#[derive(Debug)]
struct FasNodeContainer {
nodes: Vec<LinkedListEntry<FasNode, FasNodeIndex>>,
}
impl Index<FasNodeIndex> for FasNodeContainer {
type Output = LinkedListEntry<FasNode, FasNodeIndex>;
fn index(&self, index: FasNodeIndex) -> &Self::Output {
&self.nodes[index.0]
}
}
impl IndexMut<FasNodeIndex> for FasNodeContainer {
fn index_mut(&mut self, index: FasNodeIndex) -> &mut Self::Output {
&mut self.nodes[index.0]
}
}
#[derive(Debug)]
struct Buckets {
sinks_or_isolated: NodeLinkedList,
sources: NodeLinkedList,
/// Bidirectional nodes with positive-or-0 delta degree
bidirectional_pve_dd: Vec<NodeLinkedList>,
/// Bidirectional nodes with negative delta degree (index 0 is -1 dd, 1 is -2 etc)
bidirectional_nve_dd: Vec<NodeLinkedList>,
}
#[derive(Clone, Copy, PartialEq, Debug)]
struct FasNodeIndex(usize);
/// Represents a node from the input graph, tracking its current delta degree
#[derive(Debug)]
struct FasNode {
/// Node index in input graph.
graph_ix: NodeIndex<usize>,
/// All outward edges from this node (not removed during processing)
out_edges: Vec<FasNodeIndex>,
/// All inward edges from this node (not removed during processing)
in_edges: Vec<FasNodeIndex>,
/// Current out-degree of this node (decremented during processing as connected nodes are
/// removed)
out_degree: usize,
/// Current in-degree of this node (decremented during processing as connected nodes are
/// removed)
in_degree: usize,
}
impl Buckets {
fn suitable_bucket(
&mut self,
ix: FasNodeIndex,
nodes: &mut FasNodeContainer,
) -> &mut NodeLinkedList {
let node = nodes[ix].data();
if node.out_degree == 0 {
&mut self.sinks_or_isolated
} else if node.in_degree == 0 {
&mut self.sources
} else {
let delta_degree = node.out_degree as isize - node.in_degree as isize;
if delta_degree >= 0 {
let bucket_ix = delta_degree as usize;
if self.bidirectional_pve_dd.len() <= bucket_ix {
self.bidirectional_pve_dd
.resize_with(bucket_ix + 1, NodeLinkedList::new);
}
&mut self.bidirectional_pve_dd[bucket_ix]
} else {
let bucket_ix = (-delta_degree - 1) as usize;
if self.bidirectional_nve_dd.len() <= bucket_ix {
self.bidirectional_nve_dd
.resize_with(bucket_ix + 1, NodeLinkedList::new);
}
&mut self.bidirectional_nve_dd[bucket_ix]
}
}
}
fn update_neighbour_node_buckets(&mut self, ix: FasNodeIndex, nodes: &mut FasNodeContainer) {
for i in 0..nodes[ix].data().out_edges.len() {
let out_ix = nodes[ix].data().out_edges[i];
if out_ix == ix {
continue;
}
// Ignore nodes which have already been moved to the good sequence
if !nodes[out_ix].is_in_list() {
continue;
}
self.suitable_bucket(out_ix, nodes).remove(out_ix, nodes);
// Other node has lost an in-edge; reduce in-degree by 1
nodes[out_ix].data().in_degree -= 1;
self.suitable_bucket(out_ix, nodes)
.push_front(out_ix, nodes);
}
for i in 0..nodes[ix].data().in_edges.len() {
let in_ix = nodes[ix].data().in_edges[i];
if in_ix == ix {
continue;
}
// Ignore nodes which have already been moved to the good sequence
if !nodes[in_ix].is_in_list() {
continue;
}
self.suitable_bucket(in_ix, nodes).remove(in_ix, nodes);
// Other node has lost an out-edge; reduce out-degree by 1
nodes[in_ix].data().out_degree -= 1;
self.suitable_bucket(in_ix, nodes).push_front(in_ix, nodes);
}
}
fn trim_bucket_list(list: &mut Vec<NodeLinkedList>) {
let trunc_len = if let Some(highest_populated_index) =
(0..list.len()).rev().find(|i| list[*i].start.is_some())
{
highest_populated_index + 1
} else {
0
};
list.truncate(trunc_len);
}
}
mod linked_list {
use std::{marker::PhantomData, ops::IndexMut};
#[derive(PartialEq, Debug)]
pub struct LinkedList<Data, Container, Ix> {
pub start: Option<Ix>,
marker: PhantomData<(Data, Container)>,
}
#[derive(Debug)]
pub struct LinkedListEntry<Data, Ix> {
pos: Option<LinkedListPosition<Ix>>,
data: Data,
}
#[derive(Debug)]
struct LinkedListPosition<Ix> {
prev: Option<Ix>,
next: Option<Ix>,
}
impl<Data, Ix> LinkedListEntry<Data, Ix> {
pub fn new(data: Data) -> Self {
LinkedListEntry { pos: None, data }
}
pub fn data(&mut self) -> &mut Data {
&mut self.data
}
pub fn is_in_list(&mut self) -> bool {
self.pos.is_some()
}
fn pos_mut(&mut self) -> &mut LinkedListPosition<Ix> {
self.pos
.as_mut()
.expect("expected linked list entry to have populated position")
}
}
impl<Data, Container, Ix> LinkedList<Data, Container, Ix>
where
Container: IndexMut<Ix, Output = LinkedListEntry<Data, Ix>>,
Ix: PartialEq + Copy,
{
pub fn new() -> Self {
LinkedList {
start: None,
marker: PhantomData,
}
}
pub fn push_front(&mut self, push_ix: Ix, container: &mut Container) {
if let Some(start_ix) = self.start {
let entry = &mut container[start_ix];
entry.pos_mut().prev = Some(push_ix);
}
let push_entry = &mut container[push_ix];
push_entry.pos = Some(LinkedListPosition {
next: self.start,
prev: None,
});
self.start = Some(push_ix);
}
pub fn pop(&mut self, container: &mut Container) -> Option<Ix> {
if let Some(remove_ix) = self.start {
self.remove(remove_ix, container);
Some(remove_ix)
} else {
None
}
}
/// `remove_ix` **must** be a member of the list headed by `self`
pub fn remove(&mut self, remove_ix: Ix, container: &mut Container) {
debug_assert!(
self.to_vec(container).contains(&remove_ix),
"node to remove should be member of current linked list"
);
let remove_entry = &mut container[remove_ix];
let ll_entry = remove_entry.pos.take().unwrap();
if let Some(prev_ix) = ll_entry.prev {
let prev_node = &mut container[prev_ix];
prev_node.pos_mut().next = ll_entry.next;
}
if let Some(next_ix) = ll_entry.next {
let next_node = &mut container[next_ix];
next_node.pos_mut().prev = ll_entry.prev;
}
// If the removed node was head of the list
if self.start == Some(remove_ix) {
self.start = ll_entry.next;
}
}
/// For debug purposes
fn to_vec(&self, container: &mut Container) -> Vec<Ix> {
let mut ixs = Vec::new();
let mut node_ix = self.start;
while let Some(n_ix) = node_ix {
ixs.push(n_ix);
node_ix = container[n_ix].pos_mut().next;
}
ixs
}
}
}

View File

@@ -0,0 +1,143 @@
use std::collections::HashMap;
use std::hash::Hash;
use crate::algo::{BoundedMeasure, NegativeCycle};
use crate::visit::{
EdgeRef, GraphProp, IntoEdgeReferences, IntoNodeIdentifiers, NodeCompactIndexable,
};
#[allow(clippy::type_complexity, clippy::needless_range_loop)]
/// \[Generic\] [FloydWarshall algorithm](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm) is an algorithm for all pairs shortest path problem
///
/// Compute shortest paths in a weighted graph with positive or negative edge weights (but with no negative cycles)
///
/// # Arguments
/// * `graph`: graph with no negative cycle
/// * `edge_cost`: closure that returns cost of a particular edge
///
/// # Returns
/// * `Ok`: (if graph contains no negative cycle) a hashmap containing all pairs shortest paths
/// * `Err`: if graph contains negative cycle.
///
/// # Examples
/// ```rust
/// use petgraph::{prelude::*, Graph, Directed};
/// use petgraph::algo::floyd_warshall;
/// use std::collections::HashMap;
///
/// let mut graph: Graph<(), (), Directed> = Graph::new();
/// let a = graph.add_node(());
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (a, c),
/// (a, d),
/// (b, c),
/// (b, d),
/// (c, d)
/// ]);
///
/// let weight_map: HashMap<(NodeIndex, NodeIndex), i32> = [
/// ((a, a), 0), ((a, b), 1), ((a, c), 4), ((a, d), 10),
/// ((b, b), 0), ((b, c), 2), ((b, d), 2),
/// ((c, c), 0), ((c, d), 2)
/// ].iter().cloned().collect();
/// // ----- b --------
/// // | ^ | 2
/// // | 1 | 4 v
/// // 2 | a ------> c
/// // | 10 | | 2
/// // | v v
/// // ---> d <-------
///
/// let inf = std::i32::MAX;
/// let expected_res: HashMap<(NodeIndex, NodeIndex), i32> = [
/// ((a, a), 0), ((a, b), 1), ((a, c), 3), ((a, d), 3),
/// ((b, a), inf), ((b, b), 0), ((b, c), 2), ((b, d), 2),
/// ((c, a), inf), ((c, b), inf), ((c, c), 0), ((c, d), 2),
/// ((d, a), inf), ((d, b), inf), ((d, c), inf), ((d, d), 0),
/// ].iter().cloned().collect();
///
///
/// let res = floyd_warshall(&graph, |edge| {
/// if let Some(weight) = weight_map.get(&(edge.source(), edge.target())) {
/// *weight
/// } else {
/// inf
/// }
/// }).unwrap();
///
/// let nodes = [a, b, c, d];
/// for node1 in &nodes {
/// for node2 in &nodes {
/// assert_eq!(res.get(&(*node1, *node2)).unwrap(), expected_res.get(&(*node1, *node2)).unwrap());
/// }
/// }
/// ```
pub fn floyd_warshall<G, F, K>(
graph: G,
mut edge_cost: F,
) -> Result<HashMap<(G::NodeId, G::NodeId), K>, NegativeCycle>
where
G: NodeCompactIndexable + IntoEdgeReferences + IntoNodeIdentifiers + GraphProp,
G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
K: BoundedMeasure + Copy,
{
let num_of_nodes = graph.node_count();
// |V|x|V| matrix
let mut dist = vec![vec![K::max(); num_of_nodes]; num_of_nodes];
// init distances of paths with no intermediate nodes
for edge in graph.edge_references() {
let i = graph.to_index(edge.source());
let j = graph.to_index(edge.target());
let cost = edge_cost(edge);
if dist[i][j] > cost {
dist[i][j] = cost;
if !graph.is_directed() {
dist[j][i] = cost;
}
}
}
// distance of each node to itself is 0(default value)
for node in graph.node_identifiers() {
dist[graph.to_index(node)][graph.to_index(node)] = K::default();
}
for k in 0..num_of_nodes {
for i in 0..num_of_nodes {
for j in 0..num_of_nodes {
let (result, overflow) = dist[i][k].overflowing_add(dist[k][j]);
if !overflow && dist[i][j] > result {
dist[i][j] = result;
}
}
}
}
// value less than 0(default value) indicates a negative cycle
for i in 0..num_of_nodes {
if dist[i][i] < K::default() {
return Err(NegativeCycle(()));
}
}
let mut distance_map: HashMap<(G::NodeId, G::NodeId), K> =
HashMap::with_capacity(num_of_nodes * num_of_nodes);
for i in 0..num_of_nodes {
for j in 0..num_of_nodes {
distance_map.insert((graph.from_index(i), graph.from_index(j)), dist[i][j]);
}
}
Ok(distance_map)
}

View File

@@ -0,0 +1,196 @@
use std::{collections::VecDeque, ops::Sub};
use crate::{
data::DataMap,
visit::{
EdgeCount, EdgeIndexable, IntoEdges, IntoEdgesDirected, NodeCount, NodeIndexable, VisitMap,
Visitable,
},
};
use super::{EdgeRef, PositiveMeasure};
use crate::prelude::Direction;
fn residual_capacity<N>(
network: N,
edge: N::EdgeRef,
vertex: N::NodeId,
flow: N::EdgeWeight,
) -> N::EdgeWeight
where
N: NodeIndexable + IntoEdges,
N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
{
if vertex == edge.source() {
// backward edge
flow
} else if vertex == edge.target() {
// forward edge
return *edge.weight() - flow;
} else {
let end_point = NodeIndexable::to_index(&network, vertex);
panic!("Illegal endpoint {}", end_point);
}
}
/// Gets the other endpoint of graph edge, if any, otherwise panics.
fn other_endpoint<N>(network: N, edge: N::EdgeRef, vertex: N::NodeId) -> N::NodeId
where
N: NodeIndexable + IntoEdges,
{
if vertex == edge.source() {
edge.target()
} else if vertex == edge.target() {
edge.source()
} else {
let end_point = NodeIndexable::to_index(&network, vertex);
panic!("Illegal endpoint {}", end_point);
}
}
/// Tells whether there is an augmented path in the graph
fn has_augmented_path<N>(
network: N,
source: N::NodeId,
destination: N::NodeId,
edge_to: &mut [Option<N::EdgeRef>],
flows: &[N::EdgeWeight],
) -> bool
where
N: NodeCount + IntoEdgesDirected + NodeIndexable + EdgeIndexable + Visitable,
N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
{
let mut visited = network.visit_map();
let mut queue = VecDeque::new();
visited.visit(source);
queue.push_back(source);
while let Some(vertex) = queue.pop_front() {
let out_edges = network.edges_directed(vertex, Direction::Outgoing);
let in_edges = network.edges_directed(vertex, Direction::Incoming);
for edge in out_edges.chain(in_edges) {
let next = other_endpoint(&network, edge, vertex);
let edge_index: usize = EdgeIndexable::to_index(&network, edge.id());
let residual_cap = residual_capacity(&network, edge, next, flows[edge_index]);
if !visited.is_visited(&next) && (residual_cap > N::EdgeWeight::zero()) {
visited.visit(next);
edge_to[NodeIndexable::to_index(&network, next)] = Some(edge);
if destination == next {
return true;
}
queue.push_back(next);
}
}
}
false
}
fn adjust_residual_flow<N>(
network: N,
edge: N::EdgeRef,
vertex: N::NodeId,
flow: N::EdgeWeight,
delta: N::EdgeWeight,
) -> N::EdgeWeight
where
N: NodeIndexable + IntoEdges,
N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
{
if vertex == edge.source() {
// backward edge
flow - delta
} else if vertex == edge.target() {
// forward edge
flow + delta
} else {
let end_point = NodeIndexable::to_index(&network, vertex);
panic!("Illegal endpoint {}", end_point);
}
}
/// \[Generic\] Ford-Fulkerson algorithm.
///
/// Computes the [maximum flow][ff] of a weighted directed graph.
///
/// If it terminates, it returns the maximum flow and also the computed edge flows.
///
/// [ff]: https://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm
///
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::ford_fulkerson;
/// // Example from CLRS book
/// let mut graph = Graph::<u8, u8>::new();
/// let source = graph.add_node(0);
/// let _ = graph.add_node(1);
/// let _ = graph.add_node(2);
/// let _ = graph.add_node(3);
/// let _ = graph.add_node(4);
/// let destination = graph.add_node(5);
/// graph.extend_with_edges(&[
/// (0, 1, 16),
/// (0, 2, 13),
/// (1, 2, 10),
/// (1, 3, 12),
/// (2, 1, 4),
/// (2, 4, 14),
/// (3, 2, 9),
/// (3, 5, 20),
/// (4, 3, 7),
/// (4, 5, 4),
/// ]);
/// let (max_flow, _) = ford_fulkerson(&graph, source, destination);
/// assert_eq!(23, max_flow);
/// ```
pub fn ford_fulkerson<N>(
network: N,
source: N::NodeId,
destination: N::NodeId,
) -> (N::EdgeWeight, Vec<N::EdgeWeight>)
where
N: NodeCount
+ EdgeCount
+ IntoEdgesDirected
+ EdgeIndexable
+ NodeIndexable
+ DataMap
+ Visitable,
N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
{
let mut edge_to = vec![None; network.node_count()];
let mut flows = vec![N::EdgeWeight::zero(); network.edge_count()];
let mut max_flow = N::EdgeWeight::zero();
while has_augmented_path(&network, source, destination, &mut edge_to, &flows) {
let mut path_flow = N::EdgeWeight::max();
// Find the bottleneck capacity of the path
let mut vertex = destination;
let mut vertex_index = NodeIndexable::to_index(&network, vertex);
while let Some(edge) = edge_to[vertex_index] {
let edge_index = EdgeIndexable::to_index(&network, edge.id());
let residual_capacity = residual_capacity(&network, edge, vertex, flows[edge_index]);
// Minimum between the current path flow and the residual capacity.
path_flow = if path_flow > residual_capacity {
residual_capacity
} else {
path_flow
};
vertex = other_endpoint(&network, edge, vertex);
vertex_index = NodeIndexable::to_index(&network, vertex);
}
// Update the flow of each edge along the path
let mut vertex = destination;
let mut vertex_index = NodeIndexable::to_index(&network, vertex);
while let Some(edge) = edge_to[vertex_index] {
let edge_index = EdgeIndexable::to_index(&network, edge.id());
flows[edge_index] =
adjust_residual_flow(&network, edge, vertex, flows[edge_index], path_flow);
vertex = other_endpoint(&network, edge, vertex);
vertex_index = NodeIndexable::to_index(&network, vertex);
}
max_flow = max_flow + path_flow;
}
(max_flow, flows)
}

994
vendor/petgraph/src/algo/isomorphism.rs vendored Normal file
View File

@@ -0,0 +1,994 @@
use std::convert::TryFrom;
use crate::data::DataMap;
use crate::visit::EdgeCount;
use crate::visit::EdgeRef;
use crate::visit::GetAdjacencyMatrix;
use crate::visit::GraphBase;
use crate::visit::GraphProp;
use crate::visit::IntoEdgesDirected;
use crate::visit::IntoNeighborsDirected;
use crate::visit::NodeCompactIndexable;
use crate::{Incoming, Outgoing};
use self::semantic::EdgeMatcher;
use self::semantic::NoSemanticMatch;
use self::semantic::NodeMatcher;
use self::state::Vf2State;
mod state {
use super::*;
#[derive(Debug)]
// TODO: make mapping generic over the index type of the other graph.
pub struct Vf2State<'a, G: GetAdjacencyMatrix> {
/// A reference to the graph this state was built from.
pub graph: &'a G,
/// The current mapping M(s) of nodes from G0 → G1 and G1 → G0,
/// `usize::MAX` for no mapping.
pub mapping: Vec<usize>,
/// out[i] is non-zero if i is in either M_0(s) or Tout_0(s)
/// These are all the next vertices that are not mapped yet, but
/// have an outgoing edge from the mapping.
out: Vec<usize>,
/// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s)
/// These are all the incoming vertices, those not mapped yet, but
/// have an edge from them into the mapping.
/// Unused if graph is undirected -- it's identical with out in that case.
ins: Vec<usize>,
pub out_size: usize,
pub ins_size: usize,
pub adjacency_matrix: G::AdjMatrix,
generation: usize,
}
impl<'a, G> Vf2State<'a, G>
where
G: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
{
pub fn new(g: &'a G) -> Self {
let c0 = g.node_count();
Vf2State {
graph: g,
mapping: vec![std::usize::MAX; c0],
out: vec![0; c0],
ins: vec![0; c0 * (g.is_directed() as usize)],
out_size: 0,
ins_size: 0,
adjacency_matrix: g.adjacency_matrix(),
generation: 0,
}
}
/// Return **true** if we have a complete mapping
pub fn is_complete(&self) -> bool {
self.generation == self.mapping.len()
}
/// Add mapping **from** <-> **to** to the state.
pub fn push_mapping(&mut self, from: G::NodeId, to: usize) {
self.generation += 1;
self.mapping[self.graph.to_index(from)] = to;
// update T0 & T1 ins/outs
// T0out: Node in G0 not in M0 but successor of a node in M0.
// st.out[0]: Node either in M0 or successor of M0
for ix in self.graph.neighbors_directed(from, Outgoing) {
if self.out[self.graph.to_index(ix)] == 0 {
self.out[self.graph.to_index(ix)] = self.generation;
self.out_size += 1;
}
}
if self.graph.is_directed() {
for ix in self.graph.neighbors_directed(from, Incoming) {
if self.ins[self.graph.to_index(ix)] == 0 {
self.ins[self.graph.to_index(ix)] = self.generation;
self.ins_size += 1;
}
}
}
}
/// Restore the state to before the last added mapping
pub fn pop_mapping(&mut self, from: G::NodeId) {
// undo (n, m) mapping
self.mapping[self.graph.to_index(from)] = std::usize::MAX;
// unmark in ins and outs
for ix in self.graph.neighbors_directed(from, Outgoing) {
if self.out[self.graph.to_index(ix)] == self.generation {
self.out[self.graph.to_index(ix)] = 0;
self.out_size -= 1;
}
}
if self.graph.is_directed() {
for ix in self.graph.neighbors_directed(from, Incoming) {
if self.ins[self.graph.to_index(ix)] == self.generation {
self.ins[self.graph.to_index(ix)] = 0;
self.ins_size -= 1;
}
}
}
self.generation -= 1;
}
/// Find the next (least) node in the Tout set.
pub fn next_out_index(&self, from_index: usize) -> Option<usize> {
self.out[from_index..]
.iter()
.enumerate()
.find(move |&(index, &elt)| {
elt > 0 && self.mapping[from_index + index] == std::usize::MAX
})
.map(|(index, _)| index)
}
/// Find the next (least) node in the Tin set.
pub fn next_in_index(&self, from_index: usize) -> Option<usize> {
if !self.graph.is_directed() {
return None;
}
self.ins[from_index..]
.iter()
.enumerate()
.find(move |&(index, &elt)| {
elt > 0 && self.mapping[from_index + index] == std::usize::MAX
})
.map(|(index, _)| index)
}
/// Find the next (least) node in the N - M set.
pub fn next_rest_index(&self, from_index: usize) -> Option<usize> {
self.mapping[from_index..]
.iter()
.enumerate()
.find(|&(_, &elt)| elt == std::usize::MAX)
.map(|(index, _)| index)
}
}
}
mod semantic {
use super::*;
pub struct NoSemanticMatch;
pub trait NodeMatcher<G0: GraphBase, G1: GraphBase> {
fn enabled() -> bool;
fn eq(&mut self, _g0: &G0, _g1: &G1, _n0: G0::NodeId, _n1: G1::NodeId) -> bool;
}
impl<G0: GraphBase, G1: GraphBase> NodeMatcher<G0, G1> for NoSemanticMatch {
#[inline]
fn enabled() -> bool {
false
}
#[inline]
fn eq(&mut self, _g0: &G0, _g1: &G1, _n0: G0::NodeId, _n1: G1::NodeId) -> bool {
true
}
}
impl<G0, G1, F> NodeMatcher<G0, G1> for F
where
G0: GraphBase + DataMap,
G1: GraphBase + DataMap,
F: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
{
#[inline]
fn enabled() -> bool {
true
}
#[inline]
fn eq(&mut self, g0: &G0, g1: &G1, n0: G0::NodeId, n1: G1::NodeId) -> bool {
if let (Some(x), Some(y)) = (g0.node_weight(n0), g1.node_weight(n1)) {
self(x, y)
} else {
false
}
}
}
pub trait EdgeMatcher<G0: GraphBase, G1: GraphBase> {
fn enabled() -> bool;
fn eq(
&mut self,
_g0: &G0,
_g1: &G1,
e0: (G0::NodeId, G0::NodeId),
e1: (G1::NodeId, G1::NodeId),
) -> bool;
}
impl<G0: GraphBase, G1: GraphBase> EdgeMatcher<G0, G1> for NoSemanticMatch {
#[inline]
fn enabled() -> bool {
false
}
#[inline]
fn eq(
&mut self,
_g0: &G0,
_g1: &G1,
_e0: (G0::NodeId, G0::NodeId),
_e1: (G1::NodeId, G1::NodeId),
) -> bool {
true
}
}
impl<G0, G1, F> EdgeMatcher<G0, G1> for F
where
G0: GraphBase + DataMap + IntoEdgesDirected,
G1: GraphBase + DataMap + IntoEdgesDirected,
F: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
#[inline]
fn enabled() -> bool {
true
}
#[inline]
fn eq(
&mut self,
g0: &G0,
g1: &G1,
e0: (G0::NodeId, G0::NodeId),
e1: (G1::NodeId, G1::NodeId),
) -> bool {
let w0 = g0
.edges_directed(e0.0, Outgoing)
.find(|edge| edge.target() == e0.1)
.and_then(|edge| g0.edge_weight(edge.id()));
let w1 = g1
.edges_directed(e1.0, Outgoing)
.find(|edge| edge.target() == e1.1)
.and_then(|edge| g1.edge_weight(edge.id()));
if let (Some(x), Some(y)) = (w0, w1) {
self(x, y)
} else {
false
}
}
}
}
mod matching {
use super::*;
#[derive(Copy, Clone, PartialEq, Debug)]
enum OpenList {
Out,
In,
Other,
}
#[derive(Clone, PartialEq, Debug)]
enum Frame<G0, G1>
where
G0: GraphBase,
G1: GraphBase,
{
Outer,
Inner {
nodes: (G0::NodeId, G1::NodeId),
open_list: OpenList,
},
Unwind {
nodes: (G0::NodeId, G1::NodeId),
open_list: OpenList,
},
}
fn is_feasible<G0, G1, NM, EM>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
nodes: (G0::NodeId, G1::NodeId),
node_match: &mut NM,
edge_match: &mut EM,
) -> bool
where
G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
macro_rules! field {
($x:ident, 0) => {
$x.0
};
($x:ident, 1) => {
$x.1
};
($x:ident, 1 - 0) => {
$x.1
};
($x:ident, 1 - 1) => {
$x.0
};
}
macro_rules! r_succ {
($j:tt) => {{
let mut succ_count = 0;
for n_neigh in field!(st, $j)
.graph
.neighbors_directed(field!(nodes, $j), Outgoing)
{
succ_count += 1;
// handle the self loop case; it's not in the mapping (yet)
let m_neigh = if field!(nodes, $j) != n_neigh {
field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)]
} else {
field!(st, 1 - $j).graph.to_index(field!(nodes, 1 - $j))
};
if m_neigh == std::usize::MAX {
continue;
}
let has_edge = field!(st, 1 - $j).graph.is_adjacent(
&field!(st, 1 - $j).adjacency_matrix,
field!(nodes, 1 - $j),
field!(st, 1 - $j).graph.from_index(m_neigh),
);
if !has_edge {
return false;
}
}
succ_count
}};
}
macro_rules! r_pred {
($j:tt) => {{
let mut pred_count = 0;
for n_neigh in field!(st, $j)
.graph
.neighbors_directed(field!(nodes, $j), Incoming)
{
pred_count += 1;
// the self loop case is handled in outgoing
let m_neigh = field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)];
if m_neigh == std::usize::MAX {
continue;
}
let has_edge = field!(st, 1 - $j).graph.is_adjacent(
&field!(st, 1 - $j).adjacency_matrix,
field!(st, 1 - $j).graph.from_index(m_neigh),
field!(nodes, 1 - $j),
);
if !has_edge {
return false;
}
}
pred_count
}};
}
// Check syntactic feasibility of mapping by ensuring adjacencies
// of nx map to adjacencies of mx.
//
// nx == map to => mx
//
// R_succ
//
// Check that every neighbor of nx is mapped to a neighbor of mx,
// then check the reverse, from mx to nx. Check that they have the same
// count of edges.
//
// Note: We want to check the lookahead measures here if we can,
// R_out: Equal for G0, G1: Card(Succ(G, n) ^ Tout); for both Succ and Pred
// R_in: Same with Tin
// R_new: Equal for G0, G1: Ñ n Pred(G, n); both Succ and Pred,
// Ñ is G0 - M - Tin - Tout
// last attempt to add these did not speed up any of the testcases
if r_succ!(0) > r_succ!(1) {
return false;
}
// R_pred
if st.0.graph.is_directed() && r_pred!(0) > r_pred!(1) {
return false;
}
// // semantic feasibility: compare associated data for nodes
if NM::enabled() && !node_match.eq(st.0.graph, st.1.graph, nodes.0, nodes.1) {
return false;
}
// semantic feasibility: compare associated data for edges
if EM::enabled() {
macro_rules! edge_feasibility {
($j:tt) => {{
for n_neigh in field!(st, $j)
.graph
.neighbors_directed(field!(nodes, $j), Outgoing)
{
let m_neigh = if field!(nodes, $j) != n_neigh {
field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)]
} else {
field!(st, 1 - $j).graph.to_index(field!(nodes, 1 - $j))
};
if m_neigh == std::usize::MAX {
continue;
}
let e0 = (field!(nodes, $j), n_neigh);
let e1 = (
field!(nodes, 1 - $j),
field!(st, 1 - $j).graph.from_index(m_neigh),
);
let edges = (e0, e1);
if !edge_match.eq(
st.0.graph,
st.1.graph,
field!(edges, $j),
field!(edges, 1 - $j),
) {
return false;
}
}
if field!(st, $j).graph.is_directed() {
for n_neigh in field!(st, $j)
.graph
.neighbors_directed(field!(nodes, $j), Incoming)
{
// the self loop case is handled in outgoing
let m_neigh =
field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)];
if m_neigh == std::usize::MAX {
continue;
}
let e0 = (n_neigh, field!(nodes, $j));
let e1 = (
field!(st, 1 - $j).graph.from_index(m_neigh),
field!(nodes, 1 - $j),
);
let edges = (e0, e1);
if !edge_match.eq(
st.0.graph,
st.1.graph,
field!(edges, $j),
field!(edges, 1 - $j),
) {
return false;
}
}
}
}};
}
edge_feasibility!(0);
edge_feasibility!(1);
}
true
}
fn next_candidate<G0, G1>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
) -> Option<(G0::NodeId, G1::NodeId, OpenList)>
where
G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
{
let mut from_index = None;
let mut open_list = OpenList::Out;
let mut to_index = st.1.next_out_index(0);
// Try the out list
if to_index.is_some() {
from_index = st.0.next_out_index(0);
open_list = OpenList::Out;
}
// Try the in list
if to_index.is_none() || from_index.is_none() {
to_index = st.1.next_in_index(0);
if to_index.is_some() {
from_index = st.0.next_in_index(0);
open_list = OpenList::In;
}
}
// Try the other list -- disconnected graph
if to_index.is_none() || from_index.is_none() {
to_index = st.1.next_rest_index(0);
if to_index.is_some() {
from_index = st.0.next_rest_index(0);
open_list = OpenList::Other;
}
}
match (from_index, to_index) {
(Some(n), Some(m)) => Some((
st.0.graph.from_index(n),
st.1.graph.from_index(m),
open_list,
)),
// No more candidates
_ => None,
}
}
fn next_from_ix<G0, G1>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
nx: G1::NodeId,
open_list: OpenList,
) -> Option<G1::NodeId>
where
G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
{
// Find the next node index to try on the `to` side of the mapping
let start = st.1.graph.to_index(nx) + 1;
let cand1 = match open_list {
OpenList::Out => st.1.next_out_index(start),
OpenList::In => st.1.next_in_index(start),
OpenList::Other => st.1.next_rest_index(start),
}
.map(|c| c + start); // compensate for start offset.
match cand1 {
None => None, // no more candidates
Some(ix) => {
debug_assert!(ix >= start);
Some(st.1.graph.from_index(ix))
}
}
}
fn pop_state<G0, G1>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
nodes: (G0::NodeId, G1::NodeId),
) where
G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
{
st.0.pop_mapping(nodes.0);
st.1.pop_mapping(nodes.1);
}
fn push_state<G0, G1>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
nodes: (G0::NodeId, G1::NodeId),
) where
G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
{
st.0.push_mapping(nodes.0, st.1.graph.to_index(nodes.1));
st.1.push_mapping(nodes.1, st.0.graph.to_index(nodes.0));
}
/// Return Some(bool) if isomorphism is decided, else None.
pub fn try_match<G0, G1, NM, EM>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
node_match: &mut NM,
edge_match: &mut EM,
match_subgraph: bool,
) -> Option<bool>
where
G0: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
let mut stack = vec![Frame::Outer];
if isomorphisms(st, node_match, edge_match, match_subgraph, &mut stack).is_some() {
Some(true)
} else {
None
}
}
fn isomorphisms<G0, G1, NM, EM>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
node_match: &mut NM,
edge_match: &mut EM,
match_subgraph: bool,
stack: &mut Vec<Frame<G0, G1>>,
) -> Option<Vec<usize>>
where
G0: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
if st.0.is_complete() {
return Some(st.0.mapping.clone());
}
// A "depth first" search of a valid mapping from graph 1 to graph 2
// F(s, n, m) -- evaluate state s and add mapping n <-> m
// Find least T1out node (in st.out[1] but not in M[1])
let mut result = None;
while let Some(frame) = stack.pop() {
match frame {
Frame::Unwind { nodes, open_list } => {
pop_state(st, nodes);
match next_from_ix(st, nodes.1, open_list) {
None => continue,
Some(nx) => {
let f = Frame::Inner {
nodes: (nodes.0, nx),
open_list,
};
stack.push(f);
}
}
}
Frame::Outer => match next_candidate(st) {
None => continue,
Some((nx, mx, open_list)) => {
let f = Frame::Inner {
nodes: (nx, mx),
open_list,
};
stack.push(f);
}
},
Frame::Inner { nodes, open_list } => {
if is_feasible(st, nodes, node_match, edge_match) {
push_state(st, nodes);
if st.0.is_complete() {
result = Some(st.0.mapping.clone());
}
// Check cardinalities of Tin, Tout sets
if (!match_subgraph
&& st.0.out_size == st.1.out_size
&& st.0.ins_size == st.1.ins_size)
|| (match_subgraph
&& st.0.out_size <= st.1.out_size
&& st.0.ins_size <= st.1.ins_size)
{
let f0 = Frame::Unwind { nodes, open_list };
stack.push(f0);
stack.push(Frame::Outer);
continue;
}
pop_state(st, nodes);
}
match next_from_ix(st, nodes.1, open_list) {
None => continue,
Some(nx) => {
let f = Frame::Inner {
nodes: (nodes.0, nx),
open_list,
};
stack.push(f);
}
}
}
}
if result.is_some() {
return result;
}
}
result
}
pub struct GraphMatcher<'a, 'b, 'c, G0, G1, NM, EM>
where
G0: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
st: (Vf2State<'a, G0>, Vf2State<'b, G1>),
node_match: &'c mut NM,
edge_match: &'c mut EM,
match_subgraph: bool,
stack: Vec<Frame<G0, G1>>,
}
impl<'a, 'b, 'c, G0, G1, NM, EM> GraphMatcher<'a, 'b, 'c, G0, G1, NM, EM>
where
G0: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
pub fn new(
g0: &'a G0,
g1: &'b G1,
node_match: &'c mut NM,
edge_match: &'c mut EM,
match_subgraph: bool,
) -> Self {
let stack = vec![Frame::Outer];
Self {
st: (Vf2State::new(g0), Vf2State::new(g1)),
node_match,
edge_match,
match_subgraph,
stack,
}
}
}
impl<G0, G1, NM, EM> Iterator for GraphMatcher<'_, '_, '_, G0, G1, NM, EM>
where
G0: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
type Item = Vec<usize>;
fn next(&mut self) -> Option<Self::Item> {
isomorphisms(
&mut self.st,
self.node_match,
self.edge_match,
self.match_subgraph,
&mut self.stack,
)
}
fn size_hint(&self) -> (usize, Option<usize>) {
// To calculate the upper bound of results we use n! where n is the
// number of nodes in graph 1. n! values fit into a 64-bit usize up
// to n = 20, so we don't estimate an upper limit for n > 20.
let n = self.st.0.graph.node_count();
// We hardcode n! values into an array that accounts for architectures
// with smaller usizes to get our upper bound.
let upper_bounds: Vec<Option<usize>> = [
1u64,
1,
2,
6,
24,
120,
720,
5040,
40320,
362880,
3628800,
39916800,
479001600,
6227020800,
87178291200,
1307674368000,
20922789888000,
355687428096000,
6402373705728000,
121645100408832000,
2432902008176640000,
]
.iter()
.map(|n| usize::try_from(*n).ok())
.collect();
if n > upper_bounds.len() {
return (0, None);
}
(0, upper_bounds[n])
}
}
}
/// \[Generic\] Return `true` if the graphs `g0` and `g1` are isomorphic.
///
/// Using the VF2 algorithm, only matching graph syntactically (graph
/// structure).
///
/// The graphs should not be multigraphs.
///
/// **Reference**
///
/// * Luigi P. Cordella, Pasquale Foggia, Carlo Sansone, Mario Vento;
/// *A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs*
pub fn is_isomorphic<G0, G1>(g0: G0, g1: G1) -> bool
where
G0: NodeCompactIndexable + EdgeCount + GetAdjacencyMatrix + GraphProp + IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoNeighborsDirected,
{
if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
self::matching::try_match(&mut st, &mut NoSemanticMatch, &mut NoSemanticMatch, false)
.unwrap_or(false)
}
/// \[Generic\] Return `true` if the graphs `g0` and `g1` are isomorphic.
///
/// Using the VF2 algorithm, examining both syntactic and semantic
/// graph isomorphism (graph structure and matching node and edge weights).
///
/// The graphs should not be multigraphs.
pub fn is_isomorphic_matching<G0, G1, NM, EM>(
g0: G0,
g1: G1,
mut node_match: NM,
mut edge_match: EM,
) -> bool
where
G0: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp
+ IntoEdgesDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoEdgesDirected,
NM: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
EM: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
self::matching::try_match(&mut st, &mut node_match, &mut edge_match, false).unwrap_or(false)
}
/// \[Generic\] Return `true` if `g0` is isomorphic to a subgraph of `g1`.
///
/// Using the VF2 algorithm, only matching graph syntactically (graph
/// structure).
///
/// The graphs should not be multigraphs.
///
/// # Subgraph isomorphism
///
/// (adapted from [`networkx` documentation](https://networkx.github.io/documentation/stable/reference/algorithms/isomorphism.vf2.html))
///
/// Graph theory literature can be ambiguous about the meaning of the above statement,
/// and we seek to clarify it now.
///
/// In the VF2 literature, a mapping **M** is said to be a *graph-subgraph isomorphism*
/// iff **M** is an isomorphism between **G2** and a subgraph of **G1**. Thus, to say
/// that **G1** and **G2** are graph-subgraph isomorphic is to say that a subgraph of
/// **G1** is isomorphic to **G2**.
///
/// Other literature uses the phrase subgraph isomorphic as in
/// **G1** does not have a subgraph isomorphic to **G2**. Another use is as an in adverb
/// for isomorphic. Thus, to say that **G1** and **G2** are subgraph isomorphic is to say
/// that a subgraph of **G1** is isomorphic to **G2**.
///
/// Finally, the term subgraph can have multiple meanings. In this context,
/// subgraph always means a node-induced subgraph. Edge-induced subgraph
/// isomorphisms are not directly supported. For subgraphs which are not
/// induced, the term monomorphism is preferred over isomorphism.
///
/// **Reference**
///
/// * Luigi P. Cordella, Pasquale Foggia, Carlo Sansone, Mario Vento;
/// *A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs*
pub fn is_isomorphic_subgraph<G0, G1>(g0: G0, g1: G1) -> bool
where
G0: NodeCompactIndexable + EdgeCount + GetAdjacencyMatrix + GraphProp + IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoNeighborsDirected,
{
if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
self::matching::try_match(&mut st, &mut NoSemanticMatch, &mut NoSemanticMatch, true)
.unwrap_or(false)
}
/// \[Generic\] Return `true` if `g0` is isomorphic to a subgraph of `g1`.
///
/// Using the VF2 algorithm, examining both syntactic and semantic
/// graph isomorphism (graph structure and matching node and edge weights).
///
/// The graphs should not be multigraphs.
pub fn is_isomorphic_subgraph_matching<G0, G1, NM, EM>(
g0: G0,
g1: G1,
mut node_match: NM,
mut edge_match: EM,
) -> bool
where
G0: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp
+ IntoEdgesDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoEdgesDirected,
NM: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
EM: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
self::matching::try_match(&mut st, &mut node_match, &mut edge_match, true).unwrap_or(false)
}
/// Using the VF2 algorithm, examine both syntactic and semantic graph
/// isomorphism (graph structure and matching node and edge weights) and,
/// if `g0` is isomorphic to a subgraph of `g1`, return the mappings between
/// them.
///
/// The graphs should not be multigraphs.
pub fn subgraph_isomorphisms_iter<'a, G0, G1, NM, EM>(
g0: &'a G0,
g1: &'a G1,
node_match: &'a mut NM,
edge_match: &'a mut EM,
) -> Option<impl Iterator<Item = Vec<usize>> + 'a>
where
G0: 'a
+ NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp
+ IntoEdgesDirected,
G1: 'a
+ NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoEdgesDirected,
NM: 'a + FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
EM: 'a + FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
return None;
}
Some(self::matching::GraphMatcher::new(
g0, g1, node_match, edge_match, true,
))
}

View File

@@ -0,0 +1,115 @@
use std::collections::{BinaryHeap, HashMap};
use std::hash::Hash;
use crate::algo::Measure;
use crate::scored::MinScored;
use crate::visit::{EdgeRef, IntoEdges, NodeCount, NodeIndexable, Visitable};
/// \[Generic\] k'th shortest path algorithm.
///
/// Compute the length of the k'th shortest path from `start` to every reachable
/// node.
///
/// The graph should be `Visitable` and implement `IntoEdges`. The function
/// `edge_cost` should return the cost for a particular edge, which is used
/// to compute path costs. Edge costs must be non-negative.
///
/// If `goal` is not `None`, then the algorithm terminates once the `goal` node's
/// cost is calculated.
///
/// Computes in **O(k * (|E| + |V|*log(|V|)))** time (average).
///
/// Returns a `HashMap` that maps `NodeId` to path cost.
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::k_shortest_path;
/// use petgraph::prelude::*;
/// use std::collections::HashMap;
///
/// let mut graph : Graph<(),(),Directed>= Graph::new();
/// let a = graph.add_node(()); // node with no weight
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
/// let g = graph.add_node(());
/// let h = graph.add_node(());
/// // z will be in another connected component
/// let z = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// (d, a),
/// (e, f),
/// (b, e),
/// (f, g),
/// (g, h),
/// (h, e)
/// ]);
/// // a ----> b ----> e ----> f
/// // ^ | ^ |
/// // | v | v
/// // d <---- c h <---- g
///
/// let expected_res: HashMap<NodeIndex, usize> = [
/// (a, 7),
/// (b, 4),
/// (c, 5),
/// (d, 6),
/// (e, 5),
/// (f, 6),
/// (g, 7),
/// (h, 8)
/// ].iter().cloned().collect();
/// let res = k_shortest_path(&graph,b,None,2, |_| 1);
/// assert_eq!(res, expected_res);
/// // z is not inside res because there is not path from b to z.
/// ```
pub fn k_shortest_path<G, F, K>(
graph: G,
start: G::NodeId,
goal: Option<G::NodeId>,
k: usize,
mut edge_cost: F,
) -> HashMap<G::NodeId, K>
where
G: IntoEdges + Visitable + NodeCount + NodeIndexable,
G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
K: Measure + Copy,
{
let mut counter: Vec<usize> = vec![0; graph.node_count()];
let mut scores = HashMap::new();
let mut visit_next = BinaryHeap::new();
let zero_score = K::default();
visit_next.push(MinScored(zero_score, start));
while let Some(MinScored(node_score, node)) = visit_next.pop() {
counter[graph.to_index(node)] += 1;
let current_counter = counter[graph.to_index(node)];
if current_counter > k {
continue;
}
if current_counter == k {
scores.insert(node, node_score);
}
//Already reached goal k times
if goal.as_ref() == Some(&node) && current_counter == k {
break;
}
for edge in graph.edges(node) {
visit_next.push(MinScored(node_score + edge_cost(edge), edge.target()));
}
}
scores
}

606
vendor/petgraph/src/algo/matching.rs vendored Normal file
View File

@@ -0,0 +1,606 @@
use std::collections::VecDeque;
use std::hash::Hash;
use crate::visit::{
EdgeRef, GraphBase, IntoEdges, IntoNeighbors, IntoNodeIdentifiers, NodeCount, NodeIndexable,
VisitMap, Visitable,
};
/// Computed
/// [*matching*](https://en.wikipedia.org/wiki/Matching_(graph_theory)#Definitions)
/// of the graph.
pub struct Matching<G: GraphBase> {
graph: G,
mate: Vec<Option<G::NodeId>>,
n_edges: usize,
}
impl<G> Matching<G>
where
G: GraphBase,
{
fn new(graph: G, mate: Vec<Option<G::NodeId>>, n_edges: usize) -> Self {
Self {
graph,
mate,
n_edges,
}
}
}
impl<G> Matching<G>
where
G: NodeIndexable,
{
/// Gets the matched counterpart of given node, if there is any.
///
/// Returns `None` if the node is not matched or does not exist.
pub fn mate(&self, node: G::NodeId) -> Option<G::NodeId> {
self.mate.get(self.graph.to_index(node)).and_then(|&id| id)
}
/// Iterates over all edges from the matching.
///
/// An edge is represented by its endpoints. The graph is considered
/// undirected and every pair of matched nodes is reported only once.
pub fn edges(&self) -> MatchedEdges<'_, G> {
MatchedEdges {
graph: &self.graph,
mate: self.mate.as_slice(),
current: 0,
}
}
/// Iterates over all nodes from the matching.
pub fn nodes(&self) -> MatchedNodes<'_, G> {
MatchedNodes {
graph: &self.graph,
mate: self.mate.as_slice(),
current: 0,
}
}
/// Returns `true` if given edge is in the matching, or `false` otherwise.
///
/// If any of the nodes does not exist, `false` is returned.
pub fn contains_edge(&self, a: G::NodeId, b: G::NodeId) -> bool {
match self.mate(a) {
Some(mate) => mate == b,
None => false,
}
}
/// Returns `true` if given node is in the matching, or `false` otherwise.
///
/// If the node does not exist, `false` is returned.
pub fn contains_node(&self, node: G::NodeId) -> bool {
self.mate(node).is_some()
}
/// Gets the number of matched **edges**.
pub fn len(&self) -> usize {
self.n_edges
}
/// Returns `true` if the number of matched **edges** is 0.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<G> Matching<G>
where
G: NodeCount,
{
/// Returns `true` if the matching is perfect.
///
/// A matching is
/// [*perfect*](https://en.wikipedia.org/wiki/Matching_(graph_theory)#Definitions)
/// if every node in the graph is incident to an edge from the matching.
pub fn is_perfect(&self) -> bool {
let n_nodes = self.graph.node_count();
n_nodes % 2 == 0 && self.n_edges == n_nodes / 2
}
}
trait WithDummy: NodeIndexable {
fn dummy_idx(&self) -> usize;
/// Convert `i` to a node index, returns None for the dummy node
fn try_from_index(&self, i: usize) -> Option<Self::NodeId>;
}
impl<G: NodeIndexable> WithDummy for G {
fn dummy_idx(&self) -> usize {
// Gabow numbers the vertices from 1 to n, and uses 0 as the dummy
// vertex. Our vertex indices are zero-based and so we use the node
// bound as the dummy node.
self.node_bound()
}
fn try_from_index(&self, i: usize) -> Option<Self::NodeId> {
if i != self.dummy_idx() {
Some(self.from_index(i))
} else {
None
}
}
}
pub struct MatchedNodes<'a, G: GraphBase> {
graph: &'a G,
mate: &'a [Option<G::NodeId>],
current: usize,
}
impl<G> Iterator for MatchedNodes<'_, G>
where
G: NodeIndexable,
{
type Item = G::NodeId;
fn next(&mut self) -> Option<Self::Item> {
while self.current != self.mate.len() {
let current = self.current;
self.current += 1;
if self.mate[current].is_some() {
return Some(self.graph.from_index(current));
}
}
None
}
}
pub struct MatchedEdges<'a, G: GraphBase> {
graph: &'a G,
mate: &'a [Option<G::NodeId>],
current: usize,
}
impl<G> Iterator for MatchedEdges<'_, G>
where
G: NodeIndexable,
{
type Item = (G::NodeId, G::NodeId);
fn next(&mut self) -> Option<Self::Item> {
while self.current != self.mate.len() {
let current = self.current;
self.current += 1;
if let Some(mate) = self.mate[current] {
// Check if the mate is a node after the current one. If not, then
// do not report that edge since it has been already reported (the
// graph is considered undirected).
if self.graph.to_index(mate) > current {
let this = self.graph.from_index(current);
return Some((this, mate));
}
}
}
None
}
}
/// \[Generic\] Compute a
/// [*matching*](https://en.wikipedia.org/wiki/Matching_(graph_theory)) using a
/// greedy heuristic.
///
/// The input graph is treated as if undirected. The underlying heuristic is
/// unspecified, but is guaranteed to be bounded by *O(|V| + |E|)*. No
/// guarantees about the output are given other than that it is a valid
/// matching.
///
/// If you require a maximum matching, use [`maximum_matching`][1] function
/// instead.
///
/// [1]: fn.maximum_matching.html
pub fn greedy_matching<G>(graph: G) -> Matching<G>
where
G: Visitable + IntoNodeIdentifiers + NodeIndexable + IntoNeighbors,
G::NodeId: Eq + Hash,
G::EdgeId: Eq + Hash,
{
let (mates, n_edges) = greedy_matching_inner(&graph);
Matching::new(graph, mates, n_edges)
}
#[inline]
fn greedy_matching_inner<G>(graph: &G) -> (Vec<Option<G::NodeId>>, usize)
where
G: Visitable + IntoNodeIdentifiers + NodeIndexable + IntoNeighbors,
{
let mut mate = vec![None; graph.node_bound()];
let mut n_edges = 0;
let visited = &mut graph.visit_map();
for start in graph.node_identifiers() {
let mut last = Some(start);
// Function non_backtracking_dfs does not expand the node if it has been
// already visited.
non_backtracking_dfs(graph, start, visited, |next| {
// Alternate matched and unmatched edges.
if let Some(pred) = last.take() {
mate[graph.to_index(pred)] = Some(next);
mate[graph.to_index(next)] = Some(pred);
n_edges += 1;
} else {
last = Some(next);
}
});
}
(mate, n_edges)
}
fn non_backtracking_dfs<G, F>(graph: &G, source: G::NodeId, visited: &mut G::Map, mut visitor: F)
where
G: Visitable + IntoNeighbors,
F: FnMut(G::NodeId),
{
if visited.visit(source) {
for target in graph.neighbors(source) {
if !visited.is_visited(&target) {
visitor(target);
non_backtracking_dfs(graph, target, visited, visitor);
// Non-backtracking traversal, stop iterating over the
// neighbors.
break;
}
}
}
}
#[derive(Clone, Copy)]
enum Label<G: GraphBase> {
None,
Start,
// If node v is outer node, then label(v) = w is another outer node on path
// from v to start u.
Vertex(G::NodeId),
// If node v is outer node, then label(v) = (r, s) are two outer vertices
// (connected by an edge)
Edge(G::EdgeId, [G::NodeId; 2]),
// Flag is a special label used in searching for the join vertex of two
// paths.
Flag(G::EdgeId),
}
impl<G: GraphBase> Label<G> {
fn is_outer(&self) -> bool {
self != &Label::None
&& !match self {
Label::Flag(_) => true,
_ => false,
}
}
fn is_inner(&self) -> bool {
!self.is_outer()
}
fn to_vertex(&self) -> Option<G::NodeId> {
match *self {
Label::Vertex(v) => Some(v),
_ => None,
}
}
fn is_flagged(&self, edge: G::EdgeId) -> bool {
match self {
Label::Flag(flag) if flag == &edge => true,
_ => false,
}
}
}
impl<G: GraphBase> Default for Label<G> {
fn default() -> Self {
Label::None
}
}
impl<G: GraphBase> PartialEq for Label<G> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Label::None, Label::None) => true,
(Label::Start, Label::Start) => true,
(Label::Vertex(v1), Label::Vertex(v2)) => v1 == v2,
(Label::Edge(e1, _), Label::Edge(e2, _)) => e1 == e2,
(Label::Flag(e1), Label::Flag(e2)) => e1 == e2,
_ => false,
}
}
}
/// \[Generic\] Compute the [*maximum
/// matching*](https://en.wikipedia.org/wiki/Matching_(graph_theory)) using
/// [Gabow's algorithm][1].
///
/// [1]: https://dl.acm.org/doi/10.1145/321941.321942
///
/// The input graph is treated as if undirected. The algorithm runs in
/// *O(|V|³)*. An algorithm with a better time complexity might be used in the
/// future.
///
/// **Panics** if `g.node_bound()` is `std::usize::MAX`.
///
/// # Examples
///
/// ```
/// use petgraph::prelude::*;
/// use petgraph::algo::maximum_matching;
///
/// // The example graph:
/// //
/// // +-- b ---- d ---- f
/// // / | |
/// // a | |
/// // \ | |
/// // +-- c ---- e
/// //
/// // Maximum matching: { (a, b), (c, e), (d, f) }
///
/// let mut graph: UnGraph<(), ()> = UnGraph::new_undirected();
/// let a = graph.add_node(());
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
/// graph.extend_with_edges(&[(a, b), (a, c), (b, c), (b, d), (c, e), (d, e), (d, f)]);
///
/// let matching = maximum_matching(&graph);
/// assert!(matching.contains_edge(a, b));
/// assert!(matching.contains_edge(c, e));
/// assert_eq!(matching.mate(d), Some(f));
/// assert_eq!(matching.mate(f), Some(d));
/// ```
pub fn maximum_matching<G>(graph: G) -> Matching<G>
where
G: Visitable + NodeIndexable + IntoNodeIdentifiers + IntoEdges,
{
// The dummy identifier needs an unused index
assert_ne!(
graph.node_bound(),
std::usize::MAX,
"The input graph capacity should be strictly less than std::usize::MAX."
);
// Greedy algorithm should create a fairly good initial matching. The hope
// is that it speeds up the computation by doing les work in the complex
// algorithm.
let (mut mate, mut n_edges) = greedy_matching_inner(&graph);
// Gabow's algorithm uses a dummy node in the mate array.
mate.push(None);
let len = graph.node_bound() + 1;
debug_assert_eq!(mate.len(), len);
let mut label: Vec<Label<G>> = vec![Label::None; len];
let mut first_inner = vec![std::usize::MAX; len];
let visited = &mut graph.visit_map();
for start in 0..graph.node_bound() {
if mate[start].is_some() {
// The vertex is already matched. A start must be a free vertex.
continue;
}
// Begin search from the node.
label[start] = Label::Start;
first_inner[start] = graph.dummy_idx();
graph.reset_map(visited);
// start is never a dummy index
let start = graph.from_index(start);
// Queue will contain outer vertices that should be processed next. The
// start vertex is considered an outer vertex.
let mut queue = VecDeque::new();
queue.push_back(start);
// Mark the start vertex so it is not processed repeatedly.
visited.visit(start);
'search: while let Some(outer_vertex) = queue.pop_front() {
for edge in graph.edges(outer_vertex) {
if edge.source() == edge.target() {
// Ignore self-loops.
continue;
}
let other_vertex = edge.target();
let other_idx = graph.to_index(other_vertex);
if mate[other_idx].is_none() && other_vertex != start {
// An augmenting path was found. Augment the matching. If
// `other` is actually the start node, then the augmentation
// must not be performed, because the start vertex would be
// incident to two edges, which violates the matching
// property.
mate[other_idx] = Some(outer_vertex);
augment_path(&graph, outer_vertex, other_vertex, &mut mate, &label);
n_edges += 1;
// The path is augmented, so the start is no longer free
// vertex. We need to begin with a new start.
break 'search;
} else if label[other_idx].is_outer() {
// The `other` is an outer vertex (a label has been set to
// it). An odd cycle (blossom) was found. Assign this edge
// as a label to all inner vertices in paths P(outer) and
// P(other).
find_join(
&graph,
edge,
&mate,
&mut label,
&mut first_inner,
|labeled| {
if visited.visit(labeled) {
queue.push_back(labeled);
}
},
);
} else {
let mate_vertex = mate[other_idx];
let mate_idx = mate_vertex.map_or(graph.dummy_idx(), |id| graph.to_index(id));
if label[mate_idx].is_inner() {
// Mate of `other` vertex is inner (no label has been
// set to it so far). But it actually is an outer vertex
// (it is on a path to the start vertex that begins with
// a matched edge, since it is a mate of `other`).
// Assign the label of this mate to the `outer` vertex,
// so the path for it can be reconstructed using `mate`
// and this label.
label[mate_idx] = Label::Vertex(outer_vertex);
first_inner[mate_idx] = other_idx;
}
// Add the vertex to the queue only if it's not the dummy and this is its first
// discovery.
if let Some(mate_vertex) = mate_vertex {
if visited.visit(mate_vertex) {
queue.push_back(mate_vertex);
}
}
}
}
}
// Reset the labels. All vertices are inner for the next search.
for lbl in label.iter_mut() {
*lbl = Label::None;
}
}
// Discard the dummy node.
mate.pop();
Matching::new(graph, mate, n_edges)
}
fn find_join<G, F>(
graph: &G,
edge: G::EdgeRef,
mate: &[Option<G::NodeId>],
label: &mut [Label<G>],
first_inner: &mut [usize],
mut visitor: F,
) where
G: IntoEdges + NodeIndexable + Visitable,
F: FnMut(G::NodeId),
{
// Simultaneously traverse the inner vertices on paths P(source) and
// P(target) to find a join vertex - an inner vertex that is shared by these
// paths.
let source = graph.to_index(edge.source());
let target = graph.to_index(edge.target());
let mut left = first_inner[source];
let mut right = first_inner[target];
if left == right {
// No vertices can be labeled, since both paths already refer to a
// common vertex - the join.
return;
}
// Flag the (first) inner vertices. This ensures that they are assigned the
// join as their first inner vertex.
let flag = Label::Flag(edge.id());
label[left] = flag;
label[right] = flag;
// Find the join.
let join = loop {
// Swap the sides. Do not swap if the right side is already finished.
if right != graph.dummy_idx() {
std::mem::swap(&mut left, &mut right);
}
// Set left to the next inner vertex in P(source) or P(target).
// The unwraps are safe because left is not the dummy node.
let left_mate = graph.to_index(mate[left].unwrap());
let next_inner = label[left_mate].to_vertex().unwrap();
left = first_inner[graph.to_index(next_inner)];
if !label[left].is_flagged(edge.id()) {
// The inner vertex is not flagged yet, so flag it.
label[left] = flag;
} else {
// The inner vertex is already flagged. It means that the other side
// had to visit it already. Therefore it is the join vertex.
break left;
}
};
// Label all inner vertices on P(source) and P(target) with the found join.
for endpoint in [source, target].iter().copied() {
let mut inner = first_inner[endpoint];
while inner != join {
// Notify the caller about labeling a vertex.
if let Some(ix) = graph.try_from_index(inner) {
visitor(ix);
}
label[inner] = Label::Edge(edge.id(), [edge.source(), edge.target()]);
first_inner[inner] = join;
let inner_mate = graph.to_index(mate[inner].unwrap());
let next_inner = label[inner_mate].to_vertex().unwrap();
inner = first_inner[graph.to_index(next_inner)];
}
}
for (vertex_idx, vertex_label) in label.iter().enumerate() {
// To all outer vertices that are on paths P(source) and P(target) until
// the join, se the join as their first inner vertex.
if vertex_idx != graph.dummy_idx()
&& vertex_label.is_outer()
&& label[first_inner[vertex_idx]].is_outer()
{
first_inner[vertex_idx] = join;
}
}
}
fn augment_path<G>(
graph: &G,
outer: G::NodeId,
other: G::NodeId,
mate: &mut [Option<G::NodeId>],
label: &[Label<G>],
) where
G: NodeIndexable,
{
let outer_idx = graph.to_index(outer);
let temp = mate[outer_idx];
let temp_idx = temp.map_or(graph.dummy_idx(), |id| graph.to_index(id));
mate[outer_idx] = Some(other);
if mate[temp_idx] != Some(outer) {
// We are at the end of the path and so the entire path is completely
// rematched/augmented.
} else if let Label::Vertex(vertex) = label[outer_idx] {
// The outer vertex has a vertex label which refers to another outer
// vertex on the path. So we set this another outer node as the mate for
// the previous mate of the outer node.
mate[temp_idx] = Some(vertex);
if let Some(temp) = temp {
augment_path(graph, vertex, temp, mate, label);
}
} else if let Label::Edge(_, [source, target]) = label[outer_idx] {
// The outer vertex has an edge label which refers to an edge in a
// blossom. We need to augment both directions along the blossom.
augment_path(graph, source, target, mate, label);
augment_path(graph, target, source, mate, label);
} else {
panic!("Unexpected label when augmenting path");
}
}

View File

@@ -0,0 +1,117 @@
//! Minimum Spanning Tree algorithms.
use std::collections::{BinaryHeap, HashMap};
use crate::prelude::*;
use crate::data::Element;
use crate::scored::MinScored;
use crate::unionfind::UnionFind;
use crate::visit::{Data, IntoNodeReferences, NodeRef};
use crate::visit::{IntoEdgeReferences, NodeIndexable};
/// \[Generic\] Compute a *minimum spanning tree* of a graph.
///
/// The input graph is treated as if undirected.
///
/// Using Kruskal's algorithm with runtime **O(|E| log |E|)**. We actually
/// return a minimum spanning forest, i.e. a minimum spanning tree for each connected
/// component of the graph.
///
/// The resulting graph has all the vertices of the input graph (with identical node indices),
/// and **|V| - c** edges, where **c** is the number of connected components in `g`.
///
/// Use `from_elements` to create a graph from the resulting iterator.
pub fn min_spanning_tree<G>(g: G) -> MinSpanningTree<G>
where
G::NodeWeight: Clone,
G::EdgeWeight: Clone + PartialOrd,
G: IntoNodeReferences + IntoEdgeReferences + NodeIndexable,
{
// Initially each vertex is its own disjoint subgraph, track the connectedness
// of the pre-MST with a union & find datastructure.
let subgraphs = UnionFind::new(g.node_bound());
let edges = g.edge_references();
let mut sort_edges = BinaryHeap::with_capacity(edges.size_hint().0);
for edge in edges {
sort_edges.push(MinScored(
edge.weight().clone(),
(edge.source(), edge.target()),
));
}
MinSpanningTree {
graph: g,
node_ids: Some(g.node_references()),
subgraphs,
sort_edges,
node_map: HashMap::new(),
node_count: 0,
}
}
/// An iterator producing a minimum spanning forest of a graph.
#[derive(Debug, Clone)]
pub struct MinSpanningTree<G>
where
G: Data + IntoNodeReferences,
{
graph: G,
node_ids: Option<G::NodeReferences>,
subgraphs: UnionFind<usize>,
#[allow(clippy::type_complexity)]
sort_edges: BinaryHeap<MinScored<G::EdgeWeight, (G::NodeId, G::NodeId)>>,
node_map: HashMap<usize, usize>,
node_count: usize,
}
impl<G> Iterator for MinSpanningTree<G>
where
G: IntoNodeReferences + NodeIndexable,
G::NodeWeight: Clone,
G::EdgeWeight: PartialOrd,
{
type Item = Element<G::NodeWeight, G::EdgeWeight>;
fn next(&mut self) -> Option<Self::Item> {
let g = self.graph;
if let Some(ref mut iter) = self.node_ids {
if let Some(node) = iter.next() {
self.node_map.insert(g.to_index(node.id()), self.node_count);
self.node_count += 1;
return Some(Element::Node {
weight: node.weight().clone(),
});
}
}
self.node_ids = None;
// Kruskal's algorithm.
// Algorithm is this:
//
// 1. Create a pre-MST with all the vertices and no edges.
// 2. Repeat:
//
// a. Remove the shortest edge from the original graph.
// b. If the edge connects two disjoint trees in the pre-MST,
// add the edge.
while let Some(MinScored(score, (a, b))) = self.sort_edges.pop() {
// check if the edge would connect two disjoint parts
let (a_index, b_index) = (g.to_index(a), g.to_index(b));
if self.subgraphs.union(a_index, b_index) {
let (&a_order, &b_order) =
match (self.node_map.get(&a_index), self.node_map.get(&b_index)) {
(Some(a_id), Some(b_id)) => (a_id, b_id),
_ => panic!("Edge references unknown node"),
};
return Some(Element::Edge {
source: a_order,
target: b_order,
weight: score,
});
}
}
None
}
}

867
vendor/petgraph/src/algo/mod.rs vendored Normal file
View File

@@ -0,0 +1,867 @@
//! Graph algorithms.
//!
//! It is a goal to gradually migrate the algorithms to be based on graph traits
//! so that they are generally applicable. For now, some of these still require
//! the `Graph` type.
pub mod astar;
pub mod bellman_ford;
pub mod coloring;
pub mod dijkstra;
pub mod dominators;
pub mod feedback_arc_set;
pub mod floyd_warshall;
pub mod ford_fulkerson;
pub mod isomorphism;
pub mod k_shortest_path;
pub mod matching;
pub mod min_spanning_tree;
pub mod page_rank;
pub mod simple_paths;
pub mod tred;
use std::num::NonZeroUsize;
use crate::prelude::*;
use super::graph::IndexType;
use super::unionfind::UnionFind;
use super::visit::{
GraphBase, GraphRef, IntoEdgeReferences, IntoNeighbors, IntoNeighborsDirected,
IntoNodeIdentifiers, NodeCompactIndexable, NodeIndexable, Reversed, VisitMap, Visitable,
};
use super::EdgeType;
use crate::visit::Walker;
pub use astar::astar;
pub use bellman_ford::{bellman_ford, find_negative_cycle};
pub use coloring::dsatur_coloring;
pub use dijkstra::dijkstra;
pub use feedback_arc_set::greedy_feedback_arc_set;
pub use floyd_warshall::floyd_warshall;
pub use ford_fulkerson::ford_fulkerson;
pub use isomorphism::{
is_isomorphic, is_isomorphic_matching, is_isomorphic_subgraph, is_isomorphic_subgraph_matching,
subgraph_isomorphisms_iter,
};
pub use k_shortest_path::k_shortest_path;
pub use matching::{greedy_matching, maximum_matching, Matching};
pub use min_spanning_tree::min_spanning_tree;
pub use page_rank::page_rank;
pub use simple_paths::all_simple_paths;
/// \[Generic\] Return the number of connected components of the graph.
///
/// For a directed graph, this is the *weakly* connected components.
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::connected_components;
/// use petgraph::prelude::*;
///
/// let mut graph : Graph<(),(),Directed>= Graph::new();
/// let a = graph.add_node(()); // node with no weight
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
/// let g = graph.add_node(());
/// let h = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// (d, a),
/// (e, f),
/// (f, g),
/// (g, h),
/// (h, e)
/// ]);
/// // a ----> b e ----> f
/// // ^ | ^ |
/// // | v | v
/// // d <---- c h <---- g
///
/// assert_eq!(connected_components(&graph),2);
/// graph.add_edge(b,e,());
/// assert_eq!(connected_components(&graph),1);
/// ```
pub fn connected_components<G>(g: G) -> usize
where
G: NodeCompactIndexable + IntoEdgeReferences,
{
let mut vertex_sets = UnionFind::new(g.node_bound());
for edge in g.edge_references() {
let (a, b) = (edge.source(), edge.target());
// union the two vertices of the edge
vertex_sets.union(g.to_index(a), g.to_index(b));
}
let mut labels = vertex_sets.into_labeling();
labels.sort_unstable();
labels.dedup();
labels.len()
}
/// \[Generic\] Return `true` if the input graph contains a cycle.
///
/// Always treats the input graph as if undirected.
pub fn is_cyclic_undirected<G>(g: G) -> bool
where
G: NodeIndexable + IntoEdgeReferences,
{
let mut edge_sets = UnionFind::new(g.node_bound());
for edge in g.edge_references() {
let (a, b) = (edge.source(), edge.target());
// union the two vertices of the edge
// -- if they were already the same, then we have a cycle
if !edge_sets.union(g.to_index(a), g.to_index(b)) {
return true;
}
}
false
}
/// \[Generic\] Perform a topological sort of a directed graph.
///
/// If the graph was acyclic, return a vector of nodes in topological order:
/// each node is ordered before its successors.
/// Otherwise, it will return a `Cycle` error. Self loops are also cycles.
///
/// To handle graphs with cycles, use the scc algorithms or `DfsPostOrder`
/// instead of this function.
///
/// If `space` is not `None`, it is used instead of creating a new workspace for
/// graph traversal. The implementation is iterative.
pub fn toposort<G>(
g: G,
space: Option<&mut DfsSpace<G::NodeId, G::Map>>,
) -> Result<Vec<G::NodeId>, Cycle<G::NodeId>>
where
G: IntoNeighborsDirected + IntoNodeIdentifiers + Visitable,
{
// based on kosaraju scc
with_dfs(g, space, |dfs| {
dfs.reset(g);
let mut finished = g.visit_map();
let mut finish_stack = Vec::new();
for i in g.node_identifiers() {
if dfs.discovered.is_visited(&i) {
continue;
}
dfs.stack.push(i);
while let Some(&nx) = dfs.stack.last() {
if dfs.discovered.visit(nx) {
// First time visiting `nx`: Push neighbors, don't pop `nx`
for succ in g.neighbors(nx) {
if succ == nx {
// self cycle
return Err(Cycle(nx));
}
if !dfs.discovered.is_visited(&succ) {
dfs.stack.push(succ);
}
}
} else {
dfs.stack.pop();
if finished.visit(nx) {
// Second time: All reachable nodes must have been finished
finish_stack.push(nx);
}
}
}
}
finish_stack.reverse();
dfs.reset(g);
for &i in &finish_stack {
dfs.move_to(i);
let mut cycle = false;
while let Some(j) = dfs.next(Reversed(g)) {
if cycle {
return Err(Cycle(j));
}
cycle = true;
}
}
Ok(finish_stack)
})
}
/// \[Generic\] Return `true` if the input directed graph contains a cycle.
///
/// This implementation is recursive; use `toposort` if an alternative is
/// needed.
pub fn is_cyclic_directed<G>(g: G) -> bool
where
G: IntoNodeIdentifiers + IntoNeighbors + Visitable,
{
use crate::visit::{depth_first_search, DfsEvent};
depth_first_search(g, g.node_identifiers(), |event| match event {
DfsEvent::BackEdge(_, _) => Err(()),
_ => Ok(()),
})
.is_err()
}
type DfsSpaceType<G> = DfsSpace<<G as GraphBase>::NodeId, <G as Visitable>::Map>;
/// Workspace for a graph traversal.
#[derive(Clone, Debug)]
pub struct DfsSpace<N, VM> {
dfs: Dfs<N, VM>,
}
impl<N, VM> DfsSpace<N, VM>
where
N: Copy + PartialEq,
VM: VisitMap<N>,
{
pub fn new<G>(g: G) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
DfsSpace { dfs: Dfs::empty(g) }
}
}
impl<N, VM> Default for DfsSpace<N, VM>
where
VM: VisitMap<N> + Default,
{
fn default() -> Self {
DfsSpace {
dfs: Dfs {
stack: <_>::default(),
discovered: <_>::default(),
},
}
}
}
/// Create a Dfs if it's needed
fn with_dfs<G, F, R>(g: G, space: Option<&mut DfsSpaceType<G>>, f: F) -> R
where
G: GraphRef + Visitable,
F: FnOnce(&mut Dfs<G::NodeId, G::Map>) -> R,
{
let mut local_visitor;
let dfs = if let Some(v) = space {
&mut v.dfs
} else {
local_visitor = Dfs::empty(g);
&mut local_visitor
};
f(dfs)
}
/// \[Generic\] Check if there exists a path starting at `from` and reaching `to`.
///
/// If `from` and `to` are equal, this function returns true.
///
/// If `space` is not `None`, it is used instead of creating a new workspace for
/// graph traversal.
pub fn has_path_connecting<G>(
g: G,
from: G::NodeId,
to: G::NodeId,
space: Option<&mut DfsSpace<G::NodeId, G::Map>>,
) -> bool
where
G: IntoNeighbors + Visitable,
{
with_dfs(g, space, |dfs| {
dfs.reset(g);
dfs.move_to(from);
dfs.iter(g).any(|x| x == to)
})
}
/// Renamed to `kosaraju_scc`.
#[deprecated(note = "renamed to kosaraju_scc")]
pub fn scc<G>(g: G) -> Vec<Vec<G::NodeId>>
where
G: IntoNeighborsDirected + Visitable + IntoNodeIdentifiers,
{
kosaraju_scc(g)
}
/// \[Generic\] Compute the *strongly connected components* using [Kosaraju's algorithm][1].
///
/// [1]: https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
///
/// Return a vector where each element is a strongly connected component (scc).
/// The order of node ids within each scc is arbitrary, but the order of
/// the sccs is their postorder (reverse topological sort).
///
/// For an undirected graph, the sccs are simply the connected components.
///
/// This implementation is iterative and does two passes over the nodes.
pub fn kosaraju_scc<G>(g: G) -> Vec<Vec<G::NodeId>>
where
G: IntoNeighborsDirected + Visitable + IntoNodeIdentifiers,
{
let mut dfs = DfsPostOrder::empty(g);
// First phase, reverse dfs pass, compute finishing times.
// http://stackoverflow.com/a/26780899/161659
let mut finish_order = Vec::with_capacity(0);
for i in g.node_identifiers() {
if dfs.discovered.is_visited(&i) {
continue;
}
dfs.move_to(i);
while let Some(nx) = dfs.next(Reversed(g)) {
finish_order.push(nx);
}
}
let mut dfs = Dfs::from_parts(dfs.stack, dfs.discovered);
dfs.reset(g);
let mut sccs = Vec::new();
// Second phase
// Process in decreasing finishing time order
for i in finish_order.into_iter().rev() {
if dfs.discovered.is_visited(&i) {
continue;
}
// Move to the leader node `i`.
dfs.move_to(i);
let mut scc = Vec::new();
while let Some(nx) = dfs.next(g) {
scc.push(nx);
}
sccs.push(scc);
}
sccs
}
#[derive(Copy, Clone, Debug)]
struct NodeData {
rootindex: Option<NonZeroUsize>,
}
/// A reusable state for computing the *strongly connected components* using [Tarjan's algorithm][1].
///
/// [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
#[derive(Debug)]
pub struct TarjanScc<N> {
index: usize,
componentcount: usize,
nodes: Vec<NodeData>,
stack: Vec<N>,
}
impl<N> Default for TarjanScc<N> {
fn default() -> Self {
Self::new()
}
}
impl<N> TarjanScc<N> {
/// Creates a new `TarjanScc`
pub fn new() -> Self {
TarjanScc {
index: 1, // Invariant: index < componentcount at all times.
componentcount: std::usize::MAX, // Will hold if componentcount is initialized to number of nodes - 1 or higher.
nodes: Vec::new(),
stack: Vec::new(),
}
}
/// \[Generic\] Compute the *strongly connected components* using Algorithm 3 in
/// [A Space-Efficient Algorithm for Finding Strongly Connected Components][1] by David J. Pierce,
/// which is a memory-efficient variation of [Tarjan's algorithm][2].
///
///
/// [1]: https://homepages.ecs.vuw.ac.nz/~djp/files/P05.pdf
/// [2]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
///
/// Calls `f` for each strongly strongly connected component (scc).
/// The order of node ids within each scc is arbitrary, but the order of
/// the sccs is their postorder (reverse topological sort).
///
/// For an undirected graph, the sccs are simply the connected components.
///
/// This implementation is recursive and does one pass over the nodes.
pub fn run<G, F>(&mut self, g: G, mut f: F)
where
G: IntoNodeIdentifiers<NodeId = N> + IntoNeighbors<NodeId = N> + NodeIndexable<NodeId = N>,
F: FnMut(&[N]),
N: Copy + PartialEq,
{
self.nodes.clear();
self.nodes
.resize(g.node_bound(), NodeData { rootindex: None });
for n in g.node_identifiers() {
let visited = self.nodes[g.to_index(n)].rootindex.is_some();
if !visited {
self.visit(n, g, &mut f);
}
}
debug_assert!(self.stack.is_empty());
}
fn visit<G, F>(&mut self, v: G::NodeId, g: G, f: &mut F)
where
G: IntoNeighbors<NodeId = N> + NodeIndexable<NodeId = N>,
F: FnMut(&[N]),
N: Copy + PartialEq,
{
macro_rules! node {
($node:expr) => {
self.nodes[g.to_index($node)]
};
}
let node_v = &mut node![v];
debug_assert!(node_v.rootindex.is_none());
let mut v_is_local_root = true;
let v_index = self.index;
node_v.rootindex = NonZeroUsize::new(v_index);
self.index += 1;
for w in g.neighbors(v) {
if node![w].rootindex.is_none() {
self.visit(w, g, f);
}
if node![w].rootindex < node![v].rootindex {
node![v].rootindex = node![w].rootindex;
v_is_local_root = false
}
}
if v_is_local_root {
// Pop the stack and generate an SCC.
let mut indexadjustment = 1;
let c = NonZeroUsize::new(self.componentcount);
let nodes = &mut self.nodes;
let start = self
.stack
.iter()
.rposition(|&w| {
if nodes[g.to_index(v)].rootindex > nodes[g.to_index(w)].rootindex {
true
} else {
nodes[g.to_index(w)].rootindex = c;
indexadjustment += 1;
false
}
})
.map(|x| x + 1)
.unwrap_or_default();
nodes[g.to_index(v)].rootindex = c;
self.stack.push(v); // Pushing the component root to the back right before getting rid of it is somewhat ugly, but it lets it be included in f.
f(&self.stack[start..]);
self.stack.truncate(start);
self.index -= indexadjustment; // Backtrack index back to where it was before we ever encountered the component.
self.componentcount -= 1;
} else {
self.stack.push(v); // Stack is filled up when backtracking, unlike in Tarjans original algorithm.
}
}
/// Returns the index of the component in which v has been assigned. Allows for using self as a lookup table for an scc decomposition produced by self.run().
pub fn node_component_index<G>(&self, g: G, v: N) -> usize
where
G: IntoNeighbors<NodeId = N> + NodeIndexable<NodeId = N>,
N: Copy + PartialEq,
{
let rindex: usize = self.nodes[g.to_index(v)]
.rootindex
.map(NonZeroUsize::get)
.unwrap_or(0); // Compiles to no-op.
debug_assert!(
rindex != 0,
"Tried to get the component index of an unvisited node."
);
debug_assert!(
rindex > self.componentcount,
"Given node has been visited but not yet assigned to a component."
);
std::usize::MAX - rindex
}
}
/// \[Generic\] Compute the *strongly connected components* using [Tarjan's algorithm][1].
///
/// [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
/// [2]: https://homepages.ecs.vuw.ac.nz/~djp/files/P05.pdf
///
/// Return a vector where each element is a strongly connected component (scc).
/// The order of node ids within each scc is arbitrary, but the order of
/// the sccs is their postorder (reverse topological sort).
///
/// For an undirected graph, the sccs are simply the connected components.
///
/// This implementation is recursive and does one pass over the nodes. It is based on
/// [A Space-Efficient Algorithm for Finding Strongly Connected Components][2] by David J. Pierce,
/// to provide a memory-efficient implementation of [Tarjan's algorithm][1].
pub fn tarjan_scc<G>(g: G) -> Vec<Vec<G::NodeId>>
where
G: IntoNodeIdentifiers + IntoNeighbors + NodeIndexable,
{
let mut sccs = Vec::new();
{
let mut tarjan_scc = TarjanScc::new();
tarjan_scc.run(g, |scc| sccs.push(scc.to_vec()));
}
sccs
}
/// [Graph] Condense every strongly connected component into a single node and return the result.
///
/// If `make_acyclic` is true, self-loops and multi edges are ignored, guaranteeing that
/// the output is acyclic.
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::condensation;
/// use petgraph::prelude::*;
///
/// let mut graph : Graph<(),(),Directed> = Graph::new();
/// let a = graph.add_node(()); // node with no weight
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
/// let g = graph.add_node(());
/// let h = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// (d, a),
/// (b, e),
/// (e, f),
/// (f, g),
/// (g, h),
/// (h, e)
/// ]);
///
/// // a ----> b ----> e ----> f
/// // ^ | ^ |
/// // | v | v
/// // d <---- c h <---- g
///
/// let condensed_graph = condensation(graph,false);
/// let A = NodeIndex::new(0);
/// let B = NodeIndex::new(1);
/// assert_eq!(condensed_graph.node_count(), 2);
/// assert_eq!(condensed_graph.edge_count(), 9);
/// assert_eq!(condensed_graph.neighbors(A).collect::<Vec<_>>(), vec![A, A, A, A]);
/// assert_eq!(condensed_graph.neighbors(B).collect::<Vec<_>>(), vec![A, B, B, B, B]);
/// ```
/// If `make_acyclic` is true, self-loops and multi edges are ignored:
///
/// ```rust
/// # use petgraph::Graph;
/// # use petgraph::algo::condensation;
/// # use petgraph::prelude::*;
/// #
/// # let mut graph : Graph<(),(),Directed> = Graph::new();
/// # let a = graph.add_node(()); // node with no weight
/// # let b = graph.add_node(());
/// # let c = graph.add_node(());
/// # let d = graph.add_node(());
/// # let e = graph.add_node(());
/// # let f = graph.add_node(());
/// # let g = graph.add_node(());
/// # let h = graph.add_node(());
/// #
/// # graph.extend_with_edges(&[
/// # (a, b),
/// # (b, c),
/// # (c, d),
/// # (d, a),
/// # (b, e),
/// # (e, f),
/// # (f, g),
/// # (g, h),
/// # (h, e)
/// # ]);
/// let acyclic_condensed_graph = condensation(graph, true);
/// let A = NodeIndex::new(0);
/// let B = NodeIndex::new(1);
/// assert_eq!(acyclic_condensed_graph.node_count(), 2);
/// assert_eq!(acyclic_condensed_graph.edge_count(), 1);
/// assert_eq!(acyclic_condensed_graph.neighbors(B).collect::<Vec<_>>(), vec![A]);
/// ```
pub fn condensation<N, E, Ty, Ix>(
g: Graph<N, E, Ty, Ix>,
make_acyclic: bool,
) -> Graph<Vec<N>, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
let sccs = kosaraju_scc(&g);
let mut condensed: Graph<Vec<N>, E, Ty, Ix> = Graph::with_capacity(sccs.len(), g.edge_count());
// Build a map from old indices to new ones.
let mut node_map = vec![NodeIndex::end(); g.node_count()];
for comp in sccs {
let new_nix = condensed.add_node(Vec::new());
for nix in comp {
node_map[nix.index()] = new_nix;
}
}
// Consume nodes and edges of the old graph and insert them into the new one.
let (nodes, edges) = g.into_nodes_edges();
for (nix, node) in nodes.into_iter().enumerate() {
condensed[node_map[nix]].push(node.weight);
}
for edge in edges {
let source = node_map[edge.source().index()];
let target = node_map[edge.target().index()];
if make_acyclic {
if source != target {
condensed.update_edge(source, target, edge.weight);
}
} else {
condensed.add_edge(source, target, edge.weight);
}
}
condensed
}
/// An algorithm error: a cycle was found in the graph.
#[derive(Clone, Debug, PartialEq)]
pub struct Cycle<N>(pub(crate) N);
impl<N> Cycle<N> {
/// Return a node id that participates in the cycle
pub fn node_id(&self) -> N
where
N: Copy,
{
self.0
}
}
/// An algorithm error: a cycle of negative weights was found in the graph.
#[derive(Clone, Debug, PartialEq)]
pub struct NegativeCycle(pub ());
/// Return `true` if the graph is bipartite. A graph is bipartite if its nodes can be divided into
/// two disjoint and indepedent sets U and V such that every edge connects U to one in V. This
/// algorithm implements 2-coloring algorithm based on the BFS algorithm.
///
/// Always treats the input graph as if undirected.
pub fn is_bipartite_undirected<G, N, VM>(g: G, start: N) -> bool
where
G: GraphRef + Visitable<NodeId = N, Map = VM> + IntoNeighbors<NodeId = N>,
N: Copy + PartialEq + std::fmt::Debug,
VM: VisitMap<N>,
{
let mut red = g.visit_map();
red.visit(start);
let mut blue = g.visit_map();
let mut stack = ::std::collections::VecDeque::new();
stack.push_front(start);
while let Some(node) = stack.pop_front() {
let is_red = red.is_visited(&node);
let is_blue = blue.is_visited(&node);
assert!(is_red ^ is_blue);
for neighbour in g.neighbors(node) {
let is_neigbour_red = red.is_visited(&neighbour);
let is_neigbour_blue = blue.is_visited(&neighbour);
if (is_red && is_neigbour_red) || (is_blue && is_neigbour_blue) {
return false;
}
if !is_neigbour_red && !is_neigbour_blue {
//hasn't been visited yet
match (is_red, is_blue) {
(true, false) => {
blue.visit(neighbour);
}
(false, true) => {
red.visit(neighbour);
}
(_, _) => {
panic!("Invariant doesn't hold");
}
}
stack.push_back(neighbour);
}
}
}
true
}
use std::fmt::Debug;
use std::ops::Add;
/// Associated data that can be used for measures (such as length).
pub trait Measure: Debug + PartialOrd + Add<Self, Output = Self> + Default + Clone {}
impl<M> Measure for M where M: Debug + PartialOrd + Add<M, Output = M> + Default + Clone {}
/// A floating-point measure.
pub trait FloatMeasure: Measure + Copy {
fn zero() -> Self;
fn infinite() -> Self;
}
impl FloatMeasure for f32 {
fn zero() -> Self {
0.
}
fn infinite() -> Self {
1. / 0.
}
}
impl FloatMeasure for f64 {
fn zero() -> Self {
0.
}
fn infinite() -> Self {
1. / 0.
}
}
pub trait BoundedMeasure: Measure + std::ops::Sub<Self, Output = Self> {
fn min() -> Self;
fn max() -> Self;
fn overflowing_add(self, rhs: Self) -> (Self, bool);
}
macro_rules! impl_bounded_measure_integer(
( $( $t:ident ),* ) => {
$(
impl BoundedMeasure for $t {
fn min() -> Self {
std::$t::MIN
}
fn max() -> Self {
std::$t::MAX
}
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
self.overflowing_add(rhs)
}
}
)*
};
);
impl_bounded_measure_integer!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
macro_rules! impl_bounded_measure_float(
( $( $t:ident ),* ) => {
$(
impl BoundedMeasure for $t {
fn min() -> Self {
std::$t::MIN
}
fn max() -> Self {
std::$t::MAX
}
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
// for an overflow: a + b > max: both values need to be positive and a > max - b must be satisfied
let overflow = self > Self::default() && rhs > Self::default() && self > std::$t::MAX - rhs;
// for an underflow: a + b < min: overflow can not happen and both values must be negative and a < min - b must be satisfied
let underflow = !overflow && self < Self::default() && rhs < Self::default() && self < std::$t::MIN - rhs;
(self + rhs, overflow || underflow)
}
}
)*
};
);
impl_bounded_measure_float!(f32, f64);
/// A floating-point measure that can be computed from `usize`
/// and with a default measure of proximity.
pub trait UnitMeasure:
Measure
+ std::ops::Sub<Self, Output = Self>
+ std::ops::Mul<Self, Output = Self>
+ std::ops::Div<Self, Output = Self>
+ std::iter::Sum
{
fn zero() -> Self;
fn one() -> Self;
fn from_usize(nb: usize) -> Self;
fn default_tol() -> Self;
}
macro_rules! impl_unit_measure(
( $( $t:ident ),* )=> {
$(
impl UnitMeasure for $t {
fn zero() -> Self {
0 as $t
}
fn one() -> Self {
1 as $t
}
fn from_usize(nb: usize) -> Self {
nb as $t
}
fn default_tol() -> Self {
1e-6 as $t
}
}
)*
}
);
impl_unit_measure!(f32, f64);
/// Some measure of positive numbers, assuming positive
/// float-pointing numbers
pub trait PositiveMeasure: Measure + Copy {
fn zero() -> Self;
fn max() -> Self;
}
macro_rules! impl_positive_measure(
( $( $t:ident ),* )=> {
$(
impl PositiveMeasure for $t {
fn zero() -> Self {
0 as $t
}
fn max() -> Self {
std::$t::MAX
}
}
)*
}
);
impl_positive_measure!(u8, u16, u32, u64, u128, usize, f32, f64);

185
vendor/petgraph/src/algo/page_rank.rs vendored Normal file
View File

@@ -0,0 +1,185 @@
use crate::visit::{EdgeRef, IntoEdges, NodeCount, NodeIndexable};
#[cfg(feature = "rayon")]
use rayon::prelude::*;
use super::UnitMeasure;
/// \[Generic\] Page Rank algorithm.
///
/// Computes the ranks of every node in a graph using the [Page Rank algorithm][pr].
///
/// Returns a `Vec` container mapping each node index to its rank.
///
/// # Panics
/// The damping factor should be a number of type `f32` or `f64` between 0 and 1 (0 and 1 included). Otherwise, it panics.
///
/// # Complexity
/// Time complexity is **O(N|V|²|E|)**.
/// Space complexity is **O(|V| + |E|)**
/// where **N** is the number of iterations, **|V|** the number of vertices (i.e nodes) and **|E|** the number of edges.
///
/// [pr]: https://en.wikipedia.org/wiki/PageRank
///
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::page_rank;
/// let mut g: Graph<(), usize> = Graph::new();
/// assert_eq!(page_rank(&g, 0.5_f64, 1), vec![]); // empty graphs have no node ranks.
/// let a = g.add_node(());
/// let b = g.add_node(());
/// let c = g.add_node(());
/// let d = g.add_node(());
/// let e = g.add_node(());
/// g.extend_with_edges(&[(0, 1), (0, 3), (1, 2), (1, 3)]);
/// // With the following dot representation.
/// //digraph {
/// // 0 [ label = "()" ]
/// // 1 [ label = "()" ]
/// // 2 [ label = "()" ]
/// // 3 [ label = "()" ]
/// // 4 [ label = "()" ]
/// // 0 -> 1 [ label = "0.0" ]
/// // 0 -> 3 [ label = "0.0" ]
/// // 1 -> 2 [ label = "0.0" ]
/// // 1 -> 3 [ label = "0.0" ]
/// //}
/// let damping_factor = 0.7_f32;
/// let number_iterations = 10;
/// let output_ranks = page_rank(&g, damping_factor, number_iterations);
/// let expected_ranks = vec![0.14685437, 0.20267677, 0.22389607, 0.27971846, 0.14685437];
/// assert_eq!(expected_ranks, output_ranks);
/// ```
pub fn page_rank<G, D>(graph: G, damping_factor: D, nb_iter: usize) -> Vec<D>
where
G: NodeCount + IntoEdges + NodeIndexable,
D: UnitMeasure + Copy,
{
let node_count = graph.node_count();
if node_count == 0 {
return vec![];
}
assert!(
D::zero() <= damping_factor && damping_factor <= D::one(),
"Damping factor should be between 0 et 1."
);
let nb = D::from_usize(node_count);
let mut ranks = vec![D::one() / nb; node_count];
let nodeix = |i| graph.from_index(i);
let out_degrees: Vec<D> = (0..node_count)
.map(|i| graph.edges(nodeix(i)).map(|_| D::one()).sum::<D>())
.collect();
for _ in 0..nb_iter {
let pi = (0..node_count)
.enumerate()
.map(|(v, _)| {
ranks
.iter()
.enumerate()
.map(|(w, r)| {
let mut w_out_edges = graph.edges(nodeix(w));
if w_out_edges.any(|e| e.target() == nodeix(v)) {
damping_factor * *r / out_degrees[w]
} else if out_degrees[w] == D::zero() {
damping_factor * *r / nb // stochastic matrix condition
} else {
(D::one() - damping_factor) * *r / nb // random jumps
}
})
.sum::<D>()
})
.collect::<Vec<D>>();
let sum = pi.iter().copied().sum::<D>();
ranks = pi.iter().map(|r| *r / sum).collect::<Vec<D>>();
}
ranks
}
#[allow(dead_code)]
fn out_edges_info<G, D>(graph: G, index_w: usize, index_v: usize) -> (D, bool)
where
G: NodeCount + IntoEdges + NodeIndexable + std::marker::Sync,
D: UnitMeasure + Copy + std::marker::Send + std::marker::Sync,
{
let node_w = graph.from_index(index_w);
let node_v = graph.from_index(index_v);
let mut out_edges = graph.edges(node_w);
let mut out_edge = out_edges.next();
let mut out_degree = D::zero();
let mut flag_points_to = false;
while let Some(edge) = out_edge {
out_degree = out_degree + D::one();
if edge.target() == node_v {
flag_points_to = true;
}
out_edge = out_edges.next();
}
(out_degree, flag_points_to)
}
/// \[Generic\] Parallel Page Rank algorithm.
///
/// See [`page_rank`].
#[cfg(feature = "rayon")]
pub fn parallel_page_rank<G, D>(
graph: G,
damping_factor: D,
nb_iter: usize,
tol: Option<D>,
) -> Vec<D>
where
G: NodeCount + IntoEdges + NodeIndexable + std::marker::Sync,
D: UnitMeasure + Copy + std::marker::Send + std::marker::Sync,
{
let node_count = graph.node_count();
if node_count == 0 {
return vec![];
}
assert!(
D::zero() <= damping_factor && damping_factor <= D::one(),
"Damping factor should be between 0 et 1."
);
let mut tolerance = D::default_tol();
if let Some(_tol) = tol {
tolerance = _tol;
}
let nb = D::from_usize(node_count);
let mut ranks: Vec<D> = (0..node_count)
.into_par_iter()
.map(|_| D::one() / nb)
.collect();
for _ in 0..nb_iter {
let pi = (0..node_count)
.into_par_iter()
.map(|v| {
ranks
.iter()
.enumerate()
.map(|(w, r)| {
let (out_deg, w_points_to_v) = out_edges_info(graph, w, v);
if w_points_to_v {
damping_factor * *r / out_deg
} else if out_deg == D::zero() {
damping_factor * *r / nb // stochastic matrix condition
} else {
(D::one() - damping_factor) * *r / nb // random jumps
}
})
.sum::<D>()
})
.collect::<Vec<D>>();
let sum = pi.par_iter().map(|score| *score).sum::<D>();
let new_ranks = pi.par_iter().map(|r| *r / sum).collect::<Vec<D>>();
let squared_norm_2 = new_ranks
.par_iter()
.zip(&ranks)
.map(|(new, old)| (*new - *old) * (*new - *old))
.sum::<D>();
if squared_norm_2 <= tolerance {
return ranks;
} else {
ranks = new_ranks;
}
}
ranks
}

199
vendor/petgraph/src/algo/simple_paths.rs vendored Normal file
View File

@@ -0,0 +1,199 @@
use std::{
hash::Hash,
iter::{from_fn, FromIterator},
};
use indexmap::IndexSet;
use crate::{
visit::{IntoNeighborsDirected, NodeCount},
Direction::Outgoing,
};
/// Returns an iterator that produces all simple paths from `from` node to `to`, which contains at least `min_intermediate_nodes` nodes
/// and at most `max_intermediate_nodes`, if given, or limited by the graph's order otherwise. The simple path is a path without repetitions.
///
/// This algorithm is adapted from <https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.simple_paths.all_simple_paths.html>.
///
/// # Example
/// ```
/// use petgraph::{algo, prelude::*};
///
/// let mut graph = DiGraph::<&str, i32>::new();
///
/// let a = graph.add_node("a");
/// let b = graph.add_node("b");
/// let c = graph.add_node("c");
/// let d = graph.add_node("d");
///
/// graph.extend_with_edges(&[(a, b, 1), (b, c, 1), (c, d, 1), (a, b, 1), (b, d, 1)]);
///
/// let paths = algo::all_simple_paths::<Vec<_>, _>(&graph, a, d, 0, None)
/// .collect::<Vec<_>>();
///
/// assert_eq!(paths.len(), 4);
///
///
/// // Take only 2 paths.
/// let paths = algo::all_simple_paths::<Vec<_>, _>(&graph, a, d, 0, None)
/// .take(2)
/// .collect::<Vec<_>>();
///
/// assert_eq!(paths.len(), 2);
///
/// ```
///
/// # Note
///
/// The number of simple paths between a given pair of vertices almost always grows exponentially,
/// reaching `O(V!)` on a dense graphs at `V` vertices.
///
/// So if you have a large enough graph, be prepared to wait for the results for years.
/// Or consider extracting only part of the simple paths using the adapter [`Iterator::take`].
pub fn all_simple_paths<TargetColl, G>(
graph: G,
from: G::NodeId,
to: G::NodeId,
min_intermediate_nodes: usize,
max_intermediate_nodes: Option<usize>,
) -> impl Iterator<Item = TargetColl>
where
G: NodeCount,
G: IntoNeighborsDirected,
G::NodeId: Eq + Hash,
TargetColl: FromIterator<G::NodeId>,
{
// how many nodes are allowed in simple path up to target node
// it is min/max allowed path length minus one, because it is more appropriate when implementing lookahead
// than constantly add 1 to length of current path
let max_length = if let Some(l) = max_intermediate_nodes {
l + 1
} else {
graph.node_count() - 1
};
let min_length = min_intermediate_nodes + 1;
// list of visited nodes
let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
// list of childs of currently exploring path nodes,
// last elem is list of childs of last visited node
let mut stack = vec![graph.neighbors_directed(from, Outgoing)];
from_fn(move || {
while let Some(children) = stack.last_mut() {
if let Some(child) = children.next() {
if visited.len() < max_length {
if child == to {
if visited.len() >= min_length {
let path = visited
.iter()
.cloned()
.chain(Some(to))
.collect::<TargetColl>();
return Some(path);
}
} else if !visited.contains(&child) {
visited.insert(child);
stack.push(graph.neighbors_directed(child, Outgoing));
}
} else {
if (child == to || children.any(|v| v == to)) && visited.len() >= min_length {
let path = visited
.iter()
.cloned()
.chain(Some(to))
.collect::<TargetColl>();
return Some(path);
}
stack.pop();
visited.pop();
}
} else {
stack.pop();
visited.pop();
}
}
None
})
}
#[cfg(test)]
mod test {
use std::{collections::HashSet, iter::FromIterator};
use itertools::assert_equal;
use crate::{dot::Dot, prelude::DiGraph};
use super::all_simple_paths;
#[test]
fn test_all_simple_paths() {
let graph = DiGraph::<i32, i32, _>::from_edges(&[
(0, 1),
(0, 2),
(0, 3),
(1, 2),
(1, 3),
(2, 3),
(2, 4),
(3, 2),
(3, 4),
(4, 2),
(4, 5),
(5, 2),
(5, 3),
]);
let expexted_simple_paths_0_to_5 = vec![
vec![0usize, 1, 2, 3, 4, 5],
vec![0, 1, 2, 4, 5],
vec![0, 1, 3, 2, 4, 5],
vec![0, 1, 3, 4, 5],
vec![0, 2, 3, 4, 5],
vec![0, 2, 4, 5],
vec![0, 3, 2, 4, 5],
vec![0, 3, 4, 5],
];
println!("{}", Dot::new(&graph));
let actual_simple_paths_0_to_5: HashSet<Vec<_>> =
all_simple_paths(&graph, 0u32.into(), 5u32.into(), 0, None)
.map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
.collect();
assert_eq!(actual_simple_paths_0_to_5.len(), 8);
assert_eq!(
HashSet::from_iter(expexted_simple_paths_0_to_5),
actual_simple_paths_0_to_5
);
}
#[test]
fn test_one_simple_path() {
let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);
let expexted_simple_paths_0_to_1 = &[vec![0usize, 1]];
println!("{}", Dot::new(&graph));
let actual_simple_paths_0_to_1: Vec<Vec<_>> =
all_simple_paths(&graph, 0u32.into(), 1u32.into(), 0, None)
.map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
.collect();
assert_eq!(actual_simple_paths_0_to_1.len(), 1);
assert_equal(expexted_simple_paths_0_to_1, &actual_simple_paths_0_to_1);
}
#[test]
fn test_no_simple_paths() {
let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);
println!("{}", Dot::new(&graph));
let actual_simple_paths_0_to_2: Vec<Vec<_>> =
all_simple_paths(&graph, 0u32.into(), 2u32.into(), 0, None)
.map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
.collect();
assert_eq!(actual_simple_paths_0_to_2.len(), 0);
}
}

162
vendor/petgraph/src/algo/tred.rs vendored Normal file
View File

@@ -0,0 +1,162 @@
//! Compute the transitive reduction and closure of a directed acyclic graph
//!
//! ## Transitive reduction and closure
//! The *transitive closure* of a graph **G = (V, E)** is the graph **Gc = (V, Ec)**
//! such that **(i, j)** belongs to **Ec** if and only if there is a path connecting
//! **i** to **j** in **G**. The *transitive reduction* of **G** is the graph **Gr
//! = (V, Er)** such that **Er** is minimal wrt. inclusion in **E** and the transitive
//! closure of **Gr** is the same as that of **G**.
//! The transitive reduction is well-defined for acyclic graphs only.
use crate::adj::{List, UnweightedList};
use crate::graph::IndexType;
use crate::visit::{
GraphBase, IntoNeighbors, IntoNeighborsDirected, NodeCompactIndexable, NodeCount,
};
use crate::Direction;
use fixedbitset::FixedBitSet;
/// Creates a representation of the same graph respecting topological order for use in `tred::dag_transitive_reduction_closure`.
///
/// `toposort` must be a topological order on the node indices of `g` (for example obtained
/// from [`toposort`]).
///
/// [`toposort`]: ../fn.toposort.html
///
/// Returns a pair of a graph `res` and the reciprocal of the topological sort `revmap`.
///
/// `res` is the same graph as `g` with the following differences:
/// * Node and edge weights are stripped,
/// * Node indices are replaced by the corresponding rank in `toposort`,
/// * Iterating on the neighbors of a node respects topological order.
///
/// `revmap` is handy to get back to map indices in `g` to indices in `res`.
/// ```
/// use petgraph::prelude::*;
/// use petgraph::graph::DefaultIx;
/// use petgraph::visit::IntoNeighbors;
/// use petgraph::algo::tred::dag_to_toposorted_adjacency_list;
///
/// let mut g = Graph::<&str, (), Directed, DefaultIx>::new();
/// let second = g.add_node("second child");
/// let top = g.add_node("top");
/// let first = g.add_node("first child");
/// g.extend_with_edges(&[(top, second), (top, first), (first, second)]);
///
/// let toposort = vec![top, first, second];
///
/// let (res, revmap) = dag_to_toposorted_adjacency_list(&g, &toposort);
///
/// // let's compute the children of top in topological order
/// let children: Vec<NodeIndex> = res
/// .neighbors(revmap[top.index()])
/// .map(|ix: NodeIndex| toposort[ix.index()])
/// .collect();
/// assert_eq!(children, vec![first, second])
/// ```
///
/// Runtime: **O(|V| + |E|)**.
///
/// Space complexity: **O(|V| + |E|)**.
pub fn dag_to_toposorted_adjacency_list<G, Ix: IndexType>(
g: G,
toposort: &[G::NodeId],
) -> (UnweightedList<Ix>, Vec<Ix>)
where
G: GraphBase + IntoNeighborsDirected + NodeCompactIndexable + NodeCount,
G::NodeId: IndexType,
{
let mut res = List::with_capacity(g.node_count());
// map from old node index to rank in toposort
let mut revmap = vec![Ix::default(); g.node_bound()];
for (ix, &old_ix) in toposort.iter().enumerate() {
let ix = Ix::new(ix);
revmap[old_ix.index()] = ix;
let iter = g.neighbors_directed(old_ix, Direction::Incoming);
let new_ix: Ix = res.add_node_with_capacity(iter.size_hint().0);
debug_assert_eq!(new_ix.index(), ix.index());
for old_pre in iter {
let pre: Ix = revmap[old_pre.index()];
res.add_edge(pre, ix, ());
}
}
(res, revmap)
}
/// Computes the transitive reduction and closure of a DAG.
///
/// The algorithm implemented here comes from [On the calculation of
/// transitive reduction-closure of
/// orders](https://www.sciencedirect.com/science/article/pii/0012365X9390164O) by Habib, Morvan
/// and Rampon.
///
/// The input graph must be in a very specific format: an adjacency
/// list such that:
/// * Node indices are a toposort, and
/// * The neighbors of all nodes are stored in topological order.
///
/// To get such a representation, use the function [`dag_to_toposorted_adjacency_list`].
///
/// [`dag_to_toposorted_adjacency_list`]: ./fn.dag_to_toposorted_adjacency_list.html
///
/// The output is the pair of the transitive reduction and the transitive closure.
///
/// Runtime complexity: **O(|V| + \sum_{(x, y) \in Er} d(y))** where **d(y)**
/// denotes the outgoing degree of **y** in the transitive closure of **G**.
/// This is still **O(|V|³)** in the worst case like the naive algorithm but
/// should perform better for some classes of graphs.
///
/// Space complexity: **O(|E|)**.
pub fn dag_transitive_reduction_closure<E, Ix: IndexType>(
g: &List<E, Ix>,
) -> (UnweightedList<Ix>, UnweightedList<Ix>) {
let mut tred = List::with_capacity(g.node_count());
let mut tclos = List::with_capacity(g.node_count());
let mut mark = FixedBitSet::with_capacity(g.node_count());
for i in g.node_indices() {
tred.add_node();
tclos.add_node_with_capacity(g.neighbors(i).len());
}
// the algorithm relies on this iterator being toposorted
for i in g.node_indices().rev() {
// the algorighm relies on this iterator being toposorted
for x in g.neighbors(i) {
if !mark[x.index()] {
tred.add_edge(i, x, ());
tclos.add_edge(i, x, ());
for e in tclos.edge_indices_from(x) {
let y = tclos.edge_endpoints(e).unwrap().1;
if !mark[y.index()] {
mark.insert(y.index());
tclos.add_edge(i, y, ());
}
}
}
}
for y in tclos.neighbors(i) {
mark.set(y.index(), false);
}
}
(tred, tclos)
}
#[cfg(test)]
#[test]
fn test_easy_tred() {
let mut input = List::new();
let a: u8 = input.add_node();
let b = input.add_node();
let c = input.add_node();
input.add_edge(a, b, ());
input.add_edge(a, c, ());
input.add_edge(b, c, ());
let (tred, tclos) = dag_transitive_reduction_closure(&input);
assert_eq!(tred.node_count(), 3);
assert_eq!(tclos.node_count(), 3);
assert!(tred.find_edge(a, b).is_some());
assert!(tred.find_edge(b, c).is_some());
assert!(tred.find_edge(a, c).is_none());
assert!(tclos.find_edge(a, b).is_some());
assert!(tclos.find_edge(b, c).is_some());
assert!(tclos.find_edge(a, c).is_some());
}

1151
vendor/petgraph/src/csr.rs vendored Normal file

File diff suppressed because it is too large Load Diff

478
vendor/petgraph/src/data.rs vendored Normal file
View File

@@ -0,0 +1,478 @@
//! Graph traits for associated data and graph construction.
use crate::graph::IndexType;
#[cfg(feature = "graphmap")]
use crate::graphmap::{GraphMap, NodeTrait};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::StableGraph;
use crate::visit::{Data, NodeCount, NodeIndexable, Reversed};
use crate::EdgeType;
use crate::Graph;
trait_template! {
/// Access node and edge weights (associated data).
#[allow(clippy::needless_arbitrary_self_type)]
pub trait DataMap : Data {
@section self
fn node_weight(self: &Self, id: Self::NodeId) -> Option<&Self::NodeWeight>;
fn edge_weight(self: &Self, id: Self::EdgeId) -> Option<&Self::EdgeWeight>;
}
}
macro_rules! access0 {
($e:expr) => {
$e.0
};
}
DataMap! {delegate_impl []}
DataMap! {delegate_impl [['a, G], G, &'a mut G, deref_twice]}
DataMap! {delegate_impl [[G], G, Reversed<G>, access0]}
trait_template! {
/// Access node and edge weights mutably.
#[allow(clippy::needless_arbitrary_self_type)]
pub trait DataMapMut : DataMap {
@section self
fn node_weight_mut(self: &mut Self, id: Self::NodeId) -> Option<&mut Self::NodeWeight>;
fn edge_weight_mut(self: &mut Self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight>;
}
}
DataMapMut! {delegate_impl [['a, G], G, &'a mut G, deref_twice]}
DataMapMut! {delegate_impl [[G], G, Reversed<G>, access0]}
/// A graph that can be extended with further nodes and edges
pub trait Build: Data + NodeCount {
fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId;
/// Add a new edge. If parallel edges (duplicate) are not allowed and
/// the edge already exists, return `None`.
fn add_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Option<Self::EdgeId> {
Some(self.update_edge(a, b, weight))
}
/// Add or update the edge from `a` to `b`. Return the id of the affected
/// edge.
fn update_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Self::EdgeId;
}
/// A graph that can be created
pub trait Create: Build + Default {
fn with_capacity(nodes: usize, edges: usize) -> Self;
}
impl<N, E, Ty, Ix> Data for Graph<N, E, Ty, Ix>
where
Ix: IndexType,
{
type NodeWeight = N;
type EdgeWeight = E;
}
impl<N, E, Ty, Ix> DataMap for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
self.node_weight(id)
}
fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
self.edge_weight(id)
}
}
impl<N, E, Ty, Ix> DataMapMut for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
self.node_weight_mut(id)
}
fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
self.edge_weight_mut(id)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ty, Ix> DataMap for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
self.node_weight(id)
}
fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
self.edge_weight(id)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ty, Ix> DataMapMut for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
self.node_weight_mut(id)
}
fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
self.edge_weight_mut(id)
}
}
impl<N, E, Ty, Ix> Build for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
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> {
Some(self.add_edge(a, b, weight))
}
fn update_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Self::EdgeId {
self.update_edge(a, b, weight)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ty, Ix> Build for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
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> {
Some(self.add_edge(a, b, weight))
}
fn update_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Self::EdgeId {
self.update_edge(a, b, weight)
}
}
#[cfg(feature = "graphmap")]
impl<N, E, Ty> Build for GraphMap<N, E, Ty>
where
Ty: EdgeType,
N: NodeTrait,
{
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.contains_edge(a, b) {
None
} else {
let r = self.add_edge(a, b, weight);
debug_assert!(r.is_none());
Some((a, b))
}
}
fn update_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Self::EdgeId {
self.add_edge(a, b, weight);
(a, b)
}
}
impl<N, E, Ty, Ix> Create for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn with_capacity(nodes: usize, edges: usize) -> Self {
Self::with_capacity(nodes, edges)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ty, Ix> Create for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn with_capacity(nodes: usize, edges: usize) -> Self {
Self::with_capacity(nodes, edges)
}
}
#[cfg(feature = "graphmap")]
impl<N, E, Ty> Create for GraphMap<N, E, Ty>
where
Ty: EdgeType,
N: NodeTrait,
{
fn with_capacity(nodes: usize, edges: usize) -> Self {
Self::with_capacity(nodes, edges)
}
}
/// A graph element.
///
/// A sequence of Elements, for example an iterator, is laid out as follows:
/// Nodes are implicitly given the index of their appearance in the sequence.
/// The edges source and target fields refer to these indices.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Element<N, E> {
/// A graph node.
Node { weight: N },
/// A graph edge.
Edge {
source: usize,
target: usize,
weight: E,
},
}
/// Create a graph from an iterator of elements.
pub trait FromElements: Create {
fn from_elements<I>(iterable: I) -> Self
where
Self: Sized,
I: IntoIterator<Item = Element<Self::NodeWeight, Self::EdgeWeight>>,
{
let mut gr = Self::with_capacity(0, 0);
// usize -> NodeId map
let mut map = Vec::new();
for element in iterable {
match element {
Element::Node { weight } => {
map.push(gr.add_node(weight));
}
Element::Edge {
source,
target,
weight,
} => {
gr.add_edge(map[source], map[target], weight);
}
}
}
gr
}
}
fn from_elements_indexable<G, I>(iterable: I) -> G
where
G: Create + NodeIndexable,
I: IntoIterator<Item = Element<G::NodeWeight, G::EdgeWeight>>,
{
let mut gr = G::with_capacity(0, 0);
let map = |gr: &G, i| gr.from_index(i);
for element in iterable {
match element {
Element::Node { weight } => {
gr.add_node(weight);
}
Element::Edge {
source,
target,
weight,
} => {
let from = map(&gr, source);
let to = map(&gr, target);
gr.add_edge(from, to, weight);
}
}
}
gr
}
impl<N, E, Ty, Ix> FromElements for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn from_elements<I>(iterable: I) -> Self
where
Self: Sized,
I: IntoIterator<Item = Element<Self::NodeWeight, Self::EdgeWeight>>,
{
from_elements_indexable(iterable)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ty, Ix> FromElements for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn from_elements<I>(iterable: I) -> Self
where
Self: Sized,
I: IntoIterator<Item = Element<Self::NodeWeight, Self::EdgeWeight>>,
{
from_elements_indexable(iterable)
}
}
#[cfg(feature = "graphmap")]
impl<N, E, Ty> FromElements for GraphMap<N, E, Ty>
where
Ty: EdgeType,
N: NodeTrait,
{
fn from_elements<I>(iterable: I) -> Self
where
Self: Sized,
I: IntoIterator<Item = Element<Self::NodeWeight, Self::EdgeWeight>>,
{
from_elements_indexable(iterable)
}
}
/// Iterator adaptors for iterators of `Element`.
pub trait ElementIterator<N, E>: Iterator<Item = Element<N, E>> {
/// Create an iterator adaptor that filters graph elements.
///
/// The function `f` is called with each element and if its return value
/// is `true` the element is accepted and if `false` it is removed.
/// `f` is called with mutable references to the node and edge weights,
/// so that they can be mutated (but the edge endpoints can not).
///
/// This filter adapts the edge source and target indices in the
/// stream so that they are correct after the removals.
fn filter_elements<F>(self, f: F) -> FilterElements<Self, F>
where
Self: Sized,
F: FnMut(Element<&mut N, &mut E>) -> bool,
{
FilterElements {
iter: self,
node_index: 0,
map: Vec::new(),
f,
}
}
}
impl<N, E, I: ?Sized> ElementIterator<N, E> for I where I: Iterator<Item = Element<N, E>> {}
/// An iterator that filters graph elements.
///
/// See [`.filter_elements()`][1] for more information.
///
/// [1]: trait.ElementIterator.html#method.filter_elements
#[derive(Debug, Clone)]
pub struct FilterElements<I, F> {
iter: I,
node_index: usize,
map: Vec<usize>,
f: F,
}
impl<I, F, N, E> Iterator for FilterElements<I, F>
where
I: Iterator<Item = Element<N, E>>,
F: FnMut(Element<&mut N, &mut E>) -> bool,
{
type Item = Element<N, E>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let mut elt = self.iter.next()?;
let keep = (self.f)(match elt {
Element::Node { ref mut weight } => Element::Node { weight },
Element::Edge {
source,
target,
ref mut weight,
} => Element::Edge {
source,
target,
weight,
},
});
let is_node = if let Element::Node { .. } = elt {
true
} else {
false
};
if !keep && is_node {
self.map.push(self.node_index);
}
if is_node {
self.node_index += 1;
}
if !keep {
continue;
}
// map edge parts
match elt {
Element::Edge {
ref mut source,
ref mut target,
..
} => {
// Find the node indices in the map of removed ones.
// If a node was removed, the edge is as well.
// Otherwise the counts are adjusted by the number of nodes
// removed.
// Example: map: [1, 3, 4, 6]
// binary search for 2, result is Err(1). One node has been
// removed before 2.
match self.map.binary_search(source) {
Ok(_) => continue,
Err(i) => *source -= i,
}
match self.map.binary_search(target) {
Ok(_) => continue,
Err(i) => *target -= i,
}
}
Element::Node { .. } => {}
}
return Some(elt);
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}

371
vendor/petgraph/src/dot.rs vendored Normal file
View File

@@ -0,0 +1,371 @@
//! Simple graphviz dot file format output.
use std::fmt::{self, Display, Write};
use crate::visit::{
EdgeRef, GraphProp, IntoEdgeReferences, IntoNodeReferences, NodeIndexable, NodeRef,
};
/// `Dot` implements output to graphviz .dot format for a graph.
///
/// Formatting and options are rather simple, this is mostly intended
/// for debugging. Exact output may change.
///
/// # Examples
///
/// ```
/// use petgraph::Graph;
/// use petgraph::dot::{Dot, Config};
///
/// let mut graph = Graph::<_, ()>::new();
/// graph.add_node("A");
/// graph.add_node("B");
/// graph.add_node("C");
/// graph.add_node("D");
/// graph.extend_with_edges(&[
/// (0, 1), (0, 2), (0, 3),
/// (1, 2), (1, 3),
/// (2, 3),
/// ]);
///
/// println!("{:?}", Dot::with_config(&graph, &[Config::EdgeNoLabel]));
///
/// // In this case the output looks like this:
/// //
/// // digraph {
/// // 0 [label="\"A\""]
/// // 1 [label="\"B\""]
/// // 2 [label="\"C\""]
/// // 3 [label="\"D\""]
/// // 0 -> 1
/// // 0 -> 2
/// // 0 -> 3
/// // 1 -> 2
/// // 1 -> 3
/// // 2 -> 3
/// // }
///
/// // If you need multiple config options, just list them all in the slice.
/// ```
pub struct Dot<'a, G>
where
G: IntoEdgeReferences + IntoNodeReferences,
{
graph: G,
get_edge_attributes: &'a dyn Fn(G, G::EdgeRef) -> String,
get_node_attributes: &'a dyn Fn(G, G::NodeRef) -> String,
config: Configs,
}
static TYPE: [&str; 2] = ["graph", "digraph"];
static EDGE: [&str; 2] = ["--", "->"];
static INDENT: &str = " ";
impl<'a, G> Dot<'a, G>
where
G: IntoNodeReferences + IntoEdgeReferences,
{
/// Create a `Dot` formatting wrapper with default configuration.
#[inline]
pub fn new(graph: G) -> Self {
Self::with_config(graph, &[])
}
/// Create a `Dot` formatting wrapper with custom configuration.
#[inline]
pub fn with_config(graph: G, config: &'a [Config]) -> Self {
Self::with_attr_getters(graph, config, &|_, _| String::new(), &|_, _| String::new())
}
#[inline]
pub fn with_attr_getters(
graph: G,
config: &'a [Config],
get_edge_attributes: &'a dyn Fn(G, G::EdgeRef) -> String,
get_node_attributes: &'a dyn Fn(G, G::NodeRef) -> String,
) -> Self {
let config = Configs::extract(config);
Dot {
graph,
get_edge_attributes,
get_node_attributes,
config,
}
}
}
/// `Dot` configuration.
///
/// This enum does not have an exhaustive definition (will be expanded)
// TODO: #[non_exhaustive] once MSRV >= 1.40,
// and/or for a breaking change make this something like an EnumSet: https://docs.rs/enumset
#[derive(Debug, PartialEq, Eq)]
pub enum Config {
/// Use indices for node labels.
NodeIndexLabel,
/// Use indices for edge labels.
EdgeIndexLabel,
/// Use no edge labels.
EdgeNoLabel,
/// Use no node labels.
NodeNoLabel,
/// Do not print the graph/digraph string.
GraphContentOnly,
#[doc(hidden)]
_Incomplete(()),
}
macro_rules! make_config_struct {
($($variant:ident,)*) => {
#[allow(non_snake_case)]
#[derive(Default)]
struct Configs {
$($variant: bool,)*
}
impl Configs {
#[inline]
fn extract(configs: &[Config]) -> Self {
let mut conf = Self::default();
for c in configs {
match *c {
$(Config::$variant => conf.$variant = true,)*
Config::_Incomplete(()) => {}
}
}
conf
}
}
}
}
make_config_struct!(
NodeIndexLabel,
EdgeIndexLabel,
EdgeNoLabel,
NodeNoLabel,
GraphContentOnly,
);
impl<G> Dot<'_, G>
where
G: IntoNodeReferences + IntoEdgeReferences + NodeIndexable + GraphProp,
{
fn graph_fmt<NF, EF>(&self, f: &mut fmt::Formatter, node_fmt: NF, edge_fmt: EF) -> fmt::Result
where
NF: Fn(&G::NodeWeight, &mut fmt::Formatter) -> fmt::Result,
EF: Fn(&G::EdgeWeight, &mut fmt::Formatter) -> fmt::Result,
{
let g = self.graph;
if !self.config.GraphContentOnly {
writeln!(f, "{} {{", TYPE[g.is_directed() as usize])?;
}
// output all labels
for node in g.node_references() {
write!(f, "{}{} [ ", INDENT, g.to_index(node.id()),)?;
if !self.config.NodeNoLabel {
write!(f, "label = \"")?;
if self.config.NodeIndexLabel {
write!(f, "{}", g.to_index(node.id()))?;
} else {
Escaped(FnFmt(node.weight(), &node_fmt)).fmt(f)?;
}
write!(f, "\" ")?;
}
writeln!(f, "{}]", (self.get_node_attributes)(g, node))?;
}
// output all edges
for (i, edge) in g.edge_references().enumerate() {
write!(
f,
"{}{} {} {} [ ",
INDENT,
g.to_index(edge.source()),
EDGE[g.is_directed() as usize],
g.to_index(edge.target()),
)?;
if !self.config.EdgeNoLabel {
write!(f, "label = \"")?;
if self.config.EdgeIndexLabel {
write!(f, "{}", i)?;
} else {
Escaped(FnFmt(edge.weight(), &edge_fmt)).fmt(f)?;
}
write!(f, "\" ")?;
}
writeln!(f, "{}]", (self.get_edge_attributes)(g, edge))?;
}
if !self.config.GraphContentOnly {
writeln!(f, "}}")?;
}
Ok(())
}
}
impl<G> fmt::Display for Dot<'_, G>
where
G: IntoEdgeReferences + IntoNodeReferences + NodeIndexable + GraphProp,
G::EdgeWeight: fmt::Display,
G::NodeWeight: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.graph_fmt(f, fmt::Display::fmt, fmt::Display::fmt)
}
}
impl<G> fmt::LowerHex for Dot<'_, G>
where
G: IntoEdgeReferences + IntoNodeReferences + NodeIndexable + GraphProp,
G::EdgeWeight: fmt::LowerHex,
G::NodeWeight: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.graph_fmt(f, fmt::LowerHex::fmt, fmt::LowerHex::fmt)
}
}
impl<G> fmt::UpperHex for Dot<'_, G>
where
G: IntoEdgeReferences + IntoNodeReferences + NodeIndexable + GraphProp,
G::EdgeWeight: fmt::UpperHex,
G::NodeWeight: fmt::UpperHex,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.graph_fmt(f, fmt::UpperHex::fmt, fmt::UpperHex::fmt)
}
}
impl<G> fmt::Debug for Dot<'_, G>
where
G: IntoEdgeReferences + IntoNodeReferences + NodeIndexable + GraphProp,
G::EdgeWeight: fmt::Debug,
G::NodeWeight: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.graph_fmt(f, fmt::Debug::fmt, fmt::Debug::fmt)
}
}
/// Escape for Graphviz
struct Escaper<W>(W);
impl<W> fmt::Write for Escaper<W>
where
W: fmt::Write,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
for c in s.chars() {
self.write_char(c)?;
}
Ok(())
}
fn write_char(&mut self, c: char) -> fmt::Result {
match c {
'"' | '\\' => self.0.write_char('\\')?,
// \l is for left justified linebreak
'\n' => return self.0.write_str("\\l"),
_ => {}
}
self.0.write_char(c)
}
}
/// Pass Display formatting through a simple escaping filter
struct Escaped<T>(T);
impl<T> fmt::Display for Escaped<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if f.alternate() {
writeln!(&mut Escaper(f), "{:#}", &self.0)
} else {
write!(&mut Escaper(f), "{}", &self.0)
}
}
}
/// Format data using a specific format function
struct FnFmt<'a, T, F>(&'a T, F);
impl<'a, T, F> fmt::Display for FnFmt<'a, T, F>
where
F: Fn(&'a T, &mut fmt::Formatter<'_>) -> fmt::Result,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.1(self.0, f)
}
}
#[cfg(test)]
mod test {
use super::{Config, Dot, Escaper};
use crate::prelude::Graph;
use crate::visit::NodeRef;
use std::fmt::Write;
#[test]
fn test_escape() {
let mut buff = String::new();
{
let mut e = Escaper(&mut buff);
let _ = e.write_str("\" \\ \n");
}
assert_eq!(buff, "\\\" \\\\ \\l");
}
fn simple_graph() -> Graph<&'static str, &'static str> {
let mut graph = Graph::<&str, &str>::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
graph.add_edge(a, b, "edge_label");
graph
}
#[test]
fn test_nodeindexlable_option() {
let graph = simple_graph();
let dot = format!("{:?}", Dot::with_config(&graph, &[Config::NodeIndexLabel]));
assert_eq!(dot, "digraph {\n 0 [ label = \"0\" ]\n 1 [ label = \"1\" ]\n 0 -> 1 [ label = \"\\\"edge_label\\\"\" ]\n}\n");
}
#[test]
fn test_edgeindexlable_option() {
let graph = simple_graph();
let dot = format!("{:?}", Dot::with_config(&graph, &[Config::EdgeIndexLabel]));
assert_eq!(dot, "digraph {\n 0 [ label = \"\\\"A\\\"\" ]\n 1 [ label = \"\\\"B\\\"\" ]\n 0 -> 1 [ label = \"0\" ]\n}\n");
}
#[test]
fn test_edgenolable_option() {
let graph = simple_graph();
let dot = format!("{:?}", Dot::with_config(&graph, &[Config::EdgeNoLabel]));
assert_eq!(dot, "digraph {\n 0 [ label = \"\\\"A\\\"\" ]\n 1 [ label = \"\\\"B\\\"\" ]\n 0 -> 1 [ ]\n}\n");
}
#[test]
fn test_nodenolable_option() {
let graph = simple_graph();
let dot = format!("{:?}", Dot::with_config(&graph, &[Config::NodeNoLabel]));
assert_eq!(
dot,
"digraph {\n 0 [ ]\n 1 [ ]\n 0 -> 1 [ label = \"\\\"edge_label\\\"\" ]\n}\n"
);
}
#[test]
fn test_with_attr_getters() {
let graph = simple_graph();
let dot = format!(
"{:?}",
Dot::with_attr_getters(
&graph,
&[Config::NodeNoLabel, Config::EdgeNoLabel],
&|_, er| format!("label = \"{}\"", er.weight().to_uppercase()),
&|_, nr| format!("label = \"{}\"", nr.weight().to_lowercase()),
),
);
assert_eq!(dot, "digraph {\n 0 [ label = \"a\"]\n 1 [ label = \"b\"]\n 0 -> 1 [ label = \"EDGE_LABEL\"]\n}\n");
}
}

133
vendor/petgraph/src/generate.rs vendored Normal file
View File

@@ -0,0 +1,133 @@
//! ***Unstable.*** Graph generation.
//!
//! ***Unstable: API may change at any time.*** Depends on `feature = "generate"`.
//!
use crate::graph::NodeIndex;
use crate::{Directed, EdgeType, Graph};
// A DAG has the property that the adjacency matrix is lower triangular,
// diagonal zero.
//
// This means we only allow edges i → j where i < j.
//
// The set of all DAG of a particular size is simply the power set of all
// possible edges.
//
// For a graph of n=3 nodes we have (n - 1) * n / 2 = 3 possible edges.
/// A graph generator of “all” graphs of a particular size.
///
/// ***Unstable: API may change at any time.*** Depends on `feature = "generate"`.
pub struct Generator<Ty> {
acyclic: bool,
selfloops: bool,
nodes: usize,
/// number of possible edges
nedges: usize,
/// current edge bitmap
bits: u64,
g: Graph<(), (), Ty>,
}
impl Generator<Directed> {
/// Generate all possible Directed acyclic graphs (DAGs) of a particular number of vertices.
///
/// These are only generated with one per isomorphism, so they use
/// one canonical node labeling where node *i* can only have edges to node *j* if *i < j*.
///
/// For a graph of *k* vertices there are *e = (k - 1) k / 2* possible edges and
/// *2<sup>e</sup>* DAGs.
pub fn directed_acyclic(nodes: usize) -> Self {
assert!(nodes != 0);
let nedges = (nodes - 1) * nodes / 2;
assert!(nedges < 64);
Generator {
acyclic: true,
selfloops: false,
nodes: nodes,
nedges: nedges,
bits: !0,
g: Graph::with_capacity(nodes, nedges),
}
}
}
impl<Ty: EdgeType> Generator<Ty> {
/// Generate all possible graphs of a particular number of vertices.
///
/// All permutations are generated, so the graphs are not unique down to isomorphism.
///
/// For a graph of *k* vertices there are *e = k²* possible edges and
/// *2<sup>k<sup>2</sup></sup>* graphs.
pub fn all(nodes: usize, allow_selfloops: bool) -> Self {
let scale = if Ty::is_directed() { 1 } else { 2 };
let nedges = if allow_selfloops {
(nodes * nodes - nodes) / scale + nodes
} else {
(nodes * nodes) / scale - nodes
};
assert!(nedges < 64);
Generator {
acyclic: false,
selfloops: allow_selfloops,
nodes: nodes,
nedges: nedges,
bits: !0,
g: Graph::with_capacity(nodes, nedges),
}
}
fn state_to_graph(&mut self) -> &Graph<(), (), Ty> {
self.g.clear();
for _ in 0..self.nodes {
self.g.add_node(());
}
// For a DAG:
// interpret the bits in order, it's a lower triangular matrix:
// a b c d
// a x x x x
// b 0 x x x
// c 1 2 x x
// d 3 4 5 x
let mut bit = 0;
for i in 0..self.nodes {
let start = if self.acyclic || !self.g.is_directed() {
i
} else {
0
};
for j in start..self.nodes {
if i == j && !self.selfloops {
continue;
}
if self.bits & (1u64 << bit) != 0 {
self.g.add_edge(NodeIndex::new(i), NodeIndex::new(j), ());
}
bit += 1;
}
}
&self.g
}
pub fn next_ref(&mut self) -> Option<&Graph<(), (), Ty>> {
if self.bits == !0 {
self.bits = 0;
} else {
self.bits += 1;
if self.bits >= 1u64 << self.nedges {
return None;
}
}
Some(self.state_to_graph())
}
}
impl<Ty: EdgeType> Iterator for Generator<Ty> {
type Item = Graph<(), (), Ty>;
fn next(&mut self) -> Option<Self::Item> {
self.next_ref().cloned()
}
}

View File

@@ -0,0 +1,200 @@
//! [graph6 format](https://users.cecs.anu.edu.au/~bdm/data/formats.txt) decoder for undirected graphs.
use crate::{csr::Csr, graph::IndexType, Graph, Undirected};
#[cfg(feature = "graphmap")]
use crate::graphmap::GraphMap;
#[cfg(feature = "graphmap")]
use std::hash::BuildHasher;
#[cfg(feature = "matrix_graph")]
use crate::matrix_graph::{MatrixGraph, Nullable};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::{StableGraph, StableUnGraph};
const N: usize = 63;
/// A graph that can be converted from graph6 format string.
pub trait FromGraph6 {
fn from_graph6_string(graph6_string: String) -> Self;
}
/// Converts a graph6 format string into data can be used to construct an undirected graph.
/// Returns a tuple containing the graph order and its edges.
pub fn from_graph6_representation<Ix>(graph6_representation: String) -> (usize, Vec<(Ix, Ix)>)
where
Ix: IndexType,
{
let (order_bytes, adj_matrix_bytes) =
get_order_bytes_and_adj_matrix_bytes(graph6_representation);
let order_bits = bytes_vector_to_bits_vector(order_bytes);
let adj_matrix_bits = bytes_vector_to_bits_vector(adj_matrix_bytes);
let graph_order = get_bits_as_decimal(order_bits);
let edges = get_edges(graph_order, adj_matrix_bits);
(graph_order, edges)
}
// Converts a graph6 format string into a vector of bytes, converted from ASCII characters,
// split into two parts, the first representing the graph order, and the second its adjacency matrix.
fn get_order_bytes_and_adj_matrix_bytes(graph6_representation: String) -> (Vec<usize>, Vec<usize>) {
let bytes: Vec<usize> = graph6_representation
.chars()
.map(|c| (c as usize) - N)
.collect();
let mut order_bytes = vec![];
let mut adj_matrix_bytes = vec![];
let first_byte = *bytes.first().unwrap();
if first_byte == N {
order_bytes.extend_from_slice(&bytes[1..=3]);
adj_matrix_bytes.extend_from_slice(&bytes[4..]);
} else {
order_bytes.push(first_byte);
adj_matrix_bytes.extend_from_slice(&bytes[1..]);
};
(order_bytes, adj_matrix_bytes)
}
// Converts a bytes vector into a bits vector.
fn bytes_vector_to_bits_vector(bytes: Vec<usize>) -> Vec<u8> {
bytes
.iter()
.flat_map(|&byte| get_number_as_bits(byte, 6))
.collect()
}
// Get binary representation of `n` as a vector of bits with `bits_length` length.
fn get_number_as_bits(n: usize, bits_length: usize) -> Vec<u8> {
let mut bits = Vec::new();
for i in (0..bits_length).rev() {
bits.push(((n >> i) & 1) as u8);
}
bits
}
// Convert a bits vector into its decimal representation.
fn get_bits_as_decimal(bits: Vec<u8>) -> usize {
let bits_str = bits
.iter()
.map(|bit| bit.to_string())
.collect::<Vec<String>>()
.join("");
usize::from_str_radix(&bits_str, 2).unwrap()
}
// Get graph edges from its order and bits vector representation of its adjacency matrix.
fn get_edges<Ix>(order: usize, adj_matrix_bits: Vec<u8>) -> Vec<(Ix, Ix)>
where
Ix: IndexType,
{
let mut edges = vec![];
let mut i = 0;
for col in 1..order {
for lin in 0..col {
let is_adjacent = adj_matrix_bits[i] == 1;
if is_adjacent {
edges.push((Ix::new(lin), Ix::new(col)));
};
i += 1;
}
}
edges
}
impl<Ix: IndexType> FromGraph6 for Graph<(), (), Undirected, Ix> {
fn from_graph6_string(graph6_string: String) -> Self {
let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
let mut graph: Graph<(), (), Undirected, Ix> = Graph::with_capacity(order, edges.len());
for _ in 0..order {
graph.add_node(());
}
graph.extend_with_edges(edges);
graph
}
}
#[cfg(feature = "stable_graph")]
impl<Ix: IndexType> FromGraph6 for StableGraph<(), (), Undirected, Ix> {
fn from_graph6_string(graph6_string: String) -> Self {
let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
let mut graph: StableGraph<(), (), Undirected, Ix> =
StableUnGraph::with_capacity(order, edges.len());
for _ in 0..order {
graph.add_node(());
}
graph.extend_with_edges(edges);
graph
}
}
#[cfg(feature = "graphmap")]
impl<Ix: IndexType, S: BuildHasher + Default> FromGraph6 for GraphMap<Ix, (), Undirected, S> {
fn from_graph6_string(graph6_string: String) -> Self {
let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
let mut graph: GraphMap<Ix, (), Undirected, S> =
GraphMap::with_capacity(order, edges.len());
for i in 0..order {
graph.add_node(Ix::new(i));
}
for (a, b) in edges {
graph.add_edge(a, b, ());
}
graph
}
}
#[cfg(feature = "matrix_graph")]
impl<Null, Ix> FromGraph6 for MatrixGraph<(), (), Undirected, Null, Ix>
where
Null: Nullable<Wrapped = ()>,
Ix: IndexType,
{
fn from_graph6_string(graph6_string: String) -> Self {
let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
let mut graph: MatrixGraph<(), (), Undirected, Null, Ix> =
MatrixGraph::with_capacity(order);
for _ in 0..order {
graph.add_node(());
}
graph.extend_with_edges(edges.iter());
graph
}
}
impl<Ix: IndexType> FromGraph6 for Csr<(), (), Undirected, Ix> {
fn from_graph6_string(graph6_string: String) -> Self {
let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
let mut graph: Csr<(), (), Undirected, Ix> = Csr::new();
let mut nodes = Vec::new();
for _ in 0..order {
let i = graph.add_node(());
nodes.push(i);
}
for (a, b) in edges {
graph.add_edge(a, b, ());
}
graph
}
}

View File

@@ -0,0 +1,154 @@
//! [graph6 format](https://users.cecs.anu.edu.au/~bdm/data/formats.txt) encoder for undirected graphs.
use crate::{
csr::Csr,
graph::IndexType,
visit::{GetAdjacencyMatrix, IntoNodeIdentifiers},
Graph, Undirected,
};
#[cfg(feature = "graphmap")]
use crate::graphmap::{GraphMap, NodeTrait};
#[cfg(feature = "graphmap")]
use std::hash::BuildHasher;
#[cfg(feature = "matrix_graph")]
use crate::matrix_graph::{MatrixGraph, Nullable};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::StableGraph;
const N: usize = 63;
/// A graph that can be converted to graph6 format string.
pub trait ToGraph6 {
fn graph6_string(&self) -> String;
}
/// Converts a graph that implements GetAdjacencyMatrix and IntoNodeIdentifers
/// into a graph6 format string.
pub fn get_graph6_representation<G>(graph: G) -> String
where
G: GetAdjacencyMatrix + IntoNodeIdentifiers,
{
let (graph_order, mut upper_diagonal_as_bits) = get_adj_matrix_upper_diagonal_as_bits(graph);
let mut graph_order_as_bits = get_graph_order_as_bits(graph_order);
let mut graph_as_bits = vec![];
graph_as_bits.append(&mut graph_order_as_bits);
graph_as_bits.append(&mut upper_diagonal_as_bits);
bits_to_ascii(graph_as_bits)
}
// Traverse graph nodes and construct the upper diagonal of its adjacency matrix as a vector of bits.
// Returns a tuple containing:
// - `n`: graph order (number of nodes in graph)
// - `bits`: a vector of 0s and 1s encoding the upper diagonal of the graphs adjacency matrix.
fn get_adj_matrix_upper_diagonal_as_bits<G>(graph: G) -> (usize, Vec<usize>)
where
G: GetAdjacencyMatrix + IntoNodeIdentifiers,
{
let node_ids_iter = graph.node_identifiers();
let mut node_ids_vec = vec![];
let adj_matrix = graph.adjacency_matrix();
let mut bits = vec![];
let mut n = 0;
for node_id in node_ids_iter {
node_ids_vec.push(node_id);
for i in 1..=n {
let is_adjacent: bool =
graph.is_adjacent(&adj_matrix, node_ids_vec[i - 1], node_ids_vec[n]);
bits.push(if is_adjacent { 1 } else { 0 });
}
n += 1;
}
(n, bits)
}
// Converts graph order to a bits vector.
fn get_graph_order_as_bits(order: usize) -> Vec<usize> {
let to_convert_to_bits = if order < N {
vec![(order, 6)]
} else if order <= 258047 {
vec![(N, 6), (order, 18)]
} else {
panic!("Graph order not supported.")
};
to_convert_to_bits
.iter()
.flat_map(|&(n, n_of_bits)| get_number_as_bits(n, n_of_bits))
.collect()
}
// Get binary representation of `n` as a vector of bits with `bits_length` length.
fn get_number_as_bits(n: usize, bits_length: usize) -> Vec<usize> {
let mut bits = Vec::new();
for i in (0..bits_length).rev() {
bits.push((n >> i) & 1);
}
bits
}
// Convert a vector of bits to a String using ASCII encoding.
// Each 6 bits will be converted to a single ASCII character.
fn bits_to_ascii(mut bits: Vec<usize>) -> String {
while bits.len() % 6 != 0 {
bits.push(0);
}
let bits_strs = bits.iter().map(|bit| bit.to_string()).collect::<Vec<_>>();
let bytes = bits_strs
.chunks(6)
.map(|bits_chunk| bits_chunk.join(""))
.map(|bits_str| usize::from_str_radix(&bits_str, 2));
bytes
.map(|byte| char::from((N + byte.unwrap()) as u8))
.collect()
}
impl<N, E, Ix: IndexType> ToGraph6 for Graph<N, E, Undirected, Ix> {
fn graph6_string(&self) -> String {
get_graph6_representation(self)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ix: IndexType> ToGraph6 for StableGraph<N, E, Undirected, Ix> {
fn graph6_string(&self) -> String {
get_graph6_representation(self)
}
}
#[cfg(feature = "graphmap")]
impl<N: NodeTrait, E, S: BuildHasher> ToGraph6 for GraphMap<N, E, Undirected, S> {
fn graph6_string(&self) -> String {
get_graph6_representation(self)
}
}
#[cfg(feature = "matrix_graph")]
impl<N, E, Null, Ix> ToGraph6 for MatrixGraph<N, E, Undirected, Null, Ix>
where
N: NodeTrait,
Null: Nullable<Wrapped = E>,
Ix: IndexType,
{
fn graph6_string(&self) -> String {
get_graph6_representation(self)
}
}
impl<N, E, Ix: IndexType> ToGraph6 for Csr<N, E, Undirected, Ix> {
fn graph6_string(&self) -> String {
get_graph6_representation(self)
}
}

7
vendor/petgraph/src/graph6/mod.rs vendored Normal file
View File

@@ -0,0 +1,7 @@
//! Traits related to [graph6 format](https://users.cecs.anu.edu.au/~bdm/data/formats.txt) for undirected graphs.
pub use self::graph6_decoder::*;
pub use self::graph6_encoder::*;
mod graph6_decoder;
mod graph6_encoder;

108
vendor/petgraph/src/graph_impl/frozen.rs vendored Normal file
View File

@@ -0,0 +1,108 @@
use std::ops::{Deref, Index, IndexMut};
use super::Frozen;
use crate::data::{DataMap, DataMapMut};
use crate::graph::Graph;
use crate::graph::{GraphIndex, IndexType};
use crate::visit::{
Data, EdgeCount, EdgeIndexable, GetAdjacencyMatrix, GraphBase, GraphProp, IntoEdges,
IntoEdgesDirected, IntoNeighborsDirected, IntoNodeIdentifiers, NodeCompactIndexable, NodeCount,
NodeIndexable,
};
use crate::visit::{IntoEdgeReferences, IntoNeighbors, IntoNodeReferences, Visitable};
use crate::{Direction, EdgeType};
impl<'a, G> Frozen<'a, G> {
/// Create a new `Frozen` from a mutable reference to a graph.
pub fn new(gr: &'a mut G) -> Self {
Frozen(gr)
}
}
/// Deref allows transparent access to all shared reference (read-only)
/// functionality in the underlying graph.
impl<G> Deref for Frozen<'_, G> {
type Target = G;
fn deref(&self) -> &G {
self.0
}
}
impl<G, I> Index<I> for Frozen<'_, G>
where
G: Index<I>,
{
type Output = G::Output;
fn index(&self, i: I) -> &G::Output {
self.0.index(i)
}
}
impl<G, I> IndexMut<I> for Frozen<'_, G>
where
G: IndexMut<I>,
{
fn index_mut(&mut self, i: I) -> &mut G::Output {
self.0.index_mut(i)
}
}
impl<N, E, Ty, Ix> Frozen<'_, Graph<N, E, Ty, Ix>>
where
Ty: EdgeType,
Ix: IndexType,
{
#[allow(clippy::type_complexity)]
/// Index the `Graph` by two indices, any combination of
/// node or edge indices is fine.
///
/// **Panics** if the indices are equal or if they are out of bounds.
pub fn index_twice_mut<T, U>(
&mut self,
i: T,
j: U,
) -> (
&mut <Graph<N, E, Ty, Ix> as Index<T>>::Output,
&mut <Graph<N, E, Ty, Ix> as Index<U>>::Output,
)
where
Graph<N, E, Ty, Ix>: IndexMut<T> + IndexMut<U>,
T: GraphIndex,
U: GraphIndex,
{
self.0.index_twice_mut(i, j)
}
}
macro_rules! access0 {
($e:expr) => {
$e.0
};
}
impl<G> GraphBase for Frozen<'_, G>
where
G: GraphBase,
{
type NodeId = G::NodeId;
type EdgeId = G::EdgeId;
}
Data! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
DataMap! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
DataMapMut! {delegate_impl [['a, G], G, Frozen<'a, G>, access0]}
GetAdjacencyMatrix! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
IntoEdgeReferences! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoEdges! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoEdgesDirected! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoNeighbors! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoNeighborsDirected! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoNodeIdentifiers! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoNodeReferences! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
NodeCompactIndexable! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
NodeCount! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
NodeIndexable! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
EdgeCount! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
EdgeIndexable! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
GraphProp! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
Visitable! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}

2411
vendor/petgraph/src/graph_impl/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,355 @@
use serde::de::Error;
use std::marker::PhantomData;
use crate::prelude::*;
use crate::graph::Node;
use crate::graph::{Edge, IndexType};
use crate::serde_utils::CollectSeqWithLength;
use crate::serde_utils::MappedSequenceVisitor;
use crate::serde_utils::{FromDeserialized, IntoSerializable};
use crate::EdgeType;
use super::{EdgeIndex, NodeIndex};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// Serialization representation for Graph
/// Keep in sync with deserialization and StableGraph
///
/// The serialization format is as follows, in Pseudorust:
///
/// Graph {
/// nodes: [N],
/// node_holes: [NodeIndex<Ix>],
/// edge_property: EdgeProperty,
/// edges: [Option<(NodeIndex<Ix>, NodeIndex<Ix>, E)>]
/// }
///
/// The same format is used by both Graph and StableGraph.
///
/// For graph there are restrictions:
/// node_holes is always empty and edges are always Some
///
/// A stable graph serialization that obeys these restrictions
/// (effectively, it has no interior vacancies) can de deserialized
/// as a graph.
///
/// Node indices are serialized as integers and are fixed size for
/// binary formats, so the Ix parameter matters there.
#[derive(Serialize)]
#[serde(rename = "Graph")]
#[serde(bound(serialize = "N: Serialize, E: Serialize, Ix: IndexType + Serialize"))]
pub struct SerGraph<'a, N: 'a, E: 'a, Ix: 'a + IndexType> {
#[serde(serialize_with = "ser_graph_nodes")]
nodes: &'a [Node<N, Ix>],
node_holes: &'a [NodeIndex<Ix>],
edge_property: EdgeProperty,
#[serde(serialize_with = "ser_graph_edges")]
edges: &'a [Edge<E, Ix>],
}
// Deserialization representation for Graph
// Keep in sync with serialization and StableGraph
#[derive(Deserialize)]
#[serde(rename = "Graph")]
#[serde(bound(
deserialize = "N: Deserialize<'de>, E: Deserialize<'de>, Ix: IndexType + Deserialize<'de>"
))]
pub struct DeserGraph<N, E, Ix> {
#[serde(deserialize_with = "deser_graph_nodes")]
nodes: Vec<Node<N, Ix>>,
#[serde(deserialize_with = "deser_graph_node_holes")]
#[allow(unused)]
#[serde(default = "Vec::new")]
node_holes: Vec<NodeIndex<Ix>>,
edge_property: EdgeProperty,
#[serde(deserialize_with = "deser_graph_edges")]
edges: Vec<Edge<E, Ix>>,
}
impl<Ix> Serialize for NodeIndex<Ix>
where
Ix: IndexType + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de, Ix> Deserialize<'de> for NodeIndex<Ix>
where
Ix: IndexType + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(NodeIndex(Ix::deserialize(deserializer)?))
}
}
impl<Ix> Serialize for EdgeIndex<Ix>
where
Ix: IndexType + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de, Ix> Deserialize<'de> for EdgeIndex<Ix>
where
Ix: IndexType + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(EdgeIndex(Ix::deserialize(deserializer)?))
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[derive(Debug)]
pub enum EdgeProperty {
Undirected,
Directed,
}
impl EdgeProperty {
pub fn is_directed(&self) -> bool {
match *self {
EdgeProperty::Directed => true,
EdgeProperty::Undirected => false,
}
}
}
impl<Ty> From<PhantomData<Ty>> for EdgeProperty
where
Ty: EdgeType,
{
fn from(_: PhantomData<Ty>) -> Self {
if Ty::is_directed() {
EdgeProperty::Directed
} else {
EdgeProperty::Undirected
}
}
}
impl<Ty> FromDeserialized for PhantomData<Ty>
where
Ty: EdgeType,
{
type Input = EdgeProperty;
fn from_deserialized<E2>(input: Self::Input) -> Result<Self, E2>
where
E2: Error,
{
if input.is_directed() != Ty::is_directed() {
Err(E2::custom(format_args!(
"graph edge property mismatch, \
expected {:?}, found {:?}",
EdgeProperty::from(PhantomData::<Ty>),
input
)))
} else {
Ok(PhantomData)
}
}
}
fn ser_graph_nodes<S, N, Ix>(nodes: &&[Node<N, Ix>], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
N: Serialize,
Ix: Serialize + IndexType,
{
serializer.collect_seq_exact(nodes.iter().map(|node| &node.weight))
}
fn ser_graph_edges<S, E, Ix>(edges: &&[Edge<E, Ix>], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
E: Serialize,
Ix: Serialize + IndexType,
{
serializer.collect_seq_exact(
edges
.iter()
.map(|edge| Some((edge.source(), edge.target(), &edge.weight))),
)
}
fn deser_graph_nodes<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Node<N, Ix>>, D::Error>
where
D: Deserializer<'de>,
N: Deserialize<'de>,
Ix: IndexType + Deserialize<'de>,
{
deserializer.deserialize_seq(MappedSequenceVisitor::new(|n| {
Ok(Node {
weight: n,
next: [EdgeIndex::end(); 2],
})
}))
}
fn deser_graph_node_holes<'de, D, Ix>(deserializer: D) -> Result<Vec<NodeIndex<Ix>>, D::Error>
where
D: Deserializer<'de>,
Ix: IndexType + Deserialize<'de>,
{
deserializer.deserialize_seq(
MappedSequenceVisitor::<NodeIndex<Ix>, NodeIndex<Ix>, _>::new(|_| {
Err("Graph can not have holes in the node set, found non-empty node_holes")
}),
)
}
fn deser_graph_edges<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Edge<N, Ix>>, D::Error>
where
D: Deserializer<'de>,
N: Deserialize<'de>,
Ix: IndexType + Deserialize<'de>,
{
deserializer.deserialize_seq(MappedSequenceVisitor::<
Option<(NodeIndex<Ix>, NodeIndex<Ix>, N)>,
_,
_,
>::new(|x| {
if let Some((i, j, w)) = x {
Ok(Edge {
weight: w,
node: [i, j],
next: [EdgeIndex::end(); 2],
})
} else {
Err("Graph can not have holes in the edge set, found None, expected edge")
}
}))
}
impl<'a, N, E, Ty, Ix> IntoSerializable for &'a Graph<N, E, Ty, Ix>
where
Ix: IndexType,
Ty: EdgeType,
{
type Output = SerGraph<'a, N, E, Ix>;
fn into_serializable(self) -> Self::Output {
SerGraph {
nodes: &self.nodes,
node_holes: &[],
edges: &self.edges,
edge_property: EdgeProperty::from(PhantomData::<Ty>),
}
}
}
/// Requires crate feature `"serde-1"`
impl<N, E, Ty, Ix> Serialize for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType + Serialize,
N: Serialize,
E: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.into_serializable().serialize(serializer)
}
}
pub fn invalid_node_err<E>(node_index: usize, len: usize) -> E
where
E: Error,
{
E::custom(format_args!(
"invalid value: node index `{}` does not exist in graph \
with node bound {}",
node_index, len
))
}
pub fn invalid_hole_err<E>(node_index: usize) -> E
where
E: Error,
{
E::custom(format_args!(
"invalid value: node hole `{}` is not allowed.",
node_index
))
}
pub fn invalid_length_err<Ix, E>(node_or_edge: &str, len: usize) -> E
where
E: Error,
Ix: IndexType,
{
E::custom(format_args!(
"invalid size: graph {} count {} exceeds index type maximum {}",
node_or_edge,
len,
<Ix as IndexType>::max().index()
))
}
impl<'a, N, E, Ty, Ix> FromDeserialized for Graph<N, E, Ty, Ix>
where
Ix: IndexType,
Ty: EdgeType,
{
type Input = DeserGraph<N, E, Ix>;
fn from_deserialized<E2>(input: Self::Input) -> Result<Self, E2>
where
E2: Error,
{
let ty = PhantomData::<Ty>::from_deserialized(input.edge_property)?;
let nodes = input.nodes;
let edges = input.edges;
if nodes.len() >= <Ix as IndexType>::max().index() {
Err(invalid_length_err::<Ix, _>("node", nodes.len()))?
}
if edges.len() >= <Ix as IndexType>::max().index() {
Err(invalid_length_err::<Ix, _>("edge", edges.len()))?
}
let mut gr = Graph {
nodes: nodes,
edges: edges,
ty: ty,
};
let nc = gr.node_count();
gr.link_edges()
.map_err(|i| invalid_node_err(i.index(), nc))?;
Ok(gr)
}
}
/// Requires crate feature `"serde-1"`
impl<'de, N, E, Ty, Ix> Deserialize<'de> for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType + Deserialize<'de>,
N: Deserialize<'de>,
E: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Self::from_deserialized(DeserGraph::deserialize(deserializer)?)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,298 @@
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::marker::PhantomData;
use crate::prelude::*;
use crate::graph::Node;
use crate::graph::{Edge, IndexType};
use crate::serde_utils::CollectSeqWithLength;
use crate::serde_utils::MappedSequenceVisitor;
use crate::serde_utils::{FromDeserialized, IntoSerializable};
use crate::stable_graph::StableGraph;
use crate::visit::{EdgeIndexable, NodeIndexable};
use crate::EdgeType;
use super::super::serialization::{
invalid_hole_err, invalid_length_err, invalid_node_err, EdgeProperty,
};
// Serialization representation for StableGraph
// Keep in sync with deserialization and Graph
#[derive(Serialize)]
#[serde(rename = "Graph")]
#[serde(bound(serialize = "N: Serialize, E: Serialize, Ix: IndexType + Serialize"))]
pub struct SerStableGraph<'a, N: 'a, E: 'a, Ix: 'a + IndexType> {
nodes: Somes<&'a [Node<Option<N>, Ix>]>,
node_holes: Holes<&'a [Node<Option<N>, Ix>]>,
edge_property: EdgeProperty,
#[serde(serialize_with = "ser_stable_graph_edges")]
edges: &'a [Edge<Option<E>, Ix>],
}
// Deserialization representation for StableGraph
// Keep in sync with serialization and Graph
#[derive(Deserialize)]
#[serde(rename = "Graph")]
#[serde(bound(
deserialize = "N: Deserialize<'de>, E: Deserialize<'de>, Ix: IndexType + Deserialize<'de>"
))]
pub struct DeserStableGraph<N, E, Ix> {
#[serde(deserialize_with = "deser_stable_graph_nodes")]
nodes: Vec<Node<Option<N>, Ix>>,
#[serde(default = "Vec::new")]
node_holes: Vec<NodeIndex<Ix>>,
edge_property: EdgeProperty,
#[serde(deserialize_with = "deser_stable_graph_edges")]
edges: Vec<Edge<Option<E>, Ix>>,
}
/// `Somes` are the present node weights N, with known length.
struct Somes<T>(usize, T);
impl<'a, N, Ix> Serialize for Somes<&'a [Node<Option<N>, Ix>]>
where
N: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_seq_with_length(
self.0,
self.1.iter().filter_map(|node| node.weight.as_ref()),
)
}
}
/// Holes are the node indices of vacancies, with known length
struct Holes<T>(usize, T);
impl<'a, N, Ix> Serialize for Holes<&'a [Node<Option<N>, Ix>]>
where
Ix: Serialize + IndexType,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_seq_with_length(
self.0,
self.1.iter().enumerate().filter_map(|(i, node)| {
if node.weight.is_none() {
Some(NodeIndex::<Ix>::new(i))
} else {
None
}
}),
)
}
}
fn ser_stable_graph_edges<S, E, Ix>(
edges: &&[Edge<Option<E>, Ix>],
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
E: Serialize,
Ix: Serialize + IndexType,
{
serializer.collect_seq_exact(edges.iter().map(|edge| {
edge.weight
.as_ref()
.map(|w| (edge.source(), edge.target(), w))
}))
}
fn deser_stable_graph_nodes<'de, D, N, Ix>(
deserializer: D,
) -> Result<Vec<Node<Option<N>, Ix>>, D::Error>
where
D: Deserializer<'de>,
N: Deserialize<'de>,
Ix: IndexType + Deserialize<'de>,
{
deserializer.deserialize_seq(MappedSequenceVisitor::new(|n| {
Ok(Node {
weight: Some(n),
next: [EdgeIndex::end(); 2],
})
}))
}
fn deser_stable_graph_edges<'de, D, N, Ix>(
deserializer: D,
) -> Result<Vec<Edge<Option<N>, Ix>>, D::Error>
where
D: Deserializer<'de>,
N: Deserialize<'de>,
Ix: IndexType + Deserialize<'de>,
{
deserializer.deserialize_seq(MappedSequenceVisitor::<
Option<(NodeIndex<Ix>, NodeIndex<Ix>, N)>,
_,
_,
>::new(|x| {
if let Some((i, j, w)) = x {
Ok(Edge {
weight: Some(w),
node: [i, j],
next: [EdgeIndex::end(); 2],
})
} else {
Ok(Edge {
weight: None,
node: [NodeIndex::end(); 2],
next: [EdgeIndex::end(); 2],
})
}
}))
}
impl<'a, N, E, Ty, Ix> IntoSerializable for &'a StableGraph<N, E, Ty, Ix>
where
Ix: IndexType,
Ty: EdgeType,
{
type Output = SerStableGraph<'a, N, E, Ix>;
fn into_serializable(self) -> Self::Output {
let nodes = &self.raw_nodes()[..self.node_bound()];
let node_count = self.node_count();
let hole_count = nodes.len() - node_count;
let edges = &self.raw_edges()[..self.edge_bound()];
SerStableGraph {
nodes: Somes(node_count, nodes),
node_holes: Holes(hole_count, nodes),
edges: edges,
edge_property: EdgeProperty::from(PhantomData::<Ty>),
}
}
}
/// Requires crate feature `"serde-1"`
impl<N, E, Ty, Ix> Serialize for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType + Serialize,
N: Serialize,
E: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.into_serializable().serialize(serializer)
}
}
impl<'a, N, E, Ty, Ix> FromDeserialized for StableGraph<N, E, Ty, Ix>
where
Ix: IndexType,
Ty: EdgeType,
{
type Input = DeserStableGraph<N, E, Ix>;
fn from_deserialized<E2>(input: Self::Input) -> Result<Self, E2>
where
E2: Error,
{
let ty = PhantomData::<Ty>::from_deserialized(input.edge_property)?;
let node_holes = input.node_holes;
let edges = input.edges;
if edges.len() >= <Ix as IndexType>::max().index() {
Err(invalid_length_err::<Ix, _>("edge", edges.len()))?
}
let total_nodes = input.nodes.len() + node_holes.len();
let mut nodes = Vec::with_capacity(total_nodes);
let mut compact_nodes = input.nodes.into_iter();
let mut node_pos = 0;
for hole_pos in node_holes.iter() {
let hole_pos = hole_pos.index();
if !(node_pos..total_nodes).contains(&hole_pos) {
return Err(invalid_hole_err(hole_pos));
}
nodes.extend(compact_nodes.by_ref().take(hole_pos - node_pos));
nodes.push(Node {
weight: None,
next: [EdgeIndex::end(); 2],
});
node_pos = hole_pos + 1;
debug_assert_eq!(nodes.len(), node_pos);
}
nodes.extend(compact_nodes);
if nodes.len() >= <Ix as IndexType>::max().index() {
Err(invalid_length_err::<Ix, _>("node", nodes.len()))?
}
let node_bound = nodes.len();
let mut sgr = StableGraph {
g: Graph {
nodes: nodes,
edges: edges,
ty: ty,
},
node_count: 0,
edge_count: 0,
free_edge: EdgeIndex::end(),
free_node: NodeIndex::end(),
};
sgr.link_edges()
.map_err(|i| invalid_node_err(i.index(), node_bound))?;
Ok(sgr)
}
}
/// Requires crate feature `"serde-1"`
impl<'de, N, E, Ty, Ix> Deserialize<'de> for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType + Deserialize<'de>,
N: Deserialize<'de>,
E: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Self::from_deserialized(DeserStableGraph::deserialize(deserializer)?)
}
}
#[test]
fn test_from_deserialized_with_holes() {
use crate::graph::node_index;
use crate::stable_graph::StableUnGraph;
use itertools::assert_equal;
use serde::de::value::Error as SerdeError;
let input = DeserStableGraph::<_, (), u32> {
nodes: vec![
Node {
weight: Some(1),
next: [EdgeIndex::end(); 2],
},
Node {
weight: Some(4),
next: [EdgeIndex::end(); 2],
},
Node {
weight: Some(5),
next: [EdgeIndex::end(); 2],
},
],
node_holes: vec![node_index(0), node_index(2), node_index(3), node_index(6)],
edges: vec![],
edge_property: EdgeProperty::Undirected,
};
let graph = StableUnGraph::from_deserialized::<SerdeError>(input).unwrap();
assert_eq!(graph.node_count(), 3);
assert_equal(
graph.raw_nodes().iter().map(|n| n.weight.as_ref().cloned()),
vec![None, Some(1), None, None, Some(4), Some(5), None],
);
}

1504
vendor/petgraph/src/graphmap.rs vendored Normal file

File diff suppressed because it is too large Load Diff

102
vendor/petgraph/src/iter_format.rs vendored Normal file
View File

@@ -0,0 +1,102 @@
//! Formatting utils
use std::cell::RefCell;
use std::fmt;
/// Format the iterator like a map
pub struct DebugMap<F>(pub F);
impl<F, I, K, V> fmt::Debug for DebugMap<F>
where
F: Fn() -> I,
I: IntoIterator<Item = (K, V)>,
K: fmt::Debug,
V: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_map().entries((self.0)()).finish()
}
}
/// Avoid "pretty" debug
pub struct NoPretty<T>(pub T);
impl<T> fmt::Debug for NoPretty<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}
/// Format all iterator elements lazily, separated by `sep`.
///
/// The format value can only be formatted once, after that the iterator is
/// exhausted.
///
/// See [`.format()`](../trait.Itertools.html#method.format)
/// for more information.
#[derive(Clone)]
pub struct Format<'a, I> {
sep: &'a str,
/// Format uses interior mutability because Display::fmt takes &self.
inner: RefCell<Option<I>>,
}
pub trait IterFormatExt: Iterator {
fn format(self, separator: &str) -> Format<Self>
where
Self: Sized,
{
Format {
sep: separator,
inner: RefCell::new(Some(self)),
}
}
}
impl<I> IterFormatExt for I where I: Iterator {}
impl<I> Format<'_, I>
where
I: Iterator,
{
fn format<F>(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result
where
F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result,
{
let mut iter = match self.inner.borrow_mut().take() {
Some(t) => t,
None => panic!("Format: was already formatted once"),
};
if let Some(fst) = iter.next() {
cb(&fst, f)?;
for elt in iter {
if !self.sep.is_empty() {
f.write_str(self.sep)?;
}
cb(&elt, f)?;
}
}
Ok(())
}
}
macro_rules! impl_format {
($($fmt_trait:ident)*) => {
$(
impl<'a, I> fmt::$fmt_trait for Format<'a, I>
where I: Iterator,
I::Item: fmt::$fmt_trait,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f, fmt::$fmt_trait::fmt)
}
}
)*
}
}
impl_format!(Debug);

32
vendor/petgraph/src/iter_utils.rs vendored Normal file
View File

@@ -0,0 +1,32 @@
pub trait IterUtilsExt: Iterator {
/// Return the first element that maps to `Some(_)`, or None if the iterator
/// was exhausted.
fn ex_find_map<F, R>(&mut self, mut f: F) -> Option<R>
where
F: FnMut(Self::Item) -> Option<R>,
{
for elt in self {
if let result @ Some(_) = f(elt) {
return result;
}
}
None
}
/// Return the last element from the back that maps to `Some(_)`, or
/// None if the iterator was exhausted.
fn ex_rfind_map<F, R>(&mut self, mut f: F) -> Option<R>
where
F: FnMut(Self::Item) -> Option<R>,
Self: DoubleEndedIterator,
{
while let Some(elt) = self.next_back() {
if let result @ Some(_) = f(elt) {
return result;
}
}
None
}
}
impl<I> IterUtilsExt for I where I: Iterator {}

305
vendor/petgraph/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,305 @@
//! `petgraph` is a graph data structure library.
//!
//! Graphs are collections of nodes, and edges between nodes. `petgraph`
//! provides several [graph types](index.html#graph-types) (each differing in the
//! tradeoffs taken in their internal representation),
//! [algorithms](./algo/index.html#functions) on those graphs, and functionality to
//! [output graphs](./dot/struct.Dot.html) in
//! [`graphviz`](https://www.graphviz.org/) format. Both nodes and edges
//! can have arbitrary associated data, and edges may be either directed or undirected.
//!
//! # Example
//!
//! ```rust
//! use petgraph::graph::{NodeIndex, UnGraph};
//! use petgraph::algo::{dijkstra, min_spanning_tree};
//! use petgraph::data::FromElements;
//! use petgraph::dot::{Dot, Config};
//!
//! // Create an undirected graph with `i32` nodes and edges with `()` associated data.
//! let g = UnGraph::<i32, ()>::from_edges(&[
//! (1, 2), (2, 3), (3, 4),
//! (1, 4)]);
//!
//! // Find the shortest path from `1` to `4` using `1` as the cost for every edge.
//! let node_map = dijkstra(&g, 1.into(), Some(4.into()), |_| 1);
//! assert_eq!(&1i32, node_map.get(&NodeIndex::new(4)).unwrap());
//!
//! // Get the minimum spanning tree of the graph as a new graph, and check that
//! // one edge was trimmed.
//! let mst = UnGraph::<_, _>::from_elements(min_spanning_tree(&g));
//! assert_eq!(g.raw_edges().len() - 1, mst.raw_edges().len());
//!
//! // Output the tree to `graphviz` `DOT` format
//! println!("{:?}", Dot::with_config(&mst, &[Config::EdgeNoLabel]));
//! // graph {
//! // 0 [label="\"0\""]
//! // 1 [label="\"0\""]
//! // 2 [label="\"0\""]
//! // 3 [label="\"0\""]
//! // 1 -- 2
//! // 3 -- 4
//! // 2 -- 3
//! // }
//! ```
//!
//! # Graph types
//!
//! * [`Graph`](./graph/struct.Graph.html) -
//! An adjacency list graph with arbitrary associated data.
//! * [`StableGraph`](./stable_graph/struct.StableGraph.html) -
//! Similar to `Graph`, but it keeps indices stable across removals.
//! * [`GraphMap`](./graphmap/struct.GraphMap.html) -
//! An adjacency list graph backed by a hash table. The node identifiers are the keys
//! into the table.
//! * [`MatrixGraph`](./matrix_graph/struct.MatrixGraph.html) -
//! An adjacency matrix graph.
//! * [`CSR`](./csr/struct.Csr.html) -
//! A sparse adjacency matrix graph with arbitrary associated data.
//!
//! ### Generic parameters
//!
//! Each graph type is generic over a handful of parameters. All graphs share 3 common
//! parameters, `N`, `E`, and `Ty`. This is a broad overview of what those are. Each
//! type's documentation will have finer detail on these parameters.
//!
//! `N` & `E` are called *weights* in this implementation, and are associated with
//! nodes and edges respectively. They can generally be of arbitrary type, and don't have to
//! be what you might conventionally consider weight-like. For example, using `&str` for `N`
//! will work. Many algorithms that require costs let you provide a cost function that
//! translates your `N` and `E` weights into costs appropriate to the algorithm. Some graph
//! types and choices do impose bounds on `N` or `E`.
//! [`min_spanning_tree`](./algo/fn.min_spanning_tree.html) for example requires edge weights that
//! implement [`PartialOrd`](https://doc.rust-lang.org/stable/core/cmp/trait.PartialOrd.html).
//! [`GraphMap`](./graphmap/struct.GraphMap.html) requires node weights that can serve as hash
//! map keys, since that graph type does not create standalone node indices.
//!
//! `Ty` controls whether edges are [`Directed`](./enum.Directed.html) or
//! [`Undirected`](./enum.Undirected.html).
//!
//! `Ix` appears on graph types that use indices. It is exposed so you can control
//! the size of node and edge indices, and therefore the memory footprint of your graphs.
//! Allowed values are `u8`, `u16`, `u32`, and `usize`, with `u32` being the default.
//!
//! ### Shorthand types
//!
//! Each graph type vends a few shorthand type definitions that name some specific
//! generic choices. For example, [`DiGraph<_, _>`](./graph/type.DiGraph.html) is shorthand
//! for [`Graph<_, _, Directed>`](graph/struct.Graph.html).
//! [`UnMatrix<_, _>`](./matrix_graph/type.UnMatrix.html) is shorthand for
//! [`MatrixGraph<_, _, Undirected>`](./matrix_graph/struct.MatrixGraph.html). Each graph type's
//! module documentation lists the available shorthand types.
//!
//! # Crate features
//!
//! * **serde-1** -
//! Defaults off. Enables serialization for ``Graph, StableGraph, GraphMap`` using
//! [`serde 1.0`](https://crates.io/crates/serde). May require a more recent version
//! of Rust than petgraph alone.
//! * **graphmap** -
//! Defaults on. Enables [`GraphMap`](./graphmap/struct.GraphMap.html).
//! * **stable_graph** -
//! Defaults on. Enables [`StableGraph`](./stable_graph/struct.StableGraph.html).
//! * **matrix_graph** -
//! Defaults on. Enables [`MatrixGraph`](./matrix_graph/struct.MatrixGraph.html).
//!
#![doc(html_root_url = "https://docs.rs/petgraph/0.4/")]
extern crate fixedbitset;
#[cfg(feature = "graphmap")]
extern crate indexmap;
#[cfg(feature = "serde-1")]
extern crate serde;
#[cfg(feature = "serde-1")]
#[macro_use]
extern crate serde_derive;
#[cfg(all(feature = "serde-1", test))]
extern crate itertools;
#[doc(no_inline)]
pub use crate::graph::Graph;
pub use crate::Direction::{Incoming, Outgoing};
#[macro_use]
mod macros;
mod scored;
// these modules define trait-implementing macros
#[macro_use]
pub mod visit;
#[macro_use]
pub mod data;
pub mod acyclic;
pub mod adj;
pub mod algo;
pub mod csr;
pub mod dot;
#[cfg(feature = "generate")]
pub mod generate;
pub mod graph6;
mod graph_impl;
#[cfg(feature = "graphmap")]
pub mod graphmap;
mod iter_format;
mod iter_utils;
#[cfg(feature = "matrix_graph")]
pub mod matrix_graph;
#[cfg(feature = "quickcheck")]
mod quickcheck;
#[cfg(feature = "serde-1")]
mod serde_utils;
mod traits_graph;
pub mod unionfind;
mod util;
pub mod operator;
pub mod prelude;
/// `Graph<N, E, Ty, Ix>` is a graph datastructure using an adjacency list representation.
pub mod graph {
pub use crate::graph_impl::{
edge_index, node_index, DefaultIx, DiGraph, Edge, EdgeIndex, EdgeIndices, EdgeReference,
EdgeReferences, EdgeWeightsMut, Edges, EdgesConnecting, Externals, Frozen, Graph,
GraphIndex, IndexType, Neighbors, Node, NodeIndex, NodeIndices, NodeReferences,
NodeWeightsMut, UnGraph, WalkNeighbors,
};
}
#[cfg(feature = "stable_graph")]
pub use crate::graph_impl::stable_graph;
// Index into the NodeIndex and EdgeIndex arrays
/// Edge direction.
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[repr(usize)]
#[cfg_attr(
feature = "serde-1",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub enum Direction {
/// An `Outgoing` edge is an outward edge *from* the current node.
Outgoing = 0,
/// An `Incoming` edge is an inbound edge *to* the current node.
Incoming = 1,
}
impl Direction {
/// Return the opposite `Direction`.
#[inline]
pub fn opposite(self) -> Direction {
match self {
Outgoing => Incoming,
Incoming => Outgoing,
}
}
/// Return `0` for `Outgoing` and `1` for `Incoming`.
#[inline]
pub fn index(self) -> usize {
(self as usize) & 0x1
}
}
#[doc(hidden)]
pub use crate::Direction as EdgeDirection;
/// Marker type for a directed graph.
#[derive(Clone, Copy, Debug)]
#[cfg_attr(
feature = "serde-1",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub enum Directed {}
/// Marker type for an undirected graph.
#[derive(Clone, Copy, Debug)]
#[cfg_attr(
feature = "serde-1",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub enum Undirected {}
/// A graph's edge type determines whether it has directed edges or not.
pub trait EdgeType {
fn is_directed() -> bool;
}
impl EdgeType for Directed {
#[inline]
fn is_directed() -> bool {
true
}
}
impl EdgeType for Undirected {
#[inline]
fn is_directed() -> bool {
false
}
}
/// Convert an element like `(i, j)` or `(i, j, w)` into
/// a triple of source, target, edge weight.
///
/// For `Graph::from_edges` and `GraphMap::from_edges`.
pub trait IntoWeightedEdge<E> {
type NodeId;
fn into_weighted_edge(self) -> (Self::NodeId, Self::NodeId, E);
}
impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix)
where
E: Default,
{
type NodeId = Ix;
fn into_weighted_edge(self) -> (Ix, Ix, E) {
let (s, t) = self;
(s, t, E::default())
}
}
impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix, E) {
type NodeId = Ix;
fn into_weighted_edge(self) -> (Ix, Ix, E) {
self
}
}
impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix, &E)
where
E: Clone,
{
type NodeId = Ix;
fn into_weighted_edge(self) -> (Ix, Ix, E) {
let (a, b, c) = self;
(a, b, c.clone())
}
}
impl<Ix, E> IntoWeightedEdge<E> for &(Ix, Ix)
where
Ix: Copy,
E: Default,
{
type NodeId = Ix;
fn into_weighted_edge(self) -> (Ix, Ix, E) {
let (s, t) = *self;
(s, t, E::default())
}
}
impl<Ix, E> IntoWeightedEdge<E> for &(Ix, Ix, E)
where
Ix: Copy,
E: Clone,
{
type NodeId = Ix;
fn into_weighted_edge(self) -> (Ix, Ix, E) {
self.clone()
}
}

108
vendor/petgraph/src/macros.rs vendored Normal file
View File

@@ -0,0 +1,108 @@
macro_rules! clone_fields {
($name:ident, $($field:ident),+ $(,)*) => (
fn clone(&self) -> Self {
$name {
$(
$field : self . $field .clone()
),*
}
}
);
}
macro_rules! iterator_wrap {
(impl () for
struct $name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
item: $item: ty,
iter: $iter: ty,
) => ();
(
impl (Iterator $($rest:tt)*) for
$(#[$derive:meta])*
struct $name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
item: $item: ty,
iter: $iter: ty,
) => (
// having complex iterator types is kind of the point of this macro
#[allow(clippy::type_complexity)]
$(#[$derive])*
pub struct $name <$($typarm),*> where $($bounds)* {
iter: $iter,
}
impl<$($typarm),*> Iterator for $name <$($typarm),*>
where $($bounds)*
{
type Item = $item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
iterator_wrap!(
impl ($($rest)*) for
struct $name <$($typarm),*> where { $($bounds)* }
item: $item,
iter: $iter,
);
);
(
impl (ExactSizeIterator $($rest:tt)*) for
$(#[$derive:meta])*
struct $name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
item: $item: ty,
iter: $iter: ty,
) => (
impl<$($typarm),*> ExactSizeIterator for $name <$($typarm),*>
where $($bounds)*
{
#[inline]
fn len(&self) -> usize {
self.iter.len()
}
}
iterator_wrap!(
impl ($($rest)*) for
$(#[$derive])*
struct $name <$($typarm),*> where { $($bounds)* }
item: $item,
iter: $iter,
);
);
(
impl (DoubleEndedIterator $($rest:tt)*) for
$(#[$derive:meta])*
struct $name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
item: $item: ty,
iter: $iter: ty,
) => (
impl<$($typarm),*> DoubleEndedIterator for $name <$($typarm),*>
where $($bounds)*
{
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
fn rfold<B, F>(self, accum: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{ self.iter.rfold(accum, f) }
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{ self.iter.rfind(predicate) }
}
iterator_wrap!(
impl ($($rest)*) for
$(#[$derive])*
struct $name <$($typarm),*> where { $($bounds)* }
item: $item,
iter: $iter,
);
);
}

1814
vendor/petgraph/src/matrix_graph.rs vendored Normal file

File diff suppressed because it is too large Load Diff

83
vendor/petgraph/src/operator.rs vendored Normal file
View File

@@ -0,0 +1,83 @@
//! Operators for creating new graphs from existings ones.
use super::graph::{Graph, IndexType};
use super::EdgeType;
use crate::visit::IntoNodeReferences;
/// \[Generic\] complement of the graph
///
/// Computes the graph complement of the input Graph and stores it
/// in the provided empty output Graph.
///
/// The function does not create self-loops.
///
/// Computes in **O(|V|^2*log(|V|))** time (average).
///
/// Returns the complement.
///
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::operator::complement;
/// use petgraph::prelude::*;
///
/// let mut graph: Graph<(),(),Directed> = Graph::new();
/// let a = graph.add_node(()); // node with no weight
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// ]);
/// // a ----> b ----> c ----> d
///
/// let mut output: Graph<(), (), Directed> = Graph::new();
///
/// complement(&graph, &mut output, ());
///
/// let mut expected_res: Graph<(), (), Directed> = Graph::new();
/// let a = expected_res.add_node(());
/// let b = expected_res.add_node(());
/// let c = expected_res.add_node(());
/// let d = expected_res.add_node(());
/// expected_res.extend_with_edges(&[
/// (a, c),
/// (a, d),
/// (b, a),
/// (b, d),
/// (c, a),
/// (c, b),
/// (d, a),
/// (d, b),
/// (d, c),
/// ]);
///
/// for x in graph.node_indices() {
/// for y in graph.node_indices() {
/// assert_eq!(output.contains_edge(x, y), expected_res.contains_edge(x, y));
/// }
/// }
/// ```
pub fn complement<N, E, Ty, Ix>(
input: &Graph<N, E, Ty, Ix>,
output: &mut Graph<N, E, Ty, Ix>,
weight: E,
) where
Ty: EdgeType,
Ix: IndexType,
E: Clone,
N: Clone,
{
for (_node, weight) in input.node_references() {
output.add_node(weight.clone());
}
for x in input.node_indices() {
for y in input.node_indices() {
if x != y && !input.contains_edge(x, y) {
output.add_edge(x, y, weight.clone());
}
}
}
}

21
vendor/petgraph/src/prelude.rs vendored Normal file
View File

@@ -0,0 +1,21 @@
//! Commonly used items.
//!
//! ```
//! use petgraph::prelude::*;
//! ```
#[doc(no_inline)]
pub use crate::graph::{DiGraph, EdgeIndex, Graph, NodeIndex, UnGraph};
#[cfg(feature = "graphmap")]
#[doc(no_inline)]
pub use crate::graphmap::{DiGraphMap, GraphMap, UnGraphMap};
#[doc(no_inline)]
#[cfg(feature = "stable_graph")]
pub use crate::stable_graph::{StableDiGraph, StableGraph, StableUnGraph};
#[doc(no_inline)]
pub use crate::visit::{Bfs, Dfs, DfsPostOrder};
#[doc(no_inline)]
pub use crate::{Directed, Direction, Incoming, Outgoing, Undirected};
#[doc(no_inline)]
pub use crate::visit::EdgeRef;

216
vendor/petgraph/src/quickcheck.rs vendored Normal file
View File

@@ -0,0 +1,216 @@
extern crate quickcheck;
use self::quickcheck::{Arbitrary, Gen};
use crate::graph::{node_index, IndexType};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::StableGraph;
use crate::{EdgeType, Graph};
#[cfg(feature = "graphmap")]
use crate::graphmap::{GraphMap, NodeTrait};
use crate::visit::NodeIndexable;
/// Return a random float in the range [0, 1.)
fn random_01<G: Gen>(g: &mut G) -> f64 {
// from rand
let bits = 53;
let scale = 1. / ((1u64 << bits) as f64);
let x: u64 = Arbitrary::arbitrary(g);
(x >> (64 - bits)) as f64 * scale
}
/// `Arbitrary` for `Graph` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, self loops
/// possible, no parallel edges.
///
/// The exact properties of the produced graph is subject to change.
///
/// Requires crate feature `"quickcheck"`
impl<N, E, Ty, Ix> Arbitrary for Graph<N, E, Ty, Ix>
where
N: Arbitrary,
E: Arbitrary,
Ty: EdgeType + Send + 'static,
Ix: IndexType + Send,
{
fn arbitrary<G: Gen>(g: &mut G) -> Self {
let nodes = usize::arbitrary(g);
if nodes == 0 {
return Graph::with_capacity(0, 0);
}
// use X² for edge probability (bias towards lower)
let edge_prob = random_01(g) * random_01(g);
let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
let mut gr = Graph::with_capacity(nodes, edges);
for _ in 0..nodes {
gr.add_node(N::arbitrary(g));
}
for i in gr.node_indices() {
for j in gr.node_indices() {
if !gr.is_directed() && i > j {
continue;
}
let p: f64 = random_01(g);
if p <= edge_prob {
gr.add_edge(i, j, E::arbitrary(g));
}
}
}
gr
}
// shrink the graph by splitting it in two by a very
// simple algorithm, just even and odd node indices
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
let self_ = self.clone();
Box::new((0..2).filter_map(move |x| {
let gr = self_.filter_map(
|i, w| {
if i.index() % 2 == x {
Some(w.clone())
} else {
None
}
},
|_, w| Some(w.clone()),
);
// make sure we shrink
if gr.node_count() < self_.node_count() {
Some(gr)
} else {
None
}
}))
}
}
#[cfg(feature = "stable_graph")]
/// `Arbitrary` for `StableGraph` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, with possible
/// self loops, no parallel edges.
///
/// The exact properties of the produced graph is subject to change.
///
/// Requires crate features `"quickcheck"` and `"stable_graph"`
impl<N, E, Ty, Ix> Arbitrary for StableGraph<N, E, Ty, Ix>
where
N: Arbitrary,
E: Arbitrary,
Ty: EdgeType + Send + 'static,
Ix: IndexType + Send,
{
fn arbitrary<G: Gen>(g: &mut G) -> Self {
let nodes = usize::arbitrary(g);
if nodes == 0 {
return StableGraph::with_capacity(0, 0);
}
// use X² for edge probability (bias towards lower)
let edge_prob = random_01(g) * random_01(g);
let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
let mut gr = StableGraph::with_capacity(nodes, edges);
for _ in 0..nodes {
gr.add_node(N::arbitrary(g));
}
for i in 0..gr.node_count() {
for j in 0..gr.node_count() {
let i = node_index(i);
let j = node_index(j);
if !gr.is_directed() && i > j {
continue;
}
let p: f64 = random_01(g);
if p <= edge_prob {
gr.add_edge(i, j, E::arbitrary(g));
}
}
}
if bool::arbitrary(g) {
// potentially remove nodes to make holes in nodes & edge sets
let n = u8::arbitrary(g) % (gr.node_count() as u8);
for _ in 0..n {
let ni = node_index(usize::arbitrary(g) % gr.node_bound());
if gr.node_weight(ni).is_some() {
gr.remove_node(ni);
}
}
}
gr
}
// shrink the graph by splitting it in two by a very
// simple algorithm, just even and odd node indices
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
let self_ = self.clone();
Box::new((0..2).filter_map(move |x| {
let gr = self_.filter_map(
|i, w| {
if i.index() % 2 == x {
Some(w.clone())
} else {
None
}
},
|_, w| Some(w.clone()),
);
// make sure we shrink
if gr.node_count() < self_.node_count() {
Some(gr)
} else {
None
}
}))
}
}
/// `Arbitrary` for `GraphMap` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, self loops
/// possible, no parallel edges.
///
/// The exact properties of the produced graph is subject to change.
///
/// Requires crate features `"quickcheck"` and `"graphmap"`
#[cfg(feature = "graphmap")]
impl<N, E, Ty> Arbitrary for GraphMap<N, E, Ty>
where
N: NodeTrait + Arbitrary,
E: Arbitrary,
Ty: EdgeType + Clone + Send + 'static,
{
fn arbitrary<G: Gen>(g: &mut G) -> Self {
let nodes = usize::arbitrary(g);
if nodes == 0 {
return GraphMap::with_capacity(0, 0);
}
let mut nodes = (0..nodes).map(|_| N::arbitrary(g)).collect::<Vec<_>>();
nodes.sort();
nodes.dedup();
// use X² for edge probability (bias towards lower)
let edge_prob = random_01(g) * random_01(g);
let edges = ((nodes.len() as f64).powi(2) * edge_prob) as usize;
let mut gr = GraphMap::with_capacity(nodes.len(), edges);
for &node in &nodes {
gr.add_node(node);
}
for (index, &i) in nodes.iter().enumerate() {
let js = if Ty::is_directed() {
&nodes[..]
} else {
&nodes[index..]
};
for &j in js {
let p: f64 = random_01(g);
if p <= edge_prob {
gr.add_edge(i, j, E::arbitrary(g));
}
}
}
gr
}
}

93
vendor/petgraph/src/scored.rs vendored Normal file
View File

@@ -0,0 +1,93 @@
use std::cmp::Ordering;
/// `MinScored<K, T>` holds a score `K` and a scored object `T` in
/// a pair for use with a `BinaryHeap`.
///
/// `MinScored` compares in reverse order by the score, so that we can
/// use `BinaryHeap` as a min-heap to extract the score-value pair with the
/// least score.
///
/// **Note:** `MinScored` implements a total order (`Ord`), so that it is
/// possible to use float types as scores.
#[derive(Copy, Clone, Debug)]
pub struct MinScored<K, T>(pub K, pub T);
impl<K: PartialOrd, T> PartialEq for MinScored<K, T> {
#[inline]
fn eq(&self, other: &MinScored<K, T>) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl<K: PartialOrd, T> Eq for MinScored<K, T> {}
impl<K: PartialOrd, T> PartialOrd for MinScored<K, T> {
#[inline]
fn partial_cmp(&self, other: &MinScored<K, T>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<K: PartialOrd, T> Ord for MinScored<K, T> {
#[inline]
fn cmp(&self, other: &MinScored<K, T>) -> Ordering {
let a = &self.0;
let b = &other.0;
if a == b {
Ordering::Equal
} else if a < b {
Ordering::Greater
} else if a > b {
Ordering::Less
} else if a.ne(a) && b.ne(b) {
// these are the NaN cases
Ordering::Equal
} else if a.ne(a) {
// Order NaN less, so that it is last in the MinScore order
Ordering::Less
} else {
Ordering::Greater
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct MaxScored<K, T>(pub K, pub T);
impl<K: PartialOrd, T> PartialEq for MaxScored<K, T> {
#[inline]
fn eq(&self, other: &MaxScored<K, T>) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl<K: PartialOrd, T> Eq for MaxScored<K, T> {}
impl<K: PartialOrd, T> PartialOrd for MaxScored<K, T> {
#[inline]
fn partial_cmp(&self, other: &MaxScored<K, T>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<K: PartialOrd, T> Ord for MaxScored<K, T> {
#[inline]
fn cmp(&self, other: &MaxScored<K, T>) -> Ordering {
let a = &self.0;
let b = &other.0;
if a == b {
Ordering::Equal
} else if a < b {
Ordering::Less
} else if a > b {
Ordering::Greater
} else if a.ne(a) && b.ne(b) {
// these are the NaN cases
Ordering::Equal
} else if a.ne(a) {
Ordering::Less
} else {
Ordering::Greater
}
}
}

95
vendor/petgraph/src/serde_utils.rs vendored Normal file
View File

@@ -0,0 +1,95 @@
use serde::de::{Deserialize, Error, SeqAccess, Visitor};
use serde::ser::{Serialize, SerializeSeq, Serializer};
use std::fmt;
use std::marker::PhantomData;
/// Map to serializeable representation
pub trait IntoSerializable {
type Output;
fn into_serializable(self) -> Self::Output;
}
/// Map from deserialized representation
pub trait FromDeserialized: Sized {
type Input;
fn from_deserialized<E>(input: Self::Input) -> Result<Self, E>
where
E: Error;
}
/// Serde combinator. A sequence visitor that maps deserialized elements
/// lazily; the visitor can also emit new errors if the elements have errors.
pub struct MappedSequenceVisitor<T, R, F>
where
F: Fn(T) -> Result<R, &'static str>,
{
f: F,
marker: PhantomData<fn() -> T>,
}
impl<'de, F, T, R> MappedSequenceVisitor<T, R, F>
where
T: Deserialize<'de>,
F: Fn(T) -> Result<R, &'static str>,
{
pub fn new(f: F) -> Self {
MappedSequenceVisitor {
f: f,
marker: PhantomData,
}
}
}
impl<'de, F, T, R> Visitor<'de> for MappedSequenceVisitor<T, R, F>
where
T: Deserialize<'de>,
F: Fn(T) -> Result<R, &'static str>,
{
type Value = Vec<R>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a sequence")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut v = Vec::new();
while let Some(elem) = seq.next_element()? {
match (self.f)(elem) {
Err(s) => Err(<A::Error>::custom(s))?,
Ok(x) => v.push(x),
}
}
Ok(v)
}
}
pub trait CollectSeqWithLength: Serializer {
fn collect_seq_with_length<I>(self, length: usize, iterable: I) -> Result<Self::Ok, Self::Error>
where
I: IntoIterator,
I::Item: Serialize,
{
let mut count = 0;
let mut seq = self.serialize_seq(Some(length))?;
for element in iterable {
seq.serialize_element(&element)?;
count += 1;
}
debug_assert_eq!(length, count, "collect_seq_with_length: length mismatch!");
seq.end()
}
fn collect_seq_exact<I>(self, iterable: I) -> Result<Self::Ok, Self::Error>
where
I: IntoIterator,
I::Item: Serialize,
I::IntoIter: ExactSizeIterator,
{
let iter = iterable.into_iter();
self.collect_seq_with_length(iter.len(), iter)
}
}
impl<S> CollectSeqWithLength for S where S: Serializer {}

73
vendor/petgraph/src/traits_graph.rs vendored Normal file
View File

@@ -0,0 +1,73 @@
use fixedbitset::FixedBitSet;
use super::EdgeType;
use super::graph::{Graph, IndexType, NodeIndex};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::StableGraph;
use crate::visit::EdgeRef;
#[cfg(feature = "stable_graph")]
use crate::visit::{IntoEdgeReferences, NodeIndexable};
use super::visit::GetAdjacencyMatrix;
/// The adjacency matrix for **Graph** is a bitmap that's computed by
/// `.adjacency_matrix()`.
impl<N, E, Ty, Ix> GetAdjacencyMatrix for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
type AdjMatrix = FixedBitSet;
fn adjacency_matrix(&self) -> FixedBitSet {
let n = self.node_count();
let mut matrix = FixedBitSet::with_capacity(n * n);
for edge in self.edge_references() {
let i = edge.source().index() * n + edge.target().index();
matrix.put(i);
if !self.is_directed() {
let j = edge.source().index() + n * edge.target().index();
matrix.put(j);
}
}
matrix
}
fn is_adjacent(&self, matrix: &FixedBitSet, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool {
let n = self.node_count();
let index = n * a.index() + b.index();
matrix.contains(index)
}
}
#[cfg(feature = "stable_graph")]
/// The adjacency matrix for **Graph** is a bitmap that's computed by
/// `.adjacency_matrix()`.
impl<N, E, Ty, Ix> GetAdjacencyMatrix for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
type AdjMatrix = FixedBitSet;
fn adjacency_matrix(&self) -> FixedBitSet {
let n = self.node_bound();
let mut matrix = FixedBitSet::with_capacity(n * n);
for edge in self.edge_references() {
let i = edge.source().index() * n + edge.target().index();
matrix.put(i);
if !self.is_directed() {
let j = edge.source().index() + n * edge.target().index();
matrix.put(j);
}
}
matrix
}
fn is_adjacent(&self, matrix: &FixedBitSet, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool {
let n = self.node_count();
let index = n * a.index() + b.index();
matrix.contains(index)
}
}

146
vendor/petgraph/src/unionfind.rs vendored Normal file
View File

@@ -0,0 +1,146 @@
//! `UnionFind<K>` is a disjoint-set data structure.
use super::graph::IndexType;
use std::cmp::Ordering;
/// `UnionFind<K>` is a disjoint-set data structure. It tracks set membership of *n* elements
/// indexed from *0* to *n - 1*. The scalar type is `K` which must be an unsigned integer type.
///
/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>
///
/// Too awesome not to quote:
///
/// “The amortized time per operation is **O(α(n))** where **α(n)** is the
/// inverse of **f(x) = A(x, x)** with **A** being the extremely fast-growing Ackermann function.”
#[derive(Debug, Clone)]
pub struct UnionFind<K> {
// For element at index *i*, store the index of its parent; the representative itself
// stores its own index. This forms equivalence classes which are the disjoint sets, each
// with a unique representative.
parent: Vec<K>,
// It is a balancing tree structure,
// so the ranks are logarithmic in the size of the container -- a byte is more than enough.
//
// Rank is separated out both to save space and to save cache in when searching in the parent
// vector.
rank: Vec<u8>,
}
#[inline]
unsafe fn get_unchecked<K>(xs: &[K], index: usize) -> &K {
debug_assert!(index < xs.len());
xs.get_unchecked(index)
}
#[inline]
unsafe fn get_unchecked_mut<K>(xs: &mut [K], index: usize) -> &mut K {
debug_assert!(index < xs.len());
xs.get_unchecked_mut(index)
}
impl<K> UnionFind<K>
where
K: IndexType,
{
/// Create a new `UnionFind` of `n` disjoint sets.
pub fn new(n: usize) -> Self {
let rank = vec![0; n];
let parent = (0..n).map(K::new).collect::<Vec<K>>();
UnionFind { parent, rank }
}
/// Return the representative for `x`.
///
/// **Panics** if `x` is out of bounds.
pub fn find(&self, x: K) -> K {
assert!(x.index() < self.parent.len());
unsafe {
let mut x = x;
loop {
// Use unchecked indexing because we can trust the internal set ids.
let xparent = *get_unchecked(&self.parent, x.index());
if xparent == x {
break;
}
x = xparent;
}
x
}
}
/// Return the representative for `x`.
///
/// Write back the found representative, flattening the internal
/// datastructure in the process and quicken future lookups.
///
/// **Panics** if `x` is out of bounds.
pub fn find_mut(&mut self, x: K) -> K {
assert!(x.index() < self.parent.len());
unsafe { self.find_mut_recursive(x) }
}
unsafe fn find_mut_recursive(&mut self, mut x: K) -> K {
let mut parent = *get_unchecked(&self.parent, x.index());
while parent != x {
let grandparent = *get_unchecked(&self.parent, parent.index());
*get_unchecked_mut(&mut self.parent, x.index()) = grandparent;
x = parent;
parent = grandparent;
}
x
}
/// Returns `true` if the given elements belong to the same set, and returns
/// `false` otherwise.
pub fn equiv(&self, x: K, y: K) -> bool {
self.find(x) == self.find(y)
}
/// Unify the two sets containing `x` and `y`.
///
/// Return `false` if the sets were already the same, `true` if they were unified.
///
/// **Panics** if `x` or `y` is out of bounds.
pub fn union(&mut self, x: K, y: K) -> bool {
if x == y {
return false;
}
let xrep = self.find_mut(x);
let yrep = self.find_mut(y);
if xrep == yrep {
return false;
}
let xrepu = xrep.index();
let yrepu = yrep.index();
let xrank = self.rank[xrepu];
let yrank = self.rank[yrepu];
// The rank corresponds roughly to the depth of the treeset, so put the
// smaller set below the larger
match xrank.cmp(&yrank) {
Ordering::Less => self.parent[xrepu] = yrep,
Ordering::Greater => self.parent[yrepu] = xrep,
Ordering::Equal => {
self.parent[yrepu] = xrep;
self.rank[xrepu] += 1;
}
}
true
}
/// Return a vector mapping each element to its representative.
pub fn into_labeling(mut self) -> Vec<K> {
// write in the labeling of each element
unsafe {
for ix in 0..self.parent.len() {
let k = *get_unchecked(&self.parent, ix);
let xrep = self.find_mut_recursive(k);
*self.parent.get_unchecked_mut(ix) = xrep;
}
}
self.parent
}
}

16
vendor/petgraph/src/util.rs vendored Normal file
View File

@@ -0,0 +1,16 @@
use std::iter;
pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
where
I: IntoIterator,
{
iterable.into_iter().enumerate()
}
pub fn zip<I, J>(i: I, j: J) -> iter::Zip<I::IntoIter, J::IntoIter>
where
I: IntoIterator,
J: IntoIterator,
{
i.into_iter().zip(j)
}

314
vendor/petgraph/src/visit/dfsvisit.rs vendored Normal file
View File

@@ -0,0 +1,314 @@
use crate::visit::IntoNeighbors;
use crate::visit::{VisitMap, Visitable};
/// Strictly monotonically increasing event time for a depth first search.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Default, Hash)]
pub struct Time(pub usize);
/// A depth first search (DFS) visitor event.
#[derive(Copy, Clone, Debug)]
pub enum DfsEvent<N> {
Discover(N, Time),
/// An edge of the tree formed by the traversal.
TreeEdge(N, N),
/// An edge to an already visited node.
BackEdge(N, N),
/// A cross or forward edge.
///
/// For an edge *(u, v)*, if the discover time of *v* is greater than *u*,
/// then it is a forward edge, else a cross edge.
CrossForwardEdge(N, N),
/// All edges from a node have been reported.
Finish(N, Time),
}
/// Return if the expression is a break value, execute the provided statement
/// if it is a prune value.
macro_rules! try_control {
($e:expr, $p:stmt) => {
try_control!($e, $p, ());
};
($e:expr, $p:stmt, $q:stmt) => {
match $e {
x => {
if x.should_break() {
return x;
} else if x.should_prune() {
$p
} else {
$q
}
}
}
};
}
/// Control flow for `depth_first_search` callbacks.
#[derive(Copy, Clone, Debug)]
pub enum Control<B> {
/// Continue the DFS traversal as normal.
Continue,
/// Prune the current node from the DFS traversal. No more edges from this
/// node will be reported to the callback. A `DfsEvent::Finish` for this
/// node will still be reported. This can be returned in response to any
/// `DfsEvent`, except `Finish`, which will panic.
Prune,
/// Stop the DFS traversal and return the provided value.
Break(B),
}
impl<B> Control<B> {
pub fn breaking() -> Control<()> {
Control::Break(())
}
/// Get the value in `Control::Break(_)`, if present.
pub fn break_value(self) -> Option<B> {
match self {
Control::Continue | Control::Prune => None,
Control::Break(b) => Some(b),
}
}
}
/// Control flow for callbacks.
///
/// The empty return value `()` is equivalent to continue.
pub trait ControlFlow {
fn continuing() -> Self;
fn should_break(&self) -> bool;
fn should_prune(&self) -> bool;
}
impl ControlFlow for () {
fn continuing() {}
#[inline]
fn should_break(&self) -> bool {
false
}
#[inline]
fn should_prune(&self) -> bool {
false
}
}
impl<B> ControlFlow for Control<B> {
fn continuing() -> Self {
Control::Continue
}
fn should_break(&self) -> bool {
if let Control::Break(_) = *self {
true
} else {
false
}
}
fn should_prune(&self) -> bool {
match *self {
Control::Prune => true,
Control::Continue | Control::Break(_) => false,
}
}
}
impl<C: ControlFlow, E> ControlFlow for Result<C, E> {
fn continuing() -> Self {
Ok(C::continuing())
}
fn should_break(&self) -> bool {
if let Ok(ref c) = *self {
c.should_break()
} else {
true
}
}
fn should_prune(&self) -> bool {
if let Ok(ref c) = *self {
c.should_prune()
} else {
false
}
}
}
/// The default is `Continue`.
impl<B> Default for Control<B> {
fn default() -> Self {
Control::Continue
}
}
/// A recursive depth first search.
///
/// Starting points are the nodes in the iterator `starts` (specify just one
/// start vertex *x* by using `Some(x)`).
///
/// The traversal emits discovery and finish events for each reachable vertex,
/// and edge classification of each reachable edge. `visitor` is called for each
/// event, see [`DfsEvent`][de] for possible values.
///
/// The return value should implement the trait `ControlFlow`, and can be used to change
/// the control flow of the search.
///
/// `Control` Implements `ControlFlow` such that `Control::Continue` resumes the search.
/// `Control::Break` will stop the visit early, returning the contained value.
/// `Control::Prune` will stop traversing any additional edges from the current
/// node and proceed immediately to the `Finish` event.
///
/// There are implementations of `ControlFlow` for `()`, and `Result<C, E>` where
/// `C: ControlFlow`. The implementation for `()` will continue until finished.
/// For `Result`, upon encountering an `E` it will break, otherwise acting the same as `C`.
///
/// ***Panics** if you attempt to prune a node from its `Finish` event.
///
/// [de]: enum.DfsEvent.html
///
/// # Example returning `Control`.
///
/// Find a path from vertex 0 to 5, and exit the visit as soon as we reach
/// the goal vertex.
///
/// ```
/// use petgraph::prelude::*;
/// use petgraph::graph::node_index as n;
/// use petgraph::visit::depth_first_search;
/// use petgraph::visit::{DfsEvent, Control};
///
/// let gr: Graph<(), ()> = Graph::from_edges(&[
/// (0, 1), (0, 2), (0, 3),
/// (1, 3),
/// (2, 3), (2, 4),
/// (4, 0), (4, 5),
/// ]);
///
/// // record each predecessor, mapping node → node
/// let mut predecessor = vec![NodeIndex::end(); gr.node_count()];
/// let start = n(0);
/// let goal = n(5);
/// depth_first_search(&gr, Some(start), |event| {
/// if let DfsEvent::TreeEdge(u, v) = event {
/// predecessor[v.index()] = u;
/// if v == goal {
/// return Control::Break(v);
/// }
/// }
/// Control::Continue
/// });
///
/// let mut next = goal;
/// let mut path = vec![next];
/// while next != start {
/// let pred = predecessor[next.index()];
/// path.push(pred);
/// next = pred;
/// }
/// path.reverse();
/// assert_eq!(&path, &[n(0), n(2), n(4), n(5)]);
/// ```
///
/// # Example returning a `Result`.
/// ```
/// use petgraph::graph::node_index as n;
/// use petgraph::prelude::*;
/// use petgraph::visit::depth_first_search;
/// use petgraph::visit::{DfsEvent, Time};
///
/// let gr: Graph<(), ()> = Graph::from_edges(&[(0, 1), (1, 2), (1, 1), (2, 1)]);
/// let start = n(0);
/// let mut back_edges = 0;
/// let mut discover_time = 0;
/// // Stop the search, the first time a BackEdge is encountered.
/// let result = depth_first_search(&gr, Some(start), |event| {
/// match event {
/// // In the cases where Ok(()) is returned,
/// // Result falls back to the implementation of Control on the value ().
/// // In the case of (), this is to always return Control::Continue.
/// // continuing the search.
/// DfsEvent::Discover(_, Time(t)) => {
/// discover_time = t;
/// Ok(())
/// }
/// DfsEvent::BackEdge(_, _) => {
/// back_edges += 1;
/// // the implementation of ControlFlow for Result,
/// // treats this Err value as Continue::Break
/// Err(event)
/// }
/// _ => Ok(()),
/// }
/// });
///
/// // Even though the graph has more than one cycle,
/// // The number of back_edges visited by the search should always be 1.
/// assert_eq!(back_edges, 1);
/// println!("discover time:{:?}", discover_time);
/// println!("number of backedges encountered: {}", back_edges);
/// println!("back edge: {:?}", result);
/// ```
pub fn depth_first_search<G, I, F, C>(graph: G, starts: I, mut visitor: F) -> C
where
G: IntoNeighbors + Visitable,
I: IntoIterator<Item = G::NodeId>,
F: FnMut(DfsEvent<G::NodeId>) -> C,
C: ControlFlow,
{
let time = &mut Time(0);
let discovered = &mut graph.visit_map();
let finished = &mut graph.visit_map();
for start in starts {
try_control!(
dfs_visitor(graph, start, &mut visitor, discovered, finished, time),
unreachable!()
);
}
C::continuing()
}
pub(crate) fn dfs_visitor<G, F, C>(
graph: G,
u: G::NodeId,
visitor: &mut F,
discovered: &mut impl VisitMap<G::NodeId>,
finished: &mut impl VisitMap<G::NodeId>,
time: &mut Time,
) -> C
where
G: IntoNeighbors + Visitable,
F: FnMut(DfsEvent<G::NodeId>) -> C,
C: ControlFlow,
{
if !discovered.visit(u) {
return C::continuing();
}
try_control!(
visitor(DfsEvent::Discover(u, time_post_inc(time))),
{},
for v in graph.neighbors(u) {
if !discovered.is_visited(&v) {
try_control!(visitor(DfsEvent::TreeEdge(u, v)), continue);
try_control!(
dfs_visitor(graph, v, visitor, discovered, finished, time),
unreachable!()
);
} else if !finished.is_visited(&v) {
try_control!(visitor(DfsEvent::BackEdge(u, v)), continue);
} else {
try_control!(visitor(DfsEvent::CrossForwardEdge(u, v)), continue);
}
}
);
let first_finish = finished.visit(u);
debug_assert!(first_finish);
try_control!(
visitor(DfsEvent::Finish(u, time_post_inc(time))),
panic!("Pruning on the `DfsEvent::Finish` is not supported!")
);
C::continuing()
}
fn time_post_inc(x: &mut Time) -> Time {
let v = *x;
x.0 += 1;
v
}

583
vendor/petgraph/src/visit/filter.rs vendored Normal file
View File

@@ -0,0 +1,583 @@
use crate::prelude::*;
use fixedbitset::FixedBitSet;
use std::collections::HashSet;
use std::marker::PhantomData;
use crate::data::DataMap;
use crate::visit::{Data, NodeCompactIndexable, NodeCount};
use crate::visit::{
EdgeIndexable, GraphBase, GraphProp, IntoEdgeReferences, IntoEdges, IntoEdgesDirected,
IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, IntoNodeReferences, NodeIndexable,
NodeRef, VisitMap, Visitable,
};
/// A graph filter for nodes.
pub trait FilterNode<N> {
/// Return true to have the node be part of the graph
fn include_node(&self, node: N) -> bool;
}
impl<F, N> FilterNode<N> for F
where
F: Fn(N) -> bool,
{
fn include_node(&self, n: N) -> bool {
(*self)(n)
}
}
/// This filter includes the nodes that are contained in the set.
impl<N> FilterNode<N> for FixedBitSet
where
FixedBitSet: VisitMap<N>,
{
fn include_node(&self, n: N) -> bool {
self.is_visited(&n)
}
}
/// This filter includes the nodes that are contained in the set.
impl<N, S> FilterNode<N> for HashSet<N, S>
where
HashSet<N, S>: VisitMap<N>,
{
fn include_node(&self, n: N) -> bool {
self.is_visited(&n)
}
}
// Can't express these as a generic impl over all references since that would conflict with the
// impl for Fn.
impl<N> FilterNode<N> for &FixedBitSet
where
FixedBitSet: VisitMap<N>,
{
fn include_node(&self, n: N) -> bool {
self.is_visited(&n)
}
}
impl<N, S> FilterNode<N> for &HashSet<N, S>
where
HashSet<N, S>: VisitMap<N>,
{
fn include_node(&self, n: N) -> bool {
self.is_visited(&n)
}
}
/// A node-filtering graph adaptor.
#[derive(Copy, Clone, Debug)]
pub struct NodeFiltered<G, F>(pub G, pub F);
impl<F, G> NodeFiltered<G, F>
where
G: GraphBase,
F: Fn(G::NodeId) -> bool,
{
/// Create an `NodeFiltered` adaptor from the closure `filter`.
pub fn from_fn(graph: G, filter: F) -> Self {
NodeFiltered(graph, filter)
}
}
impl<G, F> GraphBase for NodeFiltered<G, F>
where
G: GraphBase,
{
type NodeId = G::NodeId;
type EdgeId = G::EdgeId;
}
impl<'a, G, F> IntoNeighbors for &'a NodeFiltered<G, F>
where
G: IntoNeighbors,
F: FilterNode<G::NodeId>,
{
type Neighbors = NodeFilteredNeighbors<'a, G::Neighbors, F>;
fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
NodeFilteredNeighbors {
include_source: self.1.include_node(n),
iter: self.0.neighbors(n),
f: &self.1,
}
}
}
/// A filtered neighbors iterator.
#[derive(Debug, Clone)]
pub struct NodeFilteredNeighbors<'a, I, F: 'a> {
include_source: bool,
iter: I,
f: &'a F,
}
impl<I, F> Iterator for NodeFilteredNeighbors<'_, I, F>
where
I: Iterator,
I::Item: Copy,
F: FilterNode<I::Item>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
if !self.include_source {
None
} else {
self.iter.find(move |&target| f.include_node(target))
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
impl<'a, G, F> IntoNeighborsDirected for &'a NodeFiltered<G, F>
where
G: IntoNeighborsDirected,
F: FilterNode<G::NodeId>,
{
type NeighborsDirected = NodeFilteredNeighbors<'a, G::NeighborsDirected, F>;
fn neighbors_directed(self, n: G::NodeId, dir: Direction) -> Self::NeighborsDirected {
NodeFilteredNeighbors {
include_source: self.1.include_node(n),
iter: self.0.neighbors_directed(n, dir),
f: &self.1,
}
}
}
impl<'a, G, F> IntoNodeIdentifiers for &'a NodeFiltered<G, F>
where
G: IntoNodeIdentifiers,
F: FilterNode<G::NodeId>,
{
type NodeIdentifiers = NodeFilteredNeighbors<'a, G::NodeIdentifiers, F>;
fn node_identifiers(self) -> Self::NodeIdentifiers {
NodeFilteredNeighbors {
include_source: true,
iter: self.0.node_identifiers(),
f: &self.1,
}
}
}
impl<'a, G, F> IntoNodeReferences for &'a NodeFiltered<G, F>
where
G: IntoNodeReferences,
F: FilterNode<G::NodeId>,
{
type NodeRef = G::NodeRef;
type NodeReferences = NodeFilteredNodes<'a, G::NodeReferences, F>;
fn node_references(self) -> Self::NodeReferences {
NodeFilteredNodes {
include_source: true,
iter: self.0.node_references(),
f: &self.1,
}
}
}
/// A filtered node references iterator.
#[derive(Debug, Clone)]
pub struct NodeFilteredNodes<'a, I, F: 'a> {
include_source: bool,
iter: I,
f: &'a F,
}
impl<I, F> Iterator for NodeFilteredNodes<'_, I, F>
where
I: Iterator,
I::Item: Copy + NodeRef,
F: FilterNode<<I::Item as NodeRef>::NodeId>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
if !self.include_source {
None
} else {
self.iter.find(move |&target| f.include_node(target.id()))
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
impl<'a, G, F> IntoEdgeReferences for &'a NodeFiltered<G, F>
where
G: IntoEdgeReferences,
F: FilterNode<G::NodeId>,
{
type EdgeRef = G::EdgeRef;
type EdgeReferences = NodeFilteredEdgeReferences<'a, G, G::EdgeReferences, F>;
fn edge_references(self) -> Self::EdgeReferences {
NodeFilteredEdgeReferences {
graph: PhantomData,
iter: self.0.edge_references(),
f: &self.1,
}
}
}
/// A filtered edges iterator.
#[derive(Debug, Clone)]
pub struct NodeFilteredEdgeReferences<'a, G, I, F: 'a> {
graph: PhantomData<G>,
iter: I,
f: &'a F,
}
impl<G, I, F> Iterator for NodeFilteredEdgeReferences<'_, G, I, F>
where
F: FilterNode<G::NodeId>,
G: IntoEdgeReferences,
I: Iterator<Item = G::EdgeRef>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
self.iter
.find(move |&edge| f.include_node(edge.source()) && f.include_node(edge.target()))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
impl<'a, G, F> IntoEdges for &'a NodeFiltered<G, F>
where
G: IntoEdges,
F: FilterNode<G::NodeId>,
{
type Edges = NodeFilteredEdges<'a, G, G::Edges, F>;
fn edges(self, a: G::NodeId) -> Self::Edges {
NodeFilteredEdges {
graph: PhantomData,
include_source: self.1.include_node(a),
iter: self.0.edges(a),
f: &self.1,
dir: Direction::Outgoing,
}
}
}
impl<'a, G, F> IntoEdgesDirected for &'a NodeFiltered<G, F>
where
G: IntoEdgesDirected,
F: FilterNode<G::NodeId>,
{
type EdgesDirected = NodeFilteredEdges<'a, G, G::EdgesDirected, F>;
fn edges_directed(self, a: G::NodeId, dir: Direction) -> Self::EdgesDirected {
NodeFilteredEdges {
graph: PhantomData,
include_source: self.1.include_node(a),
iter: self.0.edges_directed(a, dir),
f: &self.1,
dir,
}
}
}
/// A filtered edges iterator.
#[derive(Debug, Clone)]
pub struct NodeFilteredEdges<'a, G, I, F: 'a> {
graph: PhantomData<G>,
include_source: bool,
iter: I,
f: &'a F,
dir: Direction,
}
impl<G, I, F> Iterator for NodeFilteredEdges<'_, G, I, F>
where
F: FilterNode<G::NodeId>,
G: IntoEdges,
I: Iterator<Item = G::EdgeRef>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if !self.include_source {
None
} else {
let dir = self.dir;
let f = self.f;
self.iter.find(move |&edge| {
f.include_node(match dir {
Direction::Outgoing => edge.target(),
Direction::Incoming => edge.source(),
})
})
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
impl<G, F> DataMap for NodeFiltered<G, F>
where
G: DataMap,
F: FilterNode<G::NodeId>,
{
fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
if self.1.include_node(id) {
self.0.node_weight(id)
} else {
None
}
}
fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
self.0.edge_weight(id)
}
}
macro_rules! access0 {
($e:expr) => {
$e.0
};
}
Data! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
NodeIndexable! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
EdgeIndexable! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
GraphProp! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
Visitable! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
/// A graph filter for edges
pub trait FilterEdge<Edge> {
/// Return true to have the edge be part of the graph
fn include_edge(&self, edge: Edge) -> bool;
}
impl<F, N> FilterEdge<N> for F
where
F: Fn(N) -> bool,
{
fn include_edge(&self, n: N) -> bool {
(*self)(n)
}
}
/// An edge-filtering graph adaptor.
///
/// The adaptor may filter out edges. The filter implements the trait
/// `FilterEdge`. Closures of type `Fn(G::EdgeRef) -> bool` already
/// implement this trait.
///
/// The filter may use edge source, target, id, and weight to select whether to
/// include the edge or not.
#[derive(Copy, Clone, Debug)]
pub struct EdgeFiltered<G, F>(pub G, pub F);
impl<F, G> EdgeFiltered<G, F>
where
G: IntoEdgeReferences,
F: Fn(G::EdgeRef) -> bool,
{
/// Create an `EdgeFiltered` adaptor from the closure `filter`.
pub fn from_fn(graph: G, filter: F) -> Self {
EdgeFiltered(graph, filter)
}
}
impl<G, F> GraphBase for EdgeFiltered<G, F>
where
G: GraphBase,
{
type NodeId = G::NodeId;
type EdgeId = G::EdgeId;
}
impl<'a, G, F> IntoNeighbors for &'a EdgeFiltered<G, F>
where
G: IntoEdges,
F: FilterEdge<G::EdgeRef>,
{
type Neighbors = EdgeFilteredNeighbors<'a, G, F>;
fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
EdgeFilteredNeighbors {
iter: self.0.edges(n),
f: &self.1,
}
}
}
impl<'a, G, F> IntoNeighborsDirected for &'a EdgeFiltered<G, F>
where
G: IntoEdgesDirected,
F: FilterEdge<G::EdgeRef>,
{
type NeighborsDirected = EdgeFilteredNeighborsDirected<'a, G, F>;
fn neighbors_directed(self, n: G::NodeId, dir: Direction) -> Self::NeighborsDirected {
EdgeFilteredNeighborsDirected {
iter: self.0.edges_directed(n, dir),
f: &self.1,
from: n,
}
}
}
/// A filtered neighbors iterator.
#[derive(Debug, Clone)]
pub struct EdgeFilteredNeighbors<'a, G, F: 'a>
where
G: IntoEdges,
{
iter: G::Edges,
f: &'a F,
}
impl<G, F> Iterator for EdgeFilteredNeighbors<'_, G, F>
where
F: FilterEdge<G::EdgeRef>,
G: IntoEdges,
{
type Item = G::NodeId;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
(&mut self.iter)
.filter_map(move |edge| {
if f.include_edge(edge) {
Some(edge.target())
} else {
None
}
})
.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
impl<'a, G, F> IntoEdgeReferences for &'a EdgeFiltered<G, F>
where
G: IntoEdgeReferences,
F: FilterEdge<G::EdgeRef>,
{
type EdgeRef = G::EdgeRef;
type EdgeReferences = EdgeFilteredEdges<'a, G, G::EdgeReferences, F>;
fn edge_references(self) -> Self::EdgeReferences {
EdgeFilteredEdges {
graph: PhantomData,
iter: self.0.edge_references(),
f: &self.1,
}
}
}
impl<'a, G, F> IntoEdges for &'a EdgeFiltered<G, F>
where
G: IntoEdges,
F: FilterEdge<G::EdgeRef>,
{
type Edges = EdgeFilteredEdges<'a, G, G::Edges, F>;
fn edges(self, n: G::NodeId) -> Self::Edges {
EdgeFilteredEdges {
graph: PhantomData,
iter: self.0.edges(n),
f: &self.1,
}
}
}
impl<'a, G, F> IntoEdgesDirected for &'a EdgeFiltered<G, F>
where
G: IntoEdgesDirected,
F: FilterEdge<G::EdgeRef>,
{
type EdgesDirected = EdgeFilteredEdges<'a, G, G::EdgesDirected, F>;
fn edges_directed(self, n: G::NodeId, dir: Direction) -> Self::EdgesDirected {
EdgeFilteredEdges {
graph: PhantomData,
iter: self.0.edges_directed(n, dir),
f: &self.1,
}
}
}
/// A filtered edges iterator.
#[derive(Debug, Clone)]
pub struct EdgeFilteredEdges<'a, G, I, F: 'a> {
graph: PhantomData<G>,
iter: I,
f: &'a F,
}
impl<G, I, F> Iterator for EdgeFilteredEdges<'_, G, I, F>
where
F: FilterEdge<G::EdgeRef>,
G: IntoEdgeReferences,
I: Iterator<Item = G::EdgeRef>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
self.iter.find(move |&edge| f.include_edge(edge))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
/// A filtered neighbors-directed iterator.
#[derive(Debug, Clone)]
pub struct EdgeFilteredNeighborsDirected<'a, G, F: 'a>
where
G: IntoEdgesDirected,
{
iter: G::EdgesDirected,
f: &'a F,
from: G::NodeId,
}
impl<G, F> Iterator for EdgeFilteredNeighborsDirected<'_, G, F>
where
F: FilterEdge<G::EdgeRef>,
G: IntoEdgesDirected,
{
type Item = G::NodeId;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
let from = self.from;
(&mut self.iter)
.filter_map(move |edge| {
if f.include_edge(edge) {
if edge.source() != from {
Some(edge.source())
} else {
Some(edge.target()) // includes case where from == source == target
}
} else {
None
}
})
.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
Data! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
GraphProp! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
IntoNodeIdentifiers! {delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
IntoNodeReferences! {delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
NodeCompactIndexable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeCount! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeIndexable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
EdgeIndexable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
Visitable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}

135
vendor/petgraph/src/visit/macros.rs vendored Normal file
View File

@@ -0,0 +1,135 @@
/// Define a trait as usual, and a macro that can be used to instantiate
/// implementations of it.
///
/// There *must* be section markers in the trait definition:
/// @section type for associated types
/// @section self for methods
/// @section nodelegate for arbitrary tail that is not forwarded.
macro_rules! trait_template {
($(#[$doc:meta])* pub trait $name:ident $($methods:tt)*) => {
macro_rules! $name {
($m:ident $extra:tt) => {
$m! {
$extra
pub trait $name $($methods)*
}
}
}
remove_sections! { []
$(#[$doc])*
pub trait $name $($methods)*
// This is where the trait definition is reproduced by the macro.
// It makes the source links point to this place!
//
// I'm sorry, you'll have to find the source by looking at the
// source of the module the trait is defined in.
//
// We use this nifty macro so that we can automatically generate
// delegation trait impls and implement the graph traits for more
// types and combinators.
}
}
}
macro_rules! remove_sections_inner {
([$($stack:tt)*]) => {
$($stack)*
};
// escape the following tt
([$($stack:tt)*] @escape $_x:tt $($t:tt)*) => {
remove_sections_inner!([$($stack)*] $($t)*);
};
([$($stack:tt)*] @section $x:ident $($t:tt)*) => {
remove_sections_inner!([$($stack)*] $($t)*);
};
([$($stack:tt)*] $t:tt $($tail:tt)*) => {
remove_sections_inner!([$($stack)* $t] $($tail)*);
};
}
// This is the outer layer, just find the { } of the actual trait definition
// recurse once into { }, but not more.
macro_rules! remove_sections {
([$($stack:tt)*]) => {
$($stack)*
};
([$($stack:tt)*] { $($tail:tt)* }) => {
$($stack)* {
remove_sections_inner!([] $($tail)*);
}
};
([$($stack:tt)*] $t:tt $($tail:tt)*) => {
remove_sections!([$($stack)* $t] $($tail)*);
};
}
macro_rules! deref {
($e:expr) => {
*$e
};
}
macro_rules! deref_twice {
($e:expr) => {
**$e
};
}
/// Implement a trait by delegation. By default as if we are delegating
/// from &G to G.
macro_rules! delegate_impl {
([] $($rest:tt)*) => {
delegate_impl! { [['a, G], G, &'a G, deref] $($rest)* }
};
([[$($param:tt)*], $self_type:ident, $self_wrap:ty, $self_map:ident]
pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* {
// "Escaped" associated types. Stripped before making the `trait`
// itself, but forwarded when delegating impls.
$(
@escape [type $assoc_name_ext:ident]
// Associated types. Forwarded.
)*
$(
@section type
$(
$(#[$_assoc_attr:meta])*
type $assoc_name:ident $(: $assoc_bound:ty)*;
)+
)*
// Methods. Forwarded. Using $self_map!(self) around the self argument.
// Methods must use receiver `self` or explicit type like `self: &Self`
// &self and &mut self are _not_ supported.
$(
@section self
$(
$(#[$_method_attr:meta])*
fn $method_name:ident(self $(: $self_selftype:ty)* $(,$marg:ident : $marg_ty:ty)*) $(-> $mret:ty)?;
)+
)*
// Arbitrary tail that is ignored when forwarding.
$(
@section nodelegate
$($tail:tt)*
)*
}) => {
impl<$($param)*> $name for $self_wrap where $self_type: $name {
$(
$(
type $assoc_name = $self_type::$assoc_name;
)*
)*
$(
type $assoc_name_ext = $self_type::$assoc_name_ext;
)*
$(
$(
fn $method_name(self $(: $self_selftype)* $(,$marg: $marg_ty)*) $(-> $mret)? {
$self_map!(self).$method_name($($marg),*)
}
)*
)*
}
}
}

481
vendor/petgraph/src/visit/mod.rs vendored Normal file
View File

@@ -0,0 +1,481 @@
//! Graph traits and graph traversals.
//!
//! ### The `Into-` Traits
//!
//! Graph traits like [`IntoNeighbors`][in] create iterators and use the same
//! pattern that `IntoIterator` does: the trait takes a reference to a graph,
//! and produces an iterator. These traits are quite composable, but with the
//! limitation that they only use shared references to graphs.
//!
//! ### Graph Traversal
//!
//! [`Dfs`](struct.Dfs.html), [`Bfs`][bfs], [`DfsPostOrder`][dfspo] and
//! [`Topo`][topo] are basic visitors and they use “walker” methods: the
//! visitors don't hold the graph as borrowed during traversal, only for the
//! `.next()` call on the walker. They can be converted to iterators
//! through the [`Walker`][w] trait.
//!
//! There is also the callback based traversal [`depth_first_search`][dfs].
//!
//! [bfs]: struct.Bfs.html
//! [dfspo]: struct.DfsPostOrder.html
//! [topo]: struct.Topo.html
//! [dfs]: fn.depth_first_search.html
//! [w]: trait.Walker.html
//!
//! ### Other Graph Traits
//!
//! The traits are rather loosely coupled at the moment (which is intentional,
//! but will develop a bit), and there are traits missing that could be added.
//!
//! Not much is needed to be able to use the visitors on a graph. A graph
//! needs to define [`GraphBase`][gb], [`IntoNeighbors`][in] and
//! [`Visitable`][vis] as a minimum.
//!
//! [gb]: trait.GraphBase.html
//! [in]: trait.IntoNeighbors.html
//! [vis]: trait.Visitable.html
//!
//! ### Graph Trait Implementations
//!
//! The following table lists the traits that are implemented for each graph type:
//!
//! | | Graph | StableGraph | GraphMap | MatrixGraph | Csr | List |
//! | --------------------- | :---: | :---------: | :------: | :---------: | :---: | :---: |
//! | GraphBase | x | x | x | x | x | x |
//! | GraphProp | x | x | x | x | x | x |
//! | NodeCount | x | x | x | x | x | x |
//! | NodeIndexable | x | x | x | x | x | x |
//! | NodeCompactIndexable | x | | x | | x | x |
//! | EdgeCount | x | x | x | x | x | x |
//! | EdgeIndexable | x | x | x | | | |
//! | Data | x | x | x | x | x | x |
//! | IntoNodeIdentifiers | x | x | x | x | x | x |
//! | IntoNodeReferences | x | x | x | x | x | x |
//! | IntoEdgeReferences | x | x | x | x | x | x |
//! | IntoNeighbors | x | x | x | x | x | x |
//! | IntoNeighborsDirected | x | x | x | x | | |
//! | IntoEdges | x | x | x | x | x | x |
//! | IntoEdgesDirected | x | x | x | x | | |
//! | Visitable | x | x | x | x | x | x |
//! | GetAdjacencyMatrix | x | x | x | x | x | x |
// filter, reversed have their `mod` lines at the end,
// so that they can use the trait template macros
pub use self::filter::*;
pub use self::reversed::*;
pub use self::undirected_adaptor::*;
#[macro_use]
mod macros;
mod dfsvisit;
mod traversal;
pub use self::dfsvisit::*;
pub use self::traversal::*;
use fixedbitset::FixedBitSet;
use std::collections::HashSet;
use std::hash::{BuildHasher, Hash};
use super::EdgeType;
use crate::prelude::Direction;
use crate::graph::IndexType;
trait_template! {
/// Base graph trait: defines the associated node identifier and
/// edge identifier types.
pub trait GraphBase {
// FIXME: We can drop this escape/nodelegate stuff in Rust 1.18
@escape [type NodeId]
@escape [type EdgeId]
@section nodelegate
/// edge identifier
type EdgeId: Copy + PartialEq;
/// node identifier
type NodeId: Copy + PartialEq;
}
}
GraphBase! {delegate_impl []}
GraphBase! {delegate_impl [['a, G], G, &'a mut G, deref]}
/// A copyable reference to a graph.
pub trait GraphRef: Copy + GraphBase {}
impl<G> GraphRef for &G where G: GraphBase {}
trait_template! {
/// Access to the neighbors of each node
///
/// The neighbors are, depending on the graphs edge type:
///
/// - `Directed`: All targets of edges from `a`.
/// - `Undirected`: All other endpoints of edges connected to `a`.
pub trait IntoNeighbors : GraphRef {
@section type
type Neighbors: Iterator<Item=Self::NodeId>;
@section self
/// Return an iterator of the neighbors of node `a`.
fn neighbors(self, a: Self::NodeId) -> Self::Neighbors;
}
}
IntoNeighbors! {delegate_impl []}
trait_template! {
/// Access to the neighbors of each node, through incoming or outgoing edges.
///
/// Depending on the graphs edge type, the neighbors of a given directionality
/// are:
///
/// - `Directed`, `Outgoing`: All targets of edges from `a`.
/// - `Directed`, `Incoming`: All sources of edges to `a`.
/// - `Undirected`: All other endpoints of edges connected to `a`.
pub trait IntoNeighborsDirected : IntoNeighbors {
@section type
type NeighborsDirected: Iterator<Item=Self::NodeId>;
@section self
fn neighbors_directed(self, n: Self::NodeId, d: Direction)
-> Self::NeighborsDirected;
}
}
trait_template! {
/// Access to the edges of each node.
///
/// The edges are, depending on the graphs edge type:
///
/// - `Directed`: All edges from `a`.
/// - `Undirected`: All edges connected to `a`, with `a` being the source of each edge.
///
/// This is an extended version of the trait `IntoNeighbors`; the former
/// only iterates over the target node identifiers, while this trait
/// yields edge references (trait [`EdgeRef`][er]).
///
/// [er]: trait.EdgeRef.html
pub trait IntoEdges : IntoEdgeReferences + IntoNeighbors {
@section type
type Edges: Iterator<Item=Self::EdgeRef>;
@section self
fn edges(self, a: Self::NodeId) -> Self::Edges;
}
}
IntoEdges! {delegate_impl []}
trait_template! {
/// Access to all edges of each node, in the specified direction.
///
/// The edges are, depending on the direction and the graphs edge type:
///
///
/// - `Directed`, `Outgoing`: All edges from `a`.
/// - `Directed`, `Incoming`: All edges to `a`.
/// - `Undirected`, `Outgoing`: All edges connected to `a`, with `a` being the source of each edge.
/// - `Undirected`, `Incoming`: All edges connected to `a`, with `a` being the target of each edge.
///
/// This is an extended version of the trait `IntoNeighborsDirected`; the former
/// only iterates over the target node identifiers, while this trait
/// yields edge references (trait [`EdgeRef`][er]).
///
/// [er]: trait.EdgeRef.html
pub trait IntoEdgesDirected : IntoEdges + IntoNeighborsDirected {
@section type
type EdgesDirected: Iterator<Item=Self::EdgeRef>;
@section self
fn edges_directed(self, a: Self::NodeId, dir: Direction) -> Self::EdgesDirected;
}
}
IntoEdgesDirected! {delegate_impl []}
trait_template! {
/// Access to the sequence of the graphs `NodeId`s.
pub trait IntoNodeIdentifiers : GraphRef {
@section type
type NodeIdentifiers: Iterator<Item=Self::NodeId>;
@section self
fn node_identifiers(self) -> Self::NodeIdentifiers;
}
}
IntoNodeIdentifiers! {delegate_impl []}
IntoNeighborsDirected! {delegate_impl []}
trait_template! {
/// Define associated data for nodes and edges
pub trait Data : GraphBase {
@section type
type NodeWeight;
type EdgeWeight;
}
}
Data! {delegate_impl []}
Data! {delegate_impl [['a, G], G, &'a mut G, deref]}
/// An edge reference.
///
/// Edge references are used by traits `IntoEdges` and `IntoEdgeReferences`.
pub trait EdgeRef: Copy {
type NodeId;
type EdgeId;
type Weight;
/// The source node of the edge.
fn source(&self) -> Self::NodeId;
/// The target node of the edge.
fn target(&self) -> Self::NodeId;
/// A reference to the weight of the edge.
fn weight(&self) -> &Self::Weight;
/// The edges identifier.
fn id(&self) -> Self::EdgeId;
}
impl<N, E> EdgeRef for (N, N, &E)
where
N: Copy,
{
type NodeId = N;
type EdgeId = (N, N);
type Weight = E;
fn source(&self) -> N {
self.0
}
fn target(&self) -> N {
self.1
}
fn weight(&self) -> &E {
self.2
}
fn id(&self) -> (N, N) {
(self.0, self.1)
}
}
/// A node reference.
pub trait NodeRef: Copy {
type NodeId;
type Weight;
fn id(&self) -> Self::NodeId;
fn weight(&self) -> &Self::Weight;
}
trait_template! {
/// Access to the sequence of the graphs nodes
pub trait IntoNodeReferences : Data + IntoNodeIdentifiers {
@section type
type NodeRef: NodeRef<NodeId=Self::NodeId, Weight=Self::NodeWeight>;
type NodeReferences: Iterator<Item=Self::NodeRef>;
@section self
fn node_references(self) -> Self::NodeReferences;
}
}
IntoNodeReferences! {delegate_impl []}
impl<Id> NodeRef for (Id, ())
where
Id: Copy,
{
type NodeId = Id;
type Weight = ();
fn id(&self) -> Self::NodeId {
self.0
}
fn weight(&self) -> &Self::Weight {
static DUMMY: () = ();
&DUMMY
}
}
impl<Id, W> NodeRef for (Id, &W)
where
Id: Copy,
{
type NodeId = Id;
type Weight = W;
fn id(&self) -> Self::NodeId {
self.0
}
fn weight(&self) -> &Self::Weight {
self.1
}
}
trait_template! {
/// Access to the sequence of the graphs edges
pub trait IntoEdgeReferences : Data + GraphRef {
@section type
type EdgeRef: EdgeRef<NodeId=Self::NodeId, EdgeId=Self::EdgeId,
Weight=Self::EdgeWeight>;
type EdgeReferences: Iterator<Item=Self::EdgeRef>;
@section self
fn edge_references(self) -> Self::EdgeReferences;
}
}
IntoEdgeReferences! {delegate_impl [] }
trait_template! {
/// Edge kind property (directed or undirected edges)
pub trait GraphProp : GraphBase {
@section type
/// The kind of edges in the graph.
type EdgeType: EdgeType;
@section nodelegate
fn is_directed(&self) -> bool {
<Self::EdgeType>::is_directed()
}
}
}
GraphProp! {delegate_impl []}
trait_template! {
/// The graphs `NodeId`s map to indices
#[allow(clippy::needless_arbitrary_self_type)]
pub trait NodeIndexable : GraphBase {
@section self
/// Return an upper bound of the node indices in the graph
/// (suitable for the size of a bitmap).
fn node_bound(self: &Self) -> usize;
/// Convert `a` to an integer index.
fn to_index(self: &Self, a: Self::NodeId) -> usize;
/// Convert `i` to a node index. `i` must be a valid value in the graph.
fn from_index(self: &Self, i: usize) -> Self::NodeId;
}
}
NodeIndexable! {delegate_impl []}
trait_template! {
/// The graphs `NodeId`s map to indices
#[allow(clippy::needless_arbitrary_self_type)]
pub trait EdgeIndexable : GraphBase {
@section self
/// Return an upper bound of the edge indices in the graph
/// (suitable for the size of a bitmap).
fn edge_bound(self: &Self) -> usize;
/// Convert `a` to an integer index.
fn to_index(self: &Self, a: Self::EdgeId) -> usize;
/// Convert `i` to an edge index. `i` must be a valid value in the graph.
fn from_index(self: &Self, i: usize) -> Self::EdgeId;
}
}
EdgeIndexable! {delegate_impl []}
trait_template! {
/// A graph with a known node count.
#[allow(clippy::needless_arbitrary_self_type)]
pub trait NodeCount : GraphBase {
@section self
fn node_count(self: &Self) -> usize;
}
}
NodeCount! {delegate_impl []}
trait_template! {
/// The graphs `NodeId`s map to indices, in a range without holes.
///
/// The graph's node identifiers correspond to exactly the indices
/// `0..self.node_bound()`.
pub trait NodeCompactIndexable : NodeIndexable + NodeCount { }
}
NodeCompactIndexable! {delegate_impl []}
/// A mapping for storing the visited status for NodeId `N`.
pub trait VisitMap<N> {
/// Mark `a` as visited.
///
/// Return **true** if this is the first visit, false otherwise.
fn visit(&mut self, a: N) -> bool;
/// Return whether `a` has been visited before.
fn is_visited(&self, a: &N) -> bool;
}
impl<Ix> VisitMap<Ix> for FixedBitSet
where
Ix: IndexType,
{
fn visit(&mut self, x: Ix) -> bool {
!self.put(x.index())
}
fn is_visited(&self, x: &Ix) -> bool {
self.contains(x.index())
}
}
impl<N, S> VisitMap<N> for HashSet<N, S>
where
N: Hash + Eq,
S: BuildHasher,
{
fn visit(&mut self, x: N) -> bool {
self.insert(x)
}
fn is_visited(&self, x: &N) -> bool {
self.contains(x)
}
}
trait_template! {
/// A graph that can create a map that tracks the visited status of its nodes.
#[allow(clippy::needless_arbitrary_self_type)]
pub trait Visitable : GraphBase {
@section type
/// The associated map type
type Map: VisitMap<Self::NodeId>;
@section self
/// Create a new visitor map
fn visit_map(self: &Self) -> Self::Map;
/// Reset the visitor map (and resize to new size of graph if needed)
fn reset_map(self: &Self, map: &mut Self::Map);
}
}
Visitable! {delegate_impl []}
trait_template! {
/// Create or access the adjacency matrix of a graph.
///
/// The implementor can either create an adjacency matrix, or it can return
/// a placeholder if it has the needed representation internally.
#[allow(clippy::needless_arbitrary_self_type)]
pub trait GetAdjacencyMatrix : GraphBase {
@section type
/// The associated adjacency matrix type
type AdjMatrix;
@section self
/// Create the adjacency matrix
fn adjacency_matrix(self: &Self) -> Self::AdjMatrix;
/// Return true if there is an edge from `a` to `b`, false otherwise.
///
/// Computes in O(1) time.
fn is_adjacent(self: &Self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool;
}
}
GetAdjacencyMatrix! {delegate_impl []}
trait_template! {
/// A graph with a known edge count.
#[allow(clippy::needless_arbitrary_self_type)]
pub trait EdgeCount : GraphBase {
@section self
/// Return the number of edges in the graph.
fn edge_count(self: &Self) -> usize;
}
}
EdgeCount! {delegate_impl []}
mod filter;
mod reversed;
mod undirected_adaptor;

184
vendor/petgraph/src/visit/reversed.rs vendored Normal file
View File

@@ -0,0 +1,184 @@
use crate::{Direction, Incoming};
use crate::visit::{
Data, EdgeCount, EdgeIndexable, EdgeRef, GetAdjacencyMatrix, GraphBase, GraphProp, GraphRef,
IntoEdgeReferences, IntoEdges, IntoEdgesDirected, IntoNeighbors, IntoNeighborsDirected,
IntoNodeIdentifiers, IntoNodeReferences, NodeCompactIndexable, NodeCount, NodeIndexable,
Visitable,
};
/// An edge-reversing graph adaptor.
///
/// All edges have the opposite direction with `Reversed`.
#[derive(Copy, Clone, Debug)]
pub struct Reversed<G>(pub G);
impl<G: GraphBase> GraphBase for Reversed<G> {
type NodeId = G::NodeId;
type EdgeId = G::EdgeId;
}
impl<G: GraphRef> GraphRef for Reversed<G> {}
Data! {delegate_impl [[G], G, Reversed<G>, access0]}
impl<G> IntoNeighbors for Reversed<G>
where
G: IntoNeighborsDirected,
{
type Neighbors = G::NeighborsDirected;
fn neighbors(self, n: G::NodeId) -> G::NeighborsDirected {
self.0.neighbors_directed(n, Incoming)
}
}
impl<G> IntoNeighborsDirected for Reversed<G>
where
G: IntoNeighborsDirected,
{
type NeighborsDirected = G::NeighborsDirected;
fn neighbors_directed(self, n: G::NodeId, d: Direction) -> G::NeighborsDirected {
self.0.neighbors_directed(n, d.opposite())
}
}
impl<G> IntoEdges for Reversed<G>
where
G: IntoEdgesDirected,
{
type Edges = ReversedEdges<G::EdgesDirected>;
fn edges(self, a: Self::NodeId) -> Self::Edges {
ReversedEdges {
iter: self.0.edges_directed(a, Incoming),
}
}
}
impl<G> IntoEdgesDirected for Reversed<G>
where
G: IntoEdgesDirected,
{
type EdgesDirected = ReversedEdges<G::EdgesDirected>;
fn edges_directed(self, a: Self::NodeId, dir: Direction) -> Self::Edges {
ReversedEdges {
iter: self.0.edges_directed(a, dir.opposite()),
}
}
}
impl<G: Visitable> Visitable for Reversed<G> {
type Map = G::Map;
fn visit_map(&self) -> G::Map {
self.0.visit_map()
}
fn reset_map(&self, map: &mut Self::Map) {
self.0.reset_map(map);
}
}
/// A reversed edges iterator.
#[derive(Debug, Clone)]
pub struct ReversedEdges<I> {
iter: I,
}
impl<I> Iterator for ReversedEdges<I>
where
I: Iterator,
I::Item: EdgeRef,
{
type Item = ReversedEdgeReference<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(ReversedEdgeReference)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
/// A reversed edge reference
#[derive(Copy, Clone, Debug)]
pub struct ReversedEdgeReference<R>(R);
impl<R> ReversedEdgeReference<R> {
/// Return the original, unreversed edge reference.
pub fn as_unreversed(&self) -> &R {
&self.0
}
/// Consume `self` and return the original, unreversed edge reference.
pub fn into_unreversed(self) -> R {
self.0
}
}
/// An edge reference
impl<R> EdgeRef for ReversedEdgeReference<R>
where
R: EdgeRef,
{
type NodeId = R::NodeId;
type EdgeId = R::EdgeId;
type Weight = R::Weight;
fn source(&self) -> Self::NodeId {
self.0.target()
}
fn target(&self) -> Self::NodeId {
self.0.source()
}
fn weight(&self) -> &Self::Weight {
self.0.weight()
}
fn id(&self) -> Self::EdgeId {
self.0.id()
}
}
impl<G> IntoEdgeReferences for Reversed<G>
where
G: IntoEdgeReferences,
{
type EdgeRef = ReversedEdgeReference<G::EdgeRef>;
type EdgeReferences = ReversedEdgeReferences<G::EdgeReferences>;
fn edge_references(self) -> Self::EdgeReferences {
ReversedEdgeReferences {
iter: self.0.edge_references(),
}
}
}
/// A reversed edge references iterator.
#[derive(Debug, Clone)]
pub struct ReversedEdgeReferences<I> {
iter: I,
}
impl<I> Iterator for ReversedEdgeReferences<I>
where
I: Iterator,
I::Item: EdgeRef,
{
type Item = ReversedEdgeReference<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(ReversedEdgeReference)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
macro_rules! access0 {
($e:expr) => {
$e.0
};
}
NodeIndexable! {delegate_impl [[G], G, Reversed<G>, access0]}
NodeCompactIndexable! {delegate_impl [[G], G, Reversed<G>, access0]}
IntoNodeIdentifiers! {delegate_impl [[G], G, Reversed<G>, access0]}
IntoNodeReferences! {delegate_impl [[G], G, Reversed<G>, access0]}
GraphProp! {delegate_impl [[G], G, Reversed<G>, access0]}
NodeCount! {delegate_impl [[G], G, Reversed<G>, access0]}
EdgeCount! {delegate_impl [[G], G, Reversed<G>, access0]}
EdgeIndexable! {delegate_impl [[G], G, Reversed<G>, access0]}
GetAdjacencyMatrix! {delegate_impl [[G], G, Reversed<G>, access0]}

536
vendor/petgraph/src/visit/traversal.rs vendored Normal file
View File

@@ -0,0 +1,536 @@
use super::{GraphRef, IntoNodeIdentifiers, Reversed};
use super::{IntoNeighbors, IntoNeighborsDirected, VisitMap, Visitable};
use crate::Incoming;
use std::collections::VecDeque;
/// Visit nodes of a graph in a depth-first-search (DFS) emitting nodes in
/// preorder (when they are first discovered).
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
///
/// `Dfs` is not recursive.
///
/// `Dfs` does not itself borrow the graph, and because of this you can run
/// a traversal over a graph while still retaining mutable access to it, if you
/// use it like the following example:
///
/// ```
/// use petgraph::Graph;
/// use petgraph::visit::Dfs;
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut dfs = Dfs::new(&graph, a);
/// while let Some(nx) = dfs.next(&graph) {
/// // we can access `graph` mutably here still
/// graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone, Debug)]
pub struct Dfs<N, VM> {
/// The stack of nodes to visit
pub stack: Vec<N>,
/// The map of discovered nodes
pub discovered: VM,
}
impl<N, VM> Default for Dfs<N, VM>
where
VM: Default,
{
fn default() -> Self {
Dfs {
stack: Vec::new(),
discovered: VM::default(),
}
}
}
impl<N, VM> Dfs<N, VM>
where
N: Copy + PartialEq,
VM: VisitMap<N>,
{
/// Create a new **Dfs**, using the graph's visitor map, and put **start**
/// in the stack of nodes to visit.
pub fn new<G>(graph: G, start: N) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
let mut dfs = Dfs::empty(graph);
dfs.move_to(start);
dfs
}
/// Create a `Dfs` from a vector and a visit map
pub fn from_parts(stack: Vec<N>, discovered: VM) -> Self {
Dfs { stack, discovered }
}
/// Clear the visit state
pub fn reset<G>(&mut self, graph: G)
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
graph.reset_map(&mut self.discovered);
self.stack.clear();
}
/// Create a new **Dfs** using the graph's visitor map, and no stack.
pub fn empty<G>(graph: G) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
Dfs {
stack: Vec::new(),
discovered: graph.visit_map(),
}
}
/// Keep the discovered map, but clear the visit stack and restart
/// the dfs from a particular node.
pub fn move_to(&mut self, start: N) {
self.stack.clear();
self.stack.push(start);
}
/// Return the next node in the dfs, or **None** if the traversal is done.
pub fn next<G>(&mut self, graph: G) -> Option<N>
where
G: IntoNeighbors<NodeId = N>,
{
while let Some(node) = self.stack.pop() {
if self.discovered.visit(node) {
for succ in graph.neighbors(node) {
if !self.discovered.is_visited(&succ) {
self.stack.push(succ);
}
}
return Some(node);
}
}
None
}
}
/// Visit nodes in a depth-first-search (DFS) emitting nodes in postorder
/// (each node after all its descendants have been emitted).
///
/// `DfsPostOrder` is not recursive.
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
#[derive(Clone, Debug)]
pub struct DfsPostOrder<N, VM> {
/// The stack of nodes to visit
pub stack: Vec<N>,
/// The map of discovered nodes
pub discovered: VM,
/// The map of finished nodes
pub finished: VM,
}
impl<N, VM> Default for DfsPostOrder<N, VM>
where
VM: Default,
{
fn default() -> Self {
DfsPostOrder {
stack: Vec::new(),
discovered: VM::default(),
finished: VM::default(),
}
}
}
impl<N, VM> DfsPostOrder<N, VM>
where
N: Copy + PartialEq,
VM: VisitMap<N>,
{
/// Create a new `DfsPostOrder` using the graph's visitor map, and put
/// `start` in the stack of nodes to visit.
pub fn new<G>(graph: G, start: N) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
let mut dfs = Self::empty(graph);
dfs.move_to(start);
dfs
}
/// Create a new `DfsPostOrder` using the graph's visitor map, and no stack.
pub fn empty<G>(graph: G) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
DfsPostOrder {
stack: Vec::new(),
discovered: graph.visit_map(),
finished: graph.visit_map(),
}
}
/// Clear the visit state
pub fn reset<G>(&mut self, graph: G)
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
graph.reset_map(&mut self.discovered);
graph.reset_map(&mut self.finished);
self.stack.clear();
}
/// Keep the discovered and finished map, but clear the visit stack and restart
/// the dfs from a particular node.
pub fn move_to(&mut self, start: N) {
self.stack.clear();
self.stack.push(start);
}
/// Return the next node in the traversal, or `None` if the traversal is done.
pub fn next<G>(&mut self, graph: G) -> Option<N>
where
G: IntoNeighbors<NodeId = N>,
{
while let Some(&nx) = self.stack.last() {
if self.discovered.visit(nx) {
// First time visiting `nx`: Push neighbors, don't pop `nx`
for succ in graph.neighbors(nx) {
if !self.discovered.is_visited(&succ) {
self.stack.push(succ);
}
}
} else {
self.stack.pop();
if self.finished.visit(nx) {
// Second time: All reachable nodes must have been finished
return Some(nx);
}
}
}
None
}
}
/// A breadth first search (BFS) of a graph.
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
///
/// `Bfs` is not recursive.
///
/// `Bfs` does not itself borrow the graph, and because of this you can run
/// a traversal over a graph while still retaining mutable access to it, if you
/// use it like the following example:
///
/// ```
/// use petgraph::Graph;
/// use petgraph::visit::Bfs;
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut bfs = Bfs::new(&graph, a);
/// while let Some(nx) = bfs.next(&graph) {
/// // we can access `graph` mutably here still
/// graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone)]
pub struct Bfs<N, VM> {
/// The queue of nodes to visit
pub stack: VecDeque<N>,
/// The map of discovered nodes
pub discovered: VM,
}
impl<N, VM> Default for Bfs<N, VM>
where
VM: Default,
{
fn default() -> Self {
Bfs {
stack: VecDeque::new(),
discovered: VM::default(),
}
}
}
impl<N, VM> Bfs<N, VM>
where
N: Copy + PartialEq,
VM: VisitMap<N>,
{
/// Create a new **Bfs**, using the graph's visitor map, and put **start**
/// in the stack of nodes to visit.
pub fn new<G>(graph: G, start: N) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
let mut discovered = graph.visit_map();
discovered.visit(start);
let mut stack = VecDeque::new();
stack.push_front(start);
Bfs { stack, discovered }
}
/// Return the next node in the bfs, or **None** if the traversal is done.
pub fn next<G>(&mut self, graph: G) -> Option<N>
where
G: IntoNeighbors<NodeId = N>,
{
if let Some(node) = self.stack.pop_front() {
for succ in graph.neighbors(node) {
if self.discovered.visit(succ) {
self.stack.push_back(succ);
}
}
return Some(node);
}
None
}
}
/// A topological order traversal for a graph.
///
/// **Note** that `Topo` only visits nodes that are not part of cycles,
/// i.e. nodes in a true DAG. Use other visitors like `DfsPostOrder` or
/// algorithms like kosaraju_scc to handle graphs with possible cycles.
#[derive(Clone)]
pub struct Topo<N, VM> {
tovisit: Vec<N>,
ordered: VM,
}
impl<N, VM> Default for Topo<N, VM>
where
VM: Default,
{
fn default() -> Self {
Topo {
tovisit: Vec::new(),
ordered: VM::default(),
}
}
}
impl<N, VM> Topo<N, VM>
where
N: Copy + PartialEq,
VM: VisitMap<N>,
{
/// Create a new `Topo`, using the graph's visitor map, and put all
/// initial nodes in the to visit list.
pub fn new<G>(graph: G) -> Self
where
G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
{
let mut topo = Self::empty(graph);
topo.extend_with_initials(graph);
topo
}
/// Create a new `Topo` with initial nodes.
///
/// Nodes with incoming edges are ignored.
pub fn with_initials<G, I>(graph: G, initials: I) -> Self
where
G: IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
I: IntoIterator<Item = N>,
{
Topo {
tovisit: initials
.into_iter()
.filter(|&n| graph.neighbors_directed(n, Incoming).next().is_none())
.collect(),
ordered: graph.visit_map(),
}
}
fn extend_with_initials<G>(&mut self, g: G)
where
G: IntoNodeIdentifiers + IntoNeighborsDirected<NodeId = N>,
{
// find all initial nodes (nodes without incoming edges)
self.tovisit.extend(
g.node_identifiers()
.filter(move |&a| g.neighbors_directed(a, Incoming).next().is_none()),
);
}
/* Private until it has a use */
/// Create a new `Topo`, using the graph's visitor map with *no* starting
/// index specified.
fn empty<G>(graph: G) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
Topo {
ordered: graph.visit_map(),
tovisit: Vec::new(),
}
}
/// Clear visited state, and put all initial nodes in the to visit list.
pub fn reset<G>(&mut self, graph: G)
where
G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
{
graph.reset_map(&mut self.ordered);
self.tovisit.clear();
self.extend_with_initials(graph);
}
/// Return the next node in the current topological order traversal, or
/// `None` if the traversal is at the end.
///
/// *Note:* The graph may not have a complete topological order, and the only
/// way to know is to run the whole traversal and make sure it visits every node.
pub fn next<G>(&mut self, g: G) -> Option<N>
where
G: IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
{
// Take an unvisited element and find which of its neighbors are next
while let Some(nix) = self.tovisit.pop() {
if self.ordered.is_visited(&nix) {
continue;
}
self.ordered.visit(nix);
for neigh in g.neighbors(nix) {
// Look at each neighbor, and those that only have incoming edges
// from the already ordered list, they are the next to visit.
if Reversed(g)
.neighbors(neigh)
.all(|b| self.ordered.is_visited(&b))
{
self.tovisit.push(neigh);
}
}
return Some(nix);
}
None
}
}
/// A walker is a traversal state, but where part of the traversal
/// information is supplied manually to each next call.
///
/// This for example allows graph traversals that don't hold a borrow of the
/// graph they are traversing.
pub trait Walker<Context> {
type Item;
/// Advance to the next item
fn walk_next(&mut self, context: Context) -> Option<Self::Item>;
/// Create an iterator out of the walker and given `context`.
fn iter(self, context: Context) -> WalkerIter<Self, Context>
where
Self: Sized,
Context: Clone,
{
WalkerIter {
walker: self,
context,
}
}
}
/// A walker and its context wrapped into an iterator.
#[derive(Clone, Debug)]
pub struct WalkerIter<W, C> {
walker: W,
context: C,
}
impl<W, C> WalkerIter<W, C>
where
W: Walker<C>,
C: Clone,
{
pub fn context(&self) -> C {
self.context.clone()
}
pub fn inner_ref(&self) -> &W {
&self.walker
}
pub fn inner_mut(&mut self) -> &mut W {
&mut self.walker
}
}
impl<W, C> Iterator for WalkerIter<W, C>
where
W: Walker<C>,
C: Clone,
{
type Item = W::Item;
fn next(&mut self) -> Option<Self::Item> {
self.walker.walk_next(self.context.clone())
}
}
impl<C, W: ?Sized> Walker<C> for &mut W
where
W: Walker<C>,
{
type Item = W::Item;
fn walk_next(&mut self, context: C) -> Option<Self::Item> {
(**self).walk_next(context)
}
}
impl<G> Walker<G> for Dfs<G::NodeId, G::Map>
where
G: IntoNeighbors + Visitable,
{
type Item = G::NodeId;
fn walk_next(&mut self, context: G) -> Option<Self::Item> {
self.next(context)
}
}
impl<G> Walker<G> for DfsPostOrder<G::NodeId, G::Map>
where
G: IntoNeighbors + Visitable,
{
type Item = G::NodeId;
fn walk_next(&mut self, context: G) -> Option<Self::Item> {
self.next(context)
}
}
impl<G> Walker<G> for Bfs<G::NodeId, G::Map>
where
G: IntoNeighbors + Visitable,
{
type Item = G::NodeId;
fn walk_next(&mut self, context: G) -> Option<Self::Item> {
self.next(context)
}
}
impl<G> Walker<G> for Topo<G::NodeId, G::Map>
where
G: IntoNeighborsDirected + Visitable,
{
type Item = G::NodeId;
fn walk_next(&mut self, context: G) -> Option<Self::Item> {
self.next(context)
}
}

View File

@@ -0,0 +1,111 @@
use crate::visit::{
Data, GraphBase, GraphProp, GraphRef, IntoEdgeReferences, IntoEdges, IntoEdgesDirected,
IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, IntoNodeReferences,
NodeCompactIndexable, NodeCount, NodeIndexable, Visitable,
};
use crate::Direction;
/// An edge direction removing graph adaptor.
#[derive(Copy, Clone, Debug)]
pub struct UndirectedAdaptor<G>(pub G);
impl<G: GraphRef> GraphRef for UndirectedAdaptor<G> {}
impl<G> IntoNeighbors for UndirectedAdaptor<G>
where
G: IntoNeighborsDirected,
{
type Neighbors = std::iter::Chain<G::NeighborsDirected, G::NeighborsDirected>;
fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
self.0
.neighbors_directed(n, Direction::Incoming)
.chain(self.0.neighbors_directed(n, Direction::Outgoing))
}
}
impl<G> IntoEdges for UndirectedAdaptor<G>
where
G: IntoEdgesDirected,
{
type Edges = std::iter::Chain<G::EdgesDirected, G::EdgesDirected>;
fn edges(self, a: Self::NodeId) -> Self::Edges {
self.0
.edges_directed(a, Direction::Incoming)
.chain(self.0.edges_directed(a, Direction::Outgoing))
}
}
impl<G> GraphProp for UndirectedAdaptor<G>
where
G: GraphBase,
{
type EdgeType = crate::Undirected;
fn is_directed(&self) -> bool {
false
}
}
macro_rules! access0 {
($e:expr) => {
$e.0
};
}
GraphBase! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
Data! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
IntoEdgeReferences! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
Visitable! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
NodeIndexable! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
NodeCompactIndexable! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
IntoNodeIdentifiers! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
IntoNodeReferences! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
NodeCount! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
#[cfg(test)]
mod tests {
use super::*;
use crate::graph::{DiGraph, Graph};
use crate::visit::Dfs;
static LINEAR_EDGES: [(u32, u32); 5] = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)];
#[test]
pub fn test_is_reachable() {
// create a linear digraph, choose a node in the centre and check all nodes are visited
// by a dfs
let graph = DiGraph::<(), ()>::from_edges(&LINEAR_EDGES);
let mut nodes = graph.node_identifiers().collect::<Vec<_>>();
nodes.sort();
let graph = UndirectedAdaptor(&graph);
use crate::visit::Walker;
let mut visited_nodes: Vec<_> = Dfs::new(&graph, nodes[2]).iter(&graph).collect();
visited_nodes.sort();
assert_eq!(visited_nodes, nodes);
}
#[test]
pub fn test_neighbors_count() {
{
let graph = Graph::<(), ()>::from_edges(&LINEAR_EDGES);
let graph = UndirectedAdaptor(&graph);
let mut nodes = graph.node_identifiers().collect::<Vec<_>>();
nodes.sort();
assert_eq!(graph.neighbors(nodes[1]).count(), 2);
}
{
let graph = Graph::<(), ()>::from_edges(&LINEAR_EDGES);
let graph = UndirectedAdaptor(&graph);
let mut nodes = graph.node_identifiers().collect::<Vec<_>>();
nodes.sort();
assert_eq!(graph.neighbors(nodes[1]).count(), 2);
}
}
}