avl::bounds

This commit is contained in:
AF 2023-05-29 16:31:06 +00:00
parent 4736d8d112
commit d27a53bcb8
3 changed files with 333 additions and 13 deletions

View File

@ -1,3 +1,6 @@
pub mod binary;
pub mod bounds;
use std::{error::Error, fmt::Display, rc::Rc};
use crate::rcore::*;
@ -8,27 +11,30 @@ use crate::rstd::{
};
#[derive(Debug)]
pub enum TreeParseError<E> {
pub enum AvlError<E> {
Int(IntParseError),
Point(PointParseError),
Key(E),
LeafHeight(u64),
NodeHeight,
Balance(u64, u64),
HeightOverflow,
HeightMismatch { child: (u64, u64), parent: u64 },
}
impl<E> From<IntParseError> for TreeParseError<E> {
impl<E> From<IntParseError> for AvlError<E> {
fn from(value: IntParseError) -> Self {
Self::Int(value)
}
}
impl<E> From<PointParseError> for TreeParseError<E> {
impl<E> From<PointParseError> for AvlError<E> {
fn from(value: PointParseError) -> Self {
Self::Point(value)
}
}
impl<E: Display> Display for TreeParseError<E> {
impl<E: Display> Display for AvlError<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Int(int_error) => {
@ -40,15 +46,20 @@ impl<E: Display> Display for TreeParseError<E> {
Self::Key(key_error) => {
f.write_fmt(format_args!("failed to parse AVL node key: {key_error}"))
}
Self::NodeHeight => f.write_fmt(format_args!("invalid AVL non-leaf height: 0.")),
Self::LeafHeight(height) => {
f.write_fmt(format_args!("invalid AVL leaf height: {height}!=0."))
}
Self::Balance(lh, rh) => f.write_fmt(format_args!("unbalanced AVL node: {lh} {rh}.")),
Self::HeightOverflow => f.write_fmt(format_args!("AVL tree height overflow")),
Self::HeightMismatch { child, parent } => f.write_fmt(format_args!(
"AVL child-parent height mismatch: {child:?}, {parent}"
)),
}
}
}
impl<E: Error> Error for TreeParseError<E> {}
impl<E: Error> Error for AvlError<E> {}
pub struct AvlNode<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> {
l: AvlTree<'a, Ctx, A>,
@ -108,10 +119,17 @@ impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> Mentionable<'a, Ctx> for Avl
}
}
fn balanced<E>(lh: u64, rh: u64) -> Result<(), AvlError<E>> {
if std::cmp::max(lh, rh) - std::cmp::min(lh, rh) > 1 {
return Err(AvlError::Balance(lh, rh));
}
Ok(())
}
impl<'a, Ctx: Context<'a>, F: Factory<'a, Ctx>> Factory<'a, Ctx> for AvlNodeFactory<F> {
type Mtbl = AvlNode<'a, Ctx, F::Mtbl>;
type ParseError = TreeParseError<F::ParseError>;
type ParseError = AvlError<F::ParseError>;
fn deserialize(
&self,
@ -122,26 +140,24 @@ impl<'a, Ctx: Context<'a>, F: Factory<'a, Ctx>> Factory<'a, Ctx> for AvlNodeFact
let tree_factory = AvlTreeFactory(NullableFactory::new(self.clone()));
let l = tree_factory.deserialize(deserializer, resolver.clone(), addresses)?;
let r = tree_factory.deserialize(deserializer, resolver.clone(), addresses)?;
if std::cmp::max(l.height, r.height) - std::cmp::min(l.height, r.height) > 1 {
return Err(TreeParseError::Balance(l.height, r.height));
}
balanced(l.height, r.height)?;
let key = self
.0
.deserialize(deserializer, resolver.clone(), addresses)
.map_err(TreeParseError::Key)?
.map_err(AvlError::Key)?
.into();
Ok(AvlNode { l, r, key })
}
fn unexpected_tail(&self, tail: &[u8]) -> Self::ParseError {
TreeParseError::Key(self.0.unexpected_tail(tail))
AvlError::Key(self.0.unexpected_tail(tail))
}
}
impl<'a, Ctx: Context<'a>, F: Factory<'a, Ctx>> Factory<'a, Ctx> for AvlTreeFactory<F> {
type Mtbl = AvlTree<'a, Ctx, F::Mtbl>;
type ParseError = TreeParseError<F::ParseError>;
type ParseError = AvlError<F::ParseError>;
fn deserialize(
&self,
@ -153,8 +169,10 @@ impl<'a, Ctx: Context<'a>, F: Factory<'a, Ctx>> Factory<'a, Ctx> for AvlTreeFact
let height = u64::a_deserialize(deserializer)?;
if let Nullable::Null(_) = node {
if height != 0 {
return Err(TreeParseError::LeafHeight(height));
return Err(AvlError::LeafHeight(height));
}
} else if height == 0 {
return Err(AvlError::NodeHeight);
}
Ok(AvlTree { node, height })
}

View File

@ -0,0 +1,102 @@
use crate::func::*;
use super::*;
pub struct AvlReference<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> {
node: Point<'a, Ctx, AvlNode<'a, Ctx, A>>,
parent_height: u64,
}
pub type AvlResult<'a, Ctx, A, T> = Result<T, AvlError<ParseError<'a, Ctx, Fctr<'a, Ctx, A>>>>;
pub type AvlNodeResult<'a, Ctx, A> = AvlResult<'a, Ctx, A, AvlNode<'a, Ctx, A>>;
pub type AvlTreeResult<'a, Ctx, A> = AvlResult<'a, Ctx, A, AvlTree<'a, Ctx, A>>;
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> AvlNode<'a, Ctx, A> {
fn parent_height(&self) -> AvlResult<'a, Ctx, A, u64> {
std::cmp::max(self.l.height, self.r.height)
.checked_add(1)
.ok_or(AvlError::HeightOverflow)
}
pub fn into_tree(self) -> AvlTreeResult<'a, Ctx, A> {
let height = self.parent_height()?;
let node = self.into();
Ok(AvlTree { node, height })
}
pub fn new(
l: AvlTree<'a, Ctx, A>,
r: AvlTree<'a, Ctx, A>,
key: Rc<A>,
) -> AvlNodeResult<'a, Ctx, A> {
balanced(l.height, r.height)?;
Ok(Self { l, r, key })
}
fn matches_height(&self, parent_height: u64) -> AvlResult<'a, Ctx, A, ()> {
let expected = self.parent_height()?;
if expected == parent_height {
Ok(())
} else {
Err(AvlError::HeightMismatch {
child: (self.l.height, self.r.height),
parent: parent_height,
})
}
}
}
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> AvlTree<'a, Ctx, A> {
pub fn empty(factory: Fctr<'a, Ctx, A>) -> Self {
Self {
node: Nullable::Null(AvlNodeFactory(factory)),
height: 0,
}
}
pub fn reference(&self) -> Option<AvlReference<'a, Ctx, A>> {
match self.node {
Nullable::Null(_) => None,
Nullable::NotNull(ref point) => Some(AvlReference {
node: point.clone(),
parent_height: self.height,
}),
}
}
}
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> AvlReference<'a, Ctx, A> {
pub fn resolve(&self) -> Resolution<'a, Ctx, AvlNode<'a, Ctx, A>> {
let parent_height = self.parent_height;
<Ctx::T as Functor>::fmap(
move |resolution| {
let node = resolution?;
node.matches_height(parent_height)
.map_err(ResolutionError::Parse)?;
Ok(node)
},
self.node.resolve(),
)
}
}
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> Clone for AvlTree<'a, Ctx, A> {
fn clone(&self) -> Self {
Self {
node: self.node.clone(),
height: self.height,
}
}
}
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> Clone for AvlNode<'a, Ctx, A> {
fn clone(&self) -> Self {
Self {
l: self.l.clone(),
r: self.r.clone(),
key: self.key.clone(),
}
}
}

