Skip to content

Commit 3e6f139

Browse files
committed
wip
Signed-off-by: Joe Isaacs <[email protected]>
1 parent ebfa42d commit 3e6f139

File tree

5 files changed

+15
-77
lines changed

5 files changed

+15
-77
lines changed

vortex-array/src/expr/analysis/annotation_union_set.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ pub type Annotations<'a, A> = HashMap<&'a Expression, HashSet<A>>;
3535
///
3636
/// Returns a map of each expression to all annotations that any of its descendent (child)
3737
/// expressions are annotated with.
38-
///
39-
/// This "skip" behavior makes this function different from [`label_tree`], which always
40-
/// visits all nodes. Use this when you want to find the "shallowest" matches in a tree.
41-
///
42-
/// Note: This cannot use [`label_tree`] because the early termination (skip) requires
43-
/// conditional traversal based on the node's direct annotations.
4438
pub fn descendent_annotation_union_set<A: AnnotationFn>(
4539
expr: &Expression,
4640
annotate: A,

vortex-array/src/expr/analysis/labeling.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,12 @@ where
8484
type NodeTy = Expression;
8585

8686
fn visit_down(&mut self, _node: &'a Self::NodeTy) -> VortexResult<TraversalOrder> {
87-
// Continue traversing down
8887
Ok(TraversalOrder::Continue)
8988
}
9089

9190
fn visit_up(&mut self, node: &'a Expression) -> VortexResult<TraversalOrder> {
92-
// Compute self-label for this node
9391
let self_label = (self.label_edge)(node);
9492

95-
// Fold all child labels into the self label
9693
let final_label = node.children().iter().fold(self_label, |acc, child| {
9794
let child_label = self
9895
.labels

vortex-array/src/expr/analysis/null_sensitive.rs

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,16 @@ use vortex_utils::aliases::hash_map::HashMap;
66
use super::labeling::label_tree;
77
use crate::expr::Expression;
88

9-
/// Tracks whether an expression is null-sensitive.
10-
///
11-
/// An expression is null-sensitive if it or any of its children is an `is_null` operation.
12-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13-
pub enum NullSensitive {
14-
/// The expression or one of its children contains an `is_null` operation.
15-
Yes,
16-
/// The expression and all of its children do not contain an `is_null` operation.
17-
No,
18-
}
19-
20-
impl NullSensitive {
21-
/// Combine two null sensitivity labels.
22-
///
23-
/// Returns `Yes` if either label is `Yes`, otherwise `No`.
24-
pub fn combine(self, other: Self) -> Self {
25-
match (self, other) {
26-
(NullSensitive::Yes, _) | (_, NullSensitive::Yes) => NullSensitive::Yes,
27-
(NullSensitive::No, NullSensitive::No) => NullSensitive::No,
28-
}
29-
}
30-
}
31-
329
pub type NullSensitiveLabels<'a> = HashMap<&'a Expression, bool>;
3310

3411
/// Label each expression in the tree with whether it is null-sensitive.
3512
///
36-
/// An expression is null-sensitive if it or any of its descendants contain an `is_null` operation.
37-
///
38-
/// This function demonstrates the use of the general [`label_tree`] framework with:
39-
/// - **Label Edge**: Check if the node itself is null-sensitive using [`Expression::is_null_sensitive`]
40-
/// - **Merge Child**: Fold children labels with OR operation
13+
/// See [`VTable::is_null_sensitive`] for a definition of null sensitivity.
14+
/// This function operates on a tree of expressions, not just a single expression.
4115
pub fn label_null_sensitive(expr: &Expression) -> NullSensitiveLabels<'_> {
4216
label_tree(
4317
expr,
44-
// Label edge: check if this node itself is null-sensitive
4518
|expr| expr.is_null_sensitive(),
46-
// Merge child: fold children with OR (true if self OR any child is true)
4719
|acc, &child| acc | child,
4820
)
4921
}
@@ -90,24 +62,4 @@ mod tests {
9062
assert_eq!(labels.get(&right), Some(&true));
9163
assert_eq!(labels.get(&expr), Some(&true));
9264
}
93-
94-
#[test]
95-
fn test_combine() {
96-
assert_eq!(
97-
NullSensitive::Yes.combine(NullSensitive::Yes),
98-
NullSensitive::Yes
99-
);
100-
assert_eq!(
101-
NullSensitive::Yes.combine(NullSensitive::No),
102-
NullSensitive::Yes
103-
);
104-
assert_eq!(
105-
NullSensitive::No.combine(NullSensitive::Yes),
106-
NullSensitive::Yes
107-
);
108-
assert_eq!(
109-
NullSensitive::No.combine(NullSensitive::No),
110-
NullSensitive::No
111-
);
112-
}
11365
}

vortex-array/src/expr/expression.rs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -233,21 +233,7 @@ impl Expression {
233233
}
234234

235235
/// Returns whether this expression itself is null-sensitive.
236-
///
237-
/// An expression is null-sensitive if it directly operates on null values,
238-
/// such as `is_null`. Most expressions are not null-sensitive.
239-
///
240-
/// The property we are interested in is if the expression (e) distributes over
241-
/// mask.
242-
/// Define a `mask(a, m)` expression that applies the boolean array `m` to the validity of the
243-
/// array `a`.
244-
/// An unary expression `e` to be null-sensitive iff forall arrays `a` and masks `m`.
245-
/// `e(mask(a, m)) == mask(e(a), m)`.
246-
/// This can be extended to an n-ary expression.
247-
///
248-
/// This method only checks the expression itself, not its children. To check
249-
/// if an expression or any of its descendants are null-sensitive, use the
250-
/// [`crate::expr::analysis::label_null_sensitive`] function.
236+
/// See [`VTable::is_null_sensitive`].
251237
pub fn is_null_sensitive(&self) -> bool {
252238
self.vtable.as_dyn().is_null_sensitive(self.data.as_ref())
253239
}

vortex-array/src/expr/vtable.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,21 @@ pub trait VTable: 'static + Sized + Send + Sync {
114114
None
115115
}
116116

117-
/// Returns whether this expression itself is null-sensitive. Default to *true*.
117+
/// Returns whether this expression itself is null-sensitive. Conservatively default to *true*.
118118
///
119119
/// An expression is null-sensitive if it directly operates on null values,
120-
/// such as `is_null`. We must conservatively assume that all expression are null-sensitive.
120+
/// such as `is_null`. Most expressions are not null-sensitive.
121121
///
122-
/// This must only account for the expression itself being null-sensitive, not its children.
122+
/// The property we are interested in is if the expression (e) distributes over
123+
/// mask.
124+
/// Define a `mask(a, m)` expression that applies the boolean array `m` to the validity of the
125+
/// array `a`.
126+
/// An unary expression `e` to be null-sensitive iff forall arrays `a` and masks `m`.
127+
/// `e(mask(a, m)) == mask(e(a), m)`.
128+
/// This can be extended to an n-ary expression.
129+
///
130+
/// This method only checks the expression itself, not its children. To check
131+
/// if an expression or any of its descendants are null-sensitive.
123132
fn is_null_sensitive(&self, _instance: &Self::Instance) -> bool {
124133
true
125134
}

0 commit comments

Comments
 (0)