use crate::intervals::absolute::{
AbsBoundPair,
AbsInterval,
BoundedAbsInterval,
EmptiableAbsBoundPair,
EmptiableAbsInterval,
HalfBoundedAbsInterval,
HasAbsBoundPair,
HasEmptiableAbsBoundPair,
};
use crate::intervals::meta::Interval;
use crate::intervals::ops::complement::Complementable;
use crate::intervals::ops::overlap::CanPositionOverlap;
use crate::intervals::ops::remove_overlap::{
OverlapRemovable,
OverlapRemovalNoOverlapFoundError,
OverlapRemovalResult,
};
use crate::intervals::relative::{
BoundedRelInterval,
EmptiableRelBoundPair,
EmptiableRelInterval,
HalfBoundedRelInterval,
HasEmptiableRelBoundPair,
HasRelBoundPair,
RelBoundPair,
RelInterval,
};
use crate::intervals::special::{EmptyInterval, UnboundedInterval};
use crate::ops::{ComplementResult, SymmetricDifferenceResult};
pub trait SymmetricallyDifferentiable<Rhs = Self> {
type Output;
#[must_use]
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output>;
#[must_use]
fn sym_diff_with<F>(&self, rhs: &Rhs, mut f: F) -> SymmetricDifferenceResult<Self::Output>
where
F: FnMut(&Self, &Rhs) -> SymmetricDifferenceResult<Self::Output>,
{
(f)(self, rhs)
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for AbsBoundPair
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = EmptiableAbsBoundPair;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_abs_bound_pair_with_emptiable_abs_bound_pair(self, &rhs.emptiable_abs_bound_pair())
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for EmptiableAbsBoundPair
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = Self;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_emptiable_abs_bound_pair(self, &rhs.emptiable_abs_bound_pair())
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for AbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = EmptiableAbsInterval;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_abs_bound_pair_with_emptiable_abs_bound_pair(&self.abs_bound_pair(), &rhs.emptiable_abs_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for EmptiableAbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = Self;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_emptiable_abs_bound_pair(&self.emptiable_abs_bound_pair(), &rhs.emptiable_abs_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for BoundedAbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = EmptiableAbsInterval;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_abs_bound_pair_with_emptiable_abs_bound_pair(&self.abs_bound_pair(), &rhs.emptiable_abs_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for HalfBoundedAbsInterval
where
Rhs: HasEmptiableAbsBoundPair,
{
type Output = EmptiableAbsInterval;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_abs_bound_pair_with_emptiable_abs_bound_pair(&self.abs_bound_pair(), &rhs.emptiable_abs_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for RelBoundPair
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = EmptiableRelBoundPair;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_rel_bound_pair_with_emptiable_rel_bound_pair(self, &rhs.emptiable_rel_bound_pair())
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for EmptiableRelBoundPair
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = Self;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_emptiable_rel_bound_pair(self, &rhs.emptiable_rel_bound_pair())
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for RelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = EmptiableRelInterval;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_rel_bound_pair_with_emptiable_rel_bound_pair(&self.rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for EmptiableRelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = Self;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_emptiable_rel_bound_pair(&self.emptiable_rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for BoundedRelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = EmptiableRelInterval;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_rel_bound_pair_with_emptiable_rel_bound_pair(&self.rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for HalfBoundedRelInterval
where
Rhs: HasEmptiableRelBoundPair,
{
type Output = EmptiableRelInterval;
fn sym_diff(&self, rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_rel_bound_pair_with_emptiable_rel_bound_pair(&self.rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl SymmetricallyDifferentiable<AbsBoundPair> for UnboundedInterval {
type Output = EmptiableAbsInterval;
fn sym_diff(&self, rhs: &AbsBoundPair) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_abs_bound_pair(&self.abs_bound_pair(), rhs).map_symmetric_difference(Self::Output::from)
}
}
impl SymmetricallyDifferentiable<EmptiableAbsBoundPair> for UnboundedInterval {
type Output = EmptiableAbsInterval;
fn sym_diff(&self, rhs: &EmptiableAbsBoundPair) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_abs_bound_pair_with_emptiable_abs_bound_pair(&self.abs_bound_pair(), rhs)
.map_symmetric_difference(Self::Output::from)
}
}
impl SymmetricallyDifferentiable<AbsInterval> for UnboundedInterval {
type Output = EmptiableAbsInterval;
fn sym_diff(&self, rhs: &AbsInterval) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_abs_bound_pair_with_emptiable_abs_bound_pair(&self.abs_bound_pair(), &rhs.emptiable_abs_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl SymmetricallyDifferentiable<BoundedAbsInterval> for UnboundedInterval {
type Output = HalfBoundedAbsInterval;
fn sym_diff(&self, rhs: &BoundedAbsInterval) -> SymmetricDifferenceResult<Self::Output> {
match rhs.complement() {
ComplementResult::Single(single) => SymmetricDifferenceResult::Single(single),
ComplementResult::Split(split_before, split_after) => {
SymmetricDifferenceResult::Split(split_before, split_after)
},
}
}
}
impl SymmetricallyDifferentiable<HalfBoundedAbsInterval> for UnboundedInterval {
type Output = HalfBoundedAbsInterval;
fn sym_diff(&self, rhs: &HalfBoundedAbsInterval) -> SymmetricDifferenceResult<Self::Output> {
match rhs.complement() {
ComplementResult::Single(single) => SymmetricDifferenceResult::Single(single),
ComplementResult::Split(split_before, split_after) => {
SymmetricDifferenceResult::Split(split_before, split_after)
},
}
}
}
impl SymmetricallyDifferentiable<RelBoundPair> for UnboundedInterval {
type Output = EmptiableRelInterval;
fn sym_diff(&self, rhs: &RelBoundPair) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_rel_bound_pair(&self.rel_bound_pair(), rhs).map_symmetric_difference(Self::Output::from)
}
}
impl SymmetricallyDifferentiable<EmptiableRelBoundPair> for UnboundedInterval {
type Output = EmptiableRelInterval;
fn sym_diff(&self, rhs: &EmptiableRelBoundPair) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_rel_bound_pair_with_emptiable_rel_bound_pair(&self.rel_bound_pair(), rhs)
.map_symmetric_difference(Self::Output::from)
}
}
impl SymmetricallyDifferentiable<RelInterval> for UnboundedInterval {
type Output = EmptiableRelInterval;
fn sym_diff(&self, rhs: &RelInterval) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_rel_bound_pair_with_emptiable_rel_bound_pair(&self.rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl SymmetricallyDifferentiable<EmptiableRelInterval> for UnboundedInterval {
type Output = EmptiableRelInterval;
fn sym_diff(&self, rhs: &EmptiableRelInterval) -> SymmetricDifferenceResult<Self::Output> {
sym_diff_emptiable_rel_bound_pair(&self.emptiable_rel_bound_pair(), &rhs.emptiable_rel_bound_pair())
.map_symmetric_difference(Self::Output::from)
}
}
impl SymmetricallyDifferentiable<BoundedRelInterval> for UnboundedInterval {
type Output = HalfBoundedRelInterval;
fn sym_diff(&self, rhs: &BoundedRelInterval) -> SymmetricDifferenceResult<Self::Output> {
match rhs.complement() {
ComplementResult::Single(single) => SymmetricDifferenceResult::Single(single),
ComplementResult::Split(split_before, split_after) => {
SymmetricDifferenceResult::Split(split_before, split_after)
},
}
}
}
impl SymmetricallyDifferentiable<HalfBoundedRelInterval> for UnboundedInterval {
type Output = HalfBoundedRelInterval;
fn sym_diff(&self, rhs: &HalfBoundedRelInterval) -> SymmetricDifferenceResult<Self::Output> {
match rhs.complement() {
ComplementResult::Single(single) => SymmetricDifferenceResult::Single(single),
ComplementResult::Split(split_before, split_after) => {
SymmetricDifferenceResult::Split(split_before, split_after)
},
}
}
}
impl SymmetricallyDifferentiable<UnboundedInterval> for UnboundedInterval {
type Output = EmptyInterval;
fn sym_diff(&self, _rhs: &UnboundedInterval) -> SymmetricDifferenceResult<Self::Output> {
SymmetricDifferenceResult::Single(EmptyInterval)
}
}
impl SymmetricallyDifferentiable<EmptyInterval> for UnboundedInterval {
type Output = ();
fn sym_diff(&self, _rhs: &EmptyInterval) -> SymmetricDifferenceResult<Self::Output> {
SymmetricDifferenceResult::Separate
}
}
impl<Rhs> SymmetricallyDifferentiable<Rhs> for EmptyInterval
where
Rhs: Interval,
{
type Output = ();
fn sym_diff(&self, _rhs: &Rhs) -> SymmetricDifferenceResult<Self::Output> {
SymmetricDifferenceResult::Separate
}
}
#[must_use]
pub fn sym_diff_abs_bound_pair(a: &AbsBoundPair, b: &AbsBoundPair) -> SymmetricDifferenceResult<EmptiableAbsBoundPair> {
if !a.simple_overlaps(b) {
return SymmetricDifferenceResult::Separate;
}
let diff_a_with_b = match a.remove_overlap(b) {
Ok(a_removed_b) => a_removed_b,
Err(OverlapRemovalNoOverlapFoundError) => unreachable!("Overlap check already happened earlier"),
};
let diff_b_with_a = match b.remove_overlap(a) {
Ok(b_removed_a) => b_removed_a,
Err(OverlapRemovalNoOverlapFoundError) => unreachable!("Overlap check already happened earlier"),
};
match (diff_a_with_b, diff_b_with_a) {
(
OverlapRemovalResult::Single(EmptiableAbsBoundPair::Empty),
OverlapRemovalResult::Single(EmptiableAbsBoundPair::Empty),
) => SymmetricDifferenceResult::Single(EmptiableAbsBoundPair::Empty),
(OverlapRemovalResult::Single(single_diff), OverlapRemovalResult::Single(EmptiableAbsBoundPair::Empty))
| (OverlapRemovalResult::Single(EmptiableAbsBoundPair::Empty), OverlapRemovalResult::Single(single_diff)) => {
SymmetricDifferenceResult::Single(single_diff)
},
(OverlapRemovalResult::Single(first_single_diff), OverlapRemovalResult::Single(second_single_diff)) => {
SymmetricDifferenceResult::Split(first_single_diff, second_single_diff)
},
(OverlapRemovalResult::Split(split1, split2), OverlapRemovalResult::Single(EmptiableAbsBoundPair::Empty))
| (OverlapRemovalResult::Single(EmptiableAbsBoundPair::Empty), OverlapRemovalResult::Split(split1, split2)) => {
SymmetricDifferenceResult::Split(split1, split2)
},
(OverlapRemovalResult::Split(..), _) | (_, OverlapRemovalResult::Split(..)) => {
unreachable!(
"No possible interval configuration exist where A \\ B (A diff B) returns a `Split` result, but at \
the same time B \\ A (B diff A) returns anything other than an empty interval"
);
},
}
}
#[must_use]
pub fn sym_diff_abs_bound_pair_with_emptiable_abs_bound_pair(
a: &AbsBoundPair,
b: &EmptiableAbsBoundPair,
) -> SymmetricDifferenceResult<EmptiableAbsBoundPair> {
let EmptiableAbsBoundPair::Bound(b) = b else {
return SymmetricDifferenceResult::Separate;
};
sym_diff_abs_bound_pair(a, b)
}
#[must_use]
pub fn sym_diff_emptiable_abs_bound_pair(
a: &EmptiableAbsBoundPair,
b: &EmptiableAbsBoundPair,
) -> SymmetricDifferenceResult<EmptiableAbsBoundPair> {
let EmptiableAbsBoundPair::Bound(a) = a else {
return SymmetricDifferenceResult::Separate;
};
sym_diff_abs_bound_pair_with_emptiable_abs_bound_pair(a, b)
}
#[must_use]
pub fn sym_diff_rel_bound_pair(a: &RelBoundPair, b: &RelBoundPair) -> SymmetricDifferenceResult<EmptiableRelBoundPair> {
if !a.simple_overlaps(b) {
return SymmetricDifferenceResult::Separate;
}
let diff_a_with_b = match a.remove_overlap(b) {
Ok(a_removed_b) => a_removed_b,
Err(OverlapRemovalNoOverlapFoundError) => unreachable!("Overlap check already happened earlier"),
};
let diff_b_with_a = match b.remove_overlap(a) {
Ok(b_removed_a) => b_removed_a,
Err(OverlapRemovalNoOverlapFoundError) => unreachable!("Overlap check already happened earlier"),
};
match (diff_a_with_b, diff_b_with_a) {
(
OverlapRemovalResult::Single(EmptiableRelBoundPair::Empty),
OverlapRemovalResult::Single(EmptiableRelBoundPair::Empty),
) => SymmetricDifferenceResult::Single(EmptiableRelBoundPair::Empty),
(OverlapRemovalResult::Single(single_diff), OverlapRemovalResult::Single(EmptiableRelBoundPair::Empty))
| (OverlapRemovalResult::Single(EmptiableRelBoundPair::Empty), OverlapRemovalResult::Single(single_diff)) => {
SymmetricDifferenceResult::Single(single_diff)
},
(OverlapRemovalResult::Single(first_single_diff), OverlapRemovalResult::Single(second_single_diff)) => {
SymmetricDifferenceResult::Split(first_single_diff, second_single_diff)
},
(OverlapRemovalResult::Split(split1, split2), OverlapRemovalResult::Single(EmptiableRelBoundPair::Empty))
| (OverlapRemovalResult::Single(EmptiableRelBoundPair::Empty), OverlapRemovalResult::Split(split1, split2)) => {
SymmetricDifferenceResult::Split(split1, split2)
},
(OverlapRemovalResult::Split(..), _) | (_, OverlapRemovalResult::Split(..)) => {
unreachable!(
"No possible interval configuration exist where A \\ B (A diff B) returns a `Split` result, but at \
the same time B \\ A (B diff A) returns anything other than an empty interval"
);
},
}
}
#[must_use]
pub fn sym_diff_rel_bound_pair_with_emptiable_rel_bound_pair(
a: &RelBoundPair,
b: &EmptiableRelBoundPair,
) -> SymmetricDifferenceResult<EmptiableRelBoundPair> {
let EmptiableRelBoundPair::Bound(b) = b else {
return SymmetricDifferenceResult::Separate;
};
sym_diff_rel_bound_pair(a, b)
}
#[must_use]
pub fn sym_diff_emptiable_rel_bound_pair(
a: &EmptiableRelBoundPair,
b: &EmptiableRelBoundPair,
) -> SymmetricDifferenceResult<EmptiableRelBoundPair> {
let EmptiableRelBoundPair::Bound(a) = a else {
return SymmetricDifferenceResult::Separate;
};
sym_diff_rel_bound_pair_with_emptiable_rel_bound_pair(a, b)
}