vortex_array/expr/analysis/
labeling.rs1use vortex_error::VortexExpect;
5use vortex_error::VortexResult;
6use vortex_utils::aliases::hash_map::HashMap;
7
8use crate::expr::BoundExpression;
9use crate::expr::ExactBoundExpr;
10use crate::expr::traversal::NodeExt;
11use crate::expr::traversal::NodeVisitor;
12use crate::expr::traversal::TraversalOrder;
13
14pub type BoundLabels<L> = HashMap<ExactBoundExpr, L>;
16
17pub fn label_bound_tree<L: Clone>(
21 expr: &BoundExpression,
22 self_label: impl Fn(&BoundExpression) -> L,
23 mut merge_child: impl FnMut(L, &L) -> L,
24) -> BoundLabels<L> {
25 let mut visitor = BoundLabelingVisitor {
26 labels: Default::default(),
27 self_label,
28 merge_child: &mut merge_child,
29 };
30 expr.accept(&mut visitor)
31 .vortex_expect("BoundLabelingVisitor is infallible");
32 visitor.labels
33}
34
35struct BoundLabelingVisitor<'a, L, F, G>
36where
37 F: Fn(&BoundExpression) -> L,
38 G: FnMut(L, &L) -> L,
39{
40 labels: BoundLabels<L>,
41 self_label: F,
42 merge_child: &'a mut G,
43}
44
45impl<'node, 'visitor, L: Clone, F, G> NodeVisitor<'node> for BoundLabelingVisitor<'visitor, L, F, G>
46where
47 F: Fn(&BoundExpression) -> L,
48 G: FnMut(L, &L) -> L,
49{
50 type NodeTy = BoundExpression;
51
52 fn visit_down(&mut self, _node: &'node Self::NodeTy) -> VortexResult<TraversalOrder> {
53 Ok(TraversalOrder::Continue)
54 }
55
56 fn visit_up(&mut self, node: &'node Self::NodeTy) -> VortexResult<TraversalOrder> {
57 let self_label = (self.self_label)(node);
58 let final_label = node.children().iter().fold(self_label, |acc, child| {
59 let child_label = self
60 .labels
61 .get(&ExactBoundExpr(child.clone()))
62 .vortex_expect("child must have label");
63 (self.merge_child)(acc, child_label)
64 });
65 self.labels
66 .insert(ExactBoundExpr(node.clone()), final_label);
67 Ok(TraversalOrder::Continue)
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use crate::expr::col;
75 use crate::expr::eq;
76 use crate::expr::lit;
77 use crate::expr::test_harness::struct_dtype;
78
79 #[test]
80 fn test_tree_depth() -> VortexResult<()> {
81 let expr = eq(col("col1"), lit(5u16)).bind(&struct_dtype())?;
85 let depths = label_bound_tree(
86 &expr,
87 |_node| 1, |self_depth, child_depth| self_depth.max(*child_depth + 1),
89 );
90
91 assert_eq!(depths.get(&ExactBoundExpr(expr)), Some(&3));
93 Ok(())
94 }
95
96 #[test]
97 fn test_node_count() -> VortexResult<()> {
98 let expr = eq(col("col1"), lit(5u16)).bind(&struct_dtype())?;
102 let counts = label_bound_tree(
103 &expr,
104 |_node| 1, |self_count, child_count| self_count + *child_count,
106 );
107
108 assert_eq!(counts.get(&ExactBoundExpr(expr)), Some(&4));
110 Ok(())
111 }
112}