Files
grapherity/src/algorithms.rs
T

317 lines
8.1 KiB
Rust

use std::cmp::Ordering;
use std::collections::{BinaryHeap, VecDeque};
use crate::maps::VertexMap;
use crate::traits::{GraphTopology, IncidenceCursor};
#[derive(PartialEq, Eq)]
struct DistanceOrderedVertex<V> {
distance: u32,
vertex: V,
}
impl<V: Eq> PartialOrd for DistanceOrderedVertex<V> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<V: Eq> Ord for DistanceOrderedVertex<V> {
fn cmp(&self, other: &Self) -> Ordering {
other.distance.cmp(&self.distance)
}
}
pub struct DijkstraResult<V: Copy> {
pub distances: VertexMap<V, Option<u32>>,
pub predecessors: VertexMap<V, Option<V>>,
}
// TODO: Generalize the return type of the weight function.
pub fn dijkstra<G, W>(graph: &G, source: G::Vertex, weight: W) -> DijkstraResult<G::Vertex>
where
G: GraphTopology,
W: Fn(G::Edge) -> u32,
{
let mut predecessors = graph.vertex_map(None);
let distances = dijkstra_impl(graph, source, weight, |adjacent, predecessor| {
predecessors[adjacent] = Some(predecessor);
});
DijkstraResult {
distances,
predecessors,
}
}
pub fn dijkstra_unweighted<G>(graph: &G, source: G::Vertex) -> DijkstraResult<G::Vertex>
where
G: GraphTopology,
{
dijkstra(graph, source, |_| 1)
}
pub fn dijkstra_distances<G, W>(
graph: &G,
source: G::Vertex,
weight: W,
) -> VertexMap<G::Vertex, Option<u32>>
where
G: GraphTopology,
W: Fn(G::Edge) -> u32,
{
dijkstra_impl(graph, source, weight, |_, _| {})
}
pub fn dijkstra_distances_unweighted<G>(
graph: &G,
source: G::Vertex,
) -> VertexMap<G::Vertex, Option<u32>>
where
G: GraphTopology,
{
dijkstra_distances(graph, source, |_| 1)
}
fn dijkstra_impl<G, W, F>(
graph: &G,
source: G::Vertex,
weight: W,
mut on_relax: F,
) -> VertexMap<G::Vertex, Option<u32>>
where
G: GraphTopology,
W: Fn(G::Edge) -> u32,
F: FnMut(G::Vertex, G::Vertex),
{
let mut distances = graph.vertex_map(None);
let mut heap = BinaryHeap::new();
distances[source] = Some(0);
heap.push(DistanceOrderedVertex {
vertex: source,
distance: 0,
});
while let Some(v) = heap.pop() {
for incidence in graph.incidences(v.vertex) {
let new_distance = distances[v.vertex].unwrap() + weight(incidence.1);
if match distances[incidence.0] {
None => true,
Some(old_distance) if old_distance > new_distance => true,
_ => false,
} {
distances[incidence.0] = Some(new_distance);
on_relax(incidence.0, v.vertex);
heap.push(DistanceOrderedVertex {
vertex: incidence.0,
distance: new_distance,
});
}
}
}
distances
}
pub struct BfsResult<V: Copy> {
pub distances: VertexMap<V, Option<u32>>,
pub predecessors: VertexMap<V, Option<V>>,
}
pub fn bfs<G>(graph: &G, source: G::Vertex) -> BfsResult<G::Vertex>
where
G: GraphTopology,
{
let mut predecessors = graph.vertex_map(None);
let (distances, _) = bfs_impl(graph, source, |neighbor, predecessor| {
predecessors[neighbor] = Some(predecessor);
true
});
BfsResult {
distances,
predecessors,
}
}
pub fn bfs_distances<G>(graph: &G, source: G::Vertex) -> VertexMap<G::Vertex, Option<u32>>
where
G: GraphTopology,
{
bfs_impl(graph, source, |_, _| true).0
}
pub fn bfs_find<G>(graph: &G, source: G::Vertex, target: G::Vertex) -> Option<u32>
where
G: GraphTopology,
{
bfs_find_where(graph, source, |v| v == target).map(|(_, distance)| distance)
}
pub fn bfs_find_where<G, P>(graph: &G, source: G::Vertex, predicate: P) -> Option<(G::Vertex, u32)>
where
G: GraphTopology,
P: Fn(G::Vertex) -> bool,
{
if predicate(source) {
return Some((source, 0));
}
bfs_impl(graph, source, |neighbor, _| !predicate(neighbor)).1
}
fn bfs_impl<G, F>(
graph: &G,
source: G::Vertex,
mut on_discover: F,
) -> (VertexMap<G::Vertex, Option<u32>>, Option<(G::Vertex, u32)>)
where
G: GraphTopology,
F: FnMut(G::Vertex, G::Vertex) -> bool,
{
let mut distances = graph.vertex_map(None);
let mut queue = VecDeque::new();
distances[source] = Some(0);
queue.push_back(source);
while let Some(v) = queue.pop_front() {
for neighbor in graph.adjacent_vertices(v) {
if distances[neighbor].is_none() {
let distance = distances[v].unwrap() + 1;
distances[neighbor] = Some(distance);
if !on_discover(neighbor, v) {
return (distances, Some((neighbor, distance)));
}
queue.push_back(neighbor);
}
}
}
(distances, None)
}
pub struct DfsResult<V: Copy> {
pub visited: VertexMap<V, bool>,
pub predecessors: VertexMap<V, Option<V>>,
}
pub fn dfs<G>(graph: &G, source: G::Vertex) -> DfsResult<G::Vertex>
where
G: GraphTopology,
{
let mut predecessors = graph.vertex_map(None);
let (visited, _) = dfs_impl(graph, source, |neighbor, predecessor| {
predecessors[neighbor] = Some(predecessor);
true
});
DfsResult {
visited,
predecessors,
}
}
pub fn dfs_visited<G>(graph: &G, source: G::Vertex) -> VertexMap<G::Vertex, bool>
where
G: GraphTopology,
{
dfs_impl(graph, source, |_, _| true).0
}
pub fn dfs_find<G>(graph: &G, source: G::Vertex, target: G::Vertex) -> bool
where
G: GraphTopology,
{
dfs_find_where(graph, source, |v| v == target).is_some()
}
pub fn dfs_find_where<G, P>(graph: &G, source: G::Vertex, predicate: P) -> Option<G::Vertex>
where
G: GraphTopology,
P: Fn(G::Vertex) -> bool,
{
if predicate(source) {
return Some(source);
}
dfs_impl(graph, source, |neighbor, _| !predicate(neighbor)).1
}
fn dfs_impl<G, F>(
graph: &G,
source: G::Vertex,
mut on_discover: F,
) -> (VertexMap<G::Vertex, bool>, Option<G::Vertex>)
where
G: GraphTopology,
F: FnMut(G::Vertex, G::Vertex) -> bool,
{
let mut visited = graph.vertex_map(false);
visited[source] = true;
let mut stack = vec![(source, None::<G::Vertex>)];
while let Some((v, predecessor)) = stack.pop() {
if let Some(p) = predecessor {
if !on_discover(v, p) {
return (visited, Some(v));
}
}
for neighbor in graph.adjacent_vertices(v) {
if !visited[neighbor] {
visited[neighbor] = true;
stack.push((neighbor, Some(v)));
}
}
}
(visited, None)
}
pub fn find_path<G>(graph: &G, source: G::Vertex, target: G::Vertex) -> Option<Vec<G::Edge>>
where
G: GraphTopology,
{
find_path_where(graph, source, |v| v == target)
}
pub fn find_path_where<G, P>(graph: &G, source: G::Vertex, predicate: P) -> Option<Vec<G::Edge>>
where
G: GraphTopology,
P: Fn(G::Vertex) -> bool,
{
if predicate(source) {
return Some(vec![]);
}
let mut visited = graph.vertex_map(false);
visited[source] = true;
struct Frame<G: GraphTopology> {
arrival_edge: Option<G::Edge>,
cursor: G::IncidenceCursor,
}
let mut stack: Vec<Frame<G>> = vec![Frame {
arrival_edge: None,
cursor: graph.incidence_cursor(source),
}];
while let Some(frame) = stack.last_mut() {
match frame.cursor.next(graph) {
None => {
stack.pop();
}
Some((neighbor, edge)) => {
if predicate(neighbor) {
let mut path: Vec<G::Edge> =
stack.iter().filter_map(|f| f.arrival_edge).collect();
path.push(edge);
return Some(path);
}
if !visited[neighbor] {
visited[neighbor] = true;
stack.push(Frame {
arrival_edge: Some(edge),
cursor: graph.incidence_cursor(neighbor),
});
}
}
}
}
None
}