From 3f6d290f5c61e60139b62befdf933e2785e8d6a0 Mon Sep 17 00:00:00 2001 From: timofey Date: Tue, 25 Apr 2023 17:40:04 +0000 Subject: [PATCH] unbalanced tree --- .vscode/settings.json | 4 +- Cargo.toml | 1 + src/flow/traversible.rs | 2 +- src/flow/traversible/unbalanced.rs | 258 +++++++++++++++++++++++++++++ src/func/classes/stackless.rs | 2 + 5 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 src/flow/traversible/unbalanced.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 9e26dfe..4d9636b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "rust-analyzer.showUnlinkedFileNotification": false +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 89091b2..cec85ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,4 @@ radn-derive = { path = "radn-derive" } [dev-dependencies] sha2 = "0.10.6" +rand = "0.8.5" diff --git a/src/flow/traversible.rs b/src/flow/traversible.rs index abb5b1e..805f7ac 100644 --- a/src/flow/traversible.rs +++ b/src/flow/traversible.rs @@ -1,6 +1,6 @@ //! Traversible binary trees. -// pub mod unbalanced; +pub mod unbalanced; use std::rc::Rc; diff --git a/src/flow/traversible/unbalanced.rs b/src/flow/traversible/unbalanced.rs new file mode 100644 index 0000000..405effa --- /dev/null +++ b/src/flow/traversible/unbalanced.rs @@ -0,0 +1,258 @@ +use std::fmt::Display; + +use crate::func::*; + +use super::*; + +pub struct UnbalancedData; + +impl PartialEq for UnbalancedData { + fn eq(&self, _other: &Self) -> bool { + false + } + + #[allow(clippy::partialeq_ne_impl)] + fn ne(&self, _other: &Self) -> bool { + false + } +} + +pub struct UnbalancedNode<'a, T: 'a + Monad, A: 'a> { + cl: Rc>, + cr: Rc>, + key: Rc, +} + +pub type UnbalancedResolution<'a, T, A> = ::F<'a, Rc>>; + +pub struct UnbalancedReference<'a, T: 'a + Monad, A: 'a>( + Box UnbalancedResolution<'a, T, A>>, +); + +pub enum UnbalancedTree<'a, T: 'a + Monad, A: 'a> { + Leaf, + Node(Rc>), +} + +impl<'a, A: 'a + Display> Display for UnbalancedNode<'a, classes::solo::SoloClass, A> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("({} {} {})", self.cl, self.key, self.cr)) + } +} + +impl<'a, A: 'a + Display> Display for UnbalancedReference<'a, classes::solo::SoloClass, A> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{}", self.0())) + } +} + +impl<'a, A: 'a + Display> Display for UnbalancedTree<'a, classes::solo::SoloClass, A> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + UnbalancedTree::Leaf => f.write_fmt(format_args!(".")), + UnbalancedTree::Node(reference) => f.write_fmt(format_args!("{}", reference)), + } + } +} + +impl<'a, T: 'a + Monad, A: 'a> TraversibleBinaryNode<'a, T, A, UnbalancedData> + for UnbalancedNode<'a, T, A> +{ + fn split(&self) -> Split<'a, T, A, UnbalancedData> { + (self.cl.clone(), self.cr.clone(), self.key.clone()) + } + + fn to_tree(self: Rc) -> Rc> { + Rc::new(UnbalancedTree::Node(Rc::new(UnbalancedReference( + Box::new(move || T::pure(self.clone())), + )))) + } +} + +impl<'a, T: 'a + Monad, A: 'a> TraversibleBinaryReference<'a, T, A, UnbalancedData> + for UnbalancedReference<'a, T, A> +{ + fn resolve( + &self, + ) -> ::F<'a, Rc>> { + ::fmap( + |rc| rc as Rc>, + self.0(), + ) + } + + fn data(&self) -> UnbalancedData { + UnbalancedData + } +} + +impl<'a, T: 'a + Monad, A: 'a> TraversibleBinaryTree<'a, T, A, UnbalancedData> + for UnbalancedTree<'a, T, A> +{ + fn refer(&self) -> Option>> { + match self { + UnbalancedTree::Leaf => None, + UnbalancedTree::Node(reference) => Some(reference.clone()), + } + } +} + +type WrapType<'a, T, A> = + Box>) -> UnbalancedResolution<'a, T, A>>; + +pub struct UnbalancedConstructor<'a, T: 'a + Monad, A: 'a> { + wrap: WrapType<'a, T, A>, +} + +impl<'a, T: 'a + Monad, A: 'a> UnbalancedConstructor<'a, T, A> { + pub fn rc(wrap: WrapType<'a, T, A>) -> Rc { + Self { wrap }.into() + } + + pub fn leaf(&self) -> Rc> { + UnbalancedTree::Leaf.into() + } + + pub fn node( + self: &Rc, + cl: Rc>, + key: A, + cr: Rc>, + ) -> Rc> { + let node = Rc::new(UnbalancedNode { + cl, + cr, + key: key.into(), + }); + let ctr = self.clone(); + UnbalancedTree::Node(Rc::new(UnbalancedReference(Box::new(move || { + (ctr.wrap)(node.clone()) + })))) + .into() + } + + #[cfg(test)] + pub fn from_slice( + self: &Rc, + rng: &mut R, + slice: &[A], + ) -> Rc> + where + A: 'a + Clone, + { + if slice.is_empty() { + self.leaf() + } else { + let key_at = rng.gen_range(0..slice.len()); + let key = slice[key_at].clone(); + let lslice = &slice[..key_at]; + let rslice = &slice[key_at + 1..]; + self.clone().node( + self.clone().from_slice(rng, lslice), + key, + self.clone().from_slice(rng, rslice), + ) + } + } +} + +#[cfg(test)] +mod tests { + use rand::Rng; + + use super::*; + + #[test] + fn test_simple_slices() { + let ctr: Rc> = + UnbalancedConstructor::rc(Box::new(|node| node)); + let mut rng = rand::thread_rng(); + let t_set = ctr.from_slice(&mut rng, &[0]); + assert!(t_contains(&DefaultComparator, t_set.clone(), 0.into())); + assert!(!t_contains(&DefaultComparator, t_set.clone(), 1.into())); + assert!(t_subset_of_t( + &DefaultComparator, + t_set.clone(), + t_set.clone(), + None, + None + )); + assert!(!t_subset_of_t( + &DefaultComparator, + t_set.clone(), + ctr.leaf(), + None, + None + )); + assert!(t_subset_of_t( + &DefaultComparator, + ctr.leaf(), + t_set.clone(), + None, + None + )); + assert!(t_subset_of_t( + &DefaultComparator, + ctr.leaf(), + ctr.leaf(), + None, + None + )); + assert!(t_subset_of_t( + &DefaultComparator, + ctr.from_slice(&mut rng, &[0, 1, 2, 4, 5, 6, 7]), + ctr.from_slice(&mut rng, &[0, 1, 2, 3, 4, 5, 6, 7]), + None, + None + )); + assert!(!t_subset_of_t( + &DefaultComparator, + ctr.from_slice(&mut rng, &[0, 1, 2, 3, 4, 5, 6, 7]), + ctr.from_slice(&mut rng, &[0, 1, 2, 4, 5, 6, 7]), + None, + None + )); + } + + #[test] + fn test_random_slices() { + let ctr: Rc> = + UnbalancedConstructor::rc(Box::new(|node| node)); + let mut rng = rand::thread_rng(); + for _ in 0..1000 { + let big: Vec = (0..(rng.gen_range(2..10))).collect(); + let key = big[rng.gen_range(0..big.len())]; + let small: Vec = big + .iter() + .filter(|x| **x != key && rng.gen_ratio(4, 5)) + .map(|x| *x) + .collect(); + let t_small = ctr.from_slice(&mut rng, &small); + let t_big = ctr.from_slice(&mut rng, &big); + assert!( + t_subset_of_t( + &DefaultComparator, + t_small.clone(), + t_big.clone(), + None, + None + ), + "{} should be a subset of {}", + t_small, + t_big, + ); + assert!( + !t_subset_of_t( + &DefaultComparator, + t_big.clone(), + t_small.clone(), + None, + None + ), + "{} should not be a subset of {}", + t_big, + t_small, + ); + } + } +} diff --git a/src/func/classes/stackless.rs b/src/func/classes/stackless.rs index 1e5b5f8..abbb162 100644 --- a/src/func/classes/stackless.rs +++ b/src/func/classes/stackless.rs @@ -306,11 +306,13 @@ mod stackless_test { } } + #[ignore] #[test] fn test_factorial() { assert_eq!(factorial(10).evaluate(), 3628800); } + #[ignore] #[test] fn test_dumb() { let n = 1000;