Skip to content

Commit

Permalink
Merge pull request #189 from NREL/rjf/ksp-algorithm
Browse files Browse the repository at this point in the history
support for algorithms with multiple trees/routes
  • Loading branch information
robfitzgerald authored Apr 17, 2024
2 parents 29d944b + 93288ad commit 46e8100
Show file tree
Hide file tree
Showing 25 changed files with 509 additions and 645 deletions.
475 changes: 218 additions & 257 deletions docs/notebooks/open_street_maps_example.ipynb

Large diffs are not rendered by default.

13 changes: 10 additions & 3 deletions python/nrel/routee/compass/plot/plot_folium.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
"opacity": 0.8,
}

# routes should exist at a "route" key
# routes should exist at a "route.path" key
ROUTE_KEY = "route"
PATH_KEY = "path"


def plot_route_folium(
Expand Down Expand Up @@ -50,12 +51,18 @@ def plot_route_folium(
if not isinstance(result_dict, dict):
raise ValueError(f"Expected to get a dictionary but got a {type(result_dict)}")

geom = result_dict.get(ROUTE_KEY)
if geom is None:
route = result_dict.get(ROUTE_KEY)
if route is None:
raise KeyError(
f"Could not find '{ROUTE_KEY}' in result. "
"Make sure the geometry output plugin is activated"
)
geom = route.get(PATH_KEY)
if geom is None:
raise KeyError(
f"Could not find '{ROUTE_KEY}.{PATH_KEY}' in result. "
"Make sure the geometry output plugin is activated"
)

if isinstance(geom, shapely.geometry.LineString):
linestring = geom
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use crate::{
algorithm::search::{
search_algorithm::SearchAlgorithm, search_error::SearchError,
search_instance::SearchInstance, search_result::SearchResult,
},
model::road_network::vertex_id::VertexId,
};

pub fn run_ksp(
_source: VertexId,
_target: Option<VertexId>,
_si: &SearchInstance,
_underlying: Box<SearchAlgorithm>,
) -> Result<Vec<SearchResult>, SearchError> {
todo!()
}
1 change: 1 addition & 0 deletions rust/routee-compass-core/src/algorithm/search/ksp/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod ksp_single_via_paths;
3 changes: 2 additions & 1 deletion rust/routee-compass-core/src/algorithm/search/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ pub mod a_star;
pub mod backtrack;
pub mod direction;
pub mod edge_traversal;
pub mod ksp;
pub mod search_algorithm;
pub mod search_algorithm_type;
pub mod search_algorithm_result;
pub mod search_error;
pub mod search_instance;
pub mod search_result;
Expand Down
82 changes: 61 additions & 21 deletions rust/routee-compass-core/src/algorithm/search/search_algorithm.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,88 @@
use super::a_star::a_star_algorithm;
use super::backtrack;
use super::search_algorithm_result::SearchAlgorithmResult;
use super::search_error::SearchError;
use super::search_instance::SearchInstance;
use super::search_result::SearchResult;
use crate::algorithm::search::search_algorithm_type::SearchAlgorithmType;
use crate::model::road_network::{edge_id::EdgeId, vertex_id::VertexId};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum SearchAlgorithm {
#[serde(rename = "a*")]
AStarAlgorithm,
}

impl TryFrom<&serde_json::Value> for SearchAlgorithm {
type Error = SearchError;

fn try_from(config: &serde_json::Value) -> Result<Self, Self::Error> {
let alg_type: SearchAlgorithmType = config.try_into()?;
match alg_type {
SearchAlgorithmType::AStar => Ok(SearchAlgorithm::AStarAlgorithm),
}
}
KspSingleVia {
k: usize,
underlying: Box<SearchAlgorithm>,
},
}

impl SearchAlgorithm {
pub fn run_vertex_oriented(
&self,
origin: VertexId,
destination: Option<VertexId>,
src_id: VertexId,
dst_id_opt: Option<VertexId>,
search_instance: &SearchInstance,
) -> Result<SearchResult, SearchError> {
) -> Result<SearchAlgorithmResult, SearchError> {
match self {
SearchAlgorithm::AStarAlgorithm => {
a_star_algorithm::run_a_star(origin, destination, search_instance)
let search_result =
a_star_algorithm::run_a_star(src_id, dst_id_opt, search_instance)?;
let routes = match dst_id_opt {
None => vec![],
Some(dst_id) => {
let route =
backtrack::vertex_oriented_route(src_id, dst_id, &search_result.tree)?;
vec![route]
}
};
Ok(SearchAlgorithmResult {
trees: vec![search_result.tree],
routes,
iterations: search_result.iterations,
})
}
SearchAlgorithm::KspSingleVia {
k: _,
underlying: _,
} => todo!(),
}
}
pub fn run_edge_oriented(
&self,
origin: EdgeId,
destination: Option<EdgeId>,
src_id: EdgeId,
dst_id_opt: Option<EdgeId>,
search_instance: &SearchInstance,
) -> Result<SearchResult, SearchError> {
) -> Result<SearchAlgorithmResult, SearchError> {
match self {
SearchAlgorithm::AStarAlgorithm => {
a_star_algorithm::run_a_star_edge_oriented(origin, destination, search_instance)
let search_result = a_star_algorithm::run_a_star_edge_oriented(
src_id,
dst_id_opt,
search_instance,
)?;
let routes = match dst_id_opt {
None => vec![],
Some(dst_id) => {
let route = backtrack::edge_oriented_route(
src_id,
dst_id,
&search_result.tree,
search_instance.directed_graph.clone(),
)?;
vec![route]
}
};
Ok(SearchAlgorithmResult {
trees: vec![search_result.tree],
routes,
iterations: search_result.iterations,
})
}
SearchAlgorithm::KspSingleVia {
k: _,
underlying: _,
} => todo!(),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use super::{edge_traversal::EdgeTraversal, search_tree_branch::SearchTreeBranch};
use crate::model::road_network::vertex_id::VertexId;
use std::collections::HashMap;

pub struct SearchAlgorithmResult {
pub trees: Vec<HashMap<VertexId, SearchTreeBranch>>,
pub routes: Vec<Vec<EdgeTraversal>>,
pub iterations: u64,
}

This file was deleted.

3 changes: 2 additions & 1 deletion rust/routee-compass-core/src/model/unit/time_unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ use crate::util::serde::serde_ops::string_deserialize;
use serde::{Deserialize, Serialize};
use std::str::FromStr;

#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum TimeUnit {
Hours,
#[default]
Minutes,
Seconds,
Milliseconds,
Expand Down
16 changes: 6 additions & 10 deletions rust/routee-compass/src/app/compass/compass_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,8 @@ impl TryFrom<(&Config, &CompassAppBuilder)> for CompassApp {
.try_deserialize::<serde_json::Value>()?
.normalize_file_paths(&"", &root_config_path)?;

let alg_params =
config_json.get_config_section(CompassConfigurationField::Algorithm, &"TOML")?;
let search_algorithm = SearchAlgorithm::try_from(&alg_params)?;
let search_algorithm: SearchAlgorithm =
config_json.get_config_serde(&CompassConfigurationField::Algorithm, &"TOML")?;

let state_model = match config_json.get(&CompassConfigurationField::State.to_string()) {
Some(state_config) => Arc::new(StateModel::try_from(state_config)?),
Expand Down Expand Up @@ -481,12 +480,8 @@ pub fn run_single_query(
output_plugins: &[Arc<dyn OutputPlugin>],
search_app: &SearchApp,
) -> Result<serde_json::Value, CompassAppError> {
let search_result = match search_orientation {
SearchOrientation::Vertex => search_app.run_vertex_oriented(query),
SearchOrientation::Edge => search_app.run_edge_oriented(query),
};
let search_result = search_app.run(query, search_orientation);
let output = apply_output_processing(query, search_result, search_app, output_plugins);
// TODO: write to output if requested
Ok(output)
}

Expand Down Expand Up @@ -666,10 +661,11 @@ mod tests {
});
let result = app.run(vec![query], None).unwrap();
println!("{}", serde_json::to_string_pretty(&result).unwrap());
let edge_ids = result[0].get("edge_id_list").unwrap();
let route_0 = result[0].get("route").unwrap();
let path_0 = route_0.get("path").unwrap();
// path [1] is distance-optimal; path [0, 2] is time-optimal
let expected = serde_json::json!(vec![0, 2]);
assert_eq!(edge_ids, &expected);
assert_eq!(path_0, &expected);
}

// #[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ use crate::plugin::{
},
output::{
default::{
edgeidlist::builder::EdgeIdListOutputPluginBuilder,
summary::builder::SummaryOutputPluginBuilder,
traversal::builder::TraversalPluginBuilder, uuid::builder::UUIDOutputPluginBuilder,
},
Expand Down Expand Up @@ -194,12 +193,10 @@ impl CompassAppBuilder {
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 output_plugin_builders = HashMap::from([
(String::from("traversal"), traversal),
(String::from("summary"), summary),
(String::from("uuid"), uuid),
(String::from("edge_id_list"), edge_id_list),
]);

CompassAppBuilder {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
LINESTRING (-105.1683038 39.7379033, -104.8086039 41.1475252)
LINESTRING (-105.1683038 39.7379033, -111.9095014 40.7607176)
LINESTRING (-104.8086039 41.1475252, -111.9095014 40.7607176)
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ type = "raw"

[plugin]
input_plugins = []
output_plugins = [{ type = "edge_id_list" }, { type = "summary" }]
output_plugins = [
{ type = "summary" },
{ type = "traversal", route = "edge_id", geometry_input_file = "routee-compass/src/app/compass/test/speeds_test/edge_geometries.txt" },
]
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ type = "raw"

[plugin]
input_plugins = []
output_plugins = [{ type = "edge_id_list" }, { type = "summary" }]
output_plugins = [
{ type = "summary" },
{ type = "traversal", route = "edge_id", geometry_input_file = "src/app/compass/test/speeds_test/edge_geometries.txt" },
]
Loading

0 comments on commit 46e8100

Please sign in to comment.