Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rjf/traversal abstractions clone issue #44

Merged
merged 4 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rust/routee-compass-core/src/model/traversal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@ pub mod access_result;
pub mod default;
pub mod state;
pub mod traversal_model;
pub mod traversal_model_builder;
pub mod traversal_model_error;
pub mod traversal_model_service;
pub mod traversal_result;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use super::{
traversal_model_error::TraversalModelError, traversal_model_service::TraversalModelService,
};
use std::sync::Arc;

/// A [`TraversalModelBuilder`] takes a JSON object describing the configuration of a
/// traversal model and builds a [`TraversalModelService`].
///
/// A [`TraversalModelBuilder`] instance should be an empty struct that implements
/// this trait.
pub trait TraversalModelBuilder {
/// Builds a [`TraversalModelService`] from configuration.
///
/// # Arguments
///
/// * `parameters` - the contents of the "traversal" TOML config section
///
/// # Returns
///
/// A [`TraversalModelService`] designed to persist the duration of the CompassApp.
fn build(
&self,
parameters: &serde_json::Value,
) -> Result<Arc<dyn TraversalModelService>, TraversalModelError>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use super::{traversal_model::TraversalModel, traversal_model_error::TraversalModelError};
use std::sync::Arc;

/// A [`TraversalModelService`] is a persistent builder of [TraversalModel] instances.
/// Building a [`TraversalModelService`] may be an expensive operation and often includes
/// file IO on the order of the size of the road network edge list.
/// The service then builds a [TraversalModel] instance for each route query.
/// [`TraversalModelService`] must be read across the thread pool and so it implements
/// Send and Sync.
///
/// [TraversalModel]: compass_core::model::traversal::traversal_model::TraversalModel
pub trait TraversalModelService: Send + Sync {
/// Builds a [TraversalModel] for the incoming query, used as parameters for this
/// build operation.
///
/// The query is passed as parameters to this operation so that any query-time
/// coefficients may be applied to the [TraversalModel].
///
/// # Arguments
///
/// * `query` - the incoming query which may contain parameters for building the [TraversalModel]
///
/// # Returns
///
/// The [TraversalModel] instance for this query, or an error
///
/// [TraversalModel]: compass_core::model::traversal::traversal_model::TraversalModel
fn build(
&self,
query: &serde_json::Value,
) -> Result<Arc<dyn TraversalModel>, TraversalModelError>;
}
4 changes: 2 additions & 2 deletions rust/routee-compass-powertrain/src/routee/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pub mod model_type;
pub mod prediction_model;
pub mod smartcore;
pub mod speed_grade_model;
pub mod speed_grade_model_service;
pub mod speed_grade_energy_model;
pub mod speed_grade_energy_model_service;

#[cfg(feature = "onnx")]
pub mod onnx;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::prediction_model::SpeedGradePredictionModelRecord;
use super::speed_grade_model_service::SpeedGradeModelService;
use super::speed_grade_energy_model_service::SpeedGradeEnergyModelService;
use routee_compass_core::model::cost::Cost;
use routee_compass_core::model::property::edge::Edge;
use routee_compass_core::model::property::vertex::Vertex;
Expand All @@ -17,13 +17,13 @@ use std::sync::Arc;

const ZERO_ENERGY: f64 = 1e-9;

pub struct SpeedGradeModel {
pub service: Arc<SpeedGradeModelService>,
pub struct SpeedGradeEnergyModel {
pub service: Arc<SpeedGradeEnergyModelService>,
pub model_record: Arc<SpeedGradePredictionModelRecord>,
pub energy_cost_coefficient: f64,
}

impl TraversalModel for SpeedGradeModel {
impl TraversalModel for SpeedGradeEnergyModel {
fn initial_state(&self) -> TraversalState {
// distance, time, energy
vec![StateVar(0.0), StateVar(0.0), StateVar(0.0)]
Expand Down Expand Up @@ -136,11 +136,11 @@ impl TraversalModel for SpeedGradeModel {
}
}

impl TryFrom<(Arc<SpeedGradeModelService>, &serde_json::Value)> for SpeedGradeModel {
impl TryFrom<(Arc<SpeedGradeEnergyModelService>, &serde_json::Value)> for SpeedGradeEnergyModel {
type Error = TraversalModelError;

fn try_from(
input: (Arc<SpeedGradeModelService>, &serde_json::Value),
input: (Arc<SpeedGradeEnergyModelService>, &serde_json::Value),
) -> Result<Self, Self::Error> {
let (service, conf) = input;

Expand Down Expand Up @@ -185,7 +185,7 @@ impl TryFrom<(Arc<SpeedGradeModelService>, &serde_json::Value)> for SpeedGradeMo
Some(mr) => mr.clone(),
};

Ok(SpeedGradeModel {
Ok(SpeedGradeEnergyModel {
service,
model_record,
energy_cost_coefficient,
Expand Down Expand Up @@ -302,7 +302,7 @@ mod tests {
let mut model_library = HashMap::new();
model_library.insert("Toyota_Camry".to_string(), Arc::new(model_record));

let service = SpeedGradeModelService::new(
let service = SpeedGradeEnergyModelService::new(
&speed_file_path,
SpeedUnit::KilometersPerHour,
&Some(grade_file_path),
Expand All @@ -317,7 +317,7 @@ mod tests {
"model_name": "Toyota_Camry",
"energy_cost_coefficient": 0.5,
});
let model = SpeedGradeModel::try_from((arc_service, &conf)).unwrap();
let model = SpeedGradeEnergyModel::try_from((arc_service, &conf)).unwrap();
let initial = model.initial_state();
let e1 = mock_edge(0);
// 100 meters @ 10kph should take 36 seconds ((0.1/10) * 3600)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use super::prediction_model::SpeedGradePredictionModelRecord;
use super::speed_grade_energy_model::SpeedGradeEnergyModel;
use routee_compass_core::model::traversal::default::speed_lookup_model::get_max_speed;
use routee_compass_core::model::traversal::traversal_model::TraversalModel;
use routee_compass_core::model::traversal::traversal_model_error::TraversalModelError;
use routee_compass_core::model::traversal::traversal_model_service::TraversalModelService;
use routee_compass_core::util::fs::read_decoders;
use routee_compass_core::util::fs::read_utils;
use routee_compass_core::util::unit::*;
Expand All @@ -9,18 +12,29 @@ use std::path::Path;
use std::sync::Arc;

#[derive(Clone)]
pub struct SpeedGradeModelService {
pub struct SpeedGradeEnergyModelService {
pub speed_table: Arc<Box<[Speed]>>,
pub speeds_table_speed_unit: SpeedUnit,
pub max_speed: Speed,
pub grade_table: Arc<Option<Box<[Grade]>>>,
pub grade_table_grade_unit: GradeUnit,
pub output_time_unit: TimeUnit,
pub output_distance_unit: DistanceUnit,
pub energy_model_library: HashMap<String, Arc<SpeedGradePredictionModelRecord>>,
pub energy_model_library: Arc<HashMap<String, Arc<SpeedGradePredictionModelRecord>>>,
}

impl SpeedGradeModelService {
impl TraversalModelService for SpeedGradeEnergyModelService {
fn build(
&self,
query: &serde_json::Value,
) -> Result<Arc<dyn TraversalModel>, TraversalModelError> {
let arc_self = Arc::new(self.clone());
let m = SpeedGradeEnergyModel::try_from((arc_self, query))?;
Ok(Arc::new(m))
}
}

impl SpeedGradeEnergyModelService {
pub fn new<P: AsRef<Path>>(
speed_table_path: &P,
speeds_table_speed_unit: SpeedUnit,
Expand Down Expand Up @@ -60,15 +74,15 @@ impl SpeedGradeModelService {

let max_speed = get_max_speed(&speed_table)?;

Ok(SpeedGradeModelService {
Ok(SpeedGradeEnergyModelService {
speed_table,
speeds_table_speed_unit,
max_speed,
grade_table,
grade_table_grade_unit,
output_time_unit,
output_distance_unit,
energy_model_library,
energy_model_library: Arc::new(energy_model_library),
})
}
}
56 changes: 1 addition & 55 deletions rust/routee-compass/src/app/compass/config/builders.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,6 @@
use super::compass_configuration_error::CompassConfigurationError;
use crate::plugin::{input::input_plugin::InputPlugin, output::output_plugin::OutputPlugin};
use routee_compass_core::model::{
frontier::frontier_model::FrontierModel, traversal::traversal_model::TraversalModel,
};
use std::sync::Arc;

/// A [`TraversalModelBuilder`] takes a JSON object describing the configuration of a
/// traversal model and builds a [`TraversalModelService`].
///
/// A [`TraversalModelBuilder`] instance should be an empty struct that implements
/// this trait.
pub trait TraversalModelBuilder {
/// Builds a [`TraversalModelService`] from configuration.
///
/// # Arguments
///
/// * `parameters` - the contents of the "traversal" TOML config section
///
/// # Returns
///
/// A [`TraversalModelService`] designed to persist the duration of the CompassApp.
fn build(
&self,
parameters: &serde_json::Value,
) -> Result<Arc<dyn TraversalModelService>, CompassConfigurationError>;
}

/// A [`TraversalModelService`] is a persistent builder of [TraversalModel] instances.
/// Building a [`TraversalModelService`] may be an expensive operation and often includes
/// file IO on the order of the size of the road network edge list.
/// The service then builds a [TraversalModel] instance for each route query.
/// [`TraversalModelService`] must be read across the thread pool and so it implements
/// Send and Sync.
///
/// [TraversalModel]: compass_core::model::traversal::traversal_model::TraversalModel
pub trait TraversalModelService: Send + Sync {
/// Builds a [TraversalModel] for the incoming query, used as parameters for this
/// build operation.
///
/// The query is passed as parameters to this operation so that any query-time
/// coefficients may be applied to the [TraversalModel].
///
/// # Arguments
///
/// * `query` - the incoming query which may contain parameters for building the [TraversalModel]
///
/// # Returns
///
/// The [TraversalModel] instance for this query, or an error
///
/// [TraversalModel]: compass_core::model::traversal::traversal_model::TraversalModel
fn build(
&self,
query: &serde_json::Value,
) -> Result<Arc<dyn TraversalModel>, CompassConfigurationError>;
}
use routee_compass_core::model::frontier::frontier_model::FrontierModel;

/// A [`FrontierModelBuilder`] takes a JSON object describing the configuration of a
/// frontier model and builds a [FrontierModel].
Expand Down
22 changes: 15 additions & 7 deletions rust/routee-compass/src/app/compass/config/compass_app_builder.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use super::{
builders::{
FrontierModelBuilder, InputPluginBuilder, OutputPluginBuilder, TraversalModelBuilder,
TraversalModelService,
},
builders::{FrontierModelBuilder, InputPluginBuilder, OutputPluginBuilder},
compass_configuration_error::CompassConfigurationError,
compass_configuration_field::CompassConfigurationField,
config_json_extension::ConfigJsonExtensions,
Expand Down Expand Up @@ -31,7 +28,13 @@ use crate::plugin::{
},
};
use itertools::Itertools;
use routee_compass_core::model::frontier::frontier_model::FrontierModel;
use routee_compass_core::model::{
frontier::frontier_model::FrontierModel,
traversal::{
traversal_model_builder::TraversalModelBuilder,
traversal_model_service::TraversalModelService,
},
};
use std::{collections::HashMap, sync::Arc};

/// Upstream component factory of [`crate::app::compass::compass_app::CompassApp`]
Expand Down Expand Up @@ -175,14 +178,19 @@ impl CompassAppBuilder {
String::from("String"),
))?
.into();
self.traversal_model_builders
let result = self
.traversal_model_builders
.get(&tm_type)
.ok_or(CompassConfigurationError::UnknownModelNameForComponent(
tm_type.clone(),
String::from("traversal"),
self.traversal_model_builders.keys().join(", "),
))
.and_then(|b| b.build(config))
.and_then(|b| {
b.build(config)
.map_err(CompassConfigurationError::TraversalModelError)
});
result
}

/// builds a frontier model with the specified type name with the provided
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::plugin::plugin_error::PluginError;
use config::ConfigError;
use routee_compass_core::{
model::{
Expand All @@ -7,8 +8,6 @@ use routee_compass_core::{
util::conversion::conversion_error::ConversionError,
};

use crate::plugin::plugin_error::PluginError;

#[derive(thiserror::Error, Debug)]
pub enum CompassConfigurationError {
#[error("expected field {0} for component {1} provided by configuration")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::app::compass::config::compass_configuration_field::CompassConfigurationField;
use crate::app::compass::config::config_json_extension::ConfigJsonExtensions;
use crate::app::compass::config::{
builders::{TraversalModelBuilder, TraversalModelService},
compass_configuration_error::CompassConfigurationError,
compass_configuration_field::CompassConfigurationField,
};
use routee_compass_core::model::traversal::traversal_model::TraversalModel;
use routee_compass_core::model::traversal::traversal_model_builder::TraversalModelBuilder;
use routee_compass_core::model::traversal::traversal_model_error::TraversalModelError;
use routee_compass_core::model::traversal::traversal_model_service::TraversalModelService;
use routee_compass_core::util::unit::BASE_DISTANCE_UNIT;
use routee_compass_core::{
model::traversal::default::distance::DistanceModel, util::unit::DistanceUnit,
Expand All @@ -21,12 +20,14 @@ impl TraversalModelBuilder for DistanceBuilder {
fn build(
&self,
parameters: &serde_json::Value,
) -> Result<Arc<dyn TraversalModelService>, CompassConfigurationError> {
) -> Result<Arc<dyn TraversalModelService>, TraversalModelError> {
let traversal_key = CompassConfigurationField::Traversal.to_string();
let distance_unit_option = parameters.get_config_serde_optional::<DistanceUnit>(
String::from("distance_unit"),
traversal_key.clone(),
)?;
let distance_unit_option = parameters
.get_config_serde_optional::<DistanceUnit>(
String::from("distance_unit"),
traversal_key.clone(),
)
.map_err(|e| TraversalModelError::BuildError(e.to_string()))?;
let distance_unit = distance_unit_option.unwrap_or(BASE_DISTANCE_UNIT);
let m: Arc<dyn TraversalModelService> = Arc::new(DistanceService { distance_unit });
Ok(m)
Expand All @@ -37,7 +38,7 @@ impl TraversalModelService for DistanceService {
fn build(
&self,
_parameters: &serde_json::Value,
) -> Result<Arc<dyn TraversalModel>, CompassConfigurationError> {
) -> Result<Arc<dyn TraversalModel>, TraversalModelError> {
let m: Arc<dyn TraversalModel> = Arc::new(DistanceModel::new(self.distance_unit));
Ok(m)
}
Expand Down
Loading