diff --git a/ascent/src/c_lat_index.rs b/ascent/src/c_lat_index.rs index 87cfbef..1246969 100644 --- a/ascent/src/c_lat_index.rs +++ b/ascent/src/c_lat_index.rs @@ -103,7 +103,9 @@ impl<'a, K: 'a + Clone + Hash + Eq, V: 'a + Clone + Hash + Eq> RelIndexRead<'a> Some(res) } - fn len(&self) -> usize { self.unwrap_frozen().len() } + fn len_estimate(&self) -> usize { self.unwrap_frozen().len() } + + fn is_empty(&'a self) -> bool { self.unwrap_frozen().len() == 0 } } impl<'a, K: 'a + Clone + Hash + Eq, V: 'a + Clone + Hash + Eq + Sync> CRelIndexRead<'a> for CLatIndex { diff --git a/ascent/src/c_rel_full_index.rs b/ascent/src/c_rel_full_index.rs index 0aefd7c..84ed380 100644 --- a/ascent/src/c_rel_full_index.rs +++ b/ascent/src/c_rel_full_index.rs @@ -122,7 +122,9 @@ impl<'a, K: 'a + Clone + Hash + Eq, V: 'a> RelIndexRead<'a> for CRelFullIndex usize { self.unwrap_frozen().len() } + fn len_estimate(&self) -> usize { self.unwrap_frozen().len() } + + fn is_empty(&'a self) -> bool { self.unwrap_frozen().len() == 0 } } impl<'a, K: 'a + Clone + Hash + Eq, V: 'a + Sync> CRelIndexRead<'a> for CRelFullIndex { diff --git a/ascent/src/c_rel_index.rs b/ascent/src/c_rel_index.rs index a633397..8462870 100644 --- a/ascent/src/c_rel_index.rs +++ b/ascent/src/c_rel_index.rs @@ -130,13 +130,17 @@ impl<'a, K: 'a + Clone + Hash + Eq, V: 'a> RelIndexRead<'a> for CRelIndex Some(res) } - fn len(&self) -> usize { - // approximate len + fn len_estimate(&self) -> usize { let sample_size = 4; let shards = self.unwrap_frozen().shards(); let (count, sum) = shards.iter().take(sample_size).fold((0, 0), |(c, s), shard| (c + 1, s + shard.read().len())); sum * shards.len() / count } + + fn is_empty(&'a self) -> bool { + let shards = self.unwrap_frozen().shards(); + shards.iter().all(|s| s.read().is_empty()) + } } impl<'a, K: 'a + Clone + Hash + Eq, V: 'a + Sync> CRelIndexRead<'a> for CRelIndex { diff --git a/ascent/src/c_rel_no_index.rs b/ascent/src/c_rel_no_index.rs index d6186e5..7749dae 100644 --- a/ascent/src/c_rel_no_index.rs +++ b/ascent/src/c_rel_no_index.rs @@ -57,7 +57,9 @@ impl<'a, V: 'a> RelIndexRead<'a> for CRelNoIndex { } #[inline(always)] - fn len(&self) -> usize { 1 } + fn len_estimate(&self) -> usize { 1 } + + fn is_empty(&'a self) -> bool { false } } impl<'a, V: 'a + Sync + Send> CRelIndexRead<'a> for CRelNoIndex { @@ -92,7 +94,7 @@ impl<'a, V: 'a> RelIndexWrite for CRelNoIndex { impl<'a, V: 'a> RelIndexMerge for CRelNoIndex { fn move_index_contents(from: &mut Self, to: &mut Self) { let before = Instant::now(); - assert_eq!(from.len(), to.len()); + assert_eq!(from.len_estimate(), to.len_estimate()); // not necessary because we have a mut reference // assert!(!from.frozen); // assert!(!to.frozen); diff --git a/ascent/src/rel_index_boilerplate.rs b/ascent/src/rel_index_boilerplate.rs index 5f92f6d..1f3e2bf 100644 --- a/ascent/src/rel_index_boilerplate.rs +++ b/ascent/src/rel_index_boilerplate.rs @@ -68,7 +68,10 @@ where T: RelIndexRead<'a> fn index_get(&'a self, key: &Self::Key) -> Option { (**self).index_get(key) } #[inline(always)] - fn len(&self) -> usize { (**self).len() } + fn len_estimate(&self) -> usize { (**self).len_estimate() } + + #[inline(always)] + fn is_empty(&'a self) -> bool { (**self).is_empty() } } impl<'a, T> RelIndexReadAll<'a> for &'a T diff --git a/ascent/src/rel_index_read.rs b/ascent/src/rel_index_read.rs index cb6c2bb..9105982 100644 --- a/ascent/src/rel_index_read.rs +++ b/ascent/src/rel_index_read.rs @@ -13,7 +13,13 @@ pub trait RelIndexRead<'a> { type Value; type IteratorType: Iterator + Clone + 'a; fn index_get(&'a self, key: &Self::Key) -> Option; - fn len(&'a self) -> usize; + fn len_estimate(&'a self) -> usize; + + /// Is the relation **definitely** empty? + /// + /// It is OK for implementations to return `false` even if the relation may be empty, + /// as this is used to enable certain optimizations. + fn is_empty(&'a self) -> bool { false } } pub trait RelIndexReadAll<'a> { @@ -36,7 +42,10 @@ impl<'a, K: Eq + std::hash::Hash + 'a, V: Clone + 'a> RelIndexRead<'a> for RelIn } #[inline(always)] - fn len(&self) -> usize { Self::len(self) } + fn len_estimate(&self) -> usize { Self::len(self) } + + #[inline(always)] + fn is_empty(&'a self) -> bool { Self::is_empty(self) } } impl<'a, K: Eq + std::hash::Hash + 'a, V: 'a + Clone> RelIndexReadAll<'a> for RelIndexType1 { @@ -67,7 +76,10 @@ impl<'a, K: Eq + std::hash::Hash, V: 'a + Clone> RelIndexRead<'a> for HashBrownR } #[inline(always)] - fn len(&self) -> usize { Self::len(self) } + fn len_estimate(&self) -> usize { Self::len(self) } + + #[inline(always)] + fn is_empty(&'a self) -> bool { Self::is_empty(self) } } impl<'a, K: Eq + std::hash::Hash + 'a, V: 'a + Clone> RelIndexReadAll<'a> for HashBrownRelFullIndexType { @@ -98,7 +110,9 @@ impl<'a, K: Eq + std::hash::Hash, V: 'a + Clone> RelIndexRead<'a> for LatticeInd } #[inline(always)] - fn len(&self) -> usize { Self::len(self) } + fn len_estimate(&self) -> usize { Self::len(self) } + #[inline(always)] + fn is_empty(&'a self) -> bool { Self::is_empty(self) } } impl<'a, K: Eq + std::hash::Hash + 'a, V: 'a + Clone> RelIndexReadAll<'a> for LatticeIndexType { @@ -154,7 +168,10 @@ where } #[inline(always)] - fn len(&self) -> usize { self.ind1.len() + self.ind2.len() } + fn len_estimate(&self) -> usize { self.ind1.len_estimate() + self.ind2.len_estimate() } + + #[inline] + fn is_empty(&'a self) -> bool { self.ind1.is_empty() && self.ind2.is_empty() } } // impl <'a, Ind> RelIndexRead<'a> for RelIndexCombined<'a, Ind, Ind> diff --git a/ascent_base/src/lattice/ord_lattice.rs b/ascent_base/src/lattice/ord_lattice.rs index b28fc5b..14e832b 100644 --- a/ascent_base/src/lattice/ord_lattice.rs +++ b/ascent_base/src/lattice/ord_lattice.rs @@ -1,4 +1,4 @@ -use std::fmt::{Debug, Display, Formatter}; +use std::fmt::{Debug, Formatter}; use crate::Lattice; diff --git a/ascent_macro/src/ascent_codegen.rs b/ascent_macro/src/ascent_codegen.rs index de451ca..c14f312 100644 --- a/ascent_macro/src/ascent_codegen.rs +++ b/ascent_macro/src/ascent_codegen.rs @@ -826,7 +826,32 @@ fn compile_mir_rule(rule: &MirRule, scc: &MirScc, mir: &AscentMir) -> proc_macro } else { 0 }; - compile_mir_rule_inner(rule, scc, mir, par_iter_to_ind, head_update_code, 0) + let rule_body_clauses = rule.body_items.iter().filter_map(|bi| bi.clause()).collect_vec(); + let check_any_empty_rel_can_help = + rule_body_clauses.len() > 1 && !(rule.simple_join_start_index.is_some() && rule_body_clauses.len() == 2); + let any_empty_rel_code = check_any_empty_rel_can_help + .then(|| { + rule_body_clauses + .iter() + .map(|bclause| { + let rel_expr = expr_for_rel(&bclause.rel, mir); + quote_spanned! { bclause.rel_args_span=> #rel_expr.is_empty() } + }) + .reduce(|l, r| quote! { #l || #r}) + }) + .flatten(); + + let rule_compiled = compile_mir_rule_inner(rule, scc, mir, par_iter_to_ind, head_update_code, 0); + if let Some(any_empty_rel_code) = any_empty_rel_code { + quote! { + let any_rel_empty = #any_empty_rel_code; + if !any_rel_empty { + #rule_compiled + } + } + } else { + rule_compiled + } } fn compile_mir_rule_inner( @@ -844,20 +869,19 @@ fn compile_mir_rule_inner( let rule_cp2_compiled = compile_mir_rule_inner(&rule_cp2, _scc, mir, par_iter_to_ind, head_update_code, clause_ind); - if let [MirBodyItem::Clause(bcl1), MirBodyItem::Clause(bcl2)] = &rule.body_items[clause_ind..clause_ind + 2] { - let rel1_var_name = expr_for_rel(&bcl1.rel, mir); - let rel2_var_name = expr_for_rel(&bcl2.rel, mir); - - return quote_spanned! {bcl1.rel_args_span=> - if #rel1_var_name.len() <= #rel2_var_name.len() { - #rule_cp1_compiled - } else { - #rule_cp2_compiled - } - }; - } else { + let [MirBodyItem::Clause(bcl1), MirBodyItem::Clause(bcl2)] = &rule.body_items[clause_ind..clause_ind + 2] else { panic!("unexpected body items in reorderable rule") - } + }; + let rel1_var_name = expr_for_rel(&bcl1.rel, mir); + let rel2_var_name = expr_for_rel(&bcl2.rel, mir); + + return quote_spanned! {bcl1.rel_args_span=> + if #rel1_var_name.len_estimate() <= #rel2_var_name.len_estimate() { + #rule_cp1_compiled + } else { + #rule_cp2_compiled + } + }; } if clause_ind < rule.body_items.len() { let bitem = &rule.body_items[clause_ind]; diff --git a/ascent_macro/src/ascent_mir.rs b/ascent_macro/src/ascent_mir.rs index 14c7718..c49f079 100644 --- a/ascent_macro/src/ascent_mir.rs +++ b/ascent_macro/src/ascent_mir.rs @@ -97,6 +97,13 @@ impl MirBodyItem { } } + pub fn clause(&self) -> Option<&MirBodyClause> { + match self { + MirBodyItem::Clause(mir_body_clause) => Some(mir_body_clause), + _ => None, + } + } + pub fn bound_vars(&self) -> Vec { match self { MirBodyItem::Clause(cl) => { diff --git a/ascent_macro/src/ascent_syntax.rs b/ascent_macro/src/ascent_syntax.rs index 69e8b41..98c9add 100644 --- a/ascent_macro/src/ascent_syntax.rs +++ b/ascent_macro/src/ascent_syntax.rs @@ -598,10 +598,10 @@ pub(crate) struct DsAttributeContents { impl Parse for DsAttributeContents { fn parse(input: ParseStream) -> Result { - let path = syn::Path::parse_mod_style(&input)?; + let path = syn::Path::parse_mod_style(input)?; let args = if input.peek(Token![:]) { input.parse::()?; - TokenStream::parse(&input)? + TokenStream::parse(input)? } else { TokenStream::default() }; diff --git a/ascent_tests/src/tests.rs b/ascent_tests/src/tests.rs index 5a31c79..bf9415b 100644 --- a/ascent_tests/src/tests.rs +++ b/ascent_tests/src/tests.rs @@ -972,3 +972,23 @@ fn test_ds_attr() { assert_rels_eq!(res.bar, [(0, 1)]); } + +#[test] +fn test_rel_empty_check() { + let res = ascent_run_m_par! { + relation edge(i32, i32); + relation path(i32, i32); + relation legit(i32); + + path(x, z) <-- edge(x, y), path(y, z), legit(x); + path(x, y) <-- edge(x, y), legit(*&x); + + legit(0); + legit(y) <-- legit(x), path(x, y); + + edge(x, x + 1) <-- for x in 0..9; + }; + + println!("{:?}", res.path); + assert_eq!(res.path.len(), 9 * 10 / 2); +} diff --git a/byods/ascent-byods-rels/src/adaptor/bin_rel.rs b/byods/ascent-byods-rels/src/adaptor/bin_rel.rs index f693e7e..12dd7f1 100644 --- a/byods/ascent-byods-rels/src/adaptor/bin_rel.rs +++ b/byods/ascent-byods-rels/src/adaptor/bin_rel.rs @@ -60,7 +60,8 @@ impl<'a, TBinRel: ByodsBinRel> RelIndexRead<'a> for ByodsBinRelInd0<'a, TBinRel> Some(res) } - fn len(&'a self) -> usize { self.0.ind0_len_estimate() } + fn len_estimate(&'a self) -> usize { self.0.ind0_len_estimate() } + fn is_empty(&'a self) -> bool { self.0.is_empty() } } impl<'a, TBinRel: ByodsBinRel> RelIndexReadAll<'a> for ByodsBinRelInd0<'a, TBinRel> { @@ -99,7 +100,8 @@ impl<'a, TBinRel: ByodsBinRel> RelIndexRead<'a> for ByodsBinRelInd1<'a, TBinRel> Some(res) } - fn len(&'a self) -> usize { self.0.ind1_len_estimate() } + fn len_estimate(&'a self) -> usize { self.0.ind1_len_estimate() } + fn is_empty(&'a self) -> bool { self.0.is_empty() } } impl<'a, TBinRel: ByodsBinRel> RelIndexReadAll<'a> for ByodsBinRelInd1<'a, TBinRel> { @@ -136,7 +138,8 @@ impl<'a, TBinRel: ByodsBinRel> RelIndexRead<'a> for ByodsBinRelInd0_1<'a, TBinRe if self.0.contains(&key.0, &key.1) { Some(once(())) } else { None } } - fn len(&'a self) -> usize { self.0.len_estimate() } + fn len_estimate(&'a self) -> usize { self.0.len_estimate() } + fn is_empty(&'a self) -> bool { self.0.is_empty() } } impl<'a, TBinRel: ByodsBinRel> RelIndexReadAll<'a> for ByodsBinRelInd0_1<'a, TBinRel> { @@ -200,7 +203,7 @@ impl<'a, TBinRel: ByodsBinRel> RelIndexRead<'a> for ByodsBinRelIndNone<'a, TBinR Some(IteratorFromDyn::new(res)) } - fn len(&'a self) -> usize { 1 } + fn len_estimate(&'a self) -> usize { 1 } } impl<'a, TBinRel: ByodsBinRel> RelIndexReadAll<'a> for ByodsBinRelIndNone<'a, TBinRel> { diff --git a/byods/ascent-byods-rels/src/adaptor/bin_rel_to_ternary.rs b/byods/ascent-byods-rels/src/adaptor/bin_rel_to_ternary.rs index 768c544..a547df1 100644 --- a/byods/ascent-byods-rels/src/adaptor/bin_rel_to_ternary.rs +++ b/byods/ascent-byods-rels/src/adaptor/bin_rel_to_ternary.rs @@ -131,11 +131,12 @@ where Some(IteratorFromDyn::new(|| trrel.iter_all())) } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 4; let sum = self.0.map.values().map(|x| x.len_estimate()).sum::(); sum * self.0.map.len() / sample_size.min(self.0.map.len()).max(1) } + fn is_empty(&'a self) -> bool { self.0.map.is_empty() } } pub struct BinRelToTernaryInd0_1<'a, T0, T1, T2, TBinRel>(&'a BinRelToTernary) @@ -189,12 +190,13 @@ where Some(res) } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 3; let sum = self.0.map.values().take(sample_size).map(|trrel| trrel.ind0_len_estimate()).sum::(); let map_len = self.0.map.len(); sum * map_len / sample_size.min(map_len).max(1) } + fn is_empty(&'a self) -> bool { self.0.map.is_empty() } } pub struct BinRelToTernaryInd0_2<'a, T0, T1, T2, TBinRel>(&'a BinRelToTernary) @@ -248,12 +250,13 @@ where Some(res) } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 3; let sum = self.0.map.values().take(sample_size).map(|trrel| trrel.ind1_len_estimate()).sum::(); let map_len = self.0.map.len(); sum * map_len / sample_size.min(map_len).max(1) } + fn is_empty(&'a self) -> bool { self.0.map.is_empty() } } pub struct BinRelToTernaryInd1<'a, T0, T1, T2, TBinRel>(&'a BinRelToTernary) @@ -314,7 +317,8 @@ where fn index_get(&'a self, (x1,): &Self::Key) -> Option { self.get(x1) } - fn len(&self) -> usize { self.0.reverse_map1.as_ref().unwrap().len() } + fn len_estimate(&self) -> usize { self.0.reverse_map1.as_ref().unwrap().len() } + fn is_empty(&'a self) -> bool { self.0.reverse_map1.as_ref().unwrap().is_empty() } } pub struct BinRelToTernaryInd2<'a, T0, T1, T2, TBinRel>(&'a BinRelToTernary) @@ -374,7 +378,8 @@ where fn index_get(&'a self, (x2,): &Self::Key) -> Option { self.get(x2) } - fn len(&self) -> usize { self.0.reverse_map2.as_ref().unwrap().len() } + fn len_estimate(&self) -> usize { self.0.reverse_map2.as_ref().unwrap().len() } + fn is_empty(&'a self) -> bool { self.0.reverse_map2.as_ref().unwrap().is_empty() } } pub struct BinRelToTernaryInd1_2<'a, T0, T1, T2, TBinRel>(&'a BinRelToTernary) @@ -433,7 +438,7 @@ where Some(IteratorFromDyn::new(res)) } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { // TODO random estimate, could be very wrong self.0.reverse_map1.as_ref().unwrap().len() * self.0.reverse_map2.as_ref().unwrap().len() / ((self.0.map.len() as f32).sqrt() as usize) @@ -480,7 +485,7 @@ where Some(IteratorFromDyn::new(res)) } - fn len(&self) -> usize { 1 } + fn len_estimate(&self) -> usize { 1 } } pub struct BinRelToTernaryInd0_1_2<'a, T0, T1, T2, TBinRel>(&'a BinRelToTernary) @@ -544,12 +549,13 @@ where if self.0.map.get(x0)?.contains(x1, x2) { Some(once(())) } else { None } } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 3; let sum = self.0.map.values().take(sample_size).map(|rel| rel.len_estimate()).sum::(); let map_len = self.0.map.len(); sum * map_len / sample_size.min(map_len).max(1) } + fn is_empty(&'a self) -> bool { self.0.map.is_empty() } } pub struct BinRelToTernaryInd0_1_2Write<'a, T0, T1, T2, TBinRel>(&'a mut BinRelToTernary) diff --git a/byods/ascent-byods-rels/src/binary_rel.rs b/byods/ascent-byods-rels/src/binary_rel.rs index 8e682c5..0525c05 100644 --- a/byods/ascent-byods-rels/src/binary_rel.rs +++ b/byods/ascent-byods-rels/src/binary_rel.rs @@ -116,7 +116,8 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for MapRelIndexAdaptor<'a, T> { Some(res) } - fn len(&'a self) -> usize { self.0.len() } + fn len_estimate(&'a self) -> usize { self.0.len() } + fn is_empty(&'a self) -> bool { self.0.is_empty() } } pub struct RelIndexValTransformer { @@ -143,7 +144,8 @@ where Some(res) } - fn len(&'a self) -> usize { self.rel.len() } + fn len_estimate(&'a self) -> usize { self.rel.len_estimate() } + fn is_empty(&'a self) -> bool { self.rel.is_empty() } } impl<'a, T: 'a, F: 'a, V: 'a, U: 'a> RelIndexReadAll<'a> for RelIndexValTransformer diff --git a/byods/ascent-byods-rels/src/ceqrel_ind.rs b/byods/ascent-byods-rels/src/ceqrel_ind.rs index 1e9c5b8..6c6449f 100644 --- a/byods/ascent-byods-rels/src/ceqrel_ind.rs +++ b/byods/ascent-byods-rels/src/ceqrel_ind.rs @@ -130,7 +130,7 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for EqRelInd0_1<'a, T> { fn index_get(&'a self, key: &Self::Key) -> Option { self.0.index_get(key) } - fn len(&self) -> usize { self.0.len() } + fn len_estimate(&self) -> usize { self.0.len_estimate() } } impl<'a, T: Clone + Hash + Eq + Sync> CRelIndexRead<'a> for EqRelInd0_1<'a, T> { @@ -199,7 +199,7 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for EqRelInd0<'a, T> { Some(IteratorFromDyn::new(producer)) } - fn len(&self) -> usize { self.0.unwrap_frozen().combined.elem_ids.len() } + fn len_estimate(&self) -> usize { self.0.unwrap_frozen().combined.elem_ids.len() } } impl<'a, T: Clone + Hash + Eq + Sync> CRelIndexRead<'a> for EqRelInd0<'a, T> { @@ -430,7 +430,7 @@ impl<'a, T: Clone + Hash + Eq + 'a> RelIndexRead<'a> for CEqRelIndCommon { if self_.combined.contains(x, y) && !self_.old.contains(x, y) { Some(std::iter::once(())) } else { None } } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let self_ = self.unwrap_frozen(); let sample_size = 3; let sum: usize = self_.combined.sets.iter().take(sample_size).map(|s| s.len().pow(2)).sum(); @@ -540,7 +540,7 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for EqRelIndNone<'a, T> { Some(IteratorFromDyn::new(|| self.0.iter_all_added())) } - fn len(&self) -> usize { 1 } + fn len_estimate(&self) -> usize { 1 } } impl<'a, T: Clone + Hash + Eq + Sync> CRelIndexRead<'a> for EqRelIndNone<'a, T> { diff --git a/byods/ascent-byods-rels/src/eqrel_ind.rs b/byods/ascent-byods-rels/src/eqrel_ind.rs index f3180df..ee5ded0 100644 --- a/byods/ascent-byods-rels/src/eqrel_ind.rs +++ b/byods/ascent-byods-rels/src/eqrel_ind.rs @@ -124,7 +124,7 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for EqRelInd0_1<'a, T> { fn index_get(&'a self, key: &Self::Key) -> Option { self.0.index_get(key) } - fn len(&self) -> usize { self.0.len() } + fn len_estimate(&self) -> usize { self.0.len_estimate() } } impl<'a, T: Clone + Hash + Eq> RelIndexReadAll<'a> for EqRelInd0_1<'a, T> { @@ -168,7 +168,7 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for EqRelInd0<'a, T> { Some(IteratorFromDyn::new(producer)) } - fn len(&self) -> usize { self.0.combined.elem_ids.len() } + fn len_estimate(&self) -> usize { self.0.combined.elem_ids.len() } } impl<'a, T: Clone + Hash + Eq> RelIndexReadAll<'a> for EqRelInd0<'a, T> { @@ -259,7 +259,7 @@ impl<'a, T: Clone + Hash + Eq + 'a> RelIndexRead<'a> for EqRelIndCommon { if self.combined.contains(x, y) && !self.old.contains(x, y) { Some(std::iter::once(())) } else { None } } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 3; let sum: usize = self.combined.sets.iter().take(sample_size).map(|s| s.len().pow(2)).sum(); let sets_len = self.combined.sets.len(); @@ -320,7 +320,7 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for EqRelIndNone<'a, T> { Some(IteratorFromDyn::new(|| self.0.iter_all_added())) } - fn len(&self) -> usize { 1 } + fn len_estimate(&self) -> usize { 1 } } impl<'a, T: Clone + Hash + Eq> RelIndexReadAll<'a> for EqRelIndNone<'a, T> { diff --git a/byods/ascent-byods-rels/src/eqrel_ternary.rs b/byods/ascent-byods-rels/src/eqrel_ternary.rs index beaef4d..8d4c15f 100644 --- a/byods/ascent-byods-rels/src/eqrel_ternary.rs +++ b/byods/ascent-byods-rels/src/eqrel_ternary.rs @@ -224,7 +224,7 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for EqRe Some(IteratorFromDyn::new(producer)) } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 4; let (count, sum) = self .0 @@ -288,7 +288,7 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for EqRe Some(IteratorFromDyn::new(|| eqrel.iter_all_added())) } - fn len(&self) -> usize { self.0.map.len() } + fn len_estimate(&self) -> usize { self.0.map.len() } } pub struct EqRel2Ind1<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq>(&'a EqRel2IndCommon); @@ -331,7 +331,7 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for EqRe Some(IteratorFromDyn::new(res)) } - fn len(&self) -> usize { self.0.reverse_map.as_ref().unwrap().len() } + fn len_estimate(&self) -> usize { self.0.reverse_map.as_ref().unwrap().len() } } pub struct EqRel2Ind1_2<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq>(&'a EqRel2IndCommon); @@ -382,9 +382,9 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for EqRe Some(IteratorFromDyn::new(res)) } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 4; - let sum = self.0.map.values().take(sample_size).map(|eqrel| eqrel.len()).sum::(); + let sum = self.0.map.values().take(sample_size).map(|eqrel| eqrel.len_estimate()).sum::(); let map_len = self.0.map.len(); sum / sample_size.min(map_len).max(1) } @@ -442,9 +442,9 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for EqRe if self.contains_key(key) { Some(std::iter::once(&())) } else { None } } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 4; - let sum = self.0.map.values().take(sample_size).map(|eqrel| eqrel.len()).sum::(); + let sum = self.0.map.values().take(sample_size).map(|eqrel| eqrel.len_estimate()).sum::(); let map_len = self.0.map.len(); sum * map_len / sample_size.min(map_len).max(1) } @@ -480,7 +480,7 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for EqRe Some(IteratorFromDyn::new(|| self.0.iter_all_added())) } - fn len(&self) -> usize { 1 } + fn len_estimate(&self) -> usize { 1 } } macro_rules! to_eq_rel2 { diff --git a/byods/ascent-byods-rels/src/trrel_binary_ind.rs b/byods/ascent-byods-rels/src/trrel_binary_ind.rs index b3fd57d..cc80b4a 100644 --- a/byods/ascent-byods-rels/src/trrel_binary_ind.rs +++ b/byods/ascent-byods-rels/src/trrel_binary_ind.rs @@ -317,7 +317,8 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for TrRelInd0<'a, T> { Some(res) } - fn len(&self) -> usize { self.0.unwrap_old().map.len() } + fn len_estimate(&self) -> usize { self.0.unwrap_old().map.len() } + fn is_empty(&'a self) -> bool { self.0.unwrap_old().map.is_empty() } } pub struct TrRelInd1<'a, T: Clone + Hash + Eq>(pub(crate) &'a TrRelIndCommon); @@ -353,7 +354,8 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for TrRelInd1<'a, T> { Some(res) } - fn len(&self) -> usize { self.0.rel().reverse_map.len() } + fn len_estimate(&self) -> usize { self.0.rel().reverse_map.len() } + fn is_empty(&'a self) -> bool { self.0.rel().reverse_map.is_empty() } } pub struct TrRelIndNone<'a, T: Clone + Hash + Eq>(&'a TrRelIndCommon); @@ -381,7 +383,7 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for TrRelIndNone<'a, T> { Some(IteratorFromDyn::new(res)) } - fn len(&self) -> usize { 1 } + fn len_estimate(&self) -> usize { 1 } } pub struct TrRelIndFullWrite<'a, T: Clone + Hash + Eq>(&'a mut TrRelIndCommon); @@ -443,12 +445,14 @@ impl<'a, T: Clone + Hash + Eq> RelIndexRead<'a> for TrRelIndFull<'a, T> { if self.0.rel().map.get(&key.0)?.contains(&key.1) { Some(std::iter::once(())) } else { None } } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 3; let sum: usize = self.0.rel().map.values().take(sample_size).map(|x| x.len()).sum(); let map_len = self.0.rel().map.len(); sum * map_len / sample_size.min(map_len).max(1) } + + fn is_empty(&'a self) -> bool { self.0.rel().map.is_empty() } } macro_rules! to_rel_ind { diff --git a/byods/ascent-byods-rels/src/trrel_ternary_ind.rs b/byods/ascent-byods-rels/src/trrel_ternary_ind.rs index 6802c9e..b6709e2 100644 --- a/byods/ascent-byods-rels/src/trrel_ternary_ind.rs +++ b/byods/ascent-byods-rels/src/trrel_ternary_ind.rs @@ -146,11 +146,12 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for TrRe Some(IteratorFromDyn::new(|| trrel.rel().iter_all())) } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 4; let sum = self.0.map.values().map(|x| x.rel().count_estimate()).sum::(); sum * self.0.map.len() / sample_size.min(self.0.map.len()).max(1) } + fn is_empty(&'a self) -> bool { self.0.map.is_empty() } } pub struct TrRel2Ind0_1<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq>(&'a TrRel2IndCommon); @@ -187,12 +188,13 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for TrRe Some(res) } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 3; - let sum = self.0.map.values().take(sample_size).map(|trrel| TrRelInd0(&trrel).len()).sum::(); + let sum = self.0.map.values().take(sample_size).map(|trrel| TrRelInd0(&trrel).len_estimate()).sum::(); let map_len = self.0.map.len(); sum * map_len / sample_size.min(map_len).max(1) } + fn is_empty(&'a self) -> bool { self.0.map.is_empty() } } pub struct TrRel2Ind0_2<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq>(&'a TrRel2IndCommon); @@ -226,12 +228,13 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for TrRe Some(res) } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 3; - let sum = self.0.map.values().take(sample_size).map(|trrel| TrRelInd1(&trrel).len()).sum::(); + let sum = self.0.map.values().take(sample_size).map(|trrel| TrRelInd1(&trrel).len_estimate()).sum::(); let map_len = self.0.map.len(); sum * map_len / sample_size.min(map_len).max(1) } + fn is_empty(&'a self) -> bool { self.0.map.is_empty() } } pub struct TrRel2Ind1<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq>(&'a TrRel2IndCommon); @@ -269,7 +272,8 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for TrRe fn index_get(&'a self, (x1,): &Self::Key) -> Option { self.get(x1) } - fn len(&self) -> usize { self.0.reverse_map1.as_ref().unwrap().len() } + fn len_estimate(&self) -> usize { self.0.reverse_map1.as_ref().unwrap().len() } + fn is_empty(&'a self) -> bool { self.0.reverse_map1.as_ref().unwrap().is_empty() } } pub struct TrRel2Ind2<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq>(&'a TrRel2IndCommon); @@ -306,7 +310,8 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for TrRe fn index_get(&'a self, (x2,): &Self::Key) -> Option { self.get(x2) } - fn len(&self) -> usize { self.0.reverse_map2.as_ref().unwrap().len() } + fn len_estimate(&self) -> usize { self.0.reverse_map2.as_ref().unwrap().len() } + fn is_empty(&'a self) -> bool { self.0.reverse_map2.as_ref().unwrap().is_empty() } } pub struct TrRel2Ind1_2<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq>(&'a TrRel2IndCommon); @@ -349,7 +354,7 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for TrRe Some(IteratorFromDyn::new(res)) } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { // TODO random estimate, could be very wrong self.0.reverse_map1.as_ref().unwrap().len() * self.0.reverse_map2.as_ref().unwrap().len() / ((self.0.map.len() as f32).sqrt() as usize) @@ -379,7 +384,7 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for TrRe Some(IteratorFromDyn::new(res)) } - fn len(&self) -> usize { 1 } + fn len_estimate(&self) -> usize { 1 } } #[repr(transparent)] @@ -421,12 +426,13 @@ impl<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq> RelIndexRead<'a> for TrRe if self.0.map.get(x0)?.rel().contains(x1, x2) { Some(once(())) } else { None } } - fn len(&self) -> usize { + fn len_estimate(&self) -> usize { let sample_size = 3; let sum = self.0.map.values().take(sample_size).map(|trrel| trrel.rel().count_estimate()).sum::(); let map_len = self.0.map.len(); sum * map_len / sample_size.min(map_len).max(1) } + fn is_empty(&'a self) -> bool { self.0.map.is_empty() } } pub struct TrRel2IndFullWrite<'a, T0: Clone + Hash + Eq, T1: Clone + Hash + Eq>(&'a mut TrRel2IndCommon); diff --git a/byods/ascent-byods-rels/src/trrel_union_find_binary_ind.rs b/byods/ascent-byods-rels/src/trrel_union_find_binary_ind.rs index a0f42ef..6862c76 100644 --- a/byods/ascent-byods-rels/src/trrel_union_find_binary_ind.rs +++ b/byods/ascent-byods-rels/src/trrel_union_find_binary_ind.rs @@ -233,7 +233,7 @@ impl RelIndexMerge for TrRelIndCommon { Rel1::ValueIteratorType: Clone, { let mut changed = false; - if rel1.len() < rel2_rev.len() { + if rel1.len_estimate() < rel2_rev.len_estimate() { for (x, x_set) in rel1.iter_all() { if let Some(x_rev_set) = rel2_rev.index_get(x) { for w in x_rev_set {