Implement new graph data structure and dijkstra

This commit is contained in:
Joscha 2024-12-30 18:19:20 +01:00
parent 778cb6748d
commit 18e54c4ce1
6 changed files with 516 additions and 3 deletions

293
brood/src/graph.rs Normal file
View file

@ -0,0 +1,293 @@
use std::ops::{Add, AddAssign, Range, Sub, SubAssign};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct NodeIdx(pub u32);
impl NodeIdx {
pub const NONE: Self = Self(u32::MAX);
#[inline]
pub const fn new(value: usize) -> Self {
Self(value as u32)
}
#[inline]
pub const fn usize(self) -> usize {
self.0 as usize
}
}
impl From<u32> for NodeIdx {
fn from(value: u32) -> Self {
Self(value)
}
}
impl From<usize> for NodeIdx {
fn from(value: usize) -> Self {
Self::new(value)
}
}
impl Add for NodeIdx {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl AddAssign for NodeIdx {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl Sub for NodeIdx {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl SubAssign for NodeIdx {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl Add<u32> for NodeIdx {
type Output = Self;
fn add(self, rhs: u32) -> Self::Output {
Self(self.0 + rhs)
}
}
impl AddAssign<u32> for NodeIdx {
fn add_assign(&mut self, rhs: u32) {
self.0 += rhs;
}
}
impl Sub<u32> for NodeIdx {
type Output = Self;
fn sub(self, rhs: u32) -> Self::Output {
Self(self.0 - rhs)
}
}
impl SubAssign<u32> for NodeIdx {
fn sub_assign(&mut self, rhs: u32) {
self.0 -= rhs;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct EdgeIdx(pub u32);
impl EdgeIdx {
pub const NONE: Self = Self(u32::MAX);
#[inline]
pub const fn new(value: usize) -> Self {
Self(value as u32)
}
#[inline]
pub const fn usize(self) -> usize {
self.0 as usize
}
}
impl From<u32> for EdgeIdx {
fn from(value: u32) -> Self {
Self(value)
}
}
impl From<usize> for EdgeIdx {
fn from(value: usize) -> Self {
Self::new(value)
}
}
impl Add for EdgeIdx {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl AddAssign for EdgeIdx {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl Sub for EdgeIdx {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl SubAssign for EdgeIdx {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl Add<u32> for EdgeIdx {
type Output = Self;
fn add(self, rhs: u32) -> Self::Output {
Self(self.0 + rhs)
}
}
impl AddAssign<u32> for EdgeIdx {
fn add_assign(&mut self, rhs: u32) {
self.0 += rhs;
}
}
impl Sub<u32> for EdgeIdx {
type Output = Self;
fn sub(self, rhs: u32) -> Self::Output {
Self(self.0 - rhs)
}
}
impl SubAssign<u32> for EdgeIdx {
fn sub_assign(&mut self, rhs: u32) {
self.0 -= rhs;
}
}
#[derive(Default)]
pub struct Graph {
/// A node points to the first of its edges.
///
/// A special case is that if the subsequent node points to the same edge,
/// the current node has no edges.
pub nodes: Vec<EdgeIdx>,
/// An edge points to a target node.
///
/// The source node is defined implicitly by the graph data structure.
pub edges: Vec<NodeIdx>,
}
impl Graph {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(nodes: usize, edges: usize) -> Self {
Self {
nodes: Vec::with_capacity(nodes),
edges: Vec::with_capacity(edges),
}
}
pub fn check_consistency(&self) {
if self.nodes.is_empty() {
assert!(self.edges.is_empty(), "edges must belong to existing nodes");
return;
}
assert!(self.nodes.len() < u32::MAX as usize, "too many nodes");
assert!(self.edges.len() < u32::MAX as usize, "too many edges");
assert_eq!(
*self.nodes.first().unwrap(),
EdgeIdx(0),
"first node pointer must be 0"
);
for (ni, node) in self.nodes.iter().cloned().enumerate() {
assert!(
node.usize() < self.edges.len(),
"node pointers must in range"
);
if let Some(succ) = self.nodes.get(ni + 1) {
assert!(node <= *succ, "node pointers must be well-ordered");
}
}
for edge in &self.edges {
assert!(
edge.usize() < self.nodes.len(),
"edge pointers must be in range"
);
}
}
pub fn nodes(&self) -> impl Iterator<Item = NodeIdx> + '_ {
(0..self.nodes.len()).map(NodeIdx::new)
}
pub fn edges(&self) -> impl Iterator<Item = (NodeIdx, NodeIdx)> + '_ {
Edges::new(self)
}
pub fn edge_start(&self, node: NodeIdx) -> EdgeIdx {
self.nodes
.get(node.usize())
.copied()
.unwrap_or_else(|| self.edges.len().into())
}
pub fn edge_range(&self, node: NodeIdx) -> Range<usize> {
let start = self.nodes[node.usize()];
let end = self.edge_start(node + 1);
start.usize()..end.usize()
}
pub fn edges_for(&self, node: NodeIdx) -> &[NodeIdx] {
&self.edges[self.edge_range(node)]
}
}
struct Edges<'a> {
graph: &'a Graph,
ni: NodeIdx,
ei: EdgeIdx,
}
impl<'a> Edges<'a> {
fn new(graph: &'a Graph) -> Self {
Self {
graph,
ni: NodeIdx(0),
ei: EdgeIdx(0),
}
}
}
impl Iterator for Edges<'_> {
type Item = (NodeIdx, NodeIdx);
fn next(&mut self) -> Option<Self::Item> {
if self.ei.usize() >= self.graph.edges.len() {
return None;
}
let to = self.graph.edges[self.ei.usize()];
// if would not be sufficient because some nodes may not have any edges.
while self.ei >= self.graph.edge_start(self.ni + 1) {
self.ni += 1;
}
let from = self.ni;
self.ei += 1;
Some((from, to))
}
}