Skip to content

Commit

Permalink
Merge pull request #5 from SDEagle/dedup_v2
Browse files Browse the repository at this point in the history
Dedup v2
  • Loading branch information
tim3z authored Jan 19, 2018
2 parents 5e3ae11 + 2310819 commit ec0f698
Show file tree
Hide file tree
Showing 16 changed files with 235 additions and 144 deletions.
26 changes: 26 additions & 0 deletions engine/src/as_slice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use std::sync::Arc;

pub trait AsSlice<T> {
fn as_slice(&self) -> &[T];
}

impl<V> AsSlice<V> for Vec<V> where
{
fn as_slice(&self) -> &[V] {
&self[..]
}
}

impl<'a, V> AsSlice<V> for &'a [V] where
{
fn as_slice(&self) -> &[V] {
self
}
}

impl<V> AsSlice<V> for Arc<Vec<V>> where
{
fn as_slice(&self) -> &[V] {
&self[..]
}
}
140 changes: 70 additions & 70 deletions engine/src/graph/first_out_graph.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,57 @@
use super::*;
use as_slice::AsSlice;
use ::io;
use std::io::Result;
use std::path::Path;

#[derive(Debug, Clone)]
pub struct FirstOutGraph {
pub struct FirstOutGraph<FirstOutContainer, HeadContainer, WeightContainer> where
FirstOutContainer: AsSlice<u32>,
HeadContainer: AsSlice<NodeId>,
WeightContainer: AsSlice<Weight>,
{
// index of first edge of each node +1 entry in the end
first_out: Vec<u32>,
first_out: FirstOutContainer,
// the node ids to which each edge points
head: Vec<NodeId>,
head: HeadContainer,
// the weight of each edge
weight: Vec<Weight>
weight: WeightContainer,
}

impl FirstOutGraph {
pub fn new(first_out: Vec<u32>, head: Vec<NodeId>, weight: Vec<Weight>) -> FirstOutGraph {
assert_eq!(*first_out.first().unwrap(), 0);
assert_eq!(*first_out.last().unwrap() as usize, head.len());
assert_eq!(weight.len(), head.len());
pub type OwnedGraph = FirstOutGraph<Vec<u32>, Vec<NodeId>, Vec<Weight>>;

FirstOutGraph {
first_out, head, weight
}
impl<FirstOutContainer, HeadContainer, WeightContainer> FirstOutGraph<FirstOutContainer, HeadContainer, WeightContainer> where
FirstOutContainer: AsSlice<u32>,
HeadContainer: AsSlice<NodeId>,
WeightContainer: AsSlice<Weight>,
{
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: FirstOutContainer, head: HeadContainer, weight: WeightContainer) -> FirstOutGraph<FirstOutContainer, HeadContainer, WeightContainer> {
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 }
}

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());
res1.and(res2).and(res3)
}

pub fn from_adjancecy_lists(adjancecy_lists: Vec<Vec<Link>>) -> FirstOutGraph {
pub fn decompose(self) -> (FirstOutContainer, HeadContainer, WeightContainer) {
(self.first_out, self.head, self.weight)
}
}

impl OwnedGraph {
pub fn from_adjancecy_lists(adjancecy_lists: Vec<Vec<Link>>) -> 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;
Expand All @@ -37,70 +64,43 @@ impl FirstOutGraph {
.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::iter::Zip<std::slice::Iter<NodeId>, std::slice::Iter<Weight>>, 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<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 {
// vector of adjacency lists for the reverse graph
let mut reversed: Vec<Vec<Link>> = (0..self.num_nodes()).map(|_| Vec::<Link>::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 });
}
}
FirstOutGraph::from_adjancecy_lists(reversed)
}

pub fn ch_split(self, node_ranks: &Vec<u32>) -> (FirstOutGraph, FirstOutGraph) {
let mut up: Vec<Vec<Link>> = (0..self.num_nodes()).map(|_| Vec::<Link>::new() ).collect();
let mut down: Vec<Vec<Link>> = (0..self.num_nodes()).map(|_| Vec::<Link>::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 });
}
}
}

(FirstOutGraph::from_adjancecy_lists(up), FirstOutGraph::from_adjancecy_lists(down))
OwnedGraph::new(first_out, head, weight)
}
}

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);
res1.and(res2).and(res3)
impl<FirstOutContainer, HeadContainer, WeightContainer> Graph for FirstOutGraph<FirstOutContainer, HeadContainer, WeightContainer> where
FirstOutContainer: AsSlice<u32>,
HeadContainer: AsSlice<NodeId>,
WeightContainer: AsSlice<Weight>,
{
fn num_nodes(&self) -> usize {
self.first_out().len() - 1
}
}

