radn-rs/src/flow/traversible.rs
2023-04-25 17:40:04 +00:00

195 lines
6.1 KiB
Rust

//! Traversible binary trees.
pub mod unbalanced;
use std::rc::Rc;
use crate::func::*;
/// Result returned by [`Comparator::pick_smaller`].
#[derive(Debug, PartialEq)]
pub enum Comparison {
L,
/// Compared values were equal.
E,
R,
}
fn and(left: bool, right: bool) -> bool {
left && right
}
/// Returns [`Comparison`] saying which value is smaller.
///
/// ```rust
/// # use radn_rs::flow::traversible::*;
/// assert_eq!(DefaultComparator.pick_smaller(&1, &3), Comparison::L);
/// assert_eq!(DefaultComparator.pick_smaller(&2, &2), Comparison::E);
/// assert_eq!(DefaultComparator.pick_smaller(&3, &1), Comparison::R);
/// ```
pub trait Comparator<A> {
fn pick_smaller(&self, kl: &A, kr: &A) -> Comparison;
}
/// Implementation of a [Comparator] relying on [`PartialOrd`].
pub struct DefaultComparator;
impl<A: PartialOrd> Comparator<A> for DefaultComparator {
fn pick_smaller(&self, kl: &A, kr: &A) -> Comparison {
if kl < kr {
Comparison::L
} else if kr < kl {
Comparison::R
} else {
Comparison::E
}
}
}
pub type Split<'a, T, A, D> = (
Rc<dyn TraversibleBinaryTree<'a, T, A, D>>,
Rc<dyn TraversibleBinaryTree<'a, T, A, D>>,
Rc<A>,
);
pub trait TraversibleBinaryNode<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>: 'a {
fn split(&self) -> Split<'a, T, A, D>;
fn to_tree(self: Rc<Self>) -> Rc<dyn TraversibleBinaryTree<'a, T, A, D>>;
}
pub trait TraversibleBinaryReference<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>: 'a {
fn resolve(&self) -> <T as WeakFunctor>::F<'a, Rc<dyn TraversibleBinaryNode<'a, T, A, D>>>;
/// This should be enough to compare reference for equality.
fn data(&self) -> D;
}
pub trait TraversibleBinaryTree<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>: 'a {
fn refer(&self) -> Option<Rc<dyn TraversibleBinaryReference<'a, T, A, D>>>;
}
pub fn n_contains<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>(
comparator: &'a dyn Comparator<A>,
n_set: Rc<dyn TraversibleBinaryNode<'a, T, A, D>>,
key: Rc<A>,
) -> T::F<'a, bool> {
let (t_setl, t_setr, k_set) = n_set.split();
match comparator.pick_smaller(key.as_ref(), k_set.as_ref()) {
Comparison::L => t_contains(comparator, t_setl, key),
Comparison::E => T::pure(true),
Comparison::R => t_contains(comparator, t_setr, key),
}
}
pub fn r_contains<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>(
comparator: &'a dyn Comparator<A>,
r_set: Rc<dyn TraversibleBinaryReference<'a, T, A, D>>,
key: Rc<A>,
) -> T::F<'a, bool> {
T::bind(r_set.resolve(), |n_set| n_contains(comparator, n_set, key))
}
pub fn t_contains<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>(
comparator: &'a dyn Comparator<A>,
t_set: Rc<dyn TraversibleBinaryTree<'a, T, A, D>>,
key: Rc<A>,
) -> T::F<'a, bool> {
match t_set.refer() {
Some(r_set) => r_contains(comparator, r_set, key),
None => T::pure(false),
}
}
pub fn n_subset_of_n<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>(
comparator: &'a dyn Comparator<A>,
n_subset: Rc<dyn TraversibleBinaryNode<'a, T, A, D>>,
n_superset: Rc<dyn TraversibleBinaryNode<'a, T, A, D>>,
k_l: Option<Rc<A>>,
k_r: Option<Rc<A>>,
) -> T::F<'a, bool> {
let (t_superl, t_superr, k_super) = n_superset.split();
if let Some(ref a_l) = k_l {
if let Comparison::R = comparator.pick_smaller(a_l.as_ref(), k_super.as_ref()) {
return t_subset_of_t(comparator, n_subset.to_tree(), t_superr, k_l, k_r);
}
}
if let Some(ref a_r) = k_r {
if let Comparison::L = comparator.pick_smaller(a_r.as_ref(), k_super.as_ref()) {
return t_subset_of_t(comparator, n_subset.to_tree(), t_superl, k_l, k_r);
}
}
let (t_subl, t_subr, k_sub) = n_subset.split();
match comparator.pick_smaller(k_sub.as_ref(), k_super.as_ref()) {
Comparison::L => T::la2(
and,
t_contains(comparator, t_superl.clone(), k_sub.clone()),
T::la2(
and,
t_subset_of_t(comparator, t_subl, t_superl, k_l, Some(k_sub.clone())),
t_subset_of_t(
comparator,
t_subr,
n_superset.to_tree(),
Some(k_sub.clone()),
k_r,
),
),
),
Comparison::E => T::la2(
and,
t_subset_of_t(comparator, t_subl, t_superl, k_l, Some(k_sub.clone())),
t_subset_of_t(comparator, t_subr, t_superr, Some(k_sub.clone()), k_r),
),
Comparison::R => T::la2(
and,
t_contains(comparator, t_superr.clone(), k_sub.clone()),
T::la2(
and,
t_subset_of_t(
comparator,
t_subl,
n_superset.to_tree(),
k_l,
Some(k_sub.clone()),
),
t_subset_of_t(comparator, t_subr, t_superr, Some(k_sub.clone()), k_r),
),
),
}
}
pub fn r_subset_of_r<'a, T: 'a + Monad, A: 'a, D: 'a + PartialEq>(
comparator: &'a dyn Comparator<A>,
r_subset: Rc<dyn TraversibleBinaryReference<'a, T, A, D>>,
r_superset: Rc<dyn TraversibleBinaryReference<'a, T, A, D>>,
k_l: Option<Rc<A>>,
k_r: Option<Rc<A>>,
) -> T::F<'a, bool> {
T::join(T::la2(
move |n_subset, n_superset| n_subset_of_n(comparator, n_subset, n_superset, k_l, k_r),
r_subset.resolve(),
r_superset.resolve(),
))
}
pub fn t_subset_of_t<'a, T: Monad, A, D: 'a + PartialEq>(
comparator: &'a dyn Comparator<A>,
t_subset: Rc<dyn TraversibleBinaryTree<'a, T, A, D>>,
t_superset: Rc<dyn TraversibleBinaryTree<'a, T, A, D>>,
k_l: Option<Rc<A>>,
k_r: Option<Rc<A>>,
) -> T::F<'a, bool> {
match (t_subset.refer(), t_superset.refer()) {
(None, _) => T::pure(true),
(Some(_), None) => T::pure(false),
(Some(r_subset), Some(r_superset)) => {
if r_subset.data() == r_superset.data() {
T::pure(true)
} else {
r_subset_of_r(comparator, r_subset, r_superset, k_l, k_r)
}
}
}
}