From 9e1278eaca348c295c168febf371d8fe7d631b00 Mon Sep 17 00:00:00 2001 From: Joe Hellerstein Date: Mon, 26 Aug 2024 15:26:10 -0700 Subject: [PATCH] Ght macros, GhtForest and force seem to be working now --- lattices/src/ght.rs | 115 +++++++++++------ lattices/src/ght_lattice.rs | 5 +- lattices/src/ght_lazy.rs | 11 +- lattices/src/ght_test.rs | 250 ++++++++++++++---------------------- 4 files changed, 184 insertions(+), 197 deletions(-) diff --git a/lattices/src/ght.rs b/lattices/src/ght.rs index 30df5dc4b357..a27076fe999f 100644 --- a/lattices/src/ght.rs +++ b/lattices/src/ght.rs @@ -36,11 +36,15 @@ pub trait GeneralizedHashTrieNode: Default { /// E.g. if we have GhtInner> the height is 2 fn height(&self) -> Option; + /// debugging function to check that height is consistent along at least the leftmost path + fn check_height(&self) -> bool; + /// report whether node is a leaf node; else an inner node fn is_leaf(&self) -> bool; - /// Inserts items into the hash trie. - fn insert(&mut self, row: Self::Schema) -> bool; + /// Inserts items into the hash trie. Returns the height + /// of this node (leaf = 0) + fn insert(&mut self, row: Self::Schema) -> Option; /// Returns `true` if the (entire) row is found in the trie, `false` otherwise. /// See `get()` below to look just for "head" keys in this node @@ -105,6 +109,7 @@ where Node: GeneralizedHashTrieNode, { pub(crate) children: HashMap, + pub(crate) height: Option, // pub(crate) _leaf: std::marker::PhantomData, } impl Default for GhtInner @@ -116,6 +121,7 @@ where let children = Default::default(); Self { children, + height: None, // _leaf: Default::default(), } } @@ -136,29 +142,44 @@ where fn new_from(input: impl IntoIterator) -> Self { let mut retval: Self = Default::default(); + let mut height = None; for row in input { // let (_prefix, suffix) = row.clone().split(); - retval.insert(row); + height = retval.insert(row); } + retval.height = height; retval } fn height(&self) -> Option { - if let Some((_k, v)) = self.children.iter().next() { - v.height().map(|h| h + 1) - } else { - None - } + self.height + } + + fn check_height(&self) -> bool { + self.height.unwrap() + == self + .children + .iter() + .next() + .and_then(|n| n.1.height()) + .map(|h| h + 1) + .unwrap() } fn is_leaf(&self) -> bool { false } - fn insert(&mut self, row: Self::Schema) -> bool { + fn insert(&mut self, row: Self::Schema) -> Option { // TODO(mingwei): clones entire row... let (_prefix, var_args!(head, ..._rest)) = row.clone().split_by_suffix(); - self.children.entry(head).or_default().insert(row) + self.height = self + .children + .entry(head) + .or_default() + .insert(row) + .map(|h| h + 1); + self.height } fn contains<'a>(&'a self, row: ::AsRefVar<'a>) -> bool { @@ -297,12 +318,17 @@ where Some(0) } + fn check_height(&self) -> bool { + true + } + fn is_leaf(&self) -> bool { true } - fn insert(&mut self, row: Self::Schema) -> bool { - self.elements.insert(row) + fn insert(&mut self, row: Self::Schema) -> Option { + self.elements.insert(row); + self.height() } fn contains<'a>(&'a self, row: ::AsRefVar<'a>) -> bool { @@ -495,10 +521,13 @@ where ) -> bool { // TODO(mingwei): clones head... let (_prefix, var_args!(head, ..._rest)) = Self::Schema::split_by_suffix_ref(row); - self.children + let retval = self + .children .entry(head.clone()) .or_default() - .merge_leaf(row, leaf) + .merge_leaf(row, leaf); + self.height = self.get(head).and_then(|n| n.height).map(|h| h + 1); + retval } } @@ -540,8 +569,10 @@ where >>::split_by_suffix_ref(row); if let Some(old_val) = self.children.insert(head.clone(), leaf) { self.children.insert(head.clone(), old_val); + panic!(); false } else { + self.height = Some(1); true } } @@ -723,33 +754,34 @@ where /// Helper that does the heavy lifting for GhtNodeType! #[macro_export] macro_rules! GhtNodeTypeWithSchema { - // Empty key, singleton val base case. - (() => $z:ty => $( $schema:ty ),+ ) => ( - $crate::ght::GhtLeaf::<$( $schema ),*, $crate::variadics::var_type!( $z ) > - ); - // Empty key, compound val base case. - (() => $y:ty, $( $z:ty ),* => $( $schema:ty ),+ ) => ( - $crate::ght::GhtLeaf::<$( $schema ),*, ( $y, $crate::variadics::var_type!($( $z ),* )) > + // Empty key & Val (Leaf) + (() => () => $( $schema:ty ),+ ) => ( + $crate::ght::GhtLeaf::<$( $schema ),*, () > ); - // Singleton key, empty val base case. - ($a:ty => () => ( $schema:ty ),+ ) => ( - $crate::ght::GhtInner::<$a, $crate::ght::GhtLeaf::<$( $schema ),*, $crate::variadics::var_type!( $z ) >> + + // Empty key (Leaf) + (() => $( $z:ty ),* => $schema:ty ) => ( + $crate::ght::GhtLeaf::<$schema, $crate::variadics::var_type!($( $z ),* ) > ); - // Singleton key, singleton val base case. - ($a:ty => $z:ty => $( $schema:ty ),+ ) => ( - $crate::ght::GhtInner::<$a, $crate::ght::GhtLeaf::<$( $schema ),*, $crate::variadics::var_type!( $z ) >> + + // Singleton key & Empty val (Inner over Leaf) + ($a:ty => () => $schema:ty ) => ( + $crate::ght::GhtInner::<$a, $crate::ght::GhtLeaf::<$schema, () >> ); - // Singleton key, compound val base case. - ($a:ty => $y:ty, $( $z:ty ),* => $( $schema:ty ),+ ) => ( - $crate::ght::GhtInner::<$a, $crate::ght::GhtLeaf::<$( $schema ),*, $crate::variadics::var_type!($y, $( $z ),*) >> + + // Singleton key (Inner over Leaf) + ($a:ty => $( $z:ty ),* => $schema:ty ) => ( + $crate::ght::GhtInner::<$a, $crate::ght::GhtLeaf::<$schema, $crate::variadics::var_type!($( $z ),*) >> ); - // Compound key, singleton val base case. - ($a:ty, $( $b:ty ),* => $z:ty => $( $schema:ty ),+ ) => ( - $crate::ght::GhtInner::<$a, $crate::GhtNodeTypeWithSchema!($( $b ),* => $z => $( $schema ),*)> + + // Recursive case with empty val + ($a:ty, $( $b:ty ),* => () => $schema:ty ) => ( + $crate::ght::GhtInner::<$a, $crate::GhtNodeTypeWithSchema!($( $b ),* => () => $schema)> ); + // Recursive case. - ($a:ty, $( $b:ty ),* => $( $z:ty ),* => $( $schema:ty ),+ ) => ( - $crate::ght::GhtInner::<$a, $crate::GhtNodeTypeWithSchema!($( $b ),* => $( $z ),* => $( $schema ),*)> + ($a:ty, $( $b:ty ),* => $( $z:ty ),* => $schema:ty ) => ( + $crate::ght::GhtInner::<$a, $crate::GhtNodeTypeWithSchema!($( $b ),* => $( $z ),* => $schema)> ); } @@ -763,13 +795,18 @@ macro_rules! GhtNodeTypeWithSchema { /// a la var_expr!(T1, T2, T3) #[macro_export] macro_rules! GhtType { + // Empty key (() => $( $z:ty ),* ) => ( $crate::GhtNodeTypeWithSchema!(() => $( $z ),* => $crate::variadics::var_type!($( $z ),* )) ); - ($a:ty => $( $z:ty ),*) => ( - $crate::GhtNodeTypeWithSchema!($a => $( $z ),* => $crate::variadics::var_type!($a, $( $z ),+ )) + + // Recursive case empty val + ($( $b:ty ),* => () ) => ( + $crate::GhtNodeTypeWithSchema!($( $b ),* => () => $crate::variadics::var_type!($( $b ),*)) ); - ($a:ty, $( $b:ty ),* => $( $z:ty ),*) => ( - $crate::GhtNodeTypeWithSchema!($a, $( $b ),* => $( $z ),* => $crate::variadics::var_type!($a, $( $b ),*, $( $z ),*)) + + // Recursive case + ($( $b:ty ),* => $( $z:ty ),*) => ( + $crate::GhtNodeTypeWithSchema!($( $b ),* => $( $z ),* => $crate::variadics::var_type!($( $b ),*, $( $z ),*)) ); } diff --git a/lattices/src/ght_lattice.rs b/lattices/src/ght_lattice.rs index 87d5bfd537e4..9950c5b575d4 100644 --- a/lattices/src/ght_lattice.rs +++ b/lattices/src/ght_lattice.rs @@ -457,7 +457,10 @@ where children.insert(head.clone(), val); } } - GhtInner { children } + GhtInner { + children, + height: ght_a.height(), + } } } diff --git a/lattices/src/ght_lazy.rs b/lattices/src/ght_lazy.rs index a0845afc1500..f0731d77f99f 100644 --- a/lattices/src/ght_lazy.rs +++ b/lattices/src/ght_lazy.rs @@ -101,7 +101,7 @@ where /// one for each height from 1 to length of the schema macro_rules! GhtForestType { ($a:tt, $( $b:tt ),* => ()) => { - GhtType!($a, $( $b ),* => ()) + var_type!(GhtType!($a, $( $b ),* => ())) }; ($a:tt => $c:tt, $( $d:tt ),* ) => { (GhtType!($a => $c, $( $d ),*), GhtForestType!($a, $c => $( $d ),*)) @@ -148,11 +148,9 @@ impl GhtForest + GhtTakeLeaf, - SearchKey: Split, - var_type!(TrieSecond, ...TrieRest): VariadicExt + GhtForest, - SearchKey: VariadicExt + Clone, - // GhtForestStruct: GhtForest, + SearchKey: VariadicExt + Split + Clone, var_type!(TrieSecond, ...TrieRest): GhtForest, + // GhtForestStruct: GhtForest, TrieFirst::Schema: PartialEqVariadic + SplitBySuffix + Eq + Hash + Clone, TrieSecond::Schema: PartialEqVariadic + SplitBySuffix + Eq + Hash + Clone, Self: ForestFindLeaf, @@ -180,6 +178,7 @@ where _suffix_schema: PhantomData, }; rest_first.merge_leaf(row.as_ref_var(), leaf); + assert!(rest_first.check_height()); // drop through and recurse: we may have to force again in the neighbor } // recurse @@ -227,7 +226,7 @@ impl ForestFindLeaf<: where ::Schema: PartialEqVariadic, TrieFirst: GeneralizedHashTrieNode, - TrieRest: VariadicExt + ForestFindLeaf<::Schema>, + TrieRest: ForestFindLeaf<::Schema>, { fn find_containing_leaf( &self, diff --git a/lattices/src/ght_test.rs b/lattices/src/ght_test.rs index 3f02253e41da..138a46dc234f 100644 --- a/lattices/src/ght_test.rs +++ b/lattices/src/ght_test.rs @@ -12,7 +12,9 @@ mod test { // GhtNodeKeyedBimorphism, GhtValTypeProductBimorphism, }; use crate::ght_lazy::{ColumnLazyTrieNode, ForestFindLeaf, GhtForest}; // GhtForestStruct}; - use crate::{GhtForestType, GhtType, LatticeBimorphism, Merge, NaiveLatticeOrd}; + use crate::{ + GhtForestType, GhtNodeTypeWithSchema, GhtType, LatticeBimorphism, Merge, NaiveLatticeOrd, + }; #[test] fn basic_test() { @@ -73,12 +75,16 @@ mod test { let mut htrie = u64)>::default(); htrie.insert(var_expr!(42, 314, 43770)); assert_eq!(htrie.recursive_iter().count(), 1); + assert_eq!(htrie.height(), Some(2)); htrie.insert(var_expr!(42, 315, 43770)); assert_eq!(htrie.recursive_iter().count(), 2); + assert_eq!(htrie.height(), Some(2)); htrie.insert(var_expr!(42, 314, 30619)); assert_eq!(htrie.recursive_iter().count(), 3); + assert_eq!(htrie.height(), Some(2)); htrie.insert(var_expr!(43, 10, 600)); assert_eq!(htrie.recursive_iter().count(), 4); + assert_eq!(htrie.height(), Some(2)); assert!(htrie.contains(var_expr!(&42, &314, &30619))); assert!(htrie.contains(var_expr!(&42, &315, &43770))); assert!(htrie.contains(var_expr!(&43, &10, &600))); @@ -86,7 +92,9 @@ mod test { type LongKeyLongValTrie = GhtType!(u32, u64 => u16, &'static str); let mut htrie = LongKeyLongValTrie::new_from(vec![var_expr!(1, 999, 222, "hello")]); htrie.insert(var_expr!(1, 999, 111, "bye")); + assert_eq!(htrie.height(), Some(2)); htrie.insert(var_expr!(1, 1000, 123, "cya")); + assert_eq!(htrie.height(), Some(2)); // println!("htrie: {:?}", htrie); assert!(htrie.contains(var_expr!(&1, &999, &222, &"hello"))); assert!(htrie.contains(var_expr!(&1, &999, &111, &"bye"))); @@ -863,121 +871,85 @@ mod test { println!("resulting COLT is {:?}", colt); } - // #[test] - // fn test_ght_forest() { - // // [[𝑅(𝑥),𝑆(𝑥),𝑇(𝑥),T'(x)], [𝑅(𝑎)], [𝑆(𝑏)], [T'(c), 𝑇(𝑐)]] - // // - // // R(a, x, y), S(a, x, c), T(a, x, c) - // // [[R(a, x),S(a, x),T(a, x)], [T(a, c), S(a, c)]] - // type LeafType = GhtNodeType!(() => u16, u32, u64); - - // let table_r = LeafType::new_from(vec![ - // var_expr!(0, 1, 1), - // var_expr!(0, 1, 2), - // var_expr!(0, 1, 3), - // var_expr!(1, 2, 1), - // var_expr!(1, 3, 1), - // ]); - // let table_s = LeafType::new_from(vec![ - // var_expr!(0, 1, 1), - // var_expr!(0, 1, 2), - // var_expr!(0, 1, 3), - // var_expr!(0, 2, 1), - // var_expr!(0, 2, 2), - // var_expr!(0, 2, 3), - // var_expr!(1, 2, 1), - // var_expr!(1, 2, 2), - // var_expr!(1, 2, 3), - // var_expr!(1, 3, 1), - // var_expr!(1, 3, 2), - // var_expr!(1, 3, 3), - // ]); - // let table_t = LeafType::new_from(vec![ - // var_expr!(0, 1, 1), - // var_expr!(0, 1, 2), - // var_expr!(0, 1, 3), - // var_expr!(1, 3, 1), - // ]); - - // // set up S forest - // type SForest = GhtForestType!(u16, u32, u64); - // let mut s_forest = SForest::default(); - // // car(forest) is forced once - // s_forest.0 = table_s.force().unwrap(); - // assert!(s_forest.0.height().unwrap() == 1); - // assert!(s_forest.1 .0.height().is_none()); - - // // set up T forest - // type TForest = GhtForestType!(u16, u32, u64); - // let mut t_forest = TForest::default(); - // // car(forest) is forced once - // t_forest.0 = table_t.force().unwrap(); - - // // remainder of original test - // for r in table_r.elements { - // type KeyType = var_type!(u16, u32); - - // let key_len = KeyType::LEN; - // println!("r tup is {:?}", r); - // s_forest.get_leaf(r); - - // // walk forest and look for (r.0, r.1, *) - // // first check s_forest.0 - - // // fn check_prefix_iter<'a, T0, T1>(_s_forest: &'a var_type!(T0, T1)) - // // where - // // T1: HtPrefixIter, - // // { - // // } - // // check_prefix_iter(&s_forest); - - // // if contains_key(s_forest.as_mut_var(), r, key_len) - // // && contains_key(t_forest.as_mut_var(), r, key_len) - // // { - // // println!("matched {:?}", r); - // // } - // } - // } + #[test] + fn test_ght_forest() { + // [[𝑅(𝑥),𝑆(𝑥),𝑇(𝑥),T'(x)], [𝑅(𝑎)], [𝑆(𝑏)], [T'(c), 𝑇(𝑐)]] + // + // R(a, x, y), S(a, x, c), T(a, x, c) + // [[R(a, x),S(a, x),T(a, x)], [T(a, c), S(a, c)]] + type LeafType = GhtType!(() => u16, u32, u64); + + let table_r = LeafType::new_from(vec![ + var_expr!(0, 1, 1), + var_expr!(0, 1, 2), + var_expr!(0, 1, 3), + var_expr!(1, 2, 1), + var_expr!(1, 3, 1), + ]); + let table_s = LeafType::new_from(vec![ + var_expr!(0, 1, 1), + var_expr!(0, 1, 2), + var_expr!(0, 1, 3), + var_expr!(0, 2, 1), + var_expr!(0, 2, 2), + var_expr!(0, 2, 3), + var_expr!(1, 2, 1), + var_expr!(1, 2, 2), + var_expr!(1, 2, 3), + var_expr!(1, 3, 1), + var_expr!(1, 3, 2), + var_expr!(1, 3, 3), + ]); + let table_t = LeafType::new_from(vec![ + var_expr!(0, 1, 1), + var_expr!(0, 1, 2), + var_expr!(0, 1, 3), + var_expr!(1, 3, 1), + ]); + + // set up S forest + type SForest = GhtForestType!(u16, u32, u64); + let mut s_forest = SForest::default(); + // car(forest) is forced once + s_forest.0 = table_s.force().unwrap(); + assert!(s_forest.0.height().unwrap() == 1); + assert!(s_forest.1 .0.height().is_none()); + + // set up T forest + type TForest = GhtForestType!(u16, u32, u64); + let mut t_forest = TForest::default(); + // car(forest) is forced once + t_forest.0 = table_t.force().unwrap(); + + // remainder of original test + for r in table_r.elements { + type KeyType = var_type!(u16, u32); + + let key_len = KeyType::LEN; + println!("r tup is {:?}", r); + s_forest.find_containing_leaf(r.as_ref_var()); + + // walk forest and look for (r.0, r.1, *) + // first check s_forest.0 + + // fn check_prefix_iter<'a, T0, T1>(_s_forest: &'a var_type!(T0, T1)) + // where + // T1: HtPrefixIter, + // { + // } + // check_prefix_iter(&s_forest); + + // if contains_key(s_forest.as_mut_var(), r, key_len) + // && contains_key(t_forest.as_mut_var(), r, key_len) + // { + // println!("matched {:?}", r); + // } + } + } #[test] fn test_build_forest() { - // type MyForest = GhtForestStruct; - // let mut forest = MyForest::default(); - // forest.forest.0.insert(var_expr!(1, 1, 1, 1)); - // forest.forest.1 .0.insert(var_expr!(2, 2, 2, 2)); - // forest.forest.1 .1 .0.insert(var_expr!(3, 3, 3, 3)); - - type MyForest = ( - GhtInner>, - ( - GhtInner< - u8, - GhtInner>, - >, - ( - GhtInner< - u8, - GhtInner< - u16, - GhtInner>, - >, - >, - ( - GhtInner< - u8, - GhtInner< - u16, - GhtInner< - u32, - GhtInner>, - >, - >, - >, - (), - ), - ), - ), - ); + type MyForest = GhtForestType!(u8, u16, u32, u64); let mut forest = MyForest::default(); forest.0.insert(var_expr!(1, 1, 1, 1)); forest.1 .0.insert(var_expr!(2, 2, 2, 2)); @@ -1037,54 +1009,30 @@ mod test { #[test] fn test_force_forest() { - // type MyForest = GhtForestStruct; - // let mut forest = MyForest::default(); - // forest.forest.0.insert(var_expr!(1, 1, 1, 1)); - // forest.forest.0.insert(var_expr!(2, 2, 2, 2)); - // forest.forest.0.insert(var_expr!(3, 3, 3, 3)); - type MyForest = ( - GhtInner>, - ( - GhtInner< - u8, - GhtInner>, - >, - ( - GhtInner< - u8, - GhtInner< - u16, - GhtInner>, - >, - >, - ( - GhtInner< - u8, - GhtInner< - u16, - GhtInner< - u32, - GhtInner>, - >, - >, - >, - (), - ), - ), - ), - ); // GhtForestType!(u8, u16, u32, u64); + type MyForest = GhtForestType!(u8, u16, u32, u64); let mut forest = MyForest::default(); forest.0.insert(var_expr!(1, 1, 1, 1)); forest.0.insert(var_expr!(2, 2, 2, 2)); forest.0.insert(var_expr!(3, 3, 3, 3)); GhtForest::::force(&mut forest, var_expr!(1, 1, 1, 1)); + println!("Forest after forcing (1, 1, 1, 1): {:?}", forest); GhtForest::::force(&mut forest, var_expr!(2, 1, 1, 1)); + println!("Forest after forcing (2, 1, 1, 1): {:?}", forest); GhtForest::::force(&mut forest, var_expr!(3, 3, 3, 3)); - println!("{:?}", forest); + println!("Forest after forcing (3, 3, 3, 3): {:?}", forest); + println!( - "leaf: {:?}", + "(1, 1, 1, 1) leaf: {:?}", forest.find_containing_leaf(var_expr!(1, 1, 1, 1).as_ref_var()) ); + println!( + "(2, 1, 1, 1) leaf: {:?}", + forest.find_containing_leaf(var_expr!(2, 1, 1, 1).as_ref_var()) + ); + println!( + "(3, 3, 3, 3) leaf: {:?}", + forest.find_containing_leaf(var_expr!(3, 3, 3, 3).as_ref_var()) + ); } }