use crate::SpikefitSample;
use crate::err::SpikefitError;
pub(crate) fn peak_prominences_impl<T: SpikefitSample>(
x: &[T],
peaks: &[usize],
) -> Result<Vec<T>, SpikefitError> {
if x.is_empty() {
return Err(SpikefitError::SignalTooShort { len: 0 });
}
if peaks.is_empty() {
return Ok(Vec::new());
}
let mut prominences = Vec::with_capacity(peaks.len());
for &peak_idx in peaks {
if peak_idx >= x.len() {
return Err(SpikefitError::PeakOutOfBounds {
index: peak_idx,
len: x.len(),
});
}
let peak_height = x[peak_idx];
let mut left_min = peak_height;
let mut left_reached_minimum = false;
for i in (0..peak_idx).rev() {
if x[i] < left_min {
left_min = x[i];
left_reached_minimum = true;
} else if left_reached_minimum && x[i] > left_min {
break;
}
if x[i] > peak_height {
break;
}
}
let mut right_min = peak_height;
let mut right_reached_minimum = false;
for (i, &x_val) in x.iter().enumerate().skip(peak_idx + 1) {
if x_val < right_min {
right_min = x_val;
right_reached_minimum = true;
} else if right_reached_minimum && x_val > right_min {
break;
}
if x[i] > peak_height {
break;
}
}
let min_height = if left_min > right_min {
left_min
} else {
right_min
};
let prominence = peak_height - min_height;
prominences.push(prominence);
}
Ok(prominences)
}