View File

@ -0,0 +1,200 @@
use crate::{flow::comparator::*, func::*};
use super::{binary::*, *};
struct Bounds<A> {
l: Option<Rc<A>>,
r: Option<Rc<A>>,
}
impl<A> Clone for Bounds<A> {
fn clone(&self) -> Self {
Self {
l: self.l.clone(),
r: self.r.clone(),
}
}
}
pub enum BoundsError<A> {
BoundsViolated { l: Rc<A>, r: Rc<A> },
}
pub enum BoundError<A, E> {
Avl(AvlError<E>),
Bounds(BoundsError<A>),
}
impl<A, E> From<AvlError<E>> for BoundError<A, E> {
fn from(value: AvlError<E>) -> Self {
Self::Avl(value)
}
}
impl<A, E> From<BoundsError<A>> for BoundError<A, E> {
fn from(value: BoundsError<A>) -> Self {
Self::Bounds(value)
}
}
pub type BoundErrorA<'a, Ctx, A> = BoundError<A, ParseError<'a, Ctx, Fctr<'a, Ctx, A>>>;
pub type BoundResult<'a, Ctx, A, T> = Result<T, BoundErrorA<'a, Ctx, A>>;
pub type BoundNodeResult<'a, Ctx, A> = BoundResult<'a, Ctx, A, BoundNode<'a, Ctx, A>>;
pub type BoundTreeResult<'a, Ctx, A> = BoundResult<'a, Ctx, A, BoundTree<'a, Ctx, A>>;
pub struct BoundTree<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> {
tree: AvlTree<'a, Ctx, A>,
bounds: Bounds<A>,
}
pub struct BoundNode<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> {
node: AvlNode<'a, Ctx, A>,
bounds: Bounds<A>,
}
pub struct BoundReference<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> {
reference: AvlReference<'a, Ctx, A>,
bounds: Bounds<A>,
}
impl<A> Bounds<A> {
fn unbound() -> Self {
Bounds { l: None, r: None }
}
fn ordered(
l: &Rc<A>,
r: &Rc<A>,
comparator: &impl Comparator<A>,
) -> Result<(), BoundsError<A>> {
if let Comparison::R = comparator.pick_smaller(l, r) {
Err(BoundsError::BoundsViolated {
l: l.clone(),
r: r.clone(),
})
} else {
Ok(())
}
}
fn new(
l: Option<Rc<A>>,
r: Option<Rc<A>>,
comparator: &impl Comparator<A>,
) -> Result<Self, BoundsError<A>> {
if let (Some(kl), Some(kr)) = (&l, &r) {
Self::ordered(kl, kr, comparator)?
}
Ok(Bounds { l, r })
}
fn split(
self,
key: &Rc<A>,
comparator: &impl Comparator<A>,
) -> Result<(Self, Self), BoundsError<A>> {
Ok((
Self::new(self.l, Some(key.clone()), comparator)?,
Self::new(Some(key.clone()), self.r, comparator)?,
))
}
fn join(
l: Self,
r: Self,
key: &Rc<A>,
comparator: &impl Comparator<A>,
) -> Result<Self, BoundsError<A>> {
if let Some(lr) = &l.r {
Self::ordered(lr, key, comparator)?
}
if let Some(rl) = &r.l {
Self::ordered(key, rl, comparator)?
}
Self::new(l.l, r.r, comparator)
}
}
pub type BoundSplit<'a, Ctx, A> = (BoundTree<'a, Ctx, A>, BoundTree<'a, Ctx, A>, Rc<A>);
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundNode<'a, Ctx, A> {
pub fn into_tree(self) -> BoundTreeResult<'a, Ctx, A> {
let tree = self.node.into_tree()?;
let bounds = self.bounds;
Ok(BoundTree { tree, bounds })
}
pub fn new(
l: BoundTree<'a, Ctx, A>,
r: BoundTree<'a, Ctx, A>,
key: Rc<A>,
comparator: &impl Comparator<A>,
) -> BoundNodeResult<'a, Ctx, A> {
let bounds = Bounds::join(l.bounds, r.bounds, &key, comparator)?;
let node = AvlNode::new(l.tree, r.tree, key)?;
Ok(Self { node, bounds })
}
pub fn split(
&self,
comparator: &impl Comparator<A>,
) -> Result<BoundSplit<'a, Ctx, A>, BoundsError<A>> {
let (bl, br) = self.bounds.clone().split(&self.node.key, comparator)?;
Ok((
BoundTree {
tree: self.node.l.clone(),
bounds: bl,
},
BoundTree {
tree: self.node.r.clone(),
bounds: br,
},
self.node.key.clone(),
))
}
}
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundTree<'a, Ctx, A> {
pub fn empty(factory: Fctr<'a, Ctx, A>) -> Self {
Self {
tree: AvlTree::empty(factory),
bounds: Bounds::unbound(),
}
}
pub fn reference(&self) -> Option<BoundReference<'a, Ctx, A>> {
let reference = self.tree.reference()?;
let bounds = self.bounds.clone();
Some(BoundReference { reference, bounds })
}
}
type BoundResolutionError<'a, Ctx, A> =
ResolutionError<<Ctx as Context<'a>>::LookupError, BoundErrorA<'a, Ctx, A>>;
type BoundResolutionResult<'a, Ctx, A> =
Result<BoundNode<'a, Ctx, A>, BoundResolutionError<'a, Ctx, A>>;
type BoundResolution<'a, Ctx, A> = Wrapped<'a, Ctx, BoundResolutionResult<'a, Ctx, A>>;
impl<'a, Ctx: Context<'a>, A: Mentionable<'a, Ctx>> BoundReference<'a, Ctx, A> {
pub fn resolve(&self) -> BoundResolution<'a, Ctx, A> {
let bounds = self.bounds.clone();
<Ctx::T as Functor>::fmap(
move |resolution| {
let node = resolution
.map_err(|err| match err {
ResolutionError::Lookup(lookup) => ResolutionError::Lookup(lookup),
ResolutionError::Parse(avl) => ResolutionError::Parse(BoundError::Avl(avl)),
})?
.as_ref()
.clone();
Ok(BoundNode { node, bounds })
},
self.reference.resolve(),
)
}
}