From f2aaa26cb9e3d5d57f36c49f5ebd1813365d3343 Mon Sep 17 00:00:00 2001 From: "Tim \"S.D.Eagle\" Zeitz" Date: Mon, 15 Jan 2018 16:22:30 +0100 Subject: [PATCH 01/10] generic graph over owned or shared data... --- engine/src/graph/first_out_graph.rs | 104 ++++++++++++------ engine/src/import/here/mod.rs | 6 +- engine/src/io.rs | 2 +- engine/src/main.rs | 2 +- .../contraction_hierarchy/mod.rs | 10 +- .../query/async/bidirectional_dijkstra.rs | 4 +- .../src/shortest_path/query/async/dijkstra.rs | 2 +- .../query/bidirectional_dijkstra.rs | 2 +- .../query/contraction_hierarchy.rs | 6 +- engine/src/shortest_path/query/dijkstra.rs | 4 +- engine/src/shortest_path/query/mod.rs | 1 + 11 files changed, 89 insertions(+), 54 deletions(-) diff --git a/engine/src/graph/first_out_graph.rs b/engine/src/graph/first_out_graph.rs index 318419aa..76730be6 100644 --- a/engine/src/graph/first_out_graph.rs +++ b/engine/src/graph/first_out_graph.rs @@ -2,57 +2,84 @@ use super::*; use ::io; use std::io::Result; use std::path::Path; +use std::borrow::{Borrow}; +use std::marker::PhantomData; #[derive(Debug, Clone)] -pub struct FirstOutGraph { +pub struct FirstOutGraph where + FirstOutContainer: Borrow, + FirstOutInner: AsRef<[u32]>, + HeadContainer: Borrow, + HeadInner: AsRef<[NodeId]>, + WeightContainer: Borrow, + WeightInner: AsRef<[Weight]> +{ // index of first edge of each node +1 entry in the end - first_out: Vec, + first_out: FirstOutContainer, // the node ids to which each edge points - head: Vec, + head: HeadContainer, // the weight of each edge - weight: Vec + weight: WeightContainer, + _first_out_phantom: PhantomData, + _head_phantom: PhantomData, + _weight_phantom: PhantomData } -impl FirstOutGraph { - pub fn new(first_out: Vec, head: Vec, weight: Vec) -> FirstOutGraph { +pub type OwnedGraph = FirstOutGraph, Vec, Vec, Vec, Vec, Vec>; + +pub fn from_adjancecy_lists(adjancecy_lists: Vec>) -> OwnedGraph { + // create first_out array for reversed by doing a prefix sum over the adjancecy list sizes + let first_out = std::iter::once(0).chain(adjancecy_lists.iter().scan(0, |state, incoming_links| { + *state = *state + incoming_links.len() as u32; + Some(*state) + })).collect(); + + // append all adjancecy list and split the pairs into two seperate vectors + let (head, weight) = adjancecy_lists + .into_iter() + .flat_map(|neighbors| neighbors.into_iter().map(|Link { node, weight }| (node, weight) ) ) + .unzip(); + + OwnedGraph::new(first_out, head, weight) +} + +impl FirstOutGraph where + FirstOutContainer: Borrow, + FirstOutInner: AsRef<[u32]>, + HeadContainer: Borrow, + HeadInner: AsRef<[NodeId]>, + WeightContainer: Borrow, + WeightInner: AsRef<[Weight]> +{ + fn first_out(&self) -> &[u32] { self.first_out.borrow().as_ref() } + fn head(&self) -> &[u32] { self.head.borrow().as_ref() } + fn weight(&self) -> &[u32] { self.weight.borrow().as_ref() } + + pub fn new(first_out: Vec, head: Vec, weight: Vec) -> OwnedGraph { assert_eq!(*first_out.first().unwrap(), 0); assert_eq!(*first_out.last().unwrap() as usize, head.len()); assert_eq!(weight.len(), head.len()); FirstOutGraph { - first_out, head, weight + first_out, head, weight, + _first_out_phantom: PhantomData, _head_phantom: PhantomData, _weight_phantom: PhantomData } } - pub fn from_adjancecy_lists(adjancecy_lists: Vec>) -> FirstOutGraph { - // create first_out array for reversed by doing a prefix sum over the adjancecy list sizes - let first_out = std::iter::once(0).chain(adjancecy_lists.iter().scan(0, |state, incoming_links| { - *state = *state + incoming_links.len() as u32; - Some(*state) - })).collect(); - - // append all adjancecy list and split the pairs into two seperate vectors - let (head, weight) = adjancecy_lists - .into_iter() - .flat_map(|neighbors| neighbors.into_iter().map(|Link { node, weight }| (node, weight) ) ) - .unzip(); - - FirstOutGraph::new(first_out, head, weight) - } pub fn neighbor_iter(&self, node: NodeId) -> std::iter::Map, std::slice::Iter>, fn((&NodeId, &Weight))->Link> { - let range = (self.first_out[node as usize] as usize)..(self.first_out[(node + 1) as usize] as usize); - self.head[range.clone()].iter() - .zip(self.weight[range].iter()) + let range = (self.first_out()[node as usize] as usize)..(self.first_out()[(node + 1) as usize] as usize); + self.head()[range.clone()].iter() + .zip(self.weight()[range].iter()) .map( |(&neighbor, &weight)| Link { node: neighbor, weight: weight } ) } pub fn edge_index(&self, from: NodeId, to: NodeId) -> Option { - let first_out = self.first_out[from as usize] as usize; + let first_out = self.first_out()[from as usize] as usize; self.neighbor_iter(from).enumerate().find(|&(_, Link { node, .. })| node == to).map(|(i, _)| first_out + i ) } - pub fn reverse(&self) -> FirstOutGraph { + pub fn reverse(&self) -> OwnedGraph { // vector of adjacency lists for the reverse graph let mut reversed: Vec> = (0..self.num_nodes()).map(|_| Vec::::new() ).collect(); @@ -62,10 +89,10 @@ impl FirstOutGraph { reversed[neighbor as usize].push(Link { node, weight }); } } - FirstOutGraph::from_adjancecy_lists(reversed) + from_adjancecy_lists(reversed) } - pub fn ch_split(self, node_ranks: &Vec) -> (FirstOutGraph, FirstOutGraph) { + pub fn ch_split(self, node_ranks: &Vec) -> (OwnedGraph, OwnedGraph) { let mut up: Vec> = (0..self.num_nodes()).map(|_| Vec::::new() ).collect(); let mut down: Vec> = (0..self.num_nodes()).map(|_| Vec::::new() ).collect(); @@ -80,21 +107,28 @@ impl FirstOutGraph { } } - (FirstOutGraph::from_adjancecy_lists(up), FirstOutGraph::from_adjancecy_lists(down)) + (from_adjancecy_lists(up), from_adjancecy_lists(down)) } pub fn write_to_dir(&self, dir: &str) -> Result<()> { let path = Path::new(dir); - let res1 = io::write_vector_to_file(path.join("first_out").to_str().unwrap(), &self.first_out); - let res2 = io::write_vector_to_file(path.join("head").to_str().unwrap(), &self.head); - let res3 = io::write_vector_to_file(path.join("weights").to_str().unwrap(), &self.weight); + let res1 = io::write_vector_to_file(path.join("first_out").to_str().unwrap(), self.first_out()); + let res2 = io::write_vector_to_file(path.join("head").to_str().unwrap(), self.head()); + let res3 = io::write_vector_to_file(path.join("weights").to_str().unwrap(), self.weight()); res1.and(res2).and(res3) } } -impl DijkstrableGraph for FirstOutGraph { +impl DijkstrableGraph for FirstOutGraph where + FirstOutContainer: Borrow, + FirstOutInner: AsRef<[u32]>, + HeadContainer: Borrow, + HeadInner: AsRef<[NodeId]>, + WeightContainer: Borrow, + WeightInner: AsRef<[Weight]> +{ fn num_nodes(&self) -> usize { - self.first_out.len() - 1 + self.first_out().len() - 1 } fn for_each_neighbor(&self, node: NodeId, f: &mut FnMut(Link)) { diff --git a/engine/src/import/here/mod.rs b/engine/src/import/here/mod.rs index c03102f4..d3a23272 100644 --- a/engine/src/import/here/mod.rs +++ b/engine/src/import/here/mod.rs @@ -1,5 +1,5 @@ use ::graph::*; -use ::graph::first_out_graph::FirstOutGraph; +use ::graph::first_out_graph::OwnedGraph; use ::rank_select_map::RankSelectMap; use std::iter; use std::str::FromStr; @@ -130,7 +130,7 @@ pub trait RdfDataSource { fn link_geometries(&self) -> Vec; } -pub fn read_graph(source: &RdfDataSource) -> (FirstOutGraph, Vec, Vec) { +pub fn read_graph(source: &RdfDataSource) -> (OwnedGraph, Vec, Vec) { println!("read nav links"); // start with all nav links let mut nav_links: Vec = source.nav_links(); @@ -274,7 +274,7 @@ pub fn read_graph(source: &RdfDataSource) -> (FirstOutGraph, Vec, Vec) // insert a zero at the beginning - this will shift all values one to the right first_out.insert(0, 0); - let graph = FirstOutGraph::new(first_out, head, weights); + let graph = OwnedGraph::new(first_out, head, weights); let lat = nodes.iter().map(|node| ((node.lat as f64) / 100000.) as f32).collect(); let lng = nodes.iter().map(|node| ((node.lon as f64) / 100000.) as f32).collect(); (graph, lat, lng) diff --git a/engine/src/io.rs b/engine/src/io.rs index 5a06c7ed..0f7e9a24 100644 --- a/engine/src/io.rs +++ b/engine/src/io.rs @@ -23,7 +23,7 @@ pub fn read_into_vector(filename: &str) -> Result> { Ok(buffer) } -pub fn write_vector_to_file(filename: &str, vector: &Vec) -> Result<()> { +pub fn write_vector_to_file(filename: &str, vector: &[T]) -> Result<()> { let mut buffer = File::create(filename)?; let num_bytes = vector.len() * mem::size_of::(); diff --git a/engine/src/main.rs b/engine/src/main.rs index 818755c4..84af0a67 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -6,7 +6,7 @@ extern crate bmw_routing_engine; extern crate time; use bmw_routing_engine::*; -use graph::first_out_graph::FirstOutGraph as Graph; +use graph::first_out_graph::OwnedGraph as Graph; use graph::INFINITY; use shortest_path::query::dijkstra::Server as DijkServer; use shortest_path::query::bidirectional_dijkstra::Server as BiDijkServer; diff --git a/engine/src/shortest_path/contraction_hierarchy/mod.rs b/engine/src/shortest_path/contraction_hierarchy/mod.rs index 6ddc5b01..c933efab 100644 --- a/engine/src/shortest_path/contraction_hierarchy/mod.rs +++ b/engine/src/shortest_path/contraction_hierarchy/mod.rs @@ -1,5 +1,5 @@ use super::*; -use self::first_out_graph::FirstOutGraph; +use self::first_out_graph::{OwnedGraph, from_adjancecy_lists}; #[derive(Debug, PartialEq)] enum ShortcutResult { @@ -58,7 +58,7 @@ struct ContractionGraph { } impl ContractionGraph { - fn new(graph: FirstOutGraph, node_order: Vec) -> ContractionGraph { + fn new(graph: OwnedGraph, node_order: Vec) -> ContractionGraph { let n = graph.num_nodes(); let mut node_ranks = vec![0; n]; for (i, &node) in node_order.iter().enumerate() { @@ -110,7 +110,7 @@ impl ContractionGraph { } } - fn as_first_out_graphs(self) -> ((FirstOutGraph, FirstOutGraph), Option<(Vec, Vec)>) { + fn as_first_out_graphs(self) -> ((OwnedGraph, OwnedGraph), Option<(Vec, Vec)>) { let (outgoing, incoming): (Vec<(Vec, Vec)>, Vec<(Vec, Vec)>) = self.nodes.into_iter() .map(|node| { (node.outgoing.into_iter().unzip(), node.incoming.into_iter().unzip()) @@ -124,7 +124,7 @@ impl ContractionGraph { // currently we stick to the reordered graph and also translate the query node ids. // TODO make more explicit - ((FirstOutGraph::from_adjancecy_lists(outgoing), FirstOutGraph::from_adjancecy_lists(incoming)), Some((forward_shortcut_middles, backward_shortcut_middles))) + ((from_adjancecy_lists(outgoing), from_adjancecy_lists(incoming)), Some((forward_shortcut_middles, backward_shortcut_middles))) } } @@ -179,7 +179,7 @@ impl<'a> PartialContractionGraph<'a> { } } -pub fn contract(graph: FirstOutGraph, node_order: Vec) -> ((FirstOutGraph, FirstOutGraph), Option<(Vec, Vec)>) { +pub fn contract(graph: OwnedGraph, node_order: Vec) -> ((OwnedGraph, OwnedGraph), Option<(Vec, Vec)>) { let mut graph = ContractionGraph::new(graph, node_order); graph.contract(); graph.as_first_out_graphs() diff --git a/engine/src/shortest_path/query/async/bidirectional_dijkstra.rs b/engine/src/shortest_path/query/async/bidirectional_dijkstra.rs index ba1a3ec5..44e6779d 100644 --- a/engine/src/shortest_path/query/async/bidirectional_dijkstra.rs +++ b/engine/src/shortest_path/query/async/bidirectional_dijkstra.rs @@ -37,7 +37,7 @@ pub struct Server { } impl Server { - pub fn new(graph: Graph) -> Server { + pub fn new(graph: OwnedGraph) -> Server { let (forward_query_sender, forward_query_receiver) = channel(); let (forward_progress_sender, forward_progress_receiver) = channel(); let (backward_query_sender, backward_query_receiver) = channel(); @@ -69,7 +69,7 @@ impl Server { } } - fn spawn_direction_worker(graph: Graph, + fn spawn_direction_worker(graph: OwnedGraph, query_receiver: Receiver<(ServerControl, u32)>, progress_sender: Sender<(QueryProgress, u32)>, distances_pointer: Arc>, diff --git a/engine/src/shortest_path/query/async/dijkstra.rs b/engine/src/shortest_path/query/async/dijkstra.rs index 5864d171..6b0baf54 100644 --- a/engine/src/shortest_path/query/async/dijkstra.rs +++ b/engine/src/shortest_path/query/async/dijkstra.rs @@ -7,7 +7,7 @@ pub struct Server { } impl Server { - pub fn new(graph: Graph) -> Server { + pub fn new(graph: OwnedGraph) -> Server { let (query_sender, query_receiver) = channel(); let (progress_sender, progress_receiver) = channel(); diff --git a/engine/src/shortest_path/query/bidirectional_dijkstra.rs b/engine/src/shortest_path/query/bidirectional_dijkstra.rs index 8e3e5525..294a6e61 100644 --- a/engine/src/shortest_path/query/bidirectional_dijkstra.rs +++ b/engine/src/shortest_path/query/bidirectional_dijkstra.rs @@ -11,7 +11,7 @@ pub struct Server { } impl Server { - pub fn new(graph: Graph) -> Server { + pub fn new(graph: OwnedGraph) -> Server { let reversed = graph.reverse(); Server { diff --git a/engine/src/shortest_path/query/contraction_hierarchy.rs b/engine/src/shortest_path/query/contraction_hierarchy.rs index 3f84d100..52ea90b8 100644 --- a/engine/src/shortest_path/query/contraction_hierarchy.rs +++ b/engine/src/shortest_path/query/contraction_hierarchy.rs @@ -3,15 +3,15 @@ use super::*; #[derive(Debug)] pub struct Server { - forward_dijkstra: SteppedDijkstra, - backward_dijkstra: SteppedDijkstra, + forward_dijkstra: SteppedDijkstra, + backward_dijkstra: SteppedDijkstra, tentative_distance: Weight, meeting_node: NodeId, shortcut_middle_nodes: Option<(Vec, Vec)> } impl Server { - pub fn new(((up, down), shortcut_middle_nodes): ((Graph, Graph), Option<(Vec, Vec)>)) -> Server { + pub fn new(((up, down), shortcut_middle_nodes): ((OwnedGraph, OwnedGraph), Option<(Vec, Vec)>)) -> Server { Server { forward_dijkstra: SteppedDijkstra::new(up), backward_dijkstra: SteppedDijkstra::new(down), diff --git a/engine/src/shortest_path/query/dijkstra.rs b/engine/src/shortest_path/query/dijkstra.rs index b24caa39..318b5a63 100644 --- a/engine/src/shortest_path/query/dijkstra.rs +++ b/engine/src/shortest_path/query/dijkstra.rs @@ -4,11 +4,11 @@ use std::collections::LinkedList; #[derive(Debug)] pub struct Server { - dijkstra: SteppedDijkstra, + dijkstra: SteppedDijkstra, } impl Server { - pub fn new(graph: Graph) -> Server { + pub fn new(graph: OwnedGraph) -> Server { Server { dijkstra: SteppedDijkstra::new(graph) } diff --git a/engine/src/shortest_path/query/mod.rs b/engine/src/shortest_path/query/mod.rs index d89ad29e..7040880a 100644 --- a/engine/src/shortest_path/query/mod.rs +++ b/engine/src/shortest_path/query/mod.rs @@ -1,5 +1,6 @@ use super::*; use graph::first_out_graph::FirstOutGraph as Graph; +use graph::first_out_graph::OwnedGraph; pub mod async; pub mod dijkstra; From 1ded66bacc7618dc39487fb3cac9773543cae991 Mon Sep 17 00:00:00 2001 From: "Tim \"S.D.Eagle\" Zeitz" Date: Tue, 16 Jan 2018 18:34:05 +0100 Subject: [PATCH 02/10] start cleaning stuff up with traits --- engine/src/graph/first_out_graph.rs | 100 ++++++------------ engine/src/graph/mod.rs | 48 +++++++++ .../contraction_hierarchy/mod.rs | 4 +- 3 files changed, 85 insertions(+), 67 deletions(-) diff --git a/engine/src/graph/first_out_graph.rs b/engine/src/graph/first_out_graph.rs index 76730be6..09e3f3a8 100644 --- a/engine/src/graph/first_out_graph.rs +++ b/engine/src/graph/first_out_graph.rs @@ -27,22 +27,6 @@ pub struct FirstOutGraph, Vec, Vec, Vec, Vec, Vec>; -pub fn from_adjancecy_lists(adjancecy_lists: Vec>) -> OwnedGraph { - // create first_out array for reversed by doing a prefix sum over the adjancecy list sizes - let first_out = std::iter::once(0).chain(adjancecy_lists.iter().scan(0, |state, incoming_links| { - *state = *state + incoming_links.len() as u32; - Some(*state) - })).collect(); - - // append all adjancecy list and split the pairs into two seperate vectors - let (head, weight) = adjancecy_lists - .into_iter() - .flat_map(|neighbors| neighbors.into_iter().map(|Link { node, weight }| (node, weight) ) ) - .unzip(); - - OwnedGraph::new(first_out, head, weight) -} - impl FirstOutGraph where FirstOutContainer: Borrow, FirstOutInner: AsRef<[u32]>, @@ -66,50 +50,6 @@ impl std::iter::Map, std::slice::Iter>, fn((&NodeId, &Weight))->Link> { - let range = (self.first_out()[node as usize] as usize)..(self.first_out()[(node + 1) as usize] as usize); - self.head()[range.clone()].iter() - .zip(self.weight()[range].iter()) - .map( |(&neighbor, &weight)| Link { node: neighbor, weight: weight } ) - } - - pub fn edge_index(&self, from: NodeId, to: NodeId) -> Option { - let first_out = self.first_out()[from as usize] as usize; - self.neighbor_iter(from).enumerate().find(|&(_, Link { node, .. })| node == to).map(|(i, _)| first_out + i ) - } - - pub fn reverse(&self) -> OwnedGraph { - // vector of adjacency lists for the reverse graph - let mut reversed: Vec> = (0..self.num_nodes()).map(|_| Vec::::new() ).collect(); - - // iterate over all edges and insert them in the reversed structure - for node in 0..(self.num_nodes() as NodeId) { - for Link { node: neighbor, weight } in self.neighbor_iter(node) { - reversed[neighbor as usize].push(Link { node, weight }); - } - } - from_adjancecy_lists(reversed) - } - - pub fn ch_split(self, node_ranks: &Vec) -> (OwnedGraph, OwnedGraph) { - let mut up: Vec> = (0..self.num_nodes()).map(|_| Vec::::new() ).collect(); - let mut down: Vec> = (0..self.num_nodes()).map(|_| Vec::::new() ).collect(); - - // iterate over all edges and insert them in the reversed structure - for node in 0..(self.num_nodes() as NodeId) { - for Link { node: neighbor, weight } in self.neighbor_iter(node) { - if node_ranks[node as usize] < node_ranks[neighbor as usize] { - up[node as usize].push(Link { node: neighbor, weight }); - } else { - down[neighbor as usize].push(Link { node, weight }); - } - } - } - - (from_adjancecy_lists(up), from_adjancecy_lists(down)) - } - pub fn write_to_dir(&self, dir: &str) -> Result<()> { let path = Path::new(dir); let res1 = io::write_vector_to_file(path.join("first_out").to_str().unwrap(), self.first_out()); @@ -119,7 +59,25 @@ impl DijkstrableGraph for FirstOutGraph where +impl OwnedGraph { + pub fn from_adjancecy_lists(adjancecy_lists: Vec>) -> OwnedGraph { + // create first_out array for reversed by doing a prefix sum over the adjancecy list sizes + let first_out = std::iter::once(0).chain(adjancecy_lists.iter().scan(0, |state, incoming_links| { + *state = *state + incoming_links.len() as u32; + Some(*state) + })).collect(); + + // append all adjancecy list and split the pairs into two seperate vectors + let (head, weight) = adjancecy_lists + .into_iter() + .flat_map(|neighbors| neighbors.into_iter().map(|Link { node, weight }| (node, weight) ) ) + .unzip(); + + OwnedGraph::new(first_out, head, weight) + } +} + +impl Graph for FirstOutGraph where FirstOutContainer: Borrow, FirstOutInner: AsRef<[u32]>, HeadContainer: Borrow, @@ -130,11 +88,23 @@ impl usize { self.first_out().len() - 1 } +} - fn for_each_neighbor(&self, node: NodeId, f: &mut FnMut(Link)) { - for link in self.neighbor_iter(node) { - f(link); - } +impl<'a, FirstOutContainer, FirstOutInner, HeadContainer, HeadInner, WeightContainer, WeightInner> LinkIterGraph<'a> for FirstOutGraph where + FirstOutContainer: Borrow, + FirstOutInner: AsRef<[u32]>, + HeadContainer: Borrow, + HeadInner: AsRef<[NodeId]>, + WeightContainer: Borrow, + WeightInner: AsRef<[Weight]> +{ + type Iter = std::iter::Map, std::slice::Iter<'a, Weight>>, fn((&NodeId, &Weight))->Link>; + + fn neighbor_iter(&'a self, node: NodeId) -> Self::Iter { + let range = (self.first_out()[node as usize] as usize)..(self.first_out()[(node + 1) as usize] as usize); + self.head()[range.clone()].iter() + .zip(self.weight()[range].iter()) + .map( |(&neighbor, &weight)| Link { node: neighbor, weight: weight } ) } } diff --git a/engine/src/graph/mod.rs b/engine/src/graph/mod.rs index e1333759..ff390a6d 100644 --- a/engine/src/graph/mod.rs +++ b/engine/src/graph/mod.rs @@ -3,6 +3,8 @@ use shortest_path::DijkstrableGraph; pub mod first_out_graph; +use self::first_out_graph::OwnedGraph; + pub type NodeId = u32; pub type Weight = u32; pub const INFINITY: u32 = std::u32::MAX / 2; @@ -12,3 +14,49 @@ pub struct Link { pub node: NodeId, pub weight: Weight } + +pub trait Graph { + fn num_nodes(&self) -> usize; +} + +pub trait LinkIterGraph<'a>: Graph { + type Iter: Iterator + 'a; + + fn neighbor_iter(&'a self, node: NodeId) -> Self::Iter; + + fn reverse(&'a self) -> OwnedGraph { + // vector of adjacency lists for the reverse graph + let mut reversed: Vec> = (0..self.num_nodes()).map(|_| Vec::::new() ).collect(); + + // iterate over all edges and insert them in the reversed structure + for node in 0..(self.num_nodes() as NodeId) { + for Link { node: neighbor, weight } in self.neighbor_iter(node) { + reversed[neighbor as usize].push(Link { node, weight }); + } + } + + OwnedGraph::from_adjancecy_lists(reversed) + } + + fn ch_split(&'a self, node_ranks: &Vec) -> (OwnedGraph, OwnedGraph) { + let mut up: Vec> = (0..self.num_nodes()).map(|_| Vec::::new() ).collect(); + let mut down: Vec> = (0..self.num_nodes()).map(|_| Vec::::new() ).collect(); + + // iterate over all edges and insert them in the reversed structure + for node in 0..(self.num_nodes() as NodeId) { + for Link { node: neighbor, weight } in self.neighbor_iter(node) { + if node_ranks[node as usize] < node_ranks[neighbor as usize] { + up[node as usize].push(Link { node: neighbor, weight }); + } else { + down[neighbor as usize].push(Link { node, weight }); + } + } + } + + (OwnedGraph::from_adjancecy_lists(up), OwnedGraph::from_adjancecy_lists(down)) + } +} + +pub trait RandomLinkAccessGraph { + fn edge_index(&self, from: NodeId, to: NodeId) -> Option; +} diff --git a/engine/src/shortest_path/contraction_hierarchy/mod.rs b/engine/src/shortest_path/contraction_hierarchy/mod.rs index c933efab..37fd0446 100644 --- a/engine/src/shortest_path/contraction_hierarchy/mod.rs +++ b/engine/src/shortest_path/contraction_hierarchy/mod.rs @@ -1,5 +1,5 @@ use super::*; -use self::first_out_graph::{OwnedGraph, from_adjancecy_lists}; +use self::first_out_graph::OwnedGraph; #[derive(Debug, PartialEq)] enum ShortcutResult { @@ -124,7 +124,7 @@ impl ContractionGraph { // currently we stick to the reordered graph and also translate the query node ids. // TODO make more explicit - ((from_adjancecy_lists(outgoing), from_adjancecy_lists(incoming)), Some((forward_shortcut_middles, backward_shortcut_middles))) + ((OwnedGraph::from_adjancecy_lists(outgoing), OwnedGraph::from_adjancecy_lists(incoming)), Some((forward_shortcut_middles, backward_shortcut_middles))) } } From 6478d7122f95c2bab5761459459926e1d11ed24a Mon Sep 17 00:00:00 2001 From: "Tim \"S.D.Eagle\" Zeitz" Date: Wed, 17 Jan 2018 11:05:54 +0100 Subject: [PATCH 03/10] continue cleaning up, fixing all compiler errors --- engine/src/graph/first_out_graph.rs | 14 +++++ engine/src/graph/mod.rs | 1 - engine/src/main.rs | 2 +- .../contraction_hierarchy/mod.rs | 55 ++++++++++++++----- .../query/bidirectional_dijkstra.rs | 4 +- engine/src/shortest_path/query/mod.rs | 1 - engine/src/shortest_path/stepped_dijkstra.rs | 26 ++++----- 7 files changed, 69 insertions(+), 34 deletions(-) diff --git a/engine/src/graph/first_out_graph.rs b/engine/src/graph/first_out_graph.rs index 09e3f3a8..a6928761 100644 --- a/engine/src/graph/first_out_graph.rs +++ b/engine/src/graph/first_out_graph.rs @@ -108,6 +108,20 @@ impl<'a, FirstOutContainer, FirstOutInner, HeadContainer, HeadInner, WeightConta } } +impl RandomLinkAccessGraph for FirstOutGraph where + FirstOutContainer: Borrow, + FirstOutInner: AsRef<[u32]>, + HeadContainer: Borrow, + HeadInner: AsRef<[NodeId]>, + WeightContainer: Borrow, + WeightInner: AsRef<[Weight]> +{ + fn edge_index(&self, from: NodeId, to: NodeId) -> Option { + let first_out = self.first_out()[from as usize] as usize; + self.neighbor_iter(from).enumerate().find(|&(_, Link { node, .. })| node == to).map(|(i, _)| first_out + i ) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/engine/src/graph/mod.rs b/engine/src/graph/mod.rs index ff390a6d..cd67f09e 100644 --- a/engine/src/graph/mod.rs +++ b/engine/src/graph/mod.rs @@ -1,5 +1,4 @@ use std; -use shortest_path::DijkstrableGraph; pub mod first_out_graph; diff --git a/engine/src/main.rs b/engine/src/main.rs index 84af0a67..60144a7f 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -6,8 +6,8 @@ extern crate bmw_routing_engine; extern crate time; use bmw_routing_engine::*; +use graph::*; use graph::first_out_graph::OwnedGraph as Graph; -use graph::INFINITY; use shortest_path::query::dijkstra::Server as DijkServer; use shortest_path::query::bidirectional_dijkstra::Server as BiDijkServer; use shortest_path::query::async::dijkstra::Server as AsyncDijkServer; diff --git a/engine/src/shortest_path/contraction_hierarchy/mod.rs b/engine/src/shortest_path/contraction_hierarchy/mod.rs index 37fd0446..7f2ab395 100644 --- a/engine/src/shortest_path/contraction_hierarchy/mod.rs +++ b/engine/src/shortest_path/contraction_hierarchy/mod.rs @@ -190,31 +190,60 @@ struct ForwardWrapper<'a> { graph: &'a PartialContractionGraph<'a> } -impl<'a> DijkstrableGraph for ForwardWrapper<'a> { +#[derive(Debug)] +struct BackwardWrapper<'a> { + graph: &'a PartialContractionGraph<'a> +} + +impl<'a> Graph for ForwardWrapper<'a> { fn num_nodes(&self) -> usize { self.graph.nodes.len() } +} - fn for_each_neighbor(&self, node: NodeId, f: &mut FnMut(Link)) { - for &(Link { node: target, weight }, _) in self.graph.nodes[node as usize].outgoing.iter() { - f(Link { node: target - self.graph.id_offset, weight }); - } +impl<'a> Graph for BackwardWrapper<'a> { + fn num_nodes(&self) -> usize { + self.graph.nodes.len() } } +// workaround until we get an implementation of https://github.com/rust-lang/rfcs/pull/2071 #[derive(Debug)] -struct BackwardWrapper<'a> { - graph: &'a PartialContractionGraph<'a> +struct LinkMappingIterator<'a> { + iter: std::slice::Iter<'a, (Link, NodeId)>, + offset: NodeId, } -impl<'a> DijkstrableGraph for BackwardWrapper<'a> { - fn num_nodes(&self) -> usize { - self.graph.nodes.len() +impl<'a> Iterator for LinkMappingIterator<'a> { + type Item = Link; + + fn next(&mut self) -> Option { + match self.iter.next() { + Some(&(Link { node: target, weight }, _)) => Some(Link { node: target - self.offset, weight }), + None => None, + } } +} + +use std; +impl<'a, 'b> LinkIterGraph<'b> for ForwardWrapper<'a> { + type Iter = LinkMappingIterator<'b>; + + fn neighbor_iter(&'b self, node: NodeId) -> Self::Iter { + LinkMappingIterator { + iter: self.graph.nodes[node as usize].outgoing.iter(), + offset: self.graph.id_offset + } + } +} + +impl<'a, 'b> LinkIterGraph<'b> for BackwardWrapper<'a> { + type Iter = LinkMappingIterator<'b>; - fn for_each_neighbor(&self, node: NodeId, f: &mut FnMut(Link)) { - for &(Link { node: target, weight }, _) in self.graph.nodes[node as usize].incoming.iter() { - f(Link { node: target - self.graph.id_offset, weight }); + fn neighbor_iter(&'b self, node: NodeId) -> Self::Iter { + LinkMappingIterator { + iter: self.graph.nodes[node as usize].incoming.iter(), + offset: self.graph.id_offset } } } diff --git a/engine/src/shortest_path/query/bidirectional_dijkstra.rs b/engine/src/shortest_path/query/bidirectional_dijkstra.rs index 294a6e61..767b0e4e 100644 --- a/engine/src/shortest_path/query/bidirectional_dijkstra.rs +++ b/engine/src/shortest_path/query/bidirectional_dijkstra.rs @@ -2,7 +2,7 @@ use std::collections::LinkedList; use super::*; #[derive(Debug)] -pub struct Server { +pub struct Server LinkIterGraph<'a>, H: for<'a> LinkIterGraph<'a>> { pub forward_dijkstra: SteppedDijkstra, pub backward_dijkstra: SteppedDijkstra, pub tentative_distance: Weight, @@ -10,7 +10,7 @@ pub struct Server { pub meeting_node: NodeId } -impl Server { +impl LinkIterGraph<'a>, H: for<'a> LinkIterGraph<'a>> Server { pub fn new(graph: OwnedGraph) -> Server { let reversed = graph.reverse(); diff --git a/engine/src/shortest_path/query/mod.rs b/engine/src/shortest_path/query/mod.rs index 7040880a..be503f4a 100644 --- a/engine/src/shortest_path/query/mod.rs +++ b/engine/src/shortest_path/query/mod.rs @@ -1,5 +1,4 @@ use super::*; -use graph::first_out_graph::FirstOutGraph as Graph; use graph::first_out_graph::OwnedGraph; pub mod async; diff --git a/engine/src/shortest_path/stepped_dijkstra.rs b/engine/src/shortest_path/stepped_dijkstra.rs index 8e567c21..b1c7d571 100644 --- a/engine/src/shortest_path/stepped_dijkstra.rs +++ b/engine/src/shortest_path/stepped_dijkstra.rs @@ -21,7 +21,7 @@ impl Indexing for State { } #[derive(Debug)] -pub struct SteppedDijkstra { +pub struct SteppedDijkstra LinkIterGraph<'a>> { graph: Graph, distances: TimestampedVector, predecessors: Vec, @@ -32,7 +32,7 @@ pub struct SteppedDijkstra { result: Option> } -impl SteppedDijkstra { +impl LinkIterGraph<'a>> SteppedDijkstra { pub fn new(graph: Graph) -> SteppedDijkstra { let n = graph.num_nodes(); @@ -80,29 +80,23 @@ impl SteppedDijkstra { return QueryProgress::Done(Some(distance)); } - // these are necessary because otherwise the borrow checker could not figure out - // that we're only borrowing parts of self - let closest_node_priority_queue = &mut self.closest_node_priority_queue; - let distances = &mut self.distances; - let predecessors = &mut self.predecessors; - // For each node we can reach, see if we can find a way with // a lower distance going through this node - self.graph.for_each_neighbor(node, &mut |edge: Link| { + for edge in self.graph.neighbor_iter(node) { let next = State { distance: distance + edge.weight, node: edge.node }; // If so, add it to the frontier and continue - if next.distance < distances[next.node as usize] { + if next.distance < self.distances[next.node as usize] { // Relaxation, we have now found a better way - distances.set(next.node as usize, next.distance); - predecessors[next.node as usize] = node; - if closest_node_priority_queue.contains_index(next.as_index()) { - closest_node_priority_queue.decrease_key(next); + self.distances.set(next.node as usize, next.distance); + self.predecessors[next.node as usize] = node; + if self.closest_node_priority_queue.contains_index(next.as_index()) { + self.closest_node_priority_queue.decrease_key(next); } else { - closest_node_priority_queue.push(next); + self.closest_node_priority_queue.push(next); } } - }); + } QueryProgress::Progress(State { distance, node }) } else { From c777efe56b7cd714a529066cf7fec4f872344e53 Mon Sep 17 00:00:00 2001 From: "Tim \"S.D.Eagle\" Zeitz" Date: Wed, 17 Jan 2018 11:07:43 +0100 Subject: [PATCH 04/10] removing now unnecessary dijkstrable graph trait --- engine/src/shortest_path/mod.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/engine/src/shortest_path/mod.rs b/engine/src/shortest_path/mod.rs index 1d4cdb68..e1d3bcbe 100644 --- a/engine/src/shortest_path/mod.rs +++ b/engine/src/shortest_path/mod.rs @@ -11,13 +11,3 @@ pub struct Query { from: NodeId, to: NodeId } - -pub trait DijkstrableGraph { - fn num_nodes(&self) -> usize; - // not particularily liking this interface, would be much nicer to return an iterator - // sadly we would have to box it, which would be problematic in terms of performance - // even the impl trait functionality on nightly won't allow generic return types on traits - // which makes sense when you think about it, because it would need to return something - // which does dynamic dispath, which is exactly what the boxing would do... - fn for_each_neighbor(&self, node: NodeId, f: &mut FnMut(Link)); -} From 17e606a52cfbc5db64d67c3c53277d3c3790711b Mon Sep 17 00:00:00 2001 From: "Tim \"S.D.Eagle\" Zeitz" Date: Wed, 17 Jan 2018 13:40:13 +0100 Subject: [PATCH 05/10] less generic params --- engine/src/as_slice.rs | 13 +++++ engine/src/graph/first_out_graph.rs | 74 ++++++++++------------------- engine/src/lib.rs | 1 + 3 files changed, 40 insertions(+), 48 deletions(-) create mode 100644 engine/src/as_slice.rs diff --git a/engine/src/as_slice.rs b/engine/src/as_slice.rs new file mode 100644 index 00000000..b0c61fb4 --- /dev/null +++ b/engine/src/as_slice.rs @@ -0,0 +1,13 @@ +use std::borrow::Borrow; + +pub trait AsSlice { + fn as_slice(&self) -> &[T]; +} + +impl AsSlice for T where + T: Borrow<[V]>, +{ + fn as_slice(&self) -> &[V] { + self.borrow() + } +} diff --git a/engine/src/graph/first_out_graph.rs b/engine/src/graph/first_out_graph.rs index a6928761..50f099fd 100644 --- a/engine/src/graph/first_out_graph.rs +++ b/engine/src/graph/first_out_graph.rs @@ -1,18 +1,14 @@ use super::*; +use as_slice::AsSlice; use ::io; use std::io::Result; use std::path::Path; -use std::borrow::{Borrow}; -use std::marker::PhantomData; #[derive(Debug, Clone)] -pub struct FirstOutGraph where - FirstOutContainer: Borrow, - FirstOutInner: AsRef<[u32]>, - HeadContainer: Borrow, - HeadInner: AsRef<[NodeId]>, - WeightContainer: Borrow, - WeightInner: AsRef<[Weight]> +pub struct FirstOutGraph where + FirstOutContainer: AsSlice, + HeadContainer: AsSlice, + WeightContainer: AsSlice, { // index of first edge of each node +1 entry in the end first_out: FirstOutContainer, @@ -20,34 +16,25 @@ pub struct FirstOutGraph, - _head_phantom: PhantomData, - _weight_phantom: PhantomData } -pub type OwnedGraph = FirstOutGraph, Vec, Vec, Vec, Vec, Vec>; +pub type OwnedGraph = FirstOutGraph, Vec, Vec>; -impl FirstOutGraph where - FirstOutContainer: Borrow, - FirstOutInner: AsRef<[u32]>, - HeadContainer: Borrow, - HeadInner: AsRef<[NodeId]>, - WeightContainer: Borrow, - WeightInner: AsRef<[Weight]> +impl FirstOutGraph where + FirstOutContainer: AsSlice, + HeadContainer: AsSlice, + WeightContainer: AsSlice, { - fn first_out(&self) -> &[u32] { self.first_out.borrow().as_ref() } - fn head(&self) -> &[u32] { self.head.borrow().as_ref() } - fn weight(&self) -> &[u32] { self.weight.borrow().as_ref() } + fn first_out(&self) -> &[u32] { self.first_out.as_slice() } + fn head(&self) -> &[u32] { self.head.as_slice() } + fn weight(&self) -> &[u32] { self.weight.as_slice() } pub fn new(first_out: Vec, head: Vec, weight: Vec) -> OwnedGraph { assert_eq!(*first_out.first().unwrap(), 0); assert_eq!(*first_out.last().unwrap() as usize, head.len()); assert_eq!(weight.len(), head.len()); - FirstOutGraph { - first_out, head, weight, - _first_out_phantom: PhantomData, _head_phantom: PhantomData, _weight_phantom: PhantomData - } + FirstOutGraph { first_out, head, weight } } pub fn write_to_dir(&self, dir: &str) -> Result<()> { @@ -77,26 +64,20 @@ impl OwnedGraph { } } -impl Graph for FirstOutGraph where - FirstOutContainer: Borrow, - FirstOutInner: AsRef<[u32]>, - HeadContainer: Borrow, - HeadInner: AsRef<[NodeId]>, - WeightContainer: Borrow, - WeightInner: AsRef<[Weight]> +impl Graph for FirstOutGraph where + FirstOutContainer: AsSlice, + HeadContainer: AsSlice, + WeightContainer: AsSlice, { fn num_nodes(&self) -> usize { self.first_out().len() - 1 } } -impl<'a, FirstOutContainer, FirstOutInner, HeadContainer, HeadInner, WeightContainer, WeightInner> LinkIterGraph<'a> for FirstOutGraph where - FirstOutContainer: Borrow, - FirstOutInner: AsRef<[u32]>, - HeadContainer: Borrow, - HeadInner: AsRef<[NodeId]>, - WeightContainer: Borrow, - WeightInner: AsRef<[Weight]> +impl<'a, FirstOutContainer, HeadContainer, WeightContainer> LinkIterGraph<'a> for FirstOutGraph where + FirstOutContainer: AsSlice, + HeadContainer: AsSlice, + WeightContainer: AsSlice, { type Iter = std::iter::Map, std::slice::Iter<'a, Weight>>, fn((&NodeId, &Weight))->Link>; @@ -108,13 +89,10 @@ impl<'a, FirstOutContainer, FirstOutInner, HeadContainer, HeadInner, WeightConta } } -impl RandomLinkAccessGraph for FirstOutGraph where - FirstOutContainer: Borrow, - FirstOutInner: AsRef<[u32]>, - HeadContainer: Borrow, - HeadInner: AsRef<[NodeId]>, - WeightContainer: Borrow, - WeightInner: AsRef<[Weight]> +impl RandomLinkAccessGraph for FirstOutGraph where + FirstOutContainer: AsSlice, + HeadContainer: AsSlice, + WeightContainer: AsSlice, { fn edge_index(&self, from: NodeId, to: NodeId) -> Option { let first_out = self.first_out()[from as usize] as usize; diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 5fe510b1..b75bfbd8 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -15,6 +15,7 @@ pub mod io; mod index_heap; pub mod rank_select_map; pub mod import; +mod as_slice; #[cfg(test)] mod tests { From 5c7f79fee056af9807fda4f722ba6cd93112ce70 Mon Sep 17 00:00:00 2001 From: "Tim \"S.D.Eagle\" Zeitz" Date: Wed, 17 Jan 2018 13:44:20 +0100 Subject: [PATCH 06/10] allow construction of graphs with non owned data --- engine/src/graph/first_out_graph.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/src/graph/first_out_graph.rs b/engine/src/graph/first_out_graph.rs index 50f099fd..440cf645 100644 --- a/engine/src/graph/first_out_graph.rs +++ b/engine/src/graph/first_out_graph.rs @@ -29,10 +29,10 @@ impl FirstOutGraph &[u32] { self.head.as_slice() } fn weight(&self) -> &[u32] { self.weight.as_slice() } - pub fn new(first_out: Vec, head: Vec, weight: Vec) -> OwnedGraph { - assert_eq!(*first_out.first().unwrap(), 0); - assert_eq!(*first_out.last().unwrap() as usize, head.len()); - assert_eq!(weight.len(), head.len()); + pub fn new(first_out: FirstOutContainer, head: HeadContainer, weight: WeightContainer) -> FirstOutGraph { + assert_eq!(*first_out.as_slice().first().unwrap(), 0); + assert_eq!(*first_out.as_slice().last().unwrap() as usize, head.as_slice().len()); + assert_eq!(weight.as_slice().len(), head.as_slice().len()); FirstOutGraph { first_out, head, weight } } From d44678d093b661c1ec45df67075de837bb0df920 Mon Sep 17 00:00:00 2001 From: "Tim \"S.D.Eagle\" Zeitz" Date: Wed, 17 Jan 2018 14:14:10 +0100 Subject: [PATCH 07/10] start sharing graph data --- engine/src/graph/mod.rs | 2 +- engine/src/main.rs | 9 +++++---- engine/src/shortest_path/contraction_hierarchy/mod.rs | 4 ++-- engine/src/shortest_path/query/bidirectional_dijkstra.rs | 6 ++++-- engine/src/shortest_path/query/dijkstra.rs | 8 ++++---- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/engine/src/graph/mod.rs b/engine/src/graph/mod.rs index cd67f09e..1774ebbb 100644 --- a/engine/src/graph/mod.rs +++ b/engine/src/graph/mod.rs @@ -2,7 +2,7 @@ use std; pub mod first_out_graph; -use self::first_out_graph::OwnedGraph; +pub use self::first_out_graph::{OwnedGraph, FirstOutGraph}; pub type NodeId = u32; pub type Weight = u32; diff --git a/engine/src/main.rs b/engine/src/main.rs index 60144a7f..5c8998b8 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -32,11 +32,12 @@ fn main() { let to = read_into_vector(path.join("test/target").to_str().unwrap()).expect("could not read target"); let ground_truth = read_into_vector(path.join("test/travel_time_length").to_str().unwrap()).expect("could not read travel_time_length"); - let graph = Graph::new(first_out, head, travel_time); + let graph = FirstOutGraph::new(&first_out[..], &head[..], &travel_time[..]); + let owned_graph = OwnedGraph::new(first_out.clone(), head.clone(), travel_time.clone()); let mut simple_server = DijkServer::new(graph.clone()); - let mut bi_dir_server = BiDijkServer::::new(graph.clone()); - let async_server = AsyncDijkServer::new(graph.clone()); - let mut async_bi_dir_server = AsyncBiDijkServer::new(graph.clone()); + let mut bi_dir_server = BiDijkServer::new(graph.clone()); + let async_server = AsyncDijkServer::new(owned_graph.clone()); + let mut async_bi_dir_server = AsyncBiDijkServer::new(owned_graph); let ch_first_out = read_into_vector(path.join("travel_time_ch/first_out").to_str().unwrap()).expect("could not read travel_time_ch/first_out"); let ch_head = read_into_vector(path.join("travel_time_ch/head").to_str().unwrap()).expect("could not read travel_time_ch/head"); diff --git a/engine/src/shortest_path/contraction_hierarchy/mod.rs b/engine/src/shortest_path/contraction_hierarchy/mod.rs index 7f2ab395..83bd753a 100644 --- a/engine/src/shortest_path/contraction_hierarchy/mod.rs +++ b/engine/src/shortest_path/contraction_hierarchy/mod.rs @@ -58,7 +58,7 @@ struct ContractionGraph { } impl ContractionGraph { - fn new(graph: OwnedGraph, node_order: Vec) -> ContractionGraph { + fn new LinkIterGraph<'a>>(graph: Graph, node_order: Vec) -> ContractionGraph { let n = graph.num_nodes(); let mut node_ranks = vec![0; n]; for (i, &node) in node_order.iter().enumerate() { @@ -179,7 +179,7 @@ impl<'a> PartialContractionGraph<'a> { } } -pub fn contract(graph: OwnedGraph, node_order: Vec) -> ((OwnedGraph, OwnedGraph), Option<(Vec, Vec)>) { +pub fn contract LinkIterGraph<'a>>(graph: Graph, node_order: Vec) -> ((OwnedGraph, OwnedGraph), Option<(Vec, Vec)>) { let mut graph = ContractionGraph::new(graph, node_order); graph.contract(); graph.as_first_out_graphs() diff --git a/engine/src/shortest_path/query/bidirectional_dijkstra.rs b/engine/src/shortest_path/query/bidirectional_dijkstra.rs index 767b0e4e..8b6eb104 100644 --- a/engine/src/shortest_path/query/bidirectional_dijkstra.rs +++ b/engine/src/shortest_path/query/bidirectional_dijkstra.rs @@ -10,8 +10,8 @@ pub struct Server LinkIterGraph<'a>, H: for<'a> LinkIterGraph<'a>> { pub meeting_node: NodeId } -impl LinkIterGraph<'a>, H: for<'a> LinkIterGraph<'a>> Server { - pub fn new(graph: OwnedGraph) -> Server { +impl LinkIterGraph<'a>> Server { + pub fn new(graph: G) -> Server { let reversed = graph.reverse(); Server { @@ -22,7 +22,9 @@ impl LinkIterGraph<'a>, H: for<'a> LinkIterGraph<'a>> Server { meeting_node: 0 } } +} +impl LinkIterGraph<'a>, H: for<'a> LinkIterGraph<'a>> Server { pub fn distance(&mut self, from: NodeId, to: NodeId) -> Option { // initialize self.tentative_distance = INFINITY; diff --git a/engine/src/shortest_path/query/dijkstra.rs b/engine/src/shortest_path/query/dijkstra.rs index 318b5a63..6ce3a5af 100644 --- a/engine/src/shortest_path/query/dijkstra.rs +++ b/engine/src/shortest_path/query/dijkstra.rs @@ -3,12 +3,12 @@ use super::*; use std::collections::LinkedList; #[derive(Debug)] -pub struct Server { - dijkstra: SteppedDijkstra, +pub struct Server LinkIterGraph<'a>> { + dijkstra: SteppedDijkstra, } -impl Server { - pub fn new(graph: OwnedGraph) -> Server { +impl LinkIterGraph<'a>> Server { + pub fn new(graph: Graph) -> Server { Server { dijkstra: SteppedDijkstra::new(graph) } From 1379943df17ac8480a95fc2e42fcfb35036c3722 Mon Sep 17 00:00:00 2001 From: "Tim \"S.D.Eagle\" Zeitz" Date: Wed, 17 Jan 2018 15:18:08 +0100 Subject: [PATCH 08/10] almost complete deduplication achieved slight penalty on async servers because usage of Arcs can possibly fixed, if we use and decompose (and then slice) FirstOutGraphs rather than LinkIterGraphs reversed graphs are still duplicated --- engine/src/as_slice.rs | 21 +++++++++++++++---- engine/src/graph/first_out_graph.rs | 4 ++++ engine/src/main.rs | 13 ++++++------ .../query/async/bidirectional_dijkstra.rs | 5 +++-- .../src/shortest_path/query/async/dijkstra.rs | 2 +- 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/engine/src/as_slice.rs b/engine/src/as_slice.rs index b0c61fb4..d6722fbb 100644 --- a/engine/src/as_slice.rs +++ b/engine/src/as_slice.rs @@ -1,13 +1,26 @@ -use std::borrow::Borrow; +use std::sync::Arc; pub trait AsSlice { fn as_slice(&self) -> &[T]; } -impl AsSlice for T where - T: Borrow<[V]>, +impl AsSlice for Vec where { fn as_slice(&self) -> &[V] { - self.borrow() + &self[..] + } +} + +impl<'a, V> AsSlice for &'a [V] where +{ + fn as_slice(&self) -> &[V] { + self + } +} + +impl AsSlice for Arc> where +{ + fn as_slice(&self) -> &[V] { + &self[..] } } diff --git a/engine/src/graph/first_out_graph.rs b/engine/src/graph/first_out_graph.rs index 440cf645..ec4c7f17 100644 --- a/engine/src/graph/first_out_graph.rs +++ b/engine/src/graph/first_out_graph.rs @@ -44,6 +44,10 @@ impl FirstOutGraph (FirstOutContainer, HeadContainer, WeightContainer) { + (self.first_out, self.head, self.weight) + } } impl OwnedGraph { diff --git a/engine/src/main.rs b/engine/src/main.rs index 5c8998b8..b2d72370 100644 --- a/engine/src/main.rs +++ b/engine/src/main.rs @@ -1,5 +1,6 @@ use std::env; use std::path::Path; +use std::sync::Arc; extern crate bmw_routing_engine; @@ -24,20 +25,20 @@ fn main() { let arg = &args.next().expect("No directory arg given"); let path = Path::new(arg); - let first_out = read_into_vector(path.join("first_out").to_str().unwrap()).expect("could not read first_out"); - let head = read_into_vector(path.join("head").to_str().unwrap()).expect("could not read head"); - let travel_time = read_into_vector(path.join("travel_time").to_str().unwrap()).expect("could not read travel_time"); + let first_out = Arc::new(read_into_vector(path.join("first_out").to_str().unwrap()).expect("could not read first_out")); + let head = Arc::new(read_into_vector(path.join("head").to_str().unwrap()).expect("could not read head")); + let travel_time = Arc::new(read_into_vector(path.join("travel_time").to_str().unwrap()).expect("could not read travel_time")); let from = read_into_vector(path.join("test/source").to_str().unwrap()).expect("could not read source"); let to = read_into_vector(path.join("test/target").to_str().unwrap()).expect("could not read target"); let ground_truth = read_into_vector(path.join("test/travel_time_length").to_str().unwrap()).expect("could not read travel_time_length"); let graph = FirstOutGraph::new(&first_out[..], &head[..], &travel_time[..]); - let owned_graph = OwnedGraph::new(first_out.clone(), head.clone(), travel_time.clone()); + let arcd_graph = FirstOutGraph::new(first_out.clone(), head.clone(), travel_time.clone()); let mut simple_server = DijkServer::new(graph.clone()); let mut bi_dir_server = BiDijkServer::new(graph.clone()); - let async_server = AsyncDijkServer::new(owned_graph.clone()); - let mut async_bi_dir_server = AsyncBiDijkServer::new(owned_graph); + let async_server = AsyncDijkServer::new(arcd_graph.clone()); + let mut async_bi_dir_server = AsyncBiDijkServer::new(arcd_graph); let ch_first_out = read_into_vector(path.join("travel_time_ch/first_out").to_str().unwrap()).expect("could not read travel_time_ch/first_out"); let ch_head = read_into_vector(path.join("travel_time_ch/head").to_str().unwrap()).expect("could not read travel_time_ch/head"); diff --git a/engine/src/shortest_path/query/async/bidirectional_dijkstra.rs b/engine/src/shortest_path/query/async/bidirectional_dijkstra.rs index 44e6779d..119a1f86 100644 --- a/engine/src/shortest_path/query/async/bidirectional_dijkstra.rs +++ b/engine/src/shortest_path/query/async/bidirectional_dijkstra.rs @@ -37,7 +37,7 @@ pub struct Server { } impl Server { - pub fn new(graph: OwnedGraph) -> Server { + pub fn new LinkIterGraph<'a> + Send + 'static>(graph: Graph) -> Server { let (forward_query_sender, forward_query_receiver) = channel(); let (forward_progress_sender, forward_progress_receiver) = channel(); let (backward_query_sender, backward_query_receiver) = channel(); @@ -69,7 +69,8 @@ impl Server { } } - fn spawn_direction_worker(graph: OwnedGraph, + fn spawn_direction_worker LinkIterGraph<'a> + Send + 'static>( + graph: Graph, query_receiver: Receiver<(ServerControl, u32)>, progress_sender: Sender<(QueryProgress, u32)>, distances_pointer: Arc>, diff --git a/engine/src/shortest_path/query/async/dijkstra.rs b/engine/src/shortest_path/query/async/dijkstra.rs index 6b0baf54..6366246a 100644 --- a/engine/src/shortest_path/query/async/dijkstra.rs +++ b/engine/src/shortest_path/query/async/dijkstra.rs @@ -7,7 +7,7 @@ pub struct Server { } impl Server { - pub fn new(graph: OwnedGraph) -> Server { + pub fn new LinkIterGraph<'a> + Send + 'static>(graph: Graph) -> Server { let (query_sender, query_receiver) = channel(); let (progress_sender, progress_receiver) = channel(); From 9f47e853ad55acc7314f7e754d4b2dce183119a1 Mon Sep 17 00:00:00 2001 From: "Tim \"S.D.Eagle\" Zeitz" Date: Wed, 17 Jan 2018 15:27:57 +0100 Subject: [PATCH 09/10] add comment on GAT --- engine/src/graph/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/graph/mod.rs b/engine/src/graph/mod.rs index 1774ebbb..a03258da 100644 --- a/engine/src/graph/mod.rs +++ b/engine/src/graph/mod.rs @@ -19,7 +19,7 @@ pub trait Graph { } pub trait LinkIterGraph<'a>: Graph { - type Iter: Iterator + 'a; + type Iter: Iterator + 'a; // fix with https://github.com/rust-lang/rfcs/pull/1598 fn neighbor_iter(&'a self, node: NodeId) -> Self::Iter; From 2310819760e11aade706ab49807767c295d755d8 Mon Sep 17 00:00:00 2001 From: "Tim \"S.D.Eagle\" Zeitz" Date: Wed, 17 Jan 2018 15:39:36 +0100 Subject: [PATCH 10/10] some cleanup of modules --- engine/src/import/here/mod.rs | 1 - engine/src/shortest_path/contraction_hierarchy/mod.rs | 1 - engine/src/shortest_path/mod.rs | 6 ++++-- engine/src/shortest_path/query/mod.rs | 1 - engine/src/shortest_path/stepped_dijkstra.rs | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/engine/src/import/here/mod.rs b/engine/src/import/here/mod.rs index d3a23272..43eb958a 100644 --- a/engine/src/import/here/mod.rs +++ b/engine/src/import/here/mod.rs @@ -1,5 +1,4 @@ use ::graph::*; -use ::graph::first_out_graph::OwnedGraph; use ::rank_select_map::RankSelectMap; use std::iter; use std::str::FromStr; diff --git a/engine/src/shortest_path/contraction_hierarchy/mod.rs b/engine/src/shortest_path/contraction_hierarchy/mod.rs index 83bd753a..df402dd1 100644 --- a/engine/src/shortest_path/contraction_hierarchy/mod.rs +++ b/engine/src/shortest_path/contraction_hierarchy/mod.rs @@ -1,5 +1,4 @@ use super::*; -use self::first_out_graph::OwnedGraph; #[derive(Debug, PartialEq)] enum ShortcutResult { diff --git a/engine/src/shortest_path/mod.rs b/engine/src/shortest_path/mod.rs index e1d3bcbe..f42a1edf 100644 --- a/engine/src/shortest_path/mod.rs +++ b/engine/src/shortest_path/mod.rs @@ -1,8 +1,10 @@ -use super::graph::*; -use self::stepped_dijkstra::{SteppedDijkstra, QueryProgress, State}; +use graph::*; mod timestamped_vector; mod stepped_dijkstra; + +use self::stepped_dijkstra::{SteppedDijkstra, QueryProgress, State}; + pub mod contraction_hierarchy; pub mod query; diff --git a/engine/src/shortest_path/query/mod.rs b/engine/src/shortest_path/query/mod.rs index be503f4a..314241ca 100644 --- a/engine/src/shortest_path/query/mod.rs +++ b/engine/src/shortest_path/query/mod.rs @@ -1,5 +1,4 @@ use super::*; -use graph::first_out_graph::OwnedGraph; pub mod async; pub mod dijkstra; diff --git a/engine/src/shortest_path/stepped_dijkstra.rs b/engine/src/shortest_path/stepped_dijkstra.rs index b1c7d571..ca965c60 100644 --- a/engine/src/shortest_path/stepped_dijkstra.rs +++ b/engine/src/shortest_path/stepped_dijkstra.rs @@ -1,6 +1,6 @@ use super::*; +use self::timestamped_vector::TimestampedVector; use index_heap::{IndexdMinHeap, Indexing}; -use super::timestamped_vector::TimestampedVector; #[derive(Debug, Clone)] pub enum QueryProgress {