cleaned up the code

This commit is contained in:
Johannes Erwerle 2022-09-16 17:14:28 +02:00
parent ea0e22506d
commit 275c2d933e
3 changed files with 57 additions and 35 deletions

View file

@ -1,19 +1,25 @@
use crate::gridgraph::{EdgeCost, GraphNode, GridGraph, NodeId}; use crate::gridgraph::{EdgeCost, GraphNode, GridGraph, NodeId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::collections::BinaryHeap; use std::collections::BinaryHeap;
use crate::utils::DijkstraElement;
/// a single Landmark
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Landmark { pub struct Landmark {
pub node: GraphNode, pub node: GraphNode,
pub distances: Vec<EdgeCost>, pub distances: Vec<EdgeCost>,
} }
/// A set of Landmarks
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct LandmarkSet { pub struct LandmarkSet {
pub landmarks: Vec<Landmark>, pub landmarks: Vec<Landmark>,
} }
/// The LandmarkBestSet is the datastructure in which the indices of the
/// best landmarks for a certain query are stored.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LandmarkBestSet<'a> { pub struct LandmarkBestSet<'a> {
pub landmark_set: &'a LandmarkSet, pub landmark_set: &'a LandmarkSet,
@ -22,33 +28,20 @@ pub struct LandmarkBestSet<'a> {
} }
impl Landmark { impl Landmark {
/// generates a landmark (calculates all distances) for a given node.
pub fn generate(node: GraphNode, graph: &GridGraph) -> Landmark { 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 { let mut landmark = Landmark {
node, node,
distances: vec![EdgeCost::MAX; graph.nodes.len()], distances: vec![EdgeCost::MAX; graph.nodes.len()],
}; };
landmark.node = node; 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<Ordering> {
Some(self.cmp(other))
}
}
let mut heap = BinaryHeap::new(); let mut heap = BinaryHeap::new();
heap.push(DijkstraElement { heap.push(DijkstraElement {
cost: 0, cost: 0,
@ -86,7 +79,7 @@ impl Landmark {
/// calculates the lower-bounding distance estimate between the 2 nodes /// calculates the lower-bounding distance estimate between the 2 nodes
/// via the landmark. /// via the landmark.
/// If one or more of the nodes are not reachable from 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 { pub fn estimate(&self, from: NodeId, to: NodeId) -> EdgeCost {
let l_to = self.distances[to]; let l_to = self.distances[to];
let l_from = self.distances[from]; let l_from = self.distances[from];
@ -100,12 +93,7 @@ impl Landmark {
// which except for the sign are the same value. // which except for the sign are the same value.
// We can simply take the bigger one, which is handled // We can simply take the bigger one, which is handled
// nicely the abs() function // nicely the abs() function
let distance = (l_to as i64 - l_from as i64).abs() as EdgeCost; (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
} }
} }
} }

View file

@ -4,6 +4,8 @@ use crate::utils::EARTH_RADIUS;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::BinaryHeap; use std::collections::BinaryHeap;
/// datastructure to hold data required by the A* algorithm
pub struct AStar<'a> { pub struct AStar<'a> {
pub graph: &'a GridGraph, pub graph: &'a GridGraph,
} }
@ -23,8 +25,6 @@ struct HeapElement {
} }
impl Ord for 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 { fn cmp(&self, other: &Self) -> Ordering {
other.cost.cmp(&self.cost) 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 { pub fn estimate_haversine(node: &GraphNode, destination: &GraphNode) -> EdgeCost {
// simple haversine distance // simple haversine distance
(node.position.distance_to(&destination.position) * EARTH_RADIUS) as EdgeCost (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 { pub fn estimate_latitude(node: &GraphNode, destination: &GraphNode) -> EdgeCost {
let lat_dist = (node.position.lat - destination.position.lat).abs(); let lat_dist = (node.position.lat - destination.position.lat).abs();
(lat_dist * EARTH_RADIUS) as EdgeCost (lat_dist * EARTH_RADIUS) as EdgeCost
} }
impl AStar<'_> { 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<F>(&self, start: &GraphNode, end: &GraphNode, estimate: F) -> Option<Route> pub fn shortest_path<F>(&self, start: &GraphNode, end: &GraphNode, estimate: F) -> Option<Route>
where where
F: Fn(&GraphNode, &GraphNode) -> EdgeCost, F: Fn(&GraphNode, &GraphNode) -> EdgeCost,

View file

@ -1,18 +1,23 @@
use crate::alt::LandmarkSet; use crate::alt::LandmarkSet;
use crate::gridgraph::GridGraph; use crate::gridgraph::{EdgeCost, GridGraph};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use std::process::exit; use std::process::exit;
/// an approximation of the earths radius.
pub const EARTH_RADIUS: f64 = 6_371_000.0; // meters pub const EARTH_RADIUS: f64 = 6_371_000.0; // meters
/// serialization format for routing queries.
#[derive(Serialize, Deserialize, Debug, Copy, Clone)] #[derive(Serialize, Deserialize, Debug, Copy, Clone)]
pub struct RoutingQuery { pub struct RoutingQuery {
pub source: usize, pub source: usize,
pub destination: 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<GridGraph> { pub fn load_graph(path: &str) -> Box<GridGraph> {
println!("Loading file from {}", path); println!("Loading file from {}", path);
let file = match File::open(path) { let file = match File::open(path) {
@ -36,6 +41,8 @@ pub fn load_graph(path: &str) -> Box<GridGraph> {
graph graph
} }
/// loads a set of landmarks from the given path.
/// exits if an error occurs during loading.
pub fn load_landmarks(path: &str) -> LandmarkSet { pub fn load_landmarks(path: &str) -> LandmarkSet {
let landmarks = match File::open(path) { let landmarks = match File::open(path) {
Ok(f) => f, Ok(f) => f,
@ -47,3 +54,25 @@ pub fn load_landmarks(path: &str) -> LandmarkSet {
bincode::deserialize_from(BufReader::new(landmarks)).unwrap() 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<Ordering> {
Some(self.cmp(other))
}
}