use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone)]
pub struct Region {
start: usize,
end: usize,
}
impl Region {
pub fn new(s: usize, e: usize) -> Self {
Self { start: s, end: e }
}
pub fn length(&self) -> usize {
self.end - self.start
}
}
pub struct Regions(Vec<Region>);
impl Deref for Regions {
type Target = Vec<Region>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Regions {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<&Vec<(usize, usize)>> for Regions {
fn from(value: &Vec<(usize, usize)>) -> Self {
let regions = value
.iter()
.map(|v| Region {
start: v.0,
end: v.1,
})
.collect::<Vec<_>>();
Self(regions)
}
}
impl Regions {
pub fn new(regions: Vec<Region>) -> Self {
Self(regions)
}
pub fn total_length(&self) -> usize {
self.iter().map(|v| v.length()).sum()
}
pub fn merge_regions(&self) -> Self {
let mut regions = self.0.clone();
regions.sort_by_key(|v| v.start);
let mut merged_regions: Vec<Region> = Vec::new();
for region in regions {
if let Some(last) = merged_regions.last_mut() {
if region.start <= last.end {
last.end = last.end.max(region.end);
} else {
merged_regions.push(region);
}
} else {
merged_regions.push(region);
}
}
Self(merged_regions)
}
pub fn ovlp_length(&self) -> usize {
let mut total_overlap = 0;
let mut events = Vec::new();
for region in &self.0 {
events.push((region.start, 1));
events.push((region.end, -1));
}
events.sort();
let mut current_depth = 0;
let mut prev_pos = events[0].0;
for (pos, change) in events {
if current_depth > 1 {
total_overlap += pos - prev_pos;
}
current_depth += change;
prev_pos = pos;
}
total_overlap
}
pub fn ovlp_ratio(&self) -> f32 {
let merged_regions = self.merge_regions();
let len_after_merge = merged_regions.total_length();
let ovlp_len = self.ovlp_length();
if len_after_merge == 0 {
0.0
} else {
ovlp_len as f32 / len_after_merge as f32
}
}
pub fn gaps(&self, init_pos: Option<usize>, end_pos: Option<usize>) -> Vec<i64> {
if self.is_empty() {
return vec![];
}
let mut gaps = vec![];
let mut pre_pos = init_pos;
self.iter().for_each(|region| {
if let Some(pre_pos) = pre_pos {
let gap = region.start as i64 - pre_pos as i64;
gaps.push(gap);
}
pre_pos = Some(region.end);
});
if let Some(end_pos) = end_pos {
let gap = end_pos as i64 - pre_pos.unwrap() as i64;
gaps.push(gap);
}
gaps
}
}
#[cfg(test)]
mod test {
use crate::ds::region::Regions;
#[test]
fn test_calcute_overlap_metrics() {
let regions = vec![(1_usize, 5_usize), (1, 5)];
let regions: Regions = (®ions).into();
let res = regions.ovlp_ratio();
println!("{:?}", res);
let regions = vec![(1_usize, 5_usize), (5, 10)];
let regions: Regions = (®ions).into();
let res = regions.ovlp_ratio();
println!("{:?}", res);
}
#[test]
fn test_calcute_gaps() {
let regions = vec![(1_usize, 5_usize), (1, 5)];
let regions: Regions = (®ions).into();
let res = regions.gaps(Some(0), Some(100));
println!("{:?}", res);
let regions = vec![(1_usize, 5_usize), (5, 10)];
let regions: Regions = (®ions).into();
let res = regions.gaps(Some(0), Some(100));
println!("{:?}", res);
let regions = vec![(1_usize, 5_usize), (5, 10)];
let regions: Regions = (®ions).into();
let res = regions.gaps(None, None);
println!("{:?}", res);
let regions = vec![(1_usize, 5_usize), (7, 10)];
let regions: Regions = (®ions).into();
let res = regions.gaps(None, None);
println!("{:?}", res);
}
}