Skip to content

Commit

Permalink
Merge pull request #95 from NREL/ndr/turn-restrictions
Browse files Browse the repository at this point in the history
Add turn restrictions
  • Loading branch information
nreinicke authored Jan 3, 2024
2 parents 7ba1975 + 4f86155 commit 834e23e
Show file tree
Hide file tree
Showing 28 changed files with 384 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ pub fn run_a_star(
current_vertex_id
))
})?;
// grab the previous edge, if it exists
let previous_edge = current
.prev_edge_id
.map(|prev_edge_id| g.get_edge(prev_edge_id))
.transpose()
.map_err(SearchError::GraphError)?;

// visit all neighbors of this source vertex
let neighbor_triplets = g
Expand All @@ -114,7 +120,7 @@ pub fn run_a_star(
for (src_id, edge_id, dst_id) in neighbor_triplets {
// first make sure we have a valid edge
let e = g.get_edge(edge_id).map_err(SearchError::GraphError)?;
if !f.valid_frontier(e, &current.state)? {
if !f.valid_frontier(e, &current.state, previous_edge)? {
continue;
}
let et = EdgeTraversal::perform_traversal(
Expand Down Expand Up @@ -225,7 +231,7 @@ pub fn run_a_star_edge_oriented(
directed_graph.clone(),
m.clone(),
u,
f.clone(),
f,
termination_model,
)?;
if !tree.contains_key(&source_edge_dst_vertex_id) {
Expand Down Expand Up @@ -274,7 +280,7 @@ pub fn run_a_star_edge_oriented(
directed_graph.clone(),
m.clone(),
u,
f.clone(),
f,
termination_model,
)?;

Expand Down Expand Up @@ -336,7 +342,6 @@ pub fn h_cost(

#[cfg(test)]
mod tests {

use super::*;
use crate::algorithm::search::backtrack::vertex_oriented_route;
use crate::model::cost::cost_aggregation::CostAggregation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ impl TryFrom<&serde_json::Value> for SearchAlgorithm {
}

impl SearchAlgorithm {
#[allow(clippy::too_many_arguments)]
pub fn run_vertex_oriented(
&self,
origin: VertexId,
Expand All @@ -49,6 +50,7 @@ impl SearchAlgorithm {
),
}
}
#[allow(clippy::too_many_arguments)]
pub fn run_edge_oriented(
&self,
origin: EdgeId,
Expand Down
2 changes: 2 additions & 0 deletions rust/routee-compass-core/src/model/frontier/frontier_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub trait FrontierModel: Send + Sync {
///
/// * `edge` - the edge to traverse
/// * `state` - the state of the traversal at the beginning of this edge
/// * `previous_edge` - the edge that was traversed to reach this edge
///
/// # Returns
///
Expand All @@ -23,6 +24,7 @@ pub trait FrontierModel: Send + Sync {
&self,
_edge: &Edge,
_state: &TraversalState,
_previous_edge: Option<&Edge>,
) -> Result<bool, FrontierModelError> {
Ok(true)
}
Expand Down
12 changes: 7 additions & 5 deletions rust/routee-compass/src/app/compass/compass_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ use std::{
/// running RouteE Compass.
pub struct CompassApp {
pub search_app: SearchApp,
pub input_plugins: Vec<Box<dyn InputPlugin>>,
pub output_plugins: Vec<Box<dyn OutputPlugin>>,
pub input_plugins: Vec<Arc<dyn InputPlugin>>,
pub output_plugins: Vec<Arc<dyn OutputPlugin>>,
pub parallelism: usize,
pub search_orientation: SearchOrientation,
}
Expand Down Expand Up @@ -138,7 +138,9 @@ impl TryFrom<(&Config, &CompassAppBuilder)> for CompassApp {
let frontier_start = Local::now();
let frontier_params =
config_json.get_config_section(CompassConfigurationField::Frontier)?;
let frontier_model_service = builder.build_frontier_model_service(frontier_params)?;

let frontier_model_service = builder.build_frontier_model_service(&frontier_params)?;

let frontier_duration = (Local::now() - frontier_start)
.to_std()
.map_err(|e| CompassAppError::InternalError(e.to_string()))?;
Expand Down Expand Up @@ -365,7 +367,7 @@ fn to_std(dur: Duration) -> Result<std::time::Duration, CompassAppError> {
/// helper that applies the input plugins to a query, returning the result(s) or an error if failed
pub fn apply_input_plugins(
query: &serde_json::Value,
plugins: &[Box<dyn InputPlugin>],
plugins: &[Arc<dyn InputPlugin>],
) -> Result<Vec<serde_json::Value>, serde_json::Value> {
let init = Ok(vec![query.clone()]);
let result = plugins
Expand Down Expand Up @@ -399,7 +401,7 @@ pub fn apply_input_plugins(
pub fn apply_output_processing(
response_data: (&serde_json::Value, Result<SearchAppResult, CompassAppError>),
search_app: &SearchApp,
output_plugins: &[Box<dyn OutputPlugin>],
output_plugins: &[Arc<dyn OutputPlugin>],
) -> Vec<serde_json::Value> {
let (req, res) = response_data;

Expand Down
6 changes: 4 additions & 2 deletions rust/routee-compass/src/app/compass/config/builders.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use super::compass_configuration_error::CompassConfigurationError;
use crate::plugin::{input::input_plugin::InputPlugin, output::output_plugin::OutputPlugin};

Expand All @@ -23,7 +25,7 @@ pub trait InputPluginBuilder {
fn build(
&self,
parameters: &serde_json::Value,
) -> Result<Box<dyn InputPlugin>, CompassConfigurationError>;
) -> Result<Arc<dyn InputPlugin>, CompassConfigurationError>;
}

/// A [`OutputPluginBuilder`] takes a JSON object describing the configuration of an
Expand All @@ -48,5 +50,5 @@ pub trait OutputPluginBuilder {
fn build(
&self,
parameters: &serde_json::Value,
) -> Result<Box<dyn OutputPlugin>, CompassConfigurationError>;
) -> Result<Arc<dyn OutputPlugin>, CompassConfigurationError>;
}
84 changes: 47 additions & 37 deletions rust/routee-compass/src/app/compass/config/compass_app_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use super::{
compass_configuration_field::CompassConfigurationField,
config_json_extension::ConfigJsonExtensions,
frontier_model::{
no_restriction_builder::NoRestrictionBuilder,
combined::combined_builder::CombinedBuilder, no_restriction_builder::NoRestrictionBuilder,
road_class::road_class_builder::RoadClassBuilder,
turn_restrictions::turn_restriction_builder::TurnRestrictionBuilder,
},
traversal_model::{
distance_builder::DistanceBuilder, energy_model_builder::EnergyModelBuilder,
Expand All @@ -31,6 +32,7 @@ use crate::plugin::{
output_plugin::OutputPlugin,
},
};

use itertools::Itertools;
use routee_compass_core::model::{
frontier::{
Expand All @@ -41,7 +43,7 @@ use routee_compass_core::model::{
traversal_model_service::TraversalModelService,
},
};
use std::{collections::HashMap, sync::Arc};
use std::{collections::HashMap, rc::Rc, sync::Arc};

/// Upstream component factory of [`crate::app::compass::compass_app::CompassApp`]
/// that builds components when constructing a CompassApp instance.
Expand All @@ -66,10 +68,10 @@ use std::{collections::HashMap, sync::Arc};
/// * `output_plugin_builders` - a mapping of OutputPlugin `type` names to builders
///
pub struct CompassAppBuilder {
pub traversal_model_builders: HashMap<String, Box<dyn TraversalModelBuilder>>,
pub frontier_builders: HashMap<String, Box<dyn FrontierModelBuilder>>,
pub input_plugin_builders: HashMap<String, Box<dyn InputPluginBuilder>>,
pub output_plugin_builders: HashMap<String, Box<dyn OutputPluginBuilder>>,
pub traversal_model_builders: HashMap<String, Rc<dyn TraversalModelBuilder>>,
pub frontier_builders: HashMap<String, Rc<dyn FrontierModelBuilder>>,
pub input_plugin_builders: HashMap<String, Rc<dyn InputPluginBuilder>>,
pub output_plugin_builders: HashMap<String, Rc<dyn OutputPluginBuilder>>,
}

impl CompassAppBuilder {
Expand All @@ -92,19 +94,19 @@ impl CompassAppBuilder {
}
}

pub fn add_traversal_model(&mut self, name: String, builder: Box<dyn TraversalModelBuilder>) {
pub fn add_traversal_model(&mut self, name: String, builder: Rc<dyn TraversalModelBuilder>) {
let _ = self.traversal_model_builders.insert(name, builder);
}

pub fn add_frontier_model(&mut self, name: String, builder: Box<dyn FrontierModelBuilder>) {
pub fn add_frontier_model(&mut self, name: String, builder: Rc<dyn FrontierModelBuilder>) {
let _ = self.frontier_builders.insert(name, builder);
}

pub fn add_input_plugin(&mut self, name: String, builder: Box<dyn InputPluginBuilder>) {
pub fn add_input_plugin(&mut self, name: String, builder: Rc<dyn InputPluginBuilder>) {
let _ = self.input_plugin_builders.insert(name, builder);
}

pub fn add_output_plugin(&mut self, name: String, builder: Box<dyn OutputPluginBuilder>) {
pub fn add_output_plugin(&mut self, name: String, builder: Rc<dyn OutputPluginBuilder>) {
let _ = self.output_plugin_builders.insert(name, builder);
}

Expand All @@ -117,29 +119,37 @@ impl CompassAppBuilder {
/// * an instance of a CompassAppBuilder that can be used to build a CompassApp
fn default() -> CompassAppBuilder {
// Traversal model builders
let dist: Box<dyn TraversalModelBuilder> = Box::new(DistanceBuilder {});
let velo: Box<dyn TraversalModelBuilder> = Box::new(SpeedLookupBuilder {});
let energy_model: Box<dyn TraversalModelBuilder> = Box::new(EnergyModelBuilder {});
let tm_builders: HashMap<String, Box<dyn TraversalModelBuilder>> = HashMap::from([
let dist: Rc<dyn TraversalModelBuilder> = Rc::new(DistanceBuilder {});
let velo: Rc<dyn TraversalModelBuilder> = Rc::new(SpeedLookupBuilder {});
let energy_model: Rc<dyn TraversalModelBuilder> = Rc::new(EnergyModelBuilder {});
let tm_builders: HashMap<String, Rc<dyn TraversalModelBuilder>> = HashMap::from([
(String::from("distance"), dist),
(String::from("speed_table"), velo),
(String::from("energy_model"), energy_model),
]);

// Frontier model builders
let no_restriction: Box<dyn FrontierModelBuilder> = Box::new(NoRestrictionBuilder {});
let road_class: Box<dyn FrontierModelBuilder> = Box::new(RoadClassBuilder {});
let frontier_builders: HashMap<String, Box<dyn FrontierModelBuilder>> = HashMap::from([
(String::from("no_restriction"), no_restriction),
(String::from("road_class"), road_class),
]);
let no_restriction: Rc<dyn FrontierModelBuilder> = Rc::new(NoRestrictionBuilder {});
let road_class: Rc<dyn FrontierModelBuilder> = Rc::new(RoadClassBuilder {});
let turn_restruction: Rc<dyn FrontierModelBuilder> = Rc::new(TurnRestrictionBuilder {});
let base_frontier_builders: HashMap<String, Rc<dyn FrontierModelBuilder>> =
HashMap::from([
(String::from("no_restriction"), no_restriction),
(String::from("road_class"), road_class),
(String::from("turn_restriction"), turn_restruction),
]);
let combined = Rc::new(CombinedBuilder {
builders: base_frontier_builders.clone(),
});
let mut all_frontier_builders = base_frontier_builders.clone();
all_frontier_builders.insert(String::from("combined"), combined);

// Input plugin builders
let grid_search: Box<dyn InputPluginBuilder> = Box::new(GridSearchBuilder {});
let vertex_tree: Box<dyn InputPluginBuilder> = Box::new(VertexRTreeBuilder {});
let edge_rtree: Box<dyn InputPluginBuilder> = Box::new(EdgeRtreeInputPluginBuilder {});
let load_balancer: Box<dyn InputPluginBuilder> = Box::new(LoadBalancerBuilder {});
let inject: Box<dyn InputPluginBuilder> = Box::new(InjectPluginBuilder {});
let grid_search: Rc<dyn InputPluginBuilder> = Rc::new(GridSearchBuilder {});
let vertex_tree: Rc<dyn InputPluginBuilder> = Rc::new(VertexRTreeBuilder {});
let edge_rtree: Rc<dyn InputPluginBuilder> = Rc::new(EdgeRtreeInputPluginBuilder {});
let load_balancer: Rc<dyn InputPluginBuilder> = Rc::new(LoadBalancerBuilder {});
let inject: Rc<dyn InputPluginBuilder> = Rc::new(InjectPluginBuilder {});
let input_plugin_builders = HashMap::from([
(String::from("grid_search"), grid_search),
(String::from("vertex_rtree"), vertex_tree),
Expand All @@ -149,11 +159,11 @@ impl CompassAppBuilder {
]);

// Output plugin builders
let traversal: Box<dyn OutputPluginBuilder> = Box::new(TraversalPluginBuilder {});
let summary: Box<dyn OutputPluginBuilder> = Box::new(SummaryOutputPluginBuilder {});
let uuid: Box<dyn OutputPluginBuilder> = Box::new(UUIDOutputPluginBuilder {});
let edge_id_list: Box<dyn OutputPluginBuilder> = Box::new(EdgeIdListOutputPluginBuilder {});
let to_disk: Box<dyn OutputPluginBuilder> = Box::new(ToDiskOutputPluginBuilder {});
let traversal: Rc<dyn OutputPluginBuilder> = Rc::new(TraversalPluginBuilder {});
let summary: Rc<dyn OutputPluginBuilder> = Rc::new(SummaryOutputPluginBuilder {});
let uuid: Rc<dyn OutputPluginBuilder> = Rc::new(UUIDOutputPluginBuilder {});
let edge_id_list: Rc<dyn OutputPluginBuilder> = Rc::new(EdgeIdListOutputPluginBuilder {});
let to_disk: Rc<dyn OutputPluginBuilder> = Rc::new(ToDiskOutputPluginBuilder {});
let output_plugin_builders = HashMap::from([
(String::from("traversal"), traversal),
(String::from("summary"), summary),
Expand All @@ -164,7 +174,7 @@ impl CompassAppBuilder {

CompassAppBuilder {
traversal_model_builders: tm_builders,
frontier_builders,
frontier_builders: all_frontier_builders,
input_plugin_builders,
output_plugin_builders,
}
Expand Down Expand Up @@ -209,7 +219,7 @@ impl CompassAppBuilder {
/// frontier model configuration JSON
pub fn build_frontier_model_service(
&self,
config: serde_json::Value,
config: &serde_json::Value,
) -> Result<Arc<dyn FrontierModelService>, CompassConfigurationError> {
let fm_type_obj =
config
Expand All @@ -233,21 +243,21 @@ impl CompassAppBuilder {
self.frontier_builders.keys().join(", "),
))
.and_then(|b| {
b.build(&config)
b.build(config)
.map_err(CompassConfigurationError::FrontierModelError)
})
}

pub fn build_input_plugins(
&self,
config: &serde_json::Value,
) -> Result<Vec<Box<dyn InputPlugin>>, CompassConfigurationError> {
) -> Result<Vec<Arc<dyn InputPlugin>>, CompassConfigurationError> {
let input_plugins = config.get_config_array(
&CompassConfigurationField::InputPlugins,
&CompassConfigurationField::Plugins,
)?;

let mut plugins: Vec<Box<dyn InputPlugin>> = Vec::new();
let mut plugins: Vec<Arc<dyn InputPlugin>> = Vec::new();
for plugin_json in input_plugins.into_iter() {
let plugin_type_obj =
plugin_json
Expand Down Expand Up @@ -284,13 +294,13 @@ impl CompassAppBuilder {
pub fn build_output_plugins(
&self,
config: &serde_json::Value,
) -> Result<Vec<Box<dyn OutputPlugin>>, CompassConfigurationError> {
) -> Result<Vec<Arc<dyn OutputPlugin>>, CompassConfigurationError> {
let output_plugins = config.get_config_array(
&CompassConfigurationField::OutputPlugins,
&CompassConfigurationField::Plugins,
)?;

let mut plugins: Vec<Box<dyn OutputPlugin>> = Vec::new();
let mut plugins: Vec<Arc<dyn OutputPlugin>> = Vec::new();
for plugin_json in output_plugins.into_iter() {
let plugin_json_obj =
plugin_json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl CostModelService {
) -> Result<CostModelService, CompassConfigurationError> {
let vehicle_rates = vehicle_state_variable_rates
.unwrap_or(CostModelService::default_vehicle_state_variable_rates());
let network_rates = network_state_variable_rates.unwrap_or(HashMap::new());
let network_rates = network_state_variable_rates.unwrap_or_default();
let coefficients = match default_state_variable_coefficients {
Some(coefficients) => {
if coefficients.is_empty() {
Expand Down
Loading

0 comments on commit 834e23e

Please sign in to comment.