pub mod articulation_points;
pub mod astar;
pub mod bellman_ford;
pub mod bridges;
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 johnson;
pub mod k_shortest_path;
pub mod matching;
pub mod maximal_cliques;
pub mod maximum_flow;
pub mod min_spanning_tree;
pub mod page_rank;
pub mod scc;
pub mod simple_paths;
pub mod spfa;
#[cfg(feature = "stable_graph")]
pub mod steiner_tree;
pub mod tred;
use alloc::{vec, vec::Vec};
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 bridges::bridges;
pub use coloring::dsatur_coloring;
pub use dijkstra::{bidirectional_dijkstra, dijkstra};
pub use feedback_arc_set::greedy_feedback_arc_set;
pub use floyd_warshall::floyd_warshall;
pub use isomorphism::{
is_isomorphic, is_isomorphic_matching, is_isomorphic_subgraph, is_isomorphic_subgraph_matching,
subgraph_isomorphisms_iter,
};
pub use johnson::johnson;
pub use k_shortest_path::k_shortest_path;
pub use matching::{greedy_matching, maximum_matching, Matching};
pub use maximal_cliques::maximal_cliques;
pub use maximum_flow::{dinics, ford_fulkerson};
pub use min_spanning_tree::{min_spanning_tree, min_spanning_tree_prim};
pub use page_rank::page_rank;
#[allow(deprecated)]
pub use scc::scc;
pub use scc::{
kosaraju_scc::kosaraju_scc,
tarjan_scc::{tarjan_scc, TarjanScc},
};
pub use simple_paths::{all_simple_paths, all_simple_paths_multi};
pub use spfa::spfa;
#[cfg(feature = "stable_graph")]
pub use steiner_tree::steiner_tree;
#[cfg(feature = "rayon")]
pub use johnson::parallel_johnson;
pub fn connected_components<G>(g: G) -> usize
where
G: NodeCompactIndexable + IntoEdgeReferences,
{
let mut node_sets = UnionFind::new(g.node_bound());
for edge in g.edge_references() {
let (a, b) = (edge.source(), edge.target());
node_sets.union(g.to_index(a), g.to_index(b));
}
let mut labels = node_sets.into_labeling();
labels.sort_unstable();
labels.dedup();
labels.len()
}
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());
if !edge_sets.union(g.to_index(a), g.to_index(b)) {
return true;
}
}
false
}
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,
{
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) {
for succ in g.neighbors(nx) {
if succ == nx {
return Err(Cycle(nx));
}
if !dfs.discovered.is_visited(&succ) {
dfs.stack.push(succ);
}
}
} else {
dfs.stack.pop();
if finished.visit(nx) {
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)
})
}
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>;
#[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(),
},
}
}
}
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)
}
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)
})
}
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());
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;
}
}
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
}
#[derive(Clone, Debug, PartialEq)]
pub struct Cycle<N>(pub(crate) N);
impl<N> Cycle<N> {
pub fn node_id(&self) -> N
where
N: Copy,
{
self.0
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct NegativeCycle(pub ());
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 + core::fmt::Debug,
VM: VisitMap<N>,
{
let mut red = g.visit_map();
red.visit(start);
let mut blue = g.visit_map();
let mut stack = ::alloc::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 {
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 core::fmt::Debug;
use core::ops::Add;
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 {}
pub trait FloatMeasure: Measure + Copy {
fn zero() -> Self;
fn infinite() -> Self;
fn from_f32(val: f32) -> Self;
fn from_f64(val: f64) -> Self;
}
impl FloatMeasure for f32 {
fn zero() -> Self {
0.
}
fn infinite() -> Self {
1. / 0.
}
fn from_f32(val: f32) -> Self {
val
}
fn from_f64(val: f64) -> Self {
val as f32
}
}
impl FloatMeasure for f64 {
fn zero() -> Self {
0.
}
fn infinite() -> Self {
1. / 0.
}
fn from_f32(val: f32) -> Self {
val as f64
}
fn from_f64(val: f64) -> Self {
val
}
}
pub trait BoundedMeasure: Measure + core::ops::Sub<Self, Output = Self> {
fn min() -> Self;
fn max() -> Self;
fn overflowing_add(self, rhs: Self) -> (Self, bool);
fn from_f32(val: f32) -> Self;
fn from_f64(val: f64) -> Self;
}
macro_rules! impl_bounded_measure_integer(
( $( $t:ident ),* ) => {
$(
impl BoundedMeasure for $t {
fn min() -> Self {
$t::MIN
}
fn max() -> Self {
$t::MAX
}
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
self.overflowing_add(rhs)
}
fn from_f32(val: f32) -> Self {
val as $t
}
fn from_f64(val: f64) -> Self {
val as $t
}
}
)*
};
);
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 {
$t::MIN
}
fn max() -> Self {
$t::MAX
}
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
let overflow = self > Self::default() && rhs > Self::default() && self > $t::MAX - rhs;
let underflow = !overflow && self < Self::default() && rhs < Self::default() && self < $t::MIN - rhs;
(self + rhs, overflow || underflow)
}
fn from_f32(val: f32) -> Self {
val as $t
}
fn from_f64(val: f64) -> Self {
val as $t
}
}
)*
};
);
impl_bounded_measure_float!(f32, f64);
pub trait UnitMeasure:
Measure
+ core::ops::Sub<Self, Output = Self>
+ core::ops::Mul<Self, Output = Self>
+ core::ops::Div<Self, Output = Self>
+ core::iter::Sum
{
fn zero() -> Self;
fn one() -> Self;
fn from_usize(nb: usize) -> Self;
fn default_tol() -> Self;
fn from_f32(val: f32) -> Self;
fn from_f64(val: f64) -> 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
}
fn from_f32(val: f32) -> Self {
val as $t
}
fn from_f64(val: f64) -> Self {
val as $t
}
}
)*
}
);
impl_unit_measure!(f32, f64);
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 {
$t::MAX
}
}
)*
}
);
impl_positive_measure!(u8, u16, u32, u64, u128, usize, f32, f64);