use super::graph::{get_edge_neighbours, Graph, NodeId};
use super::window::FocalWindow;
use super::{map_cells, Prepared};
use ndarray::Array2;
use rustc_hash::FxHashMap;
const COLS: [i32; 8] = [0, 1, 0, -1, 1, 1, -1, -1];
const ROWS: [i32; 8] = [1, 0, -1, 0, 1, -1, 1, -1];
pub type Inject<'a> = &'a (dyn Fn(NodeId, NodeId, bool) -> Option<f32> + Sync);
pub fn decode(id: NodeId) -> (i32, i32, i32) {
((id >> 48) as i32, ((id >> 24) & 0xFF_FFFF) as i32, (id & 0xFF_FFFF) as i32)
}
pub fn encode(level: i32, row: i32, col: i32) -> Option<NodeId> {
(row >= 0 && col >= 0).then(|| ((level as u64) << 48) | ((row as u64) << 24) | col as u64)
}
pub fn edge_order(graph: &Graph, offsets: (usize, usize)) -> Vec<(NodeId, NodeId)> {
let mut sources: Vec<NodeId> = graph.data.keys().map(|&(u, _)| u).collect();
sources.sort_unstable();
sources.dedup();
let origin = |tile0: usize, level: i32| (tile0 as i32).div_euclid(level);
let mut keys = Vec::with_capacity(graph.data.len());
for u in sources {
let (level, row, col) = decode(u);
for k in 0..8 {
if let Some(v) = encode(level, row + COLS[k], col + ROWS[k]) {
if graph.data.contains_key(&(u, v)) {
keys.push((u, v));
}
}
}
let local = (row - origin(offsets.0, level), col - origin(offsets.1, level));
let (higher, count) = get_edge_neighbours(local.0, local.1, level, offsets);
for &(hi, hj) in &higher[..count] {
let up = level * 2;
let global = (hi + origin(offsets.0, up), hj + origin(offsets.1, up));
if let Some(v) = encode(up, global.0, global.1) {
if graph.data.contains_key(&(u, v)) {
keys.push((u, v));
}
}
}
}
assert_eq!(keys.len(), graph.data.len(), "Canonical order must enumerate every edge.");
keys
}
pub fn traversal(windows: &[(i32, FocalWindow)], offsets: (usize, usize)) -> FxHashMap<NodeId, f32> {
let mut trav = FxHashMap::default();
for (level, win) in windows {
let origin = (
(offsets.0 as i32).div_euclid(*level),
(offsets.1 as i32).div_euclid(*level),
);
for (idx, (&i, &j)) in win.i_array.iter().zip(&win.j_array).enumerate() {
let t = match &win.trav_values {
Some(tv) => tv[idx],
None => win.values[idx],
};
trav.insert(encode(*level, origin.0 + i, origin.1 + j).unwrap(), t);
}
}
trav
}
pub fn reweight(
graph: &mut Graph,
windows: &[(i32, FocalWindow)],
offsets: (usize, usize),
factor: f32,
dist: Inject,
) {
let trav = traversal(windows, offsets);
let source_t = trav.get(&graph.source).copied();
for (&(u, v), edge) in graph.data.iter_mut() {
if let Some(d) = dist(u, v, !trav.contains_key(&v)) {
let t = trav.get(&v).copied().or(source_t).expect("Unknown edge target.");
let w: f32 = (1.0 - factor) * t + factor;
edge.adj_dist = w * d;
edge.geo_dist = d;
}
}
}
pub fn cell(prepared: &Prepared, i: usize, j: usize, inject: Option<Inject>) -> f32 {
let windows = prepared.windows(i, j);
let mut graph = prepared.graph(i, j, &windows);
let keys = edge_order(&graph, prepared.offsets);
if let Some(dist) = inject {
reweight(&mut graph, &windows, prepared.offsets, prepared.max_cost, dist);
}
let routed = graph.route(graph.to_adjacency_in(&keys));
prepared.score(&routed.paths)
}
pub fn conn(
prepared: &Prepared,
cond: &Array2<f32>,
mask: &Array2<bool>,
inject: Option<Inject>,
) -> Array2<f32> {
map_cells(cond, mask, |i, j| cell(prepared, i, j, inject))
}