summaryrefslogtreecommitdiff
path: root/vendor/petgraph-0.6.5/src/algo/matching.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/petgraph-0.6.5/src/algo/matching.rs')
-rw-r--r--vendor/petgraph-0.6.5/src/algo/matching.rs611
1 files changed, 0 insertions, 611 deletions
diff --git a/vendor/petgraph-0.6.5/src/algo/matching.rs b/vendor/petgraph-0.6.5/src/algo/matching.rs
deleted file mode 100644
index ff9146fc..00000000
--- a/vendor/petgraph-0.6.5/src/algo/matching.rs
+++ /dev/null
@@ -1,611 +0,0 @@
-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;
- fn node_bound_with_dummy(&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 node_bound_with_dummy(&self) -> usize {
- self.node_bound() + 1
- }
-
- 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");
- }
-}