From ba9360bb2fcde017ce09f2eb4a3bbb4be96350c9 Mon Sep 17 00:00:00 2001 From: "Tim \"tim3z\" Zeitz" Date: Fri, 23 Sep 2022 11:25:37 +0200 Subject: [PATCH] lower bound validation and temporary live --- .../src/datastr/graph/time_dependent/graph.rs | 37 +++++++++ .../piecewise_linear_function.rs | 36 +++++++- tdpot/src/bin/temporary_live.rs | 83 +++++++++++++++++++ tdpot/src/bin/validate_lower_bound_prop.rs | 39 +++++++++ 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 tdpot/src/bin/temporary_live.rs create mode 100644 tdpot/src/bin/validate_lower_bound_prop.rs diff --git a/engine/src/datastr/graph/time_dependent/graph.rs b/engine/src/datastr/graph/time_dependent/graph.rs index a07a0c6a..71eaa5f0 100644 --- a/engine/src/datastr/graph/time_dependent/graph.rs +++ b/engine/src/datastr/graph/time_dependent/graph.rs @@ -147,6 +147,14 @@ impl Graph { ipp_travel_time, } } + + pub fn to_constant_lower(&mut self) { + self.ipp_travel_time = (0..self.num_arcs()) + .map(|edge| self.travel_time_function(edge as EdgeId).lower_bound()) + .collect(); + self.first_ipp_of_arc = (0..(self.num_arcs() + 1) as u32).collect(); + self.ipp_departure_time = std::iter::repeat(0).take(self.num_arcs()).collect(); + } } impl GraphTrait for Graph { @@ -445,6 +453,31 @@ impl PessimisticLiveTDGraph { }) } + pub fn is_live_slower(&self, edge_id: EdgeId, now: Timestamp) -> Option { + self.live[edge_id as usize] + .value() + .filter(|&(l, _t)| self.graph.travel_time_function(edge_id).lower_bound() <= l) + .map(|(l, t)| self.graph.travel_time_function(edge_id).lower_bound_in_range(now..t) <= l) + } + + pub fn check_global_lower(&self) { + for edge_id in 0..self.num_arcs() { + if let Some((tt, _)) = self.live[edge_id].value() { + assert!(tt >= self.graph.travel_time_function(edge_id as EdgeId).lower_bound()); + } + } + } + + pub fn remove_live_faster_than_global_lower(&mut self) { + for edge_id in 0..self.num_arcs() { + if let Some((tt, _)) = self.live[edge_id].value() { + if tt < self.graph.travel_time_function(edge_id as EdgeId).lower_bound() { + self.live[edge_id] = InRangeOption::NONE + } + } + } + } + pub fn graph(&self) -> &Graph { &self.graph } @@ -465,6 +498,10 @@ impl PessimisticLiveTDGraph { Self { graph, live } } + + pub fn to_constant_lower(&mut self) { + self.graph.to_constant_lower() + } } impl crate::datastr::graph::Graph for PessimisticLiveTDGraph { diff --git a/engine/src/datastr/graph/time_dependent/piecewise_linear_function.rs b/engine/src/datastr/graph/time_dependent/piecewise_linear_function.rs index faced83a..00c3b239 100644 --- a/engine/src/datastr/graph/time_dependent/piecewise_linear_function.rs +++ b/engine/src/datastr/graph/time_dependent/piecewise_linear_function.rs @@ -53,7 +53,7 @@ impl<'a> PiecewiseLinearFunction<'a> { *self.travel_time.iter().min().unwrap() } - /// Calculate average Weight over a given time range. + /// Calculate min Weight over a given time range. pub fn lower_bound_in_range(&self, range: Range) -> Weight { if let &[const_tt] = self.travel_time { return const_tt; @@ -88,6 +88,40 @@ impl<'a> PiecewiseLinearFunction<'a> { .unwrap() } + pub fn upper_bound_in_range(&self, range: Range) -> Weight { + if let &[const_tt] = self.travel_time { + return const_tt; + } + + let (first_range, mut second_range) = range.split(period()); + second_range.start %= period(); + second_range.end %= period(); + std::cmp::max(self.upper_bound_in_included(first_range), self.upper_bound_in_included(second_range)) + } + + pub fn upper_bound_in_included(&self, range: Range) -> Weight { + if range.is_empty() { + return INFINITY; + } + let (first_idx, first_lower) = match self.departure_time.locate(range.start, |&dt| dt) { + Location::On(index) => (index, INFINITY), + Location::Between(_lower_index, upper_index) => (upper_index, self.evaluate(range.start)), + }; + + let (last_idx, last_lower) = match self.departure_time.locate(range.end, |&dt| dt) { + Location::On(index) => (index, INFINITY), + Location::Between(lower_index, _upper_index) => (lower_index, self.evaluate(range.end)), + }; + + self.travel_time[first_idx..=last_idx] + .iter() + .copied() + .chain(std::iter::once(first_lower)) + .chain(std::iter::once(last_lower)) + .max() + .unwrap() + } + /// Find the highest value of the function pub fn upper_bound(&self) -> Weight { *self.travel_time.iter().max().unwrap() diff --git a/tdpot/src/bin/temporary_live.rs b/tdpot/src/bin/temporary_live.rs new file mode 100644 index 00000000..1634a463 --- /dev/null +++ b/tdpot/src/bin/temporary_live.rs @@ -0,0 +1,83 @@ +#[macro_use] +extern crate rust_road_router; +use rust_road_router::{ + algo::{ + ch_potentials::{td_query::Server, *}, + customizable_contraction_hierarchy::*, + dijkstra::query::td_dijkstra::*, + }, + cli::CliErr, + datastr::{graph::*, node_order::*}, + experiments::{chpot::num_queries, run_td_queries}, + io::*, + report::*, +}; +use std::{env, error::Error, path::Path}; + +fn main() -> Result<(), Box> { + let _reporter = enable_reporting("live_and_predicted_queries"); + + let mut args = env::args().skip(1); + let arg = args.next().ok_or(CliErr("No directory arg given"))?; + let path = Path::new(&arg); + + let t_live = args.next().unwrap_or("0".to_string()).parse().unwrap(); + let live_data_file = args.next().unwrap_or("live_data".to_string()); + report!("t_live", t_live); + report!("live_data_file", live_data_file); + + let mut live_graph = (live_data_file, t_live).reconstruct_from(&path)?; + live_graph.to_constant_lower(); + let graph = live_graph.graph(); + + let cch = { + let _blocked = block_reporting(); + let order = NodeOrder::from_node_order(Vec::load_from(path.join("cch_perm"))?); + CCH::fix_order_and_build(graph, order) + }; + + let queries = args.next().unwrap(); + let sources = Vec::::load_from(path.join(&queries).join("source"))?; + let targets = Vec::::load_from(path.join(&queries).join("target"))?; + let mut ranks = Vec::::load_from(path.join(&queries).join("rank")).ok().map(Vec::into_iter); + let mut report_ranks = || { + if let Some(ranks) = ranks.as_mut() { + report!("rank", ranks.next().unwrap()); + } + }; + let query_iter = sources.into_iter().zip(targets).map(|(from, to)| (from, to, t_live)).take(num_queries()); + + let pot = args.next(); + + match pot.as_deref() { + Some("zero") => { + use rust_road_router::algo::a_star::ZeroPotential; + report!("potential", "zero"); + let mut server = without_reporting(|| Server::new_no_topo(&live_graph, ZeroPotential(), PessimisticLiveTDDijkstraOps::default())); + + let mut algo_runs_ctxt = push_collection_context("algo_runs"); + run_td_queries(query_iter, &mut server, Some(&mut algo_runs_ctxt), |_, _, _, _| report_ranks(), |_, _, _| None); + } + Some("ch_potentials") => { + report!("potential", "ch_pot"); + let potential = CHPotential::reconstruct_from(&path.join("lower_bound_ch"))?; + let mut server = without_reporting(|| Server::new(&live_graph, potential, PessimisticLiveTDDijkstraOps::default())); + + let mut algo_runs_ctxt = push_collection_context("algo_runs"); + run_td_queries(query_iter, &mut server, Some(&mut algo_runs_ctxt), |_, _, _, _| report_ranks(), |_, _, _| None); + } + _ => { + report!("potential", "lower_bound_cch_pot"); + let lower_bound = (0..graph.num_arcs() as EdgeId) + .map(|edge_id| graph.travel_time_function(edge_id).lower_bound()) + .collect::>(); + let cch_pot_data = without_reporting(|| CCHPotData::new(&cch, &BorrowedGraph::new(graph.first_out(), graph.head(), &lower_bound))); + let mut server = without_reporting(|| Server::new(&live_graph, cch_pot_data.forward_potential(), PessimisticLiveTDDijkstraOps::default())); + + let mut algo_runs_ctxt = push_collection_context("algo_runs"); + run_td_queries(query_iter, &mut server, Some(&mut algo_runs_ctxt), |_, _, _, _| report_ranks(), |_, _, _| None); + } + } + + Ok(()) +} diff --git a/tdpot/src/bin/validate_lower_bound_prop.rs b/tdpot/src/bin/validate_lower_bound_prop.rs new file mode 100644 index 00000000..601a9b6d --- /dev/null +++ b/tdpot/src/bin/validate_lower_bound_prop.rs @@ -0,0 +1,39 @@ +#[macro_use] +extern crate rust_road_router; +use rust_road_router::{cli::CliErr, datastr::graph::*, io::*, report::*}; +use std::{env, error::Error, path::Path}; + +fn main() -> Result<(), Box> { + let _reporter = enable_reporting("live_and_predicted_queries"); + + let mut args = env::args().skip(1); + let arg = args.next().ok_or(CliErr("No directory arg given"))?; + let path = Path::new(&arg); + + let t_live = args.next().unwrap_or("0".to_string()).parse().unwrap(); + let live_data_file = args.next().unwrap_or("live_data".to_string()); + report!("t_live", t_live); + report!("live_data_file", live_data_file); + + let live_graph = (live_data_file, t_live).reconstruct_from(&path)?; + + // live_graph.check_global_lower(); + + let mut live_counter = 0; + let mut valid_counter = 0; + + for e in 0..live_graph.num_arcs() { + if let Some(valid) = live_graph.is_live_slower(e as EdgeId, t_live) { + live_counter += 1; + if valid { + valid_counter += 1 + } + } + } + + report!("valid_edges", valid_counter); + report!("live_edges", live_counter); + report!("total_edges", live_graph.num_arcs()); + + Ok(()) +}