use std::borrow::Cow;
use polars_core::prelude::{DataFrame, Series};
use crate::range_frame::{take_rows_owned, RangeView};
use crate::{
ClipRangesOptions, ClusterOptions, ComplementRangesOptions, CountOverlapsOptions,
ExtendRangesOptions, GroupCumsumOptions, IntersectOverlapsOptions, JoinOverlapsOptions,
MaxDisjointOptions, MergeOptions, NearestOptions, OuterRangesOptions, OverlapOptions,
OverlapPairs, Result, SetIntersectOverlapsOptions, SetUnionOverlapsOptions, SortRangesOptions,
SplitOverlapsOptions, SubtractOptions, TileRangesOptions,
};
pub(crate) trait DataFrameRanges {
fn range_overlap_pairs(
&self,
other: &DataFrame,
options: OverlapOptions,
) -> Result<OverlapPairs>;
fn range_overlap(&self, other: &DataFrame, options: OverlapOptions) -> Result<DataFrame>;
fn merge_overlaps(&self, options: MergeOptions) -> Result<DataFrame>;
fn cluster_overlaps(&self, options: ClusterOptions) -> Result<DataFrame>;
fn count_overlaps(&self, other: &DataFrame, options: CountOverlapsOptions) -> Result<Series>;
fn join_overlaps(&self, other: &DataFrame, options: JoinOverlapsOptions) -> Result<DataFrame>;
fn intersect_overlaps(
&self,
other: &DataFrame,
options: IntersectOverlapsOptions,
) -> Result<DataFrame>;
fn set_intersect_overlaps(
&self,
other: &DataFrame,
options: SetIntersectOverlapsOptions,
) -> Result<DataFrame>;
fn set_union_overlaps(
&self,
other: &DataFrame,
options: SetUnionOverlapsOptions,
) -> Result<DataFrame>;
fn sort_ranges(&self, options: SortRangesOptions) -> Result<DataFrame>;
fn extend_ranges(&self, options: ExtendRangesOptions) -> Result<DataFrame>;
fn tile_ranges(&self, options: TileRangesOptions) -> Result<DataFrame>;
fn clip_ranges(&self, options: ClipRangesOptions) -> Result<DataFrame>;
fn group_cumsum(&self, options: GroupCumsumOptions) -> Result<DataFrame>;
fn max_disjoint_overlaps(&self, options: MaxDisjointOptions) -> Result<DataFrame>;
fn split_overlaps(&self, options: SplitOverlapsOptions) -> Result<DataFrame>;
fn outer_ranges(&self, options: OuterRangesOptions) -> Result<DataFrame>;
fn complement_ranges(&self, options: ComplementRangesOptions) -> Result<DataFrame>;
fn nearest_ranges(&self, other: &DataFrame, options: NearestOptions) -> Result<DataFrame>;
fn subtract_overlaps(&self, other: &DataFrame, options: SubtractOptions) -> Result<DataFrame>;
}
impl DataFrameRanges for DataFrame {
fn range_overlap_pairs(
&self,
other: &DataFrame,
options: OverlapOptions,
) -> Result<OverlapPairs> {
overlap_pairs_fast(self, other, &options)
}
fn range_overlap(&self, other: &DataFrame, options: OverlapOptions) -> Result<DataFrame> {
overlap_fast(self, other, &options)
}
fn merge_overlaps(&self, options: MergeOptions) -> Result<DataFrame> {
RangeView::new(self)?.merge_overlaps(&options)
}
fn cluster_overlaps(&self, options: ClusterOptions) -> Result<DataFrame> {
RangeView::new(self)?.cluster_overlaps(&options)
}
fn count_overlaps(&self, other: &DataFrame, options: CountOverlapsOptions) -> Result<Series> {
let left = RangeView::new(self)?;
let right = RangeView::new(other)?;
left.count_overlaps(&right, &options)
}
fn join_overlaps(&self, other: &DataFrame, options: JoinOverlapsOptions) -> Result<DataFrame> {
let left = RangeView::new(self)?;
let right = RangeView::new(other)?;
left.join_overlaps(&right, &options)
}
fn intersect_overlaps(
&self,
other: &DataFrame,
options: IntersectOverlapsOptions,
) -> Result<DataFrame> {
let left = RangeView::new(self)?;
let right = RangeView::new(other)?;
left.intersect_overlaps(&right, &options)
}
fn set_intersect_overlaps(
&self,
other: &DataFrame,
options: SetIntersectOverlapsOptions,
) -> Result<DataFrame> {
let left = RangeView::new(self)?;
let right = RangeView::new(other)?;
left.set_intersect_overlaps(&right, &options)
}
fn set_union_overlaps(
&self,
other: &DataFrame,
options: SetUnionOverlapsOptions,
) -> Result<DataFrame> {
let left = RangeView::new(self)?;
let right = RangeView::new(other)?;
left.set_union_overlaps(&right, &options)
}
fn sort_ranges(&self, options: SortRangesOptions) -> Result<DataFrame> {
RangeView::new(self)?.sort_ranges(&options)
}
fn extend_ranges(&self, options: ExtendRangesOptions) -> Result<DataFrame> {
RangeView::new(self)?.extend_ranges(&options)
}
fn tile_ranges(&self, options: TileRangesOptions) -> Result<DataFrame> {
RangeView::new(self)?.tile_ranges(&options)
}
fn clip_ranges(&self, options: ClipRangesOptions) -> Result<DataFrame> {
RangeView::new(self)?.clip_ranges(&options)
}
fn group_cumsum(&self, options: GroupCumsumOptions) -> Result<DataFrame> {
RangeView::new(self)?.group_cumsum(&options)
}
fn max_disjoint_overlaps(&self, options: MaxDisjointOptions) -> Result<DataFrame> {
RangeView::new(self)?.max_disjoint_overlaps(&options)
}
fn split_overlaps(&self, options: SplitOverlapsOptions) -> Result<DataFrame> {
RangeView::new(self)?.split_overlaps(&options)
}
fn outer_ranges(&self, options: OuterRangesOptions) -> Result<DataFrame> {
RangeView::new(self)?.outer_ranges(&options)
}
fn complement_ranges(&self, options: ComplementRangesOptions) -> Result<DataFrame> {
RangeView::new(self)?.complement_ranges(&options)
}
fn nearest_ranges(&self, other: &DataFrame, options: NearestOptions) -> Result<DataFrame> {
nearest_fast(self, other, &options)
}
fn subtract_overlaps(&self, other: &DataFrame, options: SubtractOptions) -> Result<DataFrame> {
let left = RangeView::new(self)?;
let right = RangeView::new(other)?;
left.subtract_overlaps(&right, &options)
}
}
pub(crate) fn overlap_pairs_fast(
left: &DataFrame,
right: &DataFrame,
options: &OverlapOptions,
) -> Result<OverlapPairs> {
let left_df = rechunk_for_overlap(left);
let right_df = rechunk_for_overlap(right);
let left_view = RangeView::with_columns(
left_df.as_ref(),
options.left_start_col.as_str(),
options.left_end_col.as_str(),
)?;
let right_view = RangeView::with_columns(
right_df.as_ref(),
options.right_start_col.as_str(),
options.right_end_col.as_str(),
)?;
left_view.overlap_pairs_by_match(&right_view, &options.match_by, &options.match_by, options)
}
pub(crate) fn overlap_fast(
left: &DataFrame,
right: &DataFrame,
options: &OverlapOptions,
) -> Result<DataFrame> {
let left_df = rechunk_for_overlap(left);
let right_df = rechunk_for_overlap(right);
let left_view = RangeView::with_columns(
left_df.as_ref(),
options.left_start_col.as_str(),
options.left_end_col.as_str(),
)?;
let right_view = RangeView::with_columns(
right_df.as_ref(),
options.right_start_col.as_str(),
options.right_end_col.as_str(),
)?;
let indices = left_view.overlap_indices_by_match(
&right_view,
&options.match_by,
&options.match_by,
options,
)?;
take_rows_owned(left_df.as_ref(), indices)
}
pub(crate) fn nearest_fast(
left: &DataFrame,
right: &DataFrame,
options: &NearestOptions,
) -> Result<DataFrame> {
let left_df = rechunk_for_overlap(left);
let right_df = rechunk_for_overlap(right);
let left_view = RangeView::with_columns(
left_df.as_ref(),
options.left_start_col.as_str(),
options.left_end_col.as_str(),
)?;
let right_view = RangeView::with_columns(
right_df.as_ref(),
options.right_start_col.as_str(),
options.right_end_col.as_str(),
)?;
left_view.nearest_ranges_by_match(&right_view, &options.match_by, &options.match_by, options)
}
pub(crate) fn overlap_indices_fast(
left: &DataFrame,
right: &DataFrame,
options: &OverlapOptions,
) -> Result<Vec<u32>> {
let left_df = rechunk_for_overlap(left);
let right_df = rechunk_for_overlap(right);
let left_view = RangeView::with_columns(
left_df.as_ref(),
options.left_start_col.as_str(),
options.left_end_col.as_str(),
)?;
let right_view = RangeView::with_columns(
right_df.as_ref(),
options.right_start_col.as_str(),
options.right_end_col.as_str(),
)?;
left_view.overlap_indices_by_match(
&right_view,
&options.match_by,
&options.match_by,
options,
)
}
fn rechunk_for_overlap(df: &DataFrame) -> Cow<'_, DataFrame> {
if df.max_n_chunks() <= 1 {
return Cow::Borrowed(df);
}
let mut owned = df.clone();
owned.rechunk_mut_par();
Cow::Owned(owned)
}