|
|
|
|
@ -15,8 +15,15 @@ use rustc_hash::FxHashMap;
|
|
|
|
|
|
|
|
|
|
type PredecessorInfo<'a, 'b> = (u64, &'b Vertex<'a>);
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct ExceededGraphLimit {}
|
|
|
|
|
|
|
|
|
|
/// Return the shortest route from `start` to the end vertex.
|
|
|
|
|
fn shortest_vertex_path(start: Vertex, size_hint: usize) -> Vec<Vertex> {
|
|
|
|
|
fn shortest_vertex_path(
|
|
|
|
|
start: Vertex,
|
|
|
|
|
size_hint: usize,
|
|
|
|
|
graph_limit: usize,
|
|
|
|
|
) -> Result<Vec<Vertex>, ExceededGraphLimit> {
|
|
|
|
|
// We want to visit nodes with the shortest distance first, but
|
|
|
|
|
// RadixHeapMap is a max-heap. Ensure nodes are wrapped with
|
|
|
|
|
// Reverse to flip comparisons.
|
|
|
|
|
@ -56,6 +63,9 @@ fn shortest_vertex_path(start: Vertex, size_hint: usize) -> Vec<Vertex> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if predecessors.len() > graph_limit {
|
|
|
|
|
return Err(ExceededGraphLimit {});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => panic!("Ran out of graph nodes before reaching end"),
|
|
|
|
|
}
|
|
|
|
|
@ -77,7 +87,7 @@ fn shortest_vertex_path(start: Vertex, size_hint: usize) -> Vec<Vertex> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vertex_route.reverse();
|
|
|
|
|
vertex_route
|
|
|
|
|
Ok(vertex_route)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn shortest_path_with_edges<'a>(route: &[Vertex<'a>]) -> Vec<(Edge, Vertex<'a>)> {
|
|
|
|
|
@ -101,9 +111,13 @@ fn shortest_path_with_edges<'a>(route: &[Vertex<'a>]) -> Vec<(Edge, Vertex<'a>)>
|
|
|
|
|
///
|
|
|
|
|
/// The vec returned does not return the very last vertex. This is
|
|
|
|
|
/// necessary because a route of N vertices only has N-1 edges.
|
|
|
|
|
fn shortest_path(start: Vertex, size_hint: usize) -> Vec<(Edge, Vertex)> {
|
|
|
|
|
let vertex_path = shortest_vertex_path(start, size_hint);
|
|
|
|
|
shortest_path_with_edges(&vertex_path)
|
|
|
|
|
fn shortest_path(
|
|
|
|
|
start: Vertex,
|
|
|
|
|
size_hint: usize,
|
|
|
|
|
graph_limit: usize,
|
|
|
|
|
) -> Result<Vec<(Edge, Vertex)>, ExceededGraphLimit> {
|
|
|
|
|
let vertex_path = shortest_vertex_path(start, size_hint, graph_limit)?;
|
|
|
|
|
Ok(shortest_path_with_edges(&vertex_path))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn edge_between<'a>(before: &Vertex<'a>, after: &Vertex<'a>) -> Edge {
|
|
|
|
|
@ -113,14 +127,29 @@ fn edge_between<'a>(before: &Vertex<'a>, after: &Vertex<'a>) -> Edge {
|
|
|
|
|
|
|
|
|
|
let vertex_arena = Bump::new();
|
|
|
|
|
neighbours(before, &mut neighbour_buf, &vertex_arena);
|
|
|
|
|
|
|
|
|
|
let mut shortest_edge: Option<Edge> = None;
|
|
|
|
|
for neighbour in &mut neighbour_buf {
|
|
|
|
|
if let Some((edge, next)) = neighbour.take() {
|
|
|
|
|
// If there are multiple edges that can take us to `next`,
|
|
|
|
|
// prefer the shortest.
|
|
|
|
|
if next == after {
|
|
|
|
|
return edge;
|
|
|
|
|
let is_shorter = match shortest_edge {
|
|
|
|
|
Some(prev_edge) => edge.cost() < prev_edge.cost(),
|
|
|
|
|
None => true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if is_shorter {
|
|
|
|
|
shortest_edge = Some(edge);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(edge) = shortest_edge {
|
|
|
|
|
return edge;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
panic!(
|
|
|
|
|
"Expected a route between the two vertices {:#?} and {:#?}",
|
|
|
|
|
before, after
|
|
|
|
|
@ -162,7 +191,8 @@ pub fn mark_syntax<'a>(
|
|
|
|
|
lhs_syntax: Option<&'a Syntax<'a>>,
|
|
|
|
|
rhs_syntax: Option<&'a Syntax<'a>>,
|
|
|
|
|
change_map: &mut ChangeMap<'a>,
|
|
|
|
|
) {
|
|
|
|
|
graph_limit: usize,
|
|
|
|
|
) -> Result<(), ExceededGraphLimit> {
|
|
|
|
|
let lhs_node_count = node_count(lhs_syntax) as usize;
|
|
|
|
|
let rhs_node_count = node_count(rhs_syntax) as usize;
|
|
|
|
|
info!(
|
|
|
|
|
@ -180,7 +210,7 @@ pub fn mark_syntax<'a>(
|
|
|
|
|
let size_hint = lhs_node_count * rhs_node_count;
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(lhs_syntax, rhs_syntax);
|
|
|
|
|
let route = shortest_path(start, size_hint);
|
|
|
|
|
let route = shortest_path(start, size_hint, graph_limit)?;
|
|
|
|
|
|
|
|
|
|
let print_length = if env::var("DFT_VERBOSE").is_ok() {
|
|
|
|
|
50
|
|
|
|
|
@ -208,6 +238,7 @@ pub fn mark_syntax<'a>(
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
populate_change_map(&route, change_map);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
@ -216,6 +247,7 @@ mod tests {
|
|
|
|
|
use crate::{
|
|
|
|
|
diff::changes::ChangeKind,
|
|
|
|
|
diff::graph::Edge::*,
|
|
|
|
|
options::DEFAULT_GRAPH_LIMIT,
|
|
|
|
|
positions::SingleLineSpan,
|
|
|
|
|
syntax::{init_all_info, AtomKind},
|
|
|
|
|
};
|
|
|
|
|
@ -249,7 +281,7 @@ mod tests {
|
|
|
|
|
init_all_info(&[lhs], &[rhs]);
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(Some(lhs), Some(rhs));
|
|
|
|
|
let route = shortest_path(start, 0);
|
|
|
|
|
let route = shortest_path(start, 0, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
let actions = route.iter().map(|(action, _)| *action).collect_vec();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
@ -289,7 +321,7 @@ mod tests {
|
|
|
|
|
init_all_info(&lhs, &rhs);
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(lhs.get(0).copied(), rhs.get(0).copied());
|
|
|
|
|
let route = shortest_path(start, 0);
|
|
|
|
|
let route = shortest_path(start, 0, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
let actions = route.iter().map(|(action, _)| *action).collect_vec();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
@ -331,7 +363,7 @@ mod tests {
|
|
|
|
|
init_all_info(&lhs, &rhs);
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(lhs.get(0).copied(), rhs.get(0).copied());
|
|
|
|
|
let route = shortest_path(start, 0);
|
|
|
|
|
let route = shortest_path(start, 0, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
let actions = route.iter().map(|(action, _)| *action).collect_vec();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
@ -377,7 +409,7 @@ mod tests {
|
|
|
|
|
init_all_info(&lhs, &rhs);
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(lhs.get(0).copied(), rhs.get(0).copied());
|
|
|
|
|
let route = shortest_path(start, 0);
|
|
|
|
|
let route = shortest_path(start, 0, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
let actions = route.iter().map(|(action, _)| *action).collect_vec();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
@ -416,7 +448,7 @@ mod tests {
|
|
|
|
|
init_all_info(&lhs, &rhs);
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(lhs.get(0).copied(), rhs.get(0).copied());
|
|
|
|
|
let route = shortest_path(start, 0);
|
|
|
|
|
let route = shortest_path(start, 0, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
let actions = route.iter().map(|(action, _)| *action).collect_vec();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
@ -453,7 +485,7 @@ mod tests {
|
|
|
|
|
init_all_info(&lhs, &rhs);
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(lhs.get(0).copied(), rhs.get(0).copied());
|
|
|
|
|
let route = shortest_path(start, 0);
|
|
|
|
|
let route = shortest_path(start, 0, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
let actions = route.iter().map(|(action, _)| *action).collect_vec();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
@ -491,7 +523,7 @@ mod tests {
|
|
|
|
|
init_all_info(&lhs, &rhs);
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(lhs.get(0).copied(), rhs.get(0).copied());
|
|
|
|
|
let route = shortest_path(start, 0);
|
|
|
|
|
let route = shortest_path(start, 0, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
let actions = route.iter().map(|(action, _)| *action).collect_vec();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
@ -525,7 +557,7 @@ mod tests {
|
|
|
|
|
init_all_info(&lhs, &rhs);
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(lhs.get(0).copied(), rhs.get(0).copied());
|
|
|
|
|
let route = shortest_path(start, 0);
|
|
|
|
|
let route = shortest_path(start, 0, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
let actions = route.iter().map(|(action, _)| *action).collect_vec();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
@ -556,7 +588,7 @@ mod tests {
|
|
|
|
|
init_all_info(&lhs, &rhs);
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(lhs.get(0).copied(), rhs.get(0).copied());
|
|
|
|
|
let route = shortest_path(start, 0);
|
|
|
|
|
let route = shortest_path(start, 0, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
let actions = route.iter().map(|(action, _)| *action).collect_vec();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
@ -595,7 +627,7 @@ mod tests {
|
|
|
|
|
init_all_info(&lhs, &rhs);
|
|
|
|
|
|
|
|
|
|
let start = Vertex::new(lhs.get(0).copied(), rhs.get(0).copied());
|
|
|
|
|
let route = shortest_path(start, 0);
|
|
|
|
|
let route = shortest_path(start, 0, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
let actions = route.iter().map(|(action, _)| *action).collect_vec();
|
|
|
|
|
assert_eq!(
|
|
|
|
|
@ -617,7 +649,7 @@ mod tests {
|
|
|
|
|
init_all_info(&[lhs], &[rhs]);
|
|
|
|
|
|
|
|
|
|
let mut change_map = ChangeMap::default();
|
|
|
|
|
mark_syntax(Some(lhs), Some(rhs), &mut change_map);
|
|
|
|
|
mark_syntax(Some(lhs), Some(rhs), &mut change_map, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(change_map.get(lhs), Some(ChangeKind::Unchanged(rhs)));
|
|
|
|
|
assert_eq!(change_map.get(rhs), Some(ChangeKind::Unchanged(lhs)));
|
|
|
|
|
@ -631,7 +663,7 @@ mod tests {
|
|
|
|
|
init_all_info(&[lhs], &[rhs]);
|
|
|
|
|
|
|
|
|
|
let mut change_map = ChangeMap::default();
|
|
|
|
|
mark_syntax(Some(lhs), Some(rhs), &mut change_map);
|
|
|
|
|
mark_syntax(Some(lhs), Some(rhs), &mut change_map, DEFAULT_GRAPH_LIMIT).unwrap();
|
|
|
|
|
assert_eq!(change_map.get(lhs), Some(ChangeKind::Novel));
|
|
|
|
|
assert_eq!(change_map.get(rhs), Some(ChangeKind::Novel));
|
|
|
|
|
}
|
|
|
|
|
|