diff --git a/src/lib.rs b/src/lib.rs index 27eee44..84f6ac8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,8 +36,8 @@ use thiserror::Error; mod qc_tests; pub use qc_tests::{ - buddy_check::buddy_check, dip_check::dip_check, range_check::range_check, sct::sct, - step_check::step_check, + buddy_check::buddy_check, dip_check::dip_check, freeze_check::freeze_check, + range_check::range_check, sct::sct, step_check::step_check, }; mod util; diff --git a/src/qc_tests/freeze_check.rs b/src/qc_tests/freeze_check.rs new file mode 100644 index 0000000..1d4928f --- /dev/null +++ b/src/qc_tests/freeze_check.rs @@ -0,0 +1,45 @@ +use crate::{Error, Flag, SeriesCache}; + +/// Timeseries QC test that checks for streaks of repeating values. +/// +/// If `num_points` observations in a row are identical, the last will be flagged as Flag::Fail, if +/// any of the last `num_points` observations are missing, it will be flagged as Flag::DataMissing, +/// else Flag::Pass. +/// +/// As (`num_points` - 1) predecessors to each observation are needed, the [`SeriesCache`] provided must have +/// `num_leading_points` >= `num_points` - 1. +/// +/// ## Errors +/// +/// - data is invalid +/// - data has `num_leading_points` < `num_points` - 1 +pub fn freeze_check(data: &SeriesCache, num_points: u8) -> Result, Error> { + let (leading_trim, lead_overflow) = data + .num_leading_points + .overflowing_sub(num_points.saturating_sub(1)); + + if lead_overflow || (leading_trim + num_points) as usize > data.values.len() { + // TODO: nicer error here? + return Err(Error::InvalidInputShape("data".to_string())); + } + + let trimmed = &data.values + [leading_trim as usize..(data.values.len() - data.num_trailing_points as usize)]; + + let windows = trimmed.windows(num_points as usize); + + Ok(windows + .map(|data| { + if data.contains(&None) { + return Flag::DataMissing; + } + let data: Vec = data.iter().map(|opt| opt.unwrap()).collect(); + + let base = data[0]; + if !data.iter().any(|x| *x != base) { + return Flag::Fail; + } + Flag::Pass + }) + .collect()) +} diff --git a/src/qc_tests/mod.rs b/src/qc_tests/mod.rs index bf31198..a6f8ce4 100644 --- a/src/qc_tests/mod.rs +++ b/src/qc_tests/mod.rs @@ -1,5 +1,6 @@ pub(super) mod buddy_check; pub(super) mod dip_check; +pub(super) mod freeze_check; pub(super) mod range_check; pub(super) mod sct; pub(super) mod step_check;