impl DijkstrableGraph for FirstOutGraph {
fn num_nodes(&self) -> usize {
self.first_out.len() - 1
impl<'a, FirstOutContainer, HeadContainer, WeightContainer> LinkIterGraph<'a> for FirstOutGraph<FirstOutContainer, HeadContainer, WeightContainer> where
FirstOutContainer: AsSlice<u32>,
HeadContainer: AsSlice<NodeId>,
WeightContainer: AsSlice<Weight>,
{
type Iter = std::iter::Map<std::iter::Zip<std::slice::Iter<'a, NodeId>, 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 } )
}
}

fn for_each_neighbor(&self, node: NodeId, f: &mut FnMut(Link)) {
for link in self.neighbor_iter(node) {
f(link);
}
impl<FirstOutContainer, HeadContainer, WeightContainer> RandomLinkAccessGraph for FirstOutGraph<FirstOutContainer, HeadContainer, WeightContainer> where
FirstOutContainer: AsSlice<u32>,
HeadContainer: AsSlice<NodeId>,
WeightContainer: AsSlice<Weight>,
{
fn edge_index(&self, from: NodeId, to: NodeId) -> Option<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 )
}
}

Expand Down
49 changes: 48 additions & 1 deletion engine/src/graph/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std;
use shortest_path::DijkstrableGraph;

pub mod first_out_graph;

pub use self::first_out_graph::{OwnedGraph, FirstOutGraph};

pub type NodeId = u32;
pub type Weight = u32;
pub const INFINITY: u32 = std::u32::MAX / 2;
Expand All @@ -12,3 +13,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<Item = Link> + 'a; // fix with https://github.com/rust-lang/rfcs/pull/1598

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<Vec<Link>> = (0..self.num_nodes()).map(|_| Vec::<Link>::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<u32>) -> (OwnedGraph, OwnedGraph) {
let mut up: Vec<Vec<Link>> = (0..self.num_nodes()).map(|_| Vec::<Link>::new() ).collect();
let mut down: Vec<Vec<Link>> = (0..self.num_nodes()).map(|_| Vec::<Link>::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<usize>;
}
5 changes: 2 additions & 3 deletions engine/src/import/here/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use ::graph::*;
use ::graph::first_out_graph::FirstOutGraph;
use ::rank_select_map::RankSelectMap;
use std::iter;
use std::str::FromStr;
Expand Down Expand Up @@ -130,7 +129,7 @@ pub trait RdfDataSource {
fn link_geometries(&self) -> Vec<RdfLinkGeometry>;
}

pub fn read_graph(source: &RdfDataSource) -> (FirstOutGraph, Vec<f32>, Vec<f32>) {
pub fn read_graph(source: &RdfDataSource) -> (OwnedGraph, Vec<f32>, Vec<f32>) {
println!("read nav links");
// start with all nav links
let mut nav_links: Vec<RdfNavLink> = source.nav_links();
Expand Down Expand Up @@ -274,7 +273,7 @@ pub fn read_graph(source: &RdfDataSource) -> (FirstOutGraph, Vec<f32>, Vec<f32>)
// 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)
Expand Down
2 changes: 1 addition & 1 deletion engine/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub fn read_into_vector<T>(filename: &str) -> Result<Vec<T>> {
Ok(buffer)
}

pub fn write_vector_to_file<T>(filename: &str, vector: &Vec<T>) -> Result<()> {
pub fn write_vector_to_file<T>(filename: &str, vector: &[T]) -> Result<()> {
let mut buffer = File::create(filename)?;
let num_bytes = vector.len() * mem::size_of::<T>();

Expand Down
1 change: 1 addition & 0 deletions engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
20 changes: 11 additions & 9 deletions engine/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use std::env;
use std::path::Path;
use std::sync::Arc;

extern crate bmw_routing_engine;

extern crate time;

use bmw_routing_engine::*;
use graph::first_out_graph::FirstOutGraph as Graph;
use graph::INFINITY;
use graph::*;
use graph::first_out_graph::OwnedGraph as Graph;
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;
Expand All @@ -24,19 +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 = Graph::new(first_out, head, travel_time);
let graph = FirstOutGraph::new(&first_out[..], &head[..], &travel_time[..]);
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::<Graph, Graph>::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(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");
Expand Down
Loading

0 comments on commit ec0f698

Please sign in to comment.