pub fn segmentation(
n_timestamps: usize,
n_segments: usize,
overlapping: bool,
) -> Vec<(usize, usize)> {
assert!(n_timestamps > 0, "n_timestamps must be positive");
assert!(n_segments > 0, "n_segments must be positive");
assert!(
n_segments <= n_timestamps,
"n_segments ({n_segments}) must not exceed n_timestamps ({n_timestamps})"
);
if overlapping {
let segment_width = (n_timestamps as f64 / n_segments as f64).ceil() as usize;
let half = segment_width / 2;
(0..n_segments)
.map(|i| {
let center = (i as f64 * (n_timestamps - 1) as f64 / (n_segments - 1).max(1) as f64)
.round() as usize;
let start = center.saturating_sub(half);
let end = (start + segment_width).min(n_timestamps);
(start, end)
})
.collect()
} else {
let base_size = n_timestamps / n_segments;
let remainder = n_timestamps % n_segments;
let mut segments = Vec::with_capacity(n_segments);
let mut start = 0;
for i in 0..n_segments {
let size = base_size + if i < remainder { 1 } else { 0 };
segments.push((start, start + size));
start += size;
}
segments
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_non_overlapping_even() {
let segs = segmentation(8, 4, false);
assert_eq!(segs, vec![(0, 2), (2, 4), (4, 6), (6, 8)]);
}
#[test]
fn test_non_overlapping_uneven() {
let segs = segmentation(10, 3, false);
assert_eq!(segs, vec![(0, 4), (4, 7), (7, 10)]);
}
#[test]
fn test_non_overlapping_single() {
let segs = segmentation(5, 1, false);
assert_eq!(segs, vec![(0, 5)]);
}
#[test]
fn test_non_overlapping_identity() {
let segs = segmentation(4, 4, false);
assert_eq!(segs, vec![(0, 1), (1, 2), (2, 3), (3, 4)]);
}
#[test]
#[should_panic(expected = "must not exceed n_timestamps")]
fn test_too_many_segments() {
segmentation(3, 5, false);
}
#[test]
#[should_panic(expected = "n_timestamps must be positive")]
fn test_zero_timestamps() {
segmentation(0, 1, false);
}
#[test]
fn test_overlapping_basic() {
let segs = segmentation(8, 4, true);
assert_eq!(segs.len(), 4);
for (s, e) in &segs {
assert!(*e <= 8);
assert!(s < e);
}
}
}