use std::ops::Range;
pub const START_HEIGHT_SLOW: usize = 340_000;
pub const START_HEIGHT_FAST: usize = 508_000;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Config {
pub alpha: f64,
pub window_size: usize,
pub search_below: usize,
pub search_above: usize,
pub shape_weight: f64,
}
impl Default for Config {
fn default() -> Self {
Self {
alpha: 2.0 / 7.0,
window_size: 12,
search_below: 12,
search_above: 11,
shape_weight: 0.0,
}
}
}
impl Config {
pub fn slow() -> Self {
Self {
alpha: 0.10,
window_size: 40,
shape_weight: 8.0,
..Self::default()
}
}
pub fn for_height(height: usize) -> Self {
if height < START_HEIGHT_FAST {
Self::slow()
} else {
Self::default()
}
}
pub fn segments_for_range(range: Range<usize>) -> impl Iterator<Item = Range<usize>> {
let split = START_HEIGHT_FAST.max(range.start).min(range.end);
[range.start..split, split..range.end]
.into_iter()
.filter(|range| !range.is_empty())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn segments_for_range_splits_at_fast_start() {
let segments: Vec<_> =
Config::segments_for_range((START_HEIGHT_FAST - 2)..(START_HEIGHT_FAST + 2)).collect();
assert_eq!(
segments,
vec![
(START_HEIGHT_FAST - 2)..START_HEIGHT_FAST,
START_HEIGHT_FAST..(START_HEIGHT_FAST + 2),
]
);
}
#[test]
fn segments_for_range_omits_empty_sides() {
let slow: Vec<_> =
Config::segments_for_range((START_HEIGHT_FAST - 2)..START_HEIGHT_FAST).collect();
assert_eq!(slow, vec![(START_HEIGHT_FAST - 2)..START_HEIGHT_FAST]);
let fast: Vec<_> =
Config::segments_for_range(START_HEIGHT_FAST..(START_HEIGHT_FAST + 2)).collect();
assert_eq!(fast, vec![START_HEIGHT_FAST..(START_HEIGHT_FAST + 2)]);
}
#[test]
fn for_height_selects_regime() {
assert_eq!(Config::for_height(START_HEIGHT_FAST - 1), Config::slow());
assert_eq!(Config::for_height(START_HEIGHT_FAST), Config::default());
}
}