vortex_array/expr/analysis/
labeling.rs1use std::hash::Hash;
5
6use vortex_error::VortexExpect;
7use vortex_error::VortexResult;
8use vortex_utils::aliases::hash_map::HashMap;
9
10use crate::expr::BoundExpression;
11use crate::expr::ExactBoundExpr;
12use crate::expr::Expression;
13use crate::expr::traversal::Node;
14use crate::expr::traversal::NodeExt;
15use crate::expr::traversal::NodeVisitor;
16use crate::expr::traversal::TraversalOrder;
17
18pub type BooleanLabels<'a, N = Expression> = HashMap<&'a N, bool>;
20
21pub type BoundLabels<L> = HashMap<ExactBoundExpr, L>;
23
24pub fn label_tree<N, L: Clone>(
44 expr: &N,
45 self_label: impl Fn(&N) -> L,
46 mut merge_child: impl FnMut(L, &L) -> L,
47) -> HashMap<&N, L>
48where
49 N: Node + Eq + Hash,
50{
51 let mut visitor = LabelingVisitor {
52 labels: Default::default(),
53 self_label,
54 merge_child: &mut merge_child,
55 };
56 expr.accept(&mut visitor)
57 .vortex_expect("LabelingVisitor is infallible");
58 visitor.labels
59}
60
61pub fn label_bound_tree<L: Clone>(
65 expr: &BoundExpression,
66 self_label: impl Fn(&BoundExpression) -> L,
67 mut merge_child: impl FnMut(L, &L) -> L,
68) -> BoundLabels<L> {
69 let mut visitor = BoundLabelingVisitor {
70 labels: Default::default(),
71 self_label,
72 merge_child: &mut merge_child,
73 };
74 expr.accept(&mut visitor)
75 .vortex_expect("BoundLabelingVisitor is infallible");
76 visitor.labels
77}
78
79struct LabelingVisitor<'a, 'b, N, L, F, G>
80where
81 N: Node + Eq + Hash,
82 F: Fn(&N) -> L,
83 G: FnMut(L, &L) -> L,
84{
85 labels: HashMap<&'a N, L>,
86 self_label: F,
87 merge_child: &'b mut G,
88}
89
90impl<'a, 'b, N, L: Clone, F, G> NodeVisitor<'a> for LabelingVisitor<'a, 'b, N, L, F, G>
91where
92 N: Node + Eq + Hash,
93 F: Fn(&N) -> L,
94 G: FnMut(L, &L) -> L,
95{
96 type NodeTy = N;
97
98 fn visit_down(&mut self, _node: &'a Self::NodeTy) -> VortexResult<TraversalOrder> {
99 Ok(TraversalOrder::Continue)
100 }
101
102 fn visit_up(&mut self, node: &'a N) -> VortexResult<TraversalOrder> {
103 let self_label = (self.self_label)(node);
104
105 let final_label = node.iter_children(|children| {
106 children.fold(self_label, |acc, child| {
107 let child_label = self
108 .labels
109 .get(child)
110 .vortex_expect("child must have label");
111 (self.merge_child)(acc, child_label)
112 })
113 });
114
115 self.labels.insert(node, final_label);
116
117 Ok(TraversalOrder::Continue)
118 }
119}
120
121struct BoundLabelingVisitor<'a, L, F, G>
122where
123 F: Fn(&BoundExpression) -> L,
124 G: FnMut(L, &L) -> L,
125{
126 labels: BoundLabels<L>,
127 self_label: F,
128 merge_child: &'a mut G,
129}
130
131impl<'node, 'visitor, L: Clone, F, G> NodeVisitor<'node> for BoundLabelingVisitor<'visitor, L, F, G>
132where
133 F: Fn(&BoundExpression) -> L,
134 G: FnMut(L, &L) -> L,
135{
136 type NodeTy = BoundExpression;
137
138 fn visit_down(&mut self, _node: &'node Self::NodeTy) -> VortexResult<TraversalOrder> {
139 Ok(TraversalOrder::Continue)
140 }
141
142 fn visit_up(&mut self, node: &'node Self::NodeTy) -> VortexResult<TraversalOrder> {
143 let self_label = (self.self_label)(node);
144 let final_label = node.children().iter().fold(self_label, |acc, child| {
145 let child_label = self
146 .labels
147 .get(&ExactBoundExpr(child.clone()))
148 .vortex_expect("child must have label");
149 (self.merge_child)(acc, child_label)
150 });
151 self.labels
152 .insert(ExactBoundExpr(node.clone()), final_label);
153 Ok(TraversalOrder::Continue)
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160 use crate::expr::col;
161 use crate::expr::eq;
162 use crate::expr::lit;
163
164 #[test]
165 fn test_tree_depth() {
166 let expr = eq(col("col1"), lit(5));
170 let depths = label_tree(
171 &expr,
172 |_node| 1, |self_depth, child_depth| self_depth.max(*child_depth + 1),
174 );
175
176 assert_eq!(depths.get(&expr), Some(&3));
178 }
179
180 #[test]
181 fn test_node_count() {
182 let expr = eq(col("col1"), lit(5));
186 let counts = label_tree(
187 &expr,
188 |_node| 1, |self_count, child_count| self_count + *child_count,
190 );
191
192 assert_eq!(counts.get(&expr), Some(&4));
194 }
195}