use crate::graph::Nodes;
use crate::routing::Paths;
pub fn connectedness(paths: &Paths, nodes: &Nodes, lambda: f32) -> f32 {
let (sum_numerator, sum_denominator): (f32, f32) = (0..paths.len())
.map(|k| {
let v = paths.node[k] as usize;
let area = nodes.count[v];
let numerator = (-(paths.adj[k] / lambda)).exp() * nodes.cond[v] * nodes.pa[v] * area;
let denominator = (-(paths.geo[k] / lambda)).exp() * area;
(numerator, denominator)
})
.fold((0.0, 0.0), |(acc_num, acc_den), (num, den)| {
(acc_num + num, acc_den + den)
});
if sum_denominator > 0.0 {
sum_numerator / sum_denominator
} else {
0.0
}
}
#[inline]
fn minimax(x: &[f32]) -> f32 {
if x.is_empty() {
return 0.0;
}
let mean = x.iter().sum::<f32>() / x.len() as f32;
let min = x.iter()
.fold(f32::INFINITY, |acc, &val| acc.min(val));
0.5 * (mean + min)
}
pub fn beri_score(
paths: &Paths,
nodes: &Nodes,
n_scenario: usize,
lambda: f32,
numerator: &mut Vec<f32>,
) -> f32 {
const DENOM_VAL: f32 = 283.465;
if paths.is_empty() {
return 0.0;
}
if n_scenario == 0 {
return 0.0;
}
numerator.clear();
numerator.resize(n_scenario, 0.0);
let mut denominator = 0.0f32;
let inv_lambda: f32 = 1.0 / lambda;
for k in 0..paths.len() {
let v = paths.node[k] as usize;
let area = nodes.count[v];
let weight_num: f32 = {
let t = paths.adj[k] * inv_lambda;
let exp_term = (t * t) / DENOM_VAL;
(-exp_term).exp() * nodes.cond[v] * area
};
let weight_denom: f32 = {
let t = paths.geo[k] * inv_lambda;
let exp_term = (t * t) / DENOM_VAL;
(-exp_term).exp() * area
};
let sims = &nodes.sims[v * n_scenario..(v + 1) * n_scenario];
for (i, &sim) in sims.iter().enumerate() {
let sim = if sim.is_nan() { 0.0 } else { sim };
numerator[i] += weight_num * sim;
}
let current = if sims[0].is_nan() { 0.0 } else { sims[0] };
denominator += weight_denom * current;
}
if denominator > 0.0 {
minimax(numerator) / denominator
} else {
0.0
}
}