use crate::interval::Interval;
use crate::{BaseInterval, IntervalCollection};
use defaultmap::DefaultHashMap;
use itertools::Itertools;
use num_traits::{Num, ToPrimitive};
use std::fmt::Debug;
use std::fmt::Display;
use std::hash::Hash;
use std::ops::{AddAssign, SubAssign};
fn intervals_to_points<T, U>(input: Vec<Interval<T, U>>) -> Vec<(T, U)>
where
T: Num + PartialOrd + Clone + Eq + Hash + Copy + Display + Debug,
U: Num + PartialOrd + Default + AddAssign + SubAssign + Clone + Copy + Display + Debug,
{
let mut out: DefaultHashMap<T, U> = DefaultHashMap::new();
for entry in input.iter() {
let this = entry.to_tuple();
out[this.0] += this.2;
out[this.1] -= this.2;
}
let mut out: Vec<(T, U)> = out
.iter()
.filter(|x| *x.1 != U::zero())
.map(|x| (x.0.to_owned(), x.1.to_owned()))
.collect();
out.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
out
}
pub fn combine_intervals<T, U>(raw_ivs: Vec<Interval<T, U>>) -> IntervalCollection<T, U>
where
T: Num + PartialOrd + Clone + Hash + Copy + Eq + Display + Debug,
U: Num
+ PartialOrd
+ Default
+ AddAssign
+ SubAssign
+ Clone
+ Copy
+ ToPrimitive
+ std::iter::Sum
+ Display
+ Debug,
{
let endpoints: Vec<(T, U)> = intervals_to_points(raw_ivs);
let mut curr_val = U::zero();
let mut new_map = Vec::new();
for pt in endpoints {
curr_val += pt.1;
new_map.push((pt.0, curr_val))
}
let mut out = Vec::new();
for (lb, ub) in new_map.iter().tuple_windows() {
if lb.1 != U::zero() {
out.push(Interval::new(lb.0, ub.0, lb.1));
}
}
IntervalCollection::from_vec(out)
}
pub fn combine_as_set<T, U>(raw_ivs: Vec<Interval<T, U>>) -> Vec<BaseInterval<T>>
where
T: Num + PartialOrd + Clone + Hash + Copy + Eq + Display + Debug,
U: Num
+ PartialOrd
+ Default
+ AddAssign
+ SubAssign
+ Clone
+ Copy
+ ToPrimitive
+ std::iter::Sum
+ Display
+ Debug,
{
let endpoints: Vec<(T, U)> = intervals_to_points(raw_ivs);
let mut curr_val = U::zero();
let mut new_map = Vec::new();
for pt in endpoints {
curr_val += pt.1;
new_map.push((pt.0, curr_val))
}
let mut out = Vec::new();
for (lb, ub) in new_map.iter().tuple_windows() {
if lb.1 > U::zero() {
match out.last() {
None => {
out.push(BaseInterval::new(lb.0, ub.0));
}
Some(x) => {
if x.get_ub() == lb.0 {
let new_lb = x.get_lb();
out.pop();
out.push(BaseInterval::new(new_lb, ub.0));
} else {
out.push(BaseInterval::new(lb.0, ub.0));
}
}
}
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_with_overlap() {
let this: Vec<[i64; 3]> = vec![[0, 2, 1], [1, 3, 2]];
let this = this
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let this = combine_intervals(this);
let that: Vec<[i64; 3]> = vec![[0, 1, 1], [1, 2, 3], [2, 3, 2]];
let that = that
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let that = IntervalCollection::from_vec(that);
assert_eq!(this, that);
}
#[test]
fn test_without_overlap() {
let this: Vec<[i64; 3]> = vec![[0, 1, 1], [2, 3, 2]];
let this = this
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let this = IntervalCollection::from_vec(this);
let that: Vec<[i64; 3]> = vec![[0, 1, 1], [2, 3, 2]];
let that = that
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let that = combine_intervals(that);
assert_eq!(this, that);
}
#[test]
fn test_created_overlap() {
let this: Vec<[i64; 3]> = vec![[0, 1, 2], [2, 3, -2]];
let this = this
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let this = IntervalCollection::from_vec(this);
let that: Vec<[i64; 3]> = vec![[0, 2, 2], [1, 3, -2]];
let that = that
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let that = combine_intervals(that);
assert_eq!(this, that);
}
#[test]
fn test_merge() {
let this: Vec<[i64; 3]> = vec![[0, 1, 2], [1, 2, 2]];
let this = this
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let this = combine_intervals(this);
let that: Vec<[i64; 3]> = vec![[0, 2, 2]];
let that = that
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let that = IntervalCollection::from_vec(that);
assert_eq!(this, that);
}
#[test]
fn test_set_with_overlap() {
let this: Vec<[i64; 3]> = vec![[0, 2, 1], [1, 3, 2]];
let this = this
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let this = combine_as_set(this);
let that: Vec<[i64; 2]> = vec![[0, 3]];
let that: Vec<BaseInterval<i64>> =
that.iter().map(|x| BaseInterval::new(x[0], x[1])).collect();
assert_eq!(this, that);
}
#[test]
fn test_set_without_overlap() {
let this: Vec<[i64; 2]> = vec![[0, 1], [2, 3]];
let this: Vec<BaseInterval<i64>> =
this.iter().map(|x| BaseInterval::new(x[0], x[1])).collect();
let that: Vec<[i64; 3]> = vec![[0, 1, 1], [2, 3, 2]];
let that = that
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let that = combine_as_set(that);
assert_eq!(this, that);
}
#[test]
fn test_as_set_both_impls() {
let that: Vec<[i64; 3]> = vec![[0, 2, 1], [1, 3, 2]];
let that = that
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let this = combine_as_set(that);
let that: Vec<[i64; 3]> = vec![[0, 2, 1], [1, 3, 2]];
let that = that
.iter()
.map(|x| Interval::new(x[0], x[1], x[2]))
.collect();
let that = combine_intervals(that).to_vec_as_set();
assert_eq!(this, that);
}
}