use super::graph::EdgeData;
pub fn connectedness(segment: &[EdgeData], lambda: f32) -> f32 {
let (sum_numerator, sum_denominator): (f32, f32) = segment
.iter()
.map(|edge| {
let area = edge.num_cells;
let numerator = (-(edge.adj_dist / lambda)).exp() * edge.condition * edge.pa * area;
let denominator = (-(edge.geo_dist / 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(segment: &[EdgeData], lambda: f32) -> f32 {
const DENOM_VAL: f32 = 283.465;
if segment.is_empty() {
return 0.0;
}
let n_scenario = match segment.first() {
Some(ed) => ed.similarities.len(),
None => return 0.0,
};
if n_scenario == 0 {
return 0.0;
}
let mut numerator = vec![0.0f32; n_scenario];
let mut denominator = 0.0f32;
let inv_lambda: f32 = 1.0 / lambda;
for edge in segment {
if edge.similarities.len() < n_scenario {
continue;
}
let area = edge.num_cells;
let weight_num: f32 = {
let t = edge.adj_dist * inv_lambda;
let exp_term = (t * t) / DENOM_VAL;
(-exp_term).exp() * edge.condition * area
};
let weight_denom: f32 = {
let t = edge.geo_dist * inv_lambda;
let exp_term = (t * t) / DENOM_VAL;
(-exp_term).exp() * area
};
for (i, sim_opt) in edge.similarities.iter().take(n_scenario).enumerate() {
let sim = match sim_opt {
Some(s) => *s,
None => 0.0,
};
numerator[i] += weight_num * sim;
}
denominator += weight_denom * edge.similarities[0].unwrap_or(0.0);
}
if denominator > 0.0 {
minimax(&numerator) / denominator
} else {
0.0
}
}