use std::cmp;
use std::ops::Range;
use std::collections::HashSet;
#[cfg(not(target_arch = "wasm32"))]
use rayon::prelude::*;
use crate::idx::Idx;
use crate::ranges::{Ranges, SNORanges};
pub trait SNORanges2D<'a, T: Idx, S: Idx>: Sized {
fn make_consistent(self) -> Self;
fn is_empty(&self) -> bool;
fn contains(&self, time: T, range: &Range<S>) -> bool;
fn union(&self, other: &Self) -> Self;
fn intersection(&self, other: &Self) -> Self;
fn difference(&self, other: &Self) -> Self;
}
type Operation<T, S> = fn(
&Ranges2D<T, S>,
&Ranges2D<T, S>,
bool,
bool,
usize,
usize,
) -> Option<Ranges<S>>;
#[derive(Debug)]
pub struct Ranges2D<T: Idx, S: Idx> {
pub x: Vec<Range<T>>,
pub y: Vec<Ranges<S>>,
}
#[derive(Eq, PartialEq, Debug)]
struct BoundRange<T: Idx> {
x: T,
y_idx: usize,
start: bool
}
impl<T: Idx> BoundRange<T> {
fn new(x: T, y_idx: usize, start: bool) -> BoundRange<T> {
BoundRange {
x,
y_idx,
start
}
}
}
use std::cmp::Ordering;
impl<T: Idx> Ord for BoundRange<T> {
fn cmp(&self, other: &BoundRange<T>) -> Ordering {
self.x.cmp(&other.x)
.then_with(|| self.start.cmp(&other.start))
}
}
impl<T: Idx> PartialOrd for BoundRange<T> {
fn partial_cmp(&self, other: &BoundRange<T>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: Idx, S: Idx> Ranges2D<T, S> {
pub fn new(t: Vec<Range<T>>, s: Vec<Ranges<S>>) -> Ranges2D<T, S> {
Ranges2D { x: t, y: s }
}
fn compress(&mut self, time_ranges: Vec<Range<T>>, spatial_coverages: Vec<Ranges<S>>) {
let mut res_t = Vec::<Range<T>>::with_capacity(time_ranges.len());
let mut res_s = Vec::<Ranges<S>>::with_capacity(spatial_coverages.len());
let mut prev_s = spatial_coverages.first().unwrap().clone();
let mut prev_t = time_ranges.first().unwrap().clone();
for (cur_t, cur_s) in time_ranges.into_iter().zip(spatial_coverages.into_iter()).skip(1) {
match cur_t.start.cmp(&prev_t.end) {
Ordering::Greater => {
res_t.push(prev_t);
res_s.push(prev_s);
prev_t = cur_t;
prev_s = cur_s;
},
Ordering::Equal => {
if cur_s == prev_s {
prev_t.end = cur_t.end;
} else {
res_t.push(prev_t);
res_s.push(prev_s);
prev_t = cur_t;
prev_s = cur_s;
}
},
Ordering::Less => {
unreachable!("no overlapping time ranges at this point");
}
}
}
res_t.push(prev_t);
res_s.push(prev_s);
res_s.shrink_to_fit();
res_t.shrink_to_fit();
self.x = res_t;
self.y = res_s;
}
fn op_union(
&self,
other: &Self,
in_t1: bool,
in_t2: bool,
i: usize,
j: usize,
) -> Option<Ranges<S>> {
if in_t1 && in_t2 {
let s1 = &self.y[i >> 1];
let s2 = &other.y[j >> 1];
Some(s1.union(s2))
} else if !in_t1 && in_t2 {
let s2 = &other.y[j >> 1];
Some(s2.clone())
} else if in_t1 && !in_t2 {
let s1 = &self.y[i >> 1];
Some(s1.clone())
} else {
None
}
}
fn op_intersection(
&self,
other: &Self,
in_t1: bool,
in_t2: bool,
i: usize,
j: usize,
) -> Option<Ranges<S>> {
if in_t1 && in_t2 {
let s1 = &self.y[i >> 1];
let s2 = &other.y[j >> 1];
Some(s1.intersection(s2))
} else {
None
}
}
fn op_difference(
&self,
other: &Self,
in_t1: bool,
in_t2: bool,
i: usize,
j: usize,
) -> Option<Ranges<S>> {
if in_t1 && in_t2 {
let s1 = &self.y[i >> 1];
let s2 = &other.y[j >> 1];
Some(s1.difference(s2))
} else if in_t1 && !in_t2 {
let s1 = &self.y[i >> 1];
Some(s1.clone())
} else {
None
}
}
fn merge(&self, other: &Self, op: Operation<T, S>) -> Ranges2D<T, S> {
let t1 = &self.x;
let t1_l = t1.len() << 1;
let t2 = &other.x;
let t2_l = t2.len() << 1;
let mut t_ranges = Vec::with_capacity(3 * cmp::max(t1_l, t2_l));
let mut s_ranges = Vec::with_capacity(3 * cmp::max(t1_l, t2_l));
let mut i = 0_usize;
let mut j = 0_usize;
let mut prev_s: Option<&Ranges<S>> = None;
let mut last_t = None;
while i < t1_l || j < t2_l {
let (c, s) = if i == t1_l {
let v2 = if j & 0x1 != 0 {
t2[j >> 1].end
} else {
t2[j >> 1].start
};
let c = v2;
let in_t1 = false;
let on_rising_edge_t2 = (j & 0x1) == 0;
let in_t2 = on_rising_edge_t2;
let s = op(self, other, in_t1, in_t2, i, j);
j += 1;
(c, s)
} else if j == t2_l {
let v1 = if i & 0x1 != 0 {
t1[i >> 1].end
} else {
t1[i >> 1].start
};
let c = v1;
let on_rising_edge_t1 = (i & 0x1) == 0;
let in_t1 = on_rising_edge_t1;
let in_t2 = false;
let s = op(self, other, in_t1, in_t2, i, j);
i += 1;
(c, s)
} else {
let v1 = if i & 0x1 != 0 {
t1[i >> 1].end
} else {
t1[i >> 1].start
};
let v2 = if j & 0x1 != 0 {
t2[j >> 1].end
} else {
t2[j >> 1].start
};
let c = cmp::min(v1, v2);
let on_rising_edge_t1 = (i & 0x1) == 0;
let on_rising_edge_t2 = (j & 0x1) == 0;
let in_t1 = (on_rising_edge_t1 && c == v1) | (!on_rising_edge_t1 && c < v1);
let in_t2 = (on_rising_edge_t2 && c == v2) | (!on_rising_edge_t2 && c < v2);
let s = op(self, other, in_t1, in_t2, i, j);
if c == v1 {
i += 1;
}
if c == v2 {
j += 1;
}
(c, s)
};
if let Some(prev_ranges) = prev_s {
if let Some(cur_ranges) = s {
if cur_ranges.is_empty() {
t_ranges.push(last_t.unwrap()..c);
last_t = None;
prev_s = None;
} else if !prev_ranges.eq(&cur_ranges) {
t_ranges.push(last_t.unwrap()..c);
last_t = Some(c);
s_ranges.push(cur_ranges);
prev_s = s_ranges.last();
}
} else {
t_ranges.push(last_t.unwrap()..c);
last_t = None;
prev_s = None;
}
} else if let Some(cur_ranges) = s {
if !cur_ranges.is_empty() {
last_t = Some(c);
s_ranges.push(cur_ranges);
prev_s = s_ranges.last();
}
}
}
Ranges2D {
x: t_ranges,
y: s_ranges,
}
}
}
impl<'a, T: Idx, S: Idx> SNORanges2D<'a, T, S> for Ranges2D<T, S> {
#[cfg(not(target_arch = "wasm32"))]
fn make_consistent(mut self) -> Self {
if !self.is_empty() {
let mut sorted_time_bound_ranges = self.x.par_iter()
.enumerate()
.map(|(idx, t)| {
let start_b = BoundRange::new(t.start, idx, true);
let end_b = BoundRange::new(t.end, idx, false);
vec![start_b, end_b]
})
.flatten()
.collect::<Vec<_>>();
(&mut sorted_time_bound_ranges).par_sort_unstable_by(|l, r| {
l.cmp(r)
});
let mut time_ranges = vec![];
let mut spatial_coverages = vec![];
let mut ranges_idx = HashSet::new();
ranges_idx.insert(0);
let mut prev_time_bound = sorted_time_bound_ranges
.first()
.unwrap()
.x;
for time_bound in sorted_time_bound_ranges.iter().skip(1) {
let cur_time_bound = time_bound.x;
if cur_time_bound > prev_time_bound && !ranges_idx.is_empty() {
let spatial_coverage = ranges_idx.par_iter()
.map(|coverage_idx| self.y[*coverage_idx].clone())
.reduce(
Ranges::<S>::default,
|s1, s2| {
s1.union(&s2)
}
);
time_ranges.push(prev_time_bound..cur_time_bound);
spatial_coverages.push(spatial_coverage);
}
if time_bound.start {
ranges_idx.insert(time_bound.y_idx);
} else {
ranges_idx.remove(&time_bound.y_idx);
}
prev_time_bound = cur_time_bound;
}
self.compress(time_ranges, spatial_coverages);
}
self
}
#[cfg(target_arch = "wasm32")]
fn make_consistent(mut self) -> Self {
if !self.is_empty() {
let mut sorted_time_bound_ranges = self.x.iter()
.enumerate()
.map(|(idx, t)| {
let start_b = BoundRange::new(t.start, idx, true);
let end_b = BoundRange::new(t.end, idx, false);
vec![start_b, end_b]
})
.flatten()
.collect::<Vec<_>>();
(&mut sorted_time_bound_ranges).sort_unstable_by(|l, r| {
l.cmp(r)
});
let mut time_ranges = vec![];
let mut spatial_coverages = vec![];
let mut ranges_idx = HashSet::new();
ranges_idx.insert(0);
let mut prev_time_bound = sorted_time_bound_ranges
.first()
.unwrap()
.x;
for time_bound in sorted_time_bound_ranges.iter().skip(1) {
let cur_time_bound = time_bound.x;
if cur_time_bound > prev_time_bound && !ranges_idx.is_empty() {
let spatial_coverage = ranges_idx.iter()
.map(|coverage_idx| self.y[*coverage_idx].clone())
.reduce(|s1, s2| s1.union(&s2))
.unwrap_or(Ranges::<S>::default());
time_ranges.push(prev_time_bound..cur_time_bound);
spatial_coverages.push(spatial_coverage);
}
if time_bound.start {
ranges_idx.insert(time_bound.y_idx);
} else {
ranges_idx.remove(&time_bound.y_idx);
}
prev_time_bound = cur_time_bound;
}
self.compress(time_ranges, spatial_coverages);
}
self
}
fn is_empty(&self) -> bool {
self.x.is_empty()
}
fn contains(&self, time: T, range: &Range<S>) -> bool {
#[cfg(not(target_arch = "wasm32"))]
let in_first_dim = self.x
.par_iter()
.enumerate()
.filter_map(|(idx, r)| {
let in_time_range = time >= r.start && time <= r.end;
if in_time_range {
Some(idx)
} else {
None
}
})
.collect::<Vec<_>>();
#[cfg(target_arch = "wasm32")]
let in_first_dim = self.x
.iter()
.enumerate()
.filter_map(|(idx, r)| {
let in_time_range = time >= r.start && time <= r.end;
if in_time_range {
Some(idx)
} else {
None
}
})
.collect::<Vec<_>>();
if in_first_dim.is_empty() {
false
} else if in_first_dim.len() == 1 {
let idx_first_dim = in_first_dim.first().unwrap();
let s_coverage = &self.y[*idx_first_dim];
s_coverage.contains_range(range)
} else {
unreachable!();
}
}
fn union(&self, other: &Self) -> Self {
self.merge(other, Self::op_union)
}
fn intersection(&self, other: &Self) -> Self {
self.merge(other, Self::op_intersection)
}
fn difference(&self, other: &Self) -> Self {
self.merge(other, Self::op_difference)
}
}
impl<T: Idx, S: Idx> PartialEq for Ranges2D<T, S> {
fn eq(&self, other: &Self) -> bool {
if self.x.len() != other.x.len() {
false
} else {
if self.x != other.x {
false
} else {
for (s1, s2) in self.y.iter().zip(other.y.iter()) {
if s1 != s2 {
return false;
}
}
true
}
}
}
}
#[cfg(test)]
mod tests {
use std::ops::Range;
use crate::ranges::{Ranges, Idx};
use crate::ranges::ranges2d::{Ranges2D, SNORanges2D};
fn creating_ranges<T: Idx, S: Idx>(
ranges_t: Vec<Range<T>>,
ranges_s: Vec<Vec<Range<S>>>,
) -> Ranges2D<T, S> {
let mut vec_ranges_s = Vec::<Ranges<S>>::with_capacity(ranges_t.len());
for range_s in ranges_s.into_iter() {
vec_ranges_s.push(Ranges::<S>::new_from(range_s));
}
Ranges2D::new(ranges_t, vec_ranges_s).make_consistent()
}
#[test]
fn merge_overlapping_ranges() {
let t = vec![0..15, 0..15, 15..30, 30..45, 15..30];
let s = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![16..21]),
Ranges::<u64>::new_unchecked(vec![16..21]),
Ranges::<u64>::new_unchecked(vec![16..21]),
];
let coverage = Ranges2D::<u64, u64>::new(t, s)
.make_consistent();
let t_expect = vec![0..15, 15..45];
let s_expect = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![16..21]),
];
let coverage_expect = Ranges2D::<u64, u64>::new(t_expect, s_expect);
assert_eq!(coverage, coverage_expect);
}
#[test]
fn remove_different_length_time_ranges() {
let t = vec![0..7, 0..30];
let s = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![16..21]),
];
let coverage = Ranges2D::<u64, u64>::new(t, s)
.make_consistent();
let t_expect = vec![0..7, 7..30];
let s_expect = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..21]),
Ranges::<u64>::new_unchecked(vec![16..21])
];
let coverage_expect = Ranges2D::<u64, u64>::new(t_expect, s_expect);
assert_eq!(coverage, coverage_expect);
}
#[test]
fn remove_different_length_time_ranges2() {
let t = vec![0..30, 2..10];
let s = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![16..21]),
];
let coverage = Ranges2D::<u64, u64>::new(t, s)
.make_consistent();
let t_expect = vec![0..2, 2..10, 10..30];
let s_expect = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![0..4, 5..21]),
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18])
];
let coverage_expect = Ranges2D::<u64, u64>::new(t_expect, s_expect);
assert_eq!(coverage, coverage_expect);
}
#[test]
fn remove_different_length_time_ranges3() {
let t = vec![0..5, 2..10];
let s = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![16..21]),
];
let coverage = Ranges2D::<u64, u64>::new(t, s)
.make_consistent();
let t_expect = vec![0..2, 2..5, 5..10];
let s_expect = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![0..4, 5..21]),
Ranges::<u64>::new_unchecked(vec![16..21])
];
let coverage_expect = Ranges2D::<u64, u64>::new(t_expect, s_expect);
assert_eq!(coverage, coverage_expect);
}
#[test]
fn remove_different_length_time_ranges4() {
let t = vec![0..30, 10..30];
let s = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![16..21]),
];
let coverage = Ranges2D::<u64, u64>::new(t, s)
.make_consistent();
let t_expect = vec![0..10, 10..30];
let s_expect = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![0..4, 5..21]),
];
let coverage_expect = Ranges2D::<u64, u64>::new(t_expect, s_expect);
assert_eq!(coverage, coverage_expect);
}
#[test]
fn remove_different_length_time_ranges5() {
let t = vec![0..5, 5..20];
let s = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![16..21]),
];
let coverage = Ranges2D::<u64, u64>::new(t, s)
.make_consistent();
let t_expect = vec![0..5, 5..20];
let s_expect = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![16..21])
];
let coverage_expect = Ranges2D::<u64, u64>::new(t_expect, s_expect);
assert_eq!(coverage, coverage_expect);
}
#[test]
fn merge_overlapping_ranges_2() {
let t = vec![0..15, 0..15, 15..30, 30..45, 15..30];
let s = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![0..4]),
Ranges::<u64>::new_unchecked(vec![16..21]),
Ranges::<u64>::new_unchecked(vec![16..21, 25..26]),
];
let coverage = Ranges2D::<u64, u64>::new(t, s)
.make_consistent();
let t_expect = vec![0..15, 15..30, 30..45];
let s_expect = vec![
Ranges::<u64>::new_unchecked(vec![0..4, 5..16, 17..18]),
Ranges::<u64>::new_unchecked(vec![0..4, 16..21, 25..26]),
Ranges::<u64>::new_unchecked(vec![16..21])
];
let coverage_expect = Ranges2D::<u64, u64>::new(t_expect, s_expect);
assert_eq!(coverage, coverage_expect);
}
#[test]
fn union_ranges_1_3() {
let a = creating_ranges::<u64, u64>(vec![0..10], vec![vec![16..21]]);
let b = creating_ranges::<u64, u64>(vec![10..20], vec![vec![16..21]]);
let c = a.union(&b);
let res = creating_ranges::<u64, u64>(vec![0..20], vec![vec![16..21]]);
assert_eq!(res, c);
}
#[test]
fn union_ranges_1_3_bis() {
let a = creating_ranges::<u64, u64>(vec![0..10], vec![vec![16..21]]);
let b = creating_ranges::<u64, u64>(vec![10..20], vec![vec![16..22]]);
let c = a.union(&b);
let res =
creating_ranges::<u64, u64>(vec![0..10, 10..20], vec![vec![16..21], vec![16..22]]);
assert_eq!(res, c);
}
#[test]
fn union_ranges_covering() {
let a = creating_ranges::<u64, u64>(vec![0..10], vec![vec![16..21]]);
let b = creating_ranges::<u64, u64>(vec![9..20], vec![vec![0..17]]);
let c = a.union(&b);
let res = creating_ranges::<u64, u64>(
vec![0..9, 9..10, 10..20],
vec![vec![16..21], vec![0..21], vec![0..17]],
);
assert_eq!(res, c);
}
#[test]
fn empty_range_union() {
let a = creating_ranges::<u64, u64>(vec![0..1], vec![vec![42..43]]);
let b = creating_ranges::<u64, u64>(vec![9..20], vec![vec![0..17]]);
let c = a.union(&b);
let res = creating_ranges::<u64, u64>(vec![0..1, 9..20], vec![vec![42..43], vec![0..17]]);
assert_eq!(res, c);
}
#[test]
fn empty_range_union_bis() {
let b = creating_ranges::<u64, u64>(vec![0..9], vec![vec![0..20]]);
let a = creating_ranges::<u64, u64>(vec![9..20], vec![vec![0..17]]);
let c = a.union(&b);
let res = creating_ranges::<u64, u64>(vec![0..9, 9..20], vec![vec![0..20], vec![0..17]]);
assert_eq!(res, c);
}
#[test]
fn complex_union() {
let a = creating_ranges::<u64, u64>(
vec![0..2, 3..5, 8..9, 13..14],
vec![vec![2..3], vec![2..3], vec![5..6], vec![7..8]],
);
let b = creating_ranges::<u64, u64>(
vec![1..4, 6..7, 9..10, 11..12],
vec![vec![0..3], vec![5..6], vec![5..6], vec![10..13]],
);
let result = a.union(&b);
let expected = creating_ranges::<u64, u64>(
vec![0..1, 1..4, 4..5, 6..7, 8..10, 11..12, 13..14],
vec![
vec![2..3],
vec![0..3],
vec![2..3],
vec![5..6],
vec![5..6],
vec![10..13],
vec![7..8],
],
);
assert_eq!(expected, result);
}
#[test]
fn test_intersection() {
let empty = creating_ranges::<u64, u64>(vec![], vec![]);
let a = creating_ranges::<u64, u64>(vec![1..4, 6..7], vec![vec![0..3], vec![5..10]]);
let b = creating_ranges::<u64, u64>(vec![2..3, 6..7], vec![vec![0..5], vec![7..11]]);
let a_inter_b = a.intersection(&b);
let expect_a_inter_b =
creating_ranges::<u64, u64>(vec![2..3, 6..7], vec![vec![0..3], vec![7..10]]);
assert_eq!(expect_a_inter_b, a_inter_b);
let b_inter_empty = b.intersection(&empty);
let expect_b_inter_empty = creating_ranges::<u64, u64>(vec![], vec![]);
assert_eq!(b_inter_empty, expect_b_inter_empty);
let empty_inter_a = empty.intersection(&a);
let expect_empty_inter_a = creating_ranges::<u64, u64>(vec![], vec![]);
assert_eq!(empty_inter_a, expect_empty_inter_a);
let empty_inter_empty = empty.intersection(&empty);
let expect_empty_inter_empty = creating_ranges::<u64, u64>(vec![], vec![]);
assert_eq!(empty_inter_empty, expect_empty_inter_empty);
}
#[test]
fn test_difference() {
let empty = creating_ranges::<u64, u64>(vec![], vec![]);
let a = creating_ranges::<u64, u64>(vec![1..4, 6..7], vec![vec![0..3], vec![5..10]]);
let b = creating_ranges::<u64, u64>(vec![2..3, 6..7], vec![vec![0..5], vec![7..11]]);
let c = creating_ranges::<u64, u64>(vec![0..3, 3..7], vec![vec![0..7], vec![0..12]]);
let a_diff_b = a.difference(&b);
let expect_a_diff_b = creating_ranges::<u64, u64>(
vec![1..2, 3..4, 6..7],
vec![vec![0..3], vec![0..3], vec![5..7]],
);
assert_eq!(expect_a_diff_b, a_diff_b);
let b_diff_empty = b.difference(&empty);
assert_eq!(b_diff_empty, b);
let empty_diff_a = empty.difference(&a);
let expect_empty_diff_a = creating_ranges::<u64, u64>(vec![], vec![]);
assert_eq!(empty_diff_a, expect_empty_diff_a);
let empty_diff_empty = empty.difference(&empty);
let expect_empty_diff_empty = creating_ranges::<u64, u64>(vec![], vec![]);
assert_eq!(empty_diff_empty, expect_empty_diff_empty);
let b_diff_c = b.difference(&c);
let expect_b_diff_c = creating_ranges::<u64, u64>(vec![], vec![]);
assert_eq!(b_diff_c, expect_b_diff_c);
}
}