use std::cmp::Ordering;
use std::collections::{BinaryHeap, HashMap};
use std::hash::Hash;
use rayon::prelude::*;
use crate::batch::RleBatch;
use crate::error::{Error, Result};
use crate::identical::Identical;
use crate::num::Num;
use crate::rle::Rle;
use crate::slice::validate_intervals;
struct Sweep<V> {
length: i64,
ends: Vec<i64>,
sums: Vec<V>,
counts: Vec<i64>,
}
fn sweep<V: Num>(
starts: &[i64],
ends: &[i64],
idx: &[usize],
weight: impl Fn(usize) -> V,
) -> Sweep<V> {
let mut by_start: Vec<usize> = idx
.iter()
.copied()
.filter(|&i| starts[i] < ends[i])
.collect();
let mut by_end = by_start.clone();
by_start.sort_unstable_by_key(|&i| starts[i]);
by_end.sort_unstable_by_key(|&i| ends[i]);
let mut out = Sweep {
length: idx.iter().map(|&i| ends[i]).max().unwrap_or(0),
ends: Vec::with_capacity(2 * by_start.len()),
sums: Vec::with_capacity(2 * by_start.len()),
counts: Vec::with_capacity(2 * by_start.len()),
};
let (mut s, mut e) = (0, 0);
let mut pos = 0;
let mut sum = V::default();
let mut count = 0i64;
while e < by_end.len() {
let next_start = by_start.get(s).map_or(i64::MAX, |&i| starts[i]);
let p = next_start.min(ends[by_end[e]]);
if p > pos {
out.ends.push(p);
out.sums.push(sum);
out.counts.push(count);
pos = p;
}
while s < by_start.len() && starts[by_start[s]] == p {
sum = sum + weight(by_start[s]);
count += 1;
s += 1;
}
while e < by_end.len() && ends[by_end[e]] == p {
sum = sum - weight(by_end[e]);
count -= 1;
e += 1;
}
if count == 0 {
sum = V::default();
}
}
out
}
fn finish<S: Default, V: Identical>(sweep: Sweep<S>, mut value: impl FnMut(S, i64) -> V) -> Rle<V> {
let mut out = Rle::new();
for ((end, sum), count) in sweep.ends.into_iter().zip(sweep.sums).zip(sweep.counts) {
out.push_merged(end, value(sum, count));
}
out.extend_to(sweep.length, value(S::default(), 0))
.expect("the sweep never goes past the largest end");
out
}
fn pad<V: Identical>(mut rle: Rle<V>, length: Option<i64>, uncovered: V) -> Result<Rle<V>> {
if let Some(length) = length {
rle.extend_to(length, uncovered)?;
}
Ok(rle)
}
fn check_values<V>(starts: &[i64], values: &[V]) -> Result<()> {
if values.len() != starts.len() {
return Err(Error::LengthMismatch {
what: "values and starts",
left: values.len(),
right: starts.len(),
});
}
Ok(())
}
fn all(n: usize) -> Vec<usize> {
(0..n).collect()
}
pub fn coverage_sum<V: Num + Identical>(
starts: &[i64],
ends: &[i64],
values: &[V],
length: Option<i64>,
) -> Result<Rle<V>> {
validate_intervals(starts, ends)?;
check_values(starts, values)?;
let rle = finish(
sweep(starts, ends, &all(starts.len()), |i| values[i]),
|sum, _| sum,
);
pad(rle, length, V::default())
}
pub fn coverage_sum_opt<V: Num + Identical>(
starts: &[i64],
ends: &[i64],
values: &[V],
length: Option<i64>,
) -> Result<Rle<Option<V>>> {
validate_intervals(starts, ends)?;
check_values(starts, values)?;
let sweep = sweep(starts, ends, &all(starts.len()), |i| values[i]);
let rle = finish(sweep, |sum, count| (count > 0).then_some(sum));
pad(rle, length, None)
}
pub fn coverage_count(starts: &[i64], ends: &[i64], length: Option<i64>) -> Result<Rle<i64>> {
validate_intervals(starts, ends)?;
let rle = finish(
sweep(starts, ends, &all(starts.len()), |_| 1i64),
|_, count| count,
);
pad(rle, length, 0)
}
fn group_by_key<K: Hash + Eq + Clone>(keys: &[K]) -> (Vec<K>, Vec<Vec<usize>>) {
let mut positions: HashMap<&K, usize> = HashMap::new();
let mut unique = Vec::new();
let mut groups: Vec<Vec<usize>> = Vec::new();
for (i, key) in keys.iter().enumerate() {
let g = *positions.entry(key).or_insert_with(|| {
unique.push(key.clone());
groups.push(Vec::new());
groups.len() - 1
});
groups[g].push(i);
}
(unique, groups)
}
fn check_keys<K>(keys: &[K], starts: &[i64]) -> Result<()> {
if keys.len() != starts.len() {
return Err(Error::LengthMismatch {
what: "keys and starts",
left: keys.len(),
right: starts.len(),
});
}
Ok(())
}
pub fn coverage_sum_by_key<K, V>(
keys: &[K],
starts: &[i64],
ends: &[i64],
values: &[V],
) -> Result<RleBatch<K, V>>
where
K: Hash + Eq + Clone + Send + Sync,
V: Num + Identical,
{
validate_intervals(starts, ends)?;
check_keys(keys, starts)?;
check_values(starts, values)?;
let (unique, groups) = group_by_key(keys);
let rles = groups
.par_iter()
.map(|idx| finish(sweep(starts, ends, idx, |i| values[i]), |sum, _| sum))
.collect();
Ok(RleBatch::from_rles_unchecked(unique, rles))
}
pub fn coverage_count_by_key<K>(
keys: &[K],
starts: &[i64],
ends: &[i64],
) -> Result<RleBatch<K, i64>>
where
K: Hash + Eq + Clone + Send + Sync,
{
validate_intervals(starts, ends)?;
check_keys(keys, starts)?;
let (unique, groups) = group_by_key(keys);
let rles = groups
.par_iter()
.map(|idx| finish(sweep(starts, ends, idx, |_| 1i64), |_, count| count))
.collect();
Ok(RleBatch::from_rles_unchecked(unique, rles))
}
struct Ranked<'a, V> {
value: &'a V,
local: usize,
max: bool,
}
impl<V: PartialOrd> Ranked<'_, V> {
fn rank(&self, other: &Self) -> Ordering {
let comparable = |v: &V| v.partial_cmp(v).is_some();
let by_value = match (comparable(self.value), comparable(other.value)) {
(true, true) => {
let order = self
.value
.partial_cmp(other.value)
.unwrap_or(Ordering::Equal);
if self.max { order } else { order.reverse() }
}
(true, false) => Ordering::Greater,
(false, true) => Ordering::Less,
(false, false) => Ordering::Equal,
};
by_value.then(self.local.cmp(&other.local))
}
}
impl<V: PartialOrd> PartialEq for Ranked<'_, V> {
fn eq(&self, other: &Self) -> bool {
self.rank(other) == Ordering::Equal
}
}
impl<V: PartialOrd> Eq for Ranked<'_, V> {}
impl<V: PartialOrd> PartialOrd for Ranked<'_, V> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<V: PartialOrd> Ord for Ranked<'_, V> {
fn cmp(&self, other: &Self) -> Ordering {
self.rank(other)
}
}
fn sorted_locals(starts: &[i64], ends: &[i64], idx: &[usize]) -> (Vec<usize>, Vec<usize>) {
let mut by_start: Vec<usize> = (0..idx.len())
.filter(|&k| starts[idx[k]] < ends[idx[k]])
.collect();
let mut by_end = by_start.clone();
by_start.sort_unstable_by_key(|&k| starts[idx[k]]);
by_end.sort_unstable_by_key(|&k| ends[idx[k]]);
(by_start, by_end)
}
trait Visitor {
fn emit(&mut self, end: i64);
fn start(&mut self, k: usize);
fn stop(&mut self, k: usize);
}
fn sweep_events(starts: &[i64], ends: &[i64], idx: &[usize], visitor: &mut impl Visitor) {
let (by_start, by_end) = sorted_locals(starts, ends, idx);
let (mut s, mut e) = (0, 0);
let mut pos = 0;
while e < by_end.len() {
let next_start = by_start.get(s).map_or(i64::MAX, |&k| starts[idx[k]]);
let p = next_start.min(ends[idx[by_end[e]]]);
if p > pos {
visitor.emit(p);
pos = p;
}
while s < by_start.len() && starts[idx[by_start[s]]] == p {
visitor.start(by_start[s]);
s += 1;
}
while e < by_end.len() && ends[idx[by_end[e]]] == p {
visitor.stop(by_end[e]);
e += 1;
}
}
}
fn max_end(ends: &[i64], idx: &[usize]) -> i64 {
idx.iter().map(|&i| ends[i]).max().unwrap_or(0)
}
struct Extreme<'a, V> {
idx: &'a [usize],
values: &'a [V],
max: bool,
active: Vec<bool>,
heap: BinaryHeap<Ranked<'a, V>>,
out: Rle<Option<V>>,
}
impl<V: PartialOrd + Clone + Identical> Visitor for Extreme<'_, V> {
fn emit(&mut self, end: i64) {
while self.heap.peek().is_some_and(|top| !self.active[top.local]) {
self.heap.pop();
}
let value = self.heap.peek().map(|top| top.value.clone());
self.out.push_merged(end, value);
}
fn start(&mut self, k: usize) {
self.active[k] = true;
self.heap.push(Ranked {
value: &self.values[self.idx[k]],
local: k,
max: self.max,
});
}
fn stop(&mut self, k: usize) {
self.active[k] = false;
}
}
fn extreme<V>(
starts: &[i64],
ends: &[i64],
idx: &[usize],
values: &[V],
max: bool,
) -> Rle<Option<V>>
where
V: PartialOrd + Clone + Identical,
{
let mut visitor = Extreme {
idx,
values,
max,
active: vec![false; idx.len()],
heap: BinaryHeap::new(),
out: Rle::new(),
};
sweep_events(starts, ends, idx, &mut visitor);
let mut out = visitor.out;
out.extend_to(max_end(ends, idx), None)
.expect("the sweep never passes the largest end");
out
}
pub fn coverage_max<V>(
starts: &[i64],
ends: &[i64],
values: &[V],
length: Option<i64>,
) -> Result<Rle<Option<V>>>
where
V: PartialOrd + Clone + Identical,
{
validate_intervals(starts, ends)?;
check_values(starts, values)?;
pad(
extreme(starts, ends, &all(starts.len()), values, true),
length,
None,
)
}
pub fn coverage_min<V>(
starts: &[i64],
ends: &[i64],
values: &[V],
length: Option<i64>,
) -> Result<Rle<Option<V>>>
where
V: PartialOrd + Clone + Identical,
{
validate_intervals(starts, ends)?;
check_values(starts, values)?;
pad(
extreme(starts, ends, &all(starts.len()), values, false),
length,
None,
)
}
fn extreme_by_key<K, V>(
keys: &[K],
starts: &[i64],
ends: &[i64],
values: &[V],
max: bool,
) -> Result<RleBatch<K, Option<V>>>
where
K: Hash + Eq + Clone + Send + Sync,
V: PartialOrd + Clone + Identical + Send + Sync,
{
validate_intervals(starts, ends)?;
check_keys(keys, starts)?;
check_values(starts, values)?;
let (unique, groups) = group_by_key(keys);
let rles = groups
.par_iter()
.map(|idx| extreme(starts, ends, idx, values, max))
.collect();
Ok(RleBatch::from_rles_unchecked(unique, rles))
}
pub fn coverage_max_by_key<K, V>(
keys: &[K],
starts: &[i64],
ends: &[i64],
values: &[V],
) -> Result<RleBatch<K, Option<V>>>
where
K: Hash + Eq + Clone + Send + Sync,
V: PartialOrd + Clone + Identical + Send + Sync,
{
extreme_by_key(keys, starts, ends, values, true)
}
pub fn coverage_min_by_key<K, V>(
keys: &[K],
starts: &[i64],
ends: &[i64],
values: &[V],
) -> Result<RleBatch<K, Option<V>>>
where
K: Hash + Eq + Clone + Send + Sync,
V: PartialOrd + Clone + Identical + Send + Sync,
{
extreme_by_key(keys, starts, ends, values, false)
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OverlapPlan {
pub ends: Vec<i64>,
pub offsets: Vec<usize>,
pub interval_ids: Vec<usize>,
}
impl OverlapPlan {
pub fn num_segments(&self) -> usize {
self.ends.len()
}
pub fn ids(&self, s: usize) -> &[usize] {
&self.interval_ids[self.offsets[s]..self.offsets[s + 1]]
}
}
struct Overlap<'a> {
idx: &'a [usize],
active: Vec<usize>,
slot: Vec<usize>,
out: OverlapPlan,
}
impl Visitor for Overlap<'_> {
fn emit(&mut self, end: i64) {
let first = self.out.interval_ids.len();
self.out
.interval_ids
.extend(self.active.iter().map(|&k| self.idx[k]));
self.out.interval_ids[first..].sort_unstable();
self.out.ends.push(end);
self.out.offsets.push(self.out.interval_ids.len());
}
fn start(&mut self, k: usize) {
self.slot[k] = self.active.len();
self.active.push(k);
}
fn stop(&mut self, k: usize) {
let i = self.slot[k];
self.active.swap_remove(i);
if let Some(&moved) = self.active.get(i) {
self.slot[moved] = i;
}
}
}
fn overlap(starts: &[i64], ends: &[i64], idx: &[usize]) -> OverlapPlan {
let mut visitor = Overlap {
idx,
active: Vec::new(),
slot: vec![usize::MAX; idx.len()],
out: OverlapPlan {
ends: Vec::new(),
offsets: vec![0],
interval_ids: Vec::new(),
},
};
sweep_events(starts, ends, idx, &mut visitor);
let mut out = visitor.out;
let length = max_end(ends, idx);
if length > out.ends.last().copied().unwrap_or(0) {
out.ends.push(length);
out.offsets.push(out.interval_ids.len());
}
out
}
pub fn overlap_plan(starts: &[i64], ends: &[i64], length: Option<i64>) -> Result<OverlapPlan> {
validate_intervals(starts, ends)?;
let mut plan = overlap(starts, ends, &all(starts.len()));
if let Some(length) = length {
let current = plan.ends.last().copied().unwrap_or(0);
if length < current {
return Err(Error::LengthTooShort {
requested: length,
required: current,
});
}
if length > current {
plan.ends.push(length);
plan.offsets.push(plan.interval_ids.len());
}
}
Ok(plan)
}
pub fn overlap_plan_by_key<K>(
keys: &[K],
starts: &[i64],
ends: &[i64],
) -> Result<(Vec<K>, Vec<OverlapPlan>)>
where
K: Hash + Eq + Clone + Send + Sync,
{
validate_intervals(starts, ends)?;
check_keys(keys, starts)?;
let (unique, groups) = group_by_key(keys);
let plans = groups
.par_iter()
.map(|idx| overlap(starts, ends, idx))
.collect();
Ok((unique, plans))
}