Returns `(signature, frequency)` pairs sorted by frequency descending, filtered to those whose frequency exceeds `stable_fraction_threshold`. Frequency is the fraction of total log entries contributed by that predicate. Returns an empty Vec if the log is empty.
(&self)
| 49 | /// Frequency is the fraction of total log entries contributed by that |
| 50 | /// predicate. Returns an empty Vec if the log is empty. |
| 51 | pub fn stable_predicates(&self) -> Vec<(PredicateSignature, f32)> { |
| 52 | if self.log.is_empty() { |
| 53 | return Vec::new(); |
| 54 | } |
| 55 | |
| 56 | let total = self.log.len() as f32; |
| 57 | let mut counts: HashMap<&str, usize> = HashMap::new(); |
| 58 | for record in &self.log { |
| 59 | *counts |
| 60 | .entry(record.predicate_signature.as_str()) |
| 61 | .or_insert(0) += 1; |
| 62 | } |
| 63 | |
| 64 | let mut result: Vec<(PredicateSignature, f32)> = counts |
| 65 | .into_iter() |
| 66 | .filter_map(|(sig, count)| { |
| 67 | let freq = count as f32 / total; |
| 68 | if freq >= self.stable_fraction_threshold { |
| 69 | Some((sig.to_owned(), freq)) |
| 70 | } else { |
| 71 | None |
| 72 | } |
| 73 | }) |
| 74 | .collect(); |
| 75 | |
| 76 | result.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal)); |
| 77 | result |
| 78 | } |
| 79 | |
| 80 | /// Rough 3D cost model for a candidate subindex. |
| 81 | /// |