From 275c2d933eb16a9530a51ef6cac9b589c168a3d6 Mon Sep 17 00:00:00 2001 From: Johannes Erwerle Date: Fri, 16 Sep 2022 17:14:28 +0200 Subject: [PATCH] cleaned up the code --- src/alt.rs | 44 ++++++++++++++++---------------------------- src/astar.rs | 17 +++++++++++------ src/utils.rs | 31 ++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/src/alt.rs b/src/alt.rs index 4afb7f0..30aac24 100644 --- a/src/alt.rs +++ b/src/alt.rs @@ -1,19 +1,25 @@ use crate::gridgraph::{EdgeCost, GraphNode, GridGraph, NodeId}; use serde::{Deserialize, Serialize}; -use std::cmp::Ordering; use std::collections::BinaryHeap; +use crate::utils::DijkstraElement; +/// a single Landmark #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Landmark { pub node: GraphNode, pub distances: Vec, } + +/// A set of Landmarks #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct LandmarkSet { pub landmarks: Vec, } + +/// The LandmarkBestSet is the datastructure in which the indices of the +/// best landmarks for a certain query are stored. #[derive(Debug, Clone)] pub struct LandmarkBestSet<'a> { pub landmark_set: &'a LandmarkSet, @@ -22,33 +28,20 @@ pub struct LandmarkBestSet<'a> { } impl Landmark { + + /// generates a landmark (calculates all distances) for a given node. pub fn generate(node: GraphNode, graph: &GridGraph) -> Landmark { + + // This is running a simplified version of dijkstra. + // It also does not track the ancestors of a node, because it is + // not needed for generating hte landmarks. + let mut landmark = Landmark { node, distances: vec![EdgeCost::MAX; graph.nodes.len()], }; landmark.node = node; - #[derive(Eq, PartialEq)] - struct DijkstraElement { - index: u32, - cost: EdgeCost, - } - - impl Ord for DijkstraElement { - // inverted cmp function, such that the Max-Heap provided by Rust - // can be used as a Min-Heap - fn cmp(&self, other: &Self) -> Ordering { - other.cost.cmp(&self.cost) - } - } - - impl PartialOrd for DijkstraElement { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } - } - let mut heap = BinaryHeap::new(); heap.push(DijkstraElement { cost: 0, @@ -86,7 +79,7 @@ impl Landmark { /// calculates the lower-bounding distance estimate between the 2 nodes /// via the landmark. /// If one or more of the nodes are not reachable from the landmark - /// an estimate of `0` is returned. + /// an estimate of `EdgeCost::MAX` is returned. pub fn estimate(&self, from: NodeId, to: NodeId) -> EdgeCost { let l_to = self.distances[to]; let l_from = self.distances[from]; @@ -100,12 +93,7 @@ impl Landmark { // which except for the sign are the same value. // We can simply take the bigger one, which is handled // nicely the abs() function - let distance = (l_to as i64 - l_from as i64).abs() as EdgeCost; - //println!( - // "distance from {} to {} via landmark {} is at least {}", - // from, to, self.node.index, distance - //); - distance + (l_to as i64 - l_from as i64).abs() as EdgeCost } } } diff --git a/src/astar.rs b/src/astar.rs index abaf0ce..f919459 100644 --- a/src/astar.rs +++ b/src/astar.rs @@ -4,6 +4,8 @@ use crate::utils::EARTH_RADIUS; use std::cmp::Ordering; use std::collections::BinaryHeap; + +/// datastructure to hold data required by the A* algorithm pub struct AStar<'a> { pub graph: &'a GridGraph, } @@ -23,8 +25,6 @@ struct HeapElement { } impl Ord for HeapElement { - // inverted cmp function, such that the Max-Heap provided by Rust - // can be used as a Min-Heap fn cmp(&self, other: &Self) -> Ordering { other.cost.cmp(&self.cost) } @@ -36,21 +36,26 @@ impl PartialOrd for HeapElement { } } +/// A simple haversine distance heuristic. pub fn estimate_haversine(node: &GraphNode, destination: &GraphNode) -> EdgeCost { // simple haversine distance (node.position.distance_to(&destination.position) * EARTH_RADIUS) as EdgeCost - // let lat_dist_a = (node.position.lat - destination.position.lat).abs(); - // let lat_dist_b = (destination.position.lat - node.position.lat).abs(); - - // (lat_dist_a.min(lat_dist_b) * EARTH_RADIUS) as EdgeCost } +/// a simple heuristic based on the difference in lattitude between two points +/// The idea is that it is cheaper to calculate than the haversine distance. pub fn estimate_latitude(node: &GraphNode, destination: &GraphNode) -> EdgeCost { let lat_dist = (node.position.lat - destination.position.lat).abs(); (lat_dist * EARTH_RADIUS) as EdgeCost } + impl AStar<'_> { + + /// calculates the shortest path from start to end given the `estimate` + /// heuristic function. + /// + /// Returns `None` if no path exists. pub fn shortest_path(&self, start: &GraphNode, end: &GraphNode, estimate: F) -> Option where F: Fn(&GraphNode, &GraphNode) -> EdgeCost, diff --git a/src/utils.rs b/src/utils.rs index 3d09969..fd63548 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,18 +1,23 @@ use crate::alt::LandmarkSet; -use crate::gridgraph::GridGraph; +use crate::gridgraph::{EdgeCost, GridGraph}; use serde::{Deserialize, Serialize}; +use std::cmp::Ordering; use std::fs::File; use std::io::BufReader; use std::process::exit; +/// an approximation of the earths radius. pub const EARTH_RADIUS: f64 = 6_371_000.0; // meters +/// serialization format for routing queries. #[derive(Serialize, Deserialize, Debug, Copy, Clone)] pub struct RoutingQuery { pub source: usize, pub destination: usize, } +/// loads the graph from the given path. +/// exits if an error occurs during loading. pub fn load_graph(path: &str) -> Box { println!("Loading file from {}", path); let file = match File::open(path) { @@ -36,6 +41,8 @@ pub fn load_graph(path: &str) -> Box { graph } +/// loads a set of landmarks from the given path. +/// exits if an error occurs during loading. pub fn load_landmarks(path: &str) -> LandmarkSet { let landmarks = match File::open(path) { Ok(f) => f, @@ -47,3 +54,25 @@ pub fn load_landmarks(path: &str) -> LandmarkSet { bincode::deserialize_from(BufReader::new(landmarks)).unwrap() } + +/// A heap element for Dijkstra's algorithm. +/// +/// The comparison functions are inverted, so that Rusts MaxHeap works as a +/// MinHeap. +#[derive(Eq, PartialEq)] +pub struct DijkstraElement { + pub index: u32, + pub cost: EdgeCost, +} + +impl Ord for DijkstraElement { + fn cmp(&self, other: &Self) -> Ordering { + other.cost.cmp(&self.cost) + } +} + +impl PartialOrd for DijkstraElement { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +}