feat(router): Start implementing route pruning support

This commit is contained in:
Daniel S. 2019-09-28 15:41:25 +02:00
parent 0107cf2f8e
commit 88a0378dfe
2 changed files with 38 additions and 25 deletions

View file

@ -114,7 +114,7 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> {
py: Python<'static>, py: Python<'static>,
hops: Vec<String>, hops: Vec<String>,
range: f32, range: f32,
prune: Option<(usize,f64)>, prune: Option<(usize, f32)>,
mode: String, mode: String,
primary: bool, primary: bool,
permute: bool, permute: bool,

View file

@ -57,7 +57,7 @@ pub struct RouteOpts {
pub keep_last: bool, pub keep_last: bool,
pub factor: Option<f32>, pub factor: Option<f32>,
pub mode: Mode, pub mode: Mode,
pub prune: Option<(usize,f64)>, pub prune: Option<(usize, f32)>,
pub systems: Vec<SysEntry>, pub systems: Vec<SysEntry>,
pub callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>, pub callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>,
} }
@ -193,8 +193,7 @@ pub struct Router {
range: f32, range: f32,
primary_only: bool, primary_only: bool,
path: PathBuf, path: PathBuf,
prune: Option<(usize,f64)>, prune: Option<(usize, f32)>,
prune_map: FnvHashMap<u32, (usize,f64)>,
callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>, callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>,
} }
@ -202,7 +201,7 @@ impl Router {
pub fn new( pub fn new(
path: &PathBuf, path: &PathBuf,
range: f32, range: f32,
prune: Option<(usize,f64)>, prune: Option<(usize, f32)>,
primary_only: bool, primary_only: bool,
callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>, callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>,
) -> Result<Self, String> { ) -> Result<Self, String> {
@ -249,7 +248,6 @@ impl Router {
path: path.clone(), path: path.clone(),
callback, callback,
prune, prune,
prune_map: FnvHashMap::default()
}; };
println!( println!(
"{} Systems loaded in {}", "{} Systems loaded in {}",
@ -307,7 +305,6 @@ impl Router {
path, path,
callback, callback,
prune: None, prune: None,
prune_map: FnvHashMap::default()
}, },
)) ))
} }
@ -320,10 +317,9 @@ impl Router {
self.points_in_sphere(&sys.pos, sys.mult * r) self.points_in_sphere(&sys.pos, sys.mult * r)
} }
fn valid(&self, sys: &System, src: &System, dst: &System) -> bool { fn valid(&self, sys: &System) -> bool {
let scoopable = self.scoopable.contains(&sys.id); let scoopable = self.scoopable.contains(&sys.id);
return scoopable; return scoopable;
// TODO: check prune map
} }
pub fn best_multiroute( pub fn best_multiroute(
@ -379,6 +375,14 @@ impl Router {
for pair in waypoints.windows(2) { for pair in waypoints.windows(2) {
match pair { match pair {
[src, dst] => { [src, dst] => {
let d_total=dist(&src.pos,&dst.pos);
println!("Plotting route from [{}] to [{}]...", src.system, dst.system);
println!(
"Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}",
range,
d_total,
d_total / range
);
let block = match mode { let block = match mode {
Mode::BFS => self.route_bfs(&src, &dst, range)?, Mode::BFS => self.route_bfs(&src, &dst, range)?,
Mode::Greedy => self.route_greedy(&src, &dst, range)?, Mode::Greedy => self.route_greedy(&src, &dst, range)?,
@ -510,7 +514,7 @@ impl Router {
} }
queue.extend( queue.extend(
self.neighbours(&sys, range) self.neighbours(&sys, range)
.filter(|&nb| (self.valid(nb, &src, &dst) || (nb.id == goal_sys.id))) .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id)))
.filter(|&nb| seen.insert(nb.id)) .filter(|&nb| seen.insert(nb.id))
.map(|nb| { .map(|nb| {
prev.insert(nb.id, sys); prev.insert(nb.id, sys);
@ -583,11 +587,11 @@ impl Router {
let mut prev = FnvHashMap::default(); let mut prev = FnvHashMap::default();
let mut seen = FnvHashSet::default(); let mut seen = FnvHashSet::default();
let mut found = false; let mut found = false;
let mut queue: Vec<(f32, f32, usize, &System)> = Vec::new(); let mut queue: Vec<(f32, usize, &System)> = Vec::new();
queue.push((-goal_sys.mult, start_sys.distp(goal_sys), 0, &start_sys)); queue.push((start_sys.distp(goal_sys), 0, &start_sys));
seen.insert(start_sys.id); seen.insert(start_sys.id);
while !(queue.is_empty() || found) { while !(queue.is_empty() || found) {
while let Some((_, _, depth, sys)) = queue.pop() { while let Some((_, depth, sys)) = queue.pop() {
if t_last.elapsed().as_millis() > 100 { if t_last.elapsed().as_millis() > 100 {
t_last = Instant::now(); t_last = Instant::now();
state.depth = depth; state.depth = depth;
@ -611,7 +615,7 @@ impl Router {
} }
queue.extend( queue.extend(
self.neighbours(&sys, range) self.neighbours(&sys, range)
.filter(|&nb| (self.valid(nb, &src, &dst) || (nb.id == goal_sys.id))) .filter(|&nb| (self.valid(nb) || (nb.id == goal_sys.id)))
.filter(|&nb| seen.insert(nb.id)) .filter(|&nb| seen.insert(nb.id))
.map(|nb| { .map(|nb| {
prev.insert(nb.id, sys); prev.insert(nb.id, sys);
@ -619,10 +623,10 @@ impl Router {
if d_g < d_rem { if d_g < d_rem {
d_rem = d_g; d_rem = d_g;
} }
(-nb.mult, d_g, depth + 1, nb) (d_g, depth + 1, nb)
}), }),
); );
queue.sort_by(|a, b| fcmp(a.0, b.0).then(fcmp(a.1, b.1))); queue.sort_by(|a, b| fcmp(a.0, b.0).then(a.1.cmp(&b.1)));
queue.reverse(); queue.reverse();
} }
} }
@ -786,6 +790,7 @@ impl Router {
range: f32, range: f32,
) -> Result<Vec<System>, String> { ) -> Result<Vec<System>, String> {
println!("Running BFS"); println!("Running BFS");
let min_improvement = self.prune.map(|v| (v.0,v.1*range)).unwrap_or_else(|| (0,0.0));
let src_name = start_sys.system.clone(); let src_name = start_sys.system.clone();
let dst_name = goal_sys.system.clone(); let dst_name = goal_sys.system.clone();
let d_total = dist(&start_sys.pos, &goal_sys.pos); let d_total = dist(&start_sys.pos, &goal_sys.pos);
@ -804,15 +809,9 @@ impl Router {
system: start_sys.system.clone(), system: start_sys.system.clone(),
body: start_sys.body.clone(), body: start_sys.body.clone(),
}; };
println!("Plotting route from {} to {}...", src_name, dst_name);
println!(
"Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}",
range,
d_total,
d_total / range
);
let total = self.tree.size() as f32; let total = self.tree.size() as f32;
let mut prev = FnvHashMap::default(); let mut prev: FnvHashMap<u32, &System> = FnvHashMap::default();
let mut prune_map: FnvHashMap<u32, (usize, f32)> = FnvHashMap::default();
let mut seen = FnvHashSet::default(); let mut seen = FnvHashSet::default();
let mut depth = 0; let mut depth = 0;
let mut found = false; let mut found = false;
@ -847,10 +846,24 @@ impl Router {
}; };
t_last = Instant::now(); t_last = Instant::now();
} }
if self.prune.is_some() {
let best_dist = if let Some(p_sys) = prev.get(&sys.id) {
dist2(&p_sys.pos, &goal_sys.pos).min(
prune_map
.get(&p_sys.id)
.map(|v| v.1)
.unwrap_or(std::f32::MAX),
)
} else {
dist2(&sys.pos, &goal_sys.pos)
};
prune_map.insert(sys.id, (depth, best_dist));
}
// TODO: check improvement, if too small: continue
queue_next.extend( queue_next.extend(
self.neighbours(&sys, range) self.neighbours(&sys, range)
.filter(|&nb| { .filter(|&nb| {
(self.valid(nb, &start_sys, &goal_sys) || (nb.id == goal_sys.id)) (self.valid(nb) || (nb.id == goal_sys.id))
}) })
.filter(|&nb| seen.insert(nb.id)) .filter(|&nb| seen.insert(nb.id))
.map(|nb| { .map(|nb| {