pub fn sakoe_chiba_band(n: usize, m: usize, window_size: usize) -> Vec<(usize, usize)> {
assert!(n > 0 && m > 0, "Dimensions must be positive");
(0..n)
.map(|i| {
let center = (i as f64 * (m - 1) as f64 / (n - 1).max(1) as f64).round() as isize;
let lo = (center - window_size as isize).max(0) as usize;
let hi = ((center + window_size as isize) as usize).min(m - 1);
(lo, hi)
})
.collect()
}
pub fn itakura_parallelogram(n: usize, m: usize, max_slope: f64) -> Vec<(usize, usize)> {
assert!(n > 0 && m > 0, "Dimensions must be positive");
assert!(max_slope >= 1.0, "max_slope must be >= 1.0");
let min_slope = 1.0 / max_slope;
(0..n)
.map(|i| {
let i_f = i as f64;
let n_f = (n - 1) as f64;
let m_f = (m - 1) as f64;
let upper1 = (i_f * max_slope * m_f / n_f).floor() as usize;
let upper2 = (m_f - (n_f - i_f) * min_slope * m_f / n_f).ceil() as usize;
let hi = upper1.min(upper2).min(m - 1);
let lower1 = (i_f * min_slope * m_f / n_f).ceil() as usize;
let lower2 = (m_f - (n_f - i_f) * max_slope * m_f / n_f).max(0.0).floor() as usize;
let lo = lower1.max(lower2);
(lo, hi)
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sakoe_chiba_basic() {
let band = sakoe_chiba_band(5, 5, 1);
assert_eq!(band.len(), 5);
assert_eq!(band[0], (0, 1));
assert_eq!(band[2], (1, 3));
assert_eq!(band[4], (3, 4));
}
#[test]
fn test_sakoe_chiba_full() {
let band = sakoe_chiba_band(4, 4, 10);
for &(lo, hi) in &band {
assert_eq!(lo, 0);
assert_eq!(hi, 3);
}
}
#[test]
fn test_itakura_basic() {
let band = itakura_parallelogram(5, 5, 2.0);
assert_eq!(band.len(), 5);
assert_eq!(band[0].0, 0);
assert_eq!(band[4].1, 4);
}
#[test]
fn test_itakura_symmetric() {
let band = itakura_parallelogram(10, 10, 2.0);
for i in 0..10 {
let (lo, hi) = band[i];
assert!(lo <= i);
assert!(hi >= i);
}
}
}