Skip to content

Commit 4293838

Browse files
committed
Remove legacy stat falsification hooks
Signed-off-by: Nicholas Gates <nick@nickgates.com>
1 parent 52fd443 commit 4293838

13 files changed

Lines changed: 9 additions & 447 deletions

File tree

vortex-array/src/expr/expression.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -114,28 +114,6 @@ impl Expression {
114114
self.scalar_fn.validity(self)
115115
}
116116

117-
/// An expression over zone-statistics which implies all records in the zone evaluate to false.
118-
///
119-
/// Given an expression, `e`, if `e.stat_falsification(..)` evaluates to true, it is guaranteed
120-
/// that `e` evaluates to false on all records in the zone. However, the inverse is not
121-
/// necessarily true: even if the falsification evaluates to false, `e` need not evaluate to
122-
/// true on all records.
123-
///
124-
/// The [`StatsCatalog`] can be used to constrain or rename stats used in the final expr.
125-
///
126-
/// # Examples
127-
///
128-
/// - An expression over one variable: `x > 0` is false for all records in a zone if the maximum
129-
/// value of the column `x` in that zone is less than or equal to zero: `max(x) <= 0`.
130-
/// - An expression over two variables: `x > y` becomes `max(x) <= min(y)`.
131-
/// - A conjunctive expression: `x > y AND z < x` becomes `max(x) <= min(y) OR min(z) >= max(x).
132-
///
133-
/// Some expressions, in theory, have falsifications but this function does not support them
134-
/// such as `x < (y < z)` or `x LIKE "needle%"`.
135-
pub fn stat_falsification(&self, catalog: &dyn StatsCatalog) -> Option<Expression> {
136-
self.scalar_fn().stat_falsification(self, catalog)
137-
}
138-
139117
/// Returns an expression that proves this predicate is definitely false from stats.
140118
///
141119
/// `scope` is the dtype of the row this expression evaluates over.

vortex-array/src/expr/pruning/pruning_expr.rs

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4-
#[cfg(test)]
5-
use std::cell::RefCell;
64
use std::iter;
75

86
use itertools::Itertools;
97
use vortex_error::VortexResult;
108
use vortex_session::VortexSession;
11-
#[cfg(test)]
12-
use vortex_utils::aliases::hash_map::HashMap;
139
use vortex_utils::aliases::hash_set::HashSet;
1410

1511
use super::relation::Relation;
@@ -19,8 +15,6 @@ use crate::dtype::FieldName;
1915
use crate::dtype::FieldPath;
2016
use crate::dtype::FieldPathSet;
2117
use crate::expr::Expression;
22-
#[cfg(test)]
23-
use crate::expr::StatsCatalog;
2418
use crate::expr::analysis::referenced_field_paths;
2519
use crate::expr::get_item;
2620
use crate::expr::is_root;
@@ -34,27 +28,6 @@ use crate::stats::bind::bind_stats;
3428

3529
pub type RequiredStats = Relation<FieldPath, Stat>;
3630

37-
// A catalog that returns a stat column whenever it is required, tracking all accessed
38-
// stats and returning them later.
39-
#[cfg(test)]
40-
#[derive(Default)]
41-
pub(crate) struct TrackingStatsCatalog {
42-
usage: RefCell<HashMap<(FieldPath, Stat), Expression>>,
43-
}
44-
45-
#[cfg(test)]
46-
impl StatsCatalog for TrackingStatsCatalog {
47-
fn stats_ref(&self, field_path: &FieldPath, stat: Stat) -> Option<Expression> {
48-
let mut expr = root();
49-
let name = field_path_stat_field_name(field_path, stat);
50-
expr = get_item(name, expr);
51-
self.usage
52-
.borrow_mut()
53-
.insert((field_path.clone(), stat), expr.clone());
54-
Some(expr)
55-
}
56-
}
57-
5831
#[doc(hidden)]
5932
pub fn field_path_stat_field_name(field_path: &FieldPath, stat: Stat) -> FieldName {
6033
field_path

vortex-array/src/scalar_fn/erased.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,15 +181,6 @@ impl ScalarFnRef {
181181
self.0.simplify_untyped(expr)
182182
}
183183

184-
/// Compute stat falsification expression.
185-
pub(crate) fn stat_falsification(
186-
&self,
187-
expr: &Expression,
188-
catalog: &dyn StatsCatalog,
189-
) -> Option<Expression> {
190-
self.0.stat_falsification(expr, catalog)
191-
}
192-
193184
/// Compute stat expression.
194185
pub(crate) fn stat_expression(
195186
&self,

vortex-array/src/scalar_fn/fns/between/mod.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,13 @@ use crate::arrays::Primitive;
2525
use crate::builtins::ArrayBuiltins;
2626
use crate::dtype::DType;
2727
use crate::dtype::DType::Bool;
28-
use crate::expr::StatsCatalog;
2928
use crate::expr::expression::Expression;
3029
use crate::scalar::Scalar;
3130
use crate::scalar_fn::Arity;
3231
use crate::scalar_fn::ChildName;
3332
use crate::scalar_fn::ExecutionArgs;
3433
use crate::scalar_fn::ScalarFnId;
3534
use crate::scalar_fn::ScalarFnVTable;
36-
use crate::scalar_fn::ScalarFnVTableExt;
37-
use crate::scalar_fn::fns::binary::Binary;
3835
use crate::scalar_fn::fns::binary::execute_boolean;
3936
use crate::scalar_fn::fns::operators::CompareOperator;
4037
use crate::scalar_fn::fns::operators::Operator;
@@ -298,22 +295,6 @@ impl ScalarFnVTable for Between {
298295
between_canonical(&arr, &lower, &upper, options, ctx)
299296
}
300297

301-
fn stat_falsification(
302-
&self,
303-
options: &Self::Options,
304-
expr: &Expression,
305-
catalog: &dyn StatsCatalog,
306-
) -> Option<Expression> {
307-
let arr = expr.child(0).clone();
308-
let lower = expr.child(1).clone();
309-
let upper = expr.child(2).clone();
310-
311-
let lhs = Binary.new_expr(options.lower_strict.to_operator(), [lower, arr.clone()]);
312-
let rhs = Binary.new_expr(options.upper_strict.to_operator(), [arr, upper]);
313-
314-
and(lhs, rhs).stat_falsification(catalog)
315-
}
316-
317298
fn validity(
318299
&self,
319300
_options: &Self::Options,

vortex-array/src/scalar_fn/fns/binary/mod.rs

Lines changed: 4 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,9 @@ use crate::ArrayRef;
1818
use crate::ExecutionCtx;
1919
use crate::dtype::DType;
2020
use crate::dtype::Nullability;
21-
use crate::expr::StatsCatalog;
2221
use crate::expr::and;
23-
use crate::expr::and_collect;
24-
use crate::expr::eq;
2522
use crate::expr::expression::Expression;
26-
use crate::expr::gt;
27-
use crate::expr::gt_eq;
2823
use crate::expr::lit;
29-
use crate::expr::lt;
30-
use crate::expr::lt_eq;
31-
use crate::expr::or_collect;
32-
use crate::expr::stats::Stat;
3324
use crate::scalar_fn::Arity;
3425
use crate::scalar_fn::ChildName;
3526
use crate::scalar_fn::ExecutionArgs;
@@ -221,110 +212,6 @@ impl ScalarFnVTable for Binary {
221212
})
222213
}
223214

224-
fn stat_falsification(
225-
&self,
226-
operator: &Operator,
227-
expr: &Expression,
228-
catalog: &dyn StatsCatalog,
229-
) -> Option<Expression> {
230-
// Wrap another predicate with an optional NaNCount check, if the stat is available.
231-
//
232-
// For example, regular pruning conversion for `A >= B` would be
233-
//
234-
// A.max < B.min
235-
//
236-
// With NaN predicate introduction, we'd conjunct it with a check for NaNCount, resulting
237-
// in:
238-
//
239-
// (A.nan_count = 0) AND (B.nan_count = 0) AND A.max < B.min
240-
//
241-
// Non-floating point column and literal expressions should be unaffected as they do not
242-
// have a nan_count statistic defined.
243-
fn with_nan_predicate(
244-
lhs: &Expression,
245-
rhs: &Expression,
246-
value_predicate: Expression,
247-
catalog: &dyn StatsCatalog,
248-
) -> Expression {
249-
let nan_predicate = and_collect(
250-
lhs.stat_expression(Stat::NaNCount, catalog)
251-
.into_iter()
252-
.chain(rhs.stat_expression(Stat::NaNCount, catalog))
253-
.map(|nans| eq(nans, lit(0u64))),
254-
);
255-
256-
if let Some(nan_check) = nan_predicate {
257-
and(nan_check, value_predicate)
258-
} else {
259-
value_predicate
260-
}
261-
}
262-
263-
let lhs = expr.child(0);
264-
let rhs = expr.child(1);
265-
match operator {
266-
Operator::Eq => {
267-
let min_lhs = lhs.stat_min(catalog);
268-
let max_lhs = lhs.stat_max(catalog);
269-
270-
let min_rhs = rhs.stat_min(catalog);
271-
let max_rhs = rhs.stat_max(catalog);
272-
273-
let left = min_lhs.zip(max_rhs).map(|(a, b)| gt(a, b));
274-
let right = min_rhs.zip(max_lhs).map(|(a, b)| gt(a, b));
275-
276-
let min_max_check = or_collect(left.into_iter().chain(right))?;
277-
278-
// NaN is not captured by the min/max stat, so we must check NaNCount before pruning
279-
Some(with_nan_predicate(lhs, rhs, min_max_check, catalog))
280-
}
281-
Operator::NotEq => {
282-
let min_lhs = lhs.stat_min(catalog)?;
283-
let max_lhs = lhs.stat_max(catalog)?;
284-
285-
let min_rhs = rhs.stat_min(catalog)?;
286-
let max_rhs = rhs.stat_max(catalog)?;
287-
288-
let min_max_check = and(eq(min_lhs, max_rhs), eq(max_lhs, min_rhs));
289-
290-
Some(with_nan_predicate(lhs, rhs, min_max_check, catalog))
291-
}
292-
Operator::Gt => {
293-
let min_max_check = lt_eq(lhs.stat_max(catalog)?, rhs.stat_min(catalog)?);
294-
295-
Some(with_nan_predicate(lhs, rhs, min_max_check, catalog))
296-
}
297-
Operator::Gte => {
298-
// NaN is not captured by the min/max stat, so we must check NaNCount before pruning
299-
let min_max_check = lt(lhs.stat_max(catalog)?, rhs.stat_min(catalog)?);
300-
301-
Some(with_nan_predicate(lhs, rhs, min_max_check, catalog))
302-
}
303-
Operator::Lt => {
304-
// NaN is not captured by the min/max stat, so we must check NaNCount before pruning
305-
let min_max_check = gt_eq(lhs.stat_min(catalog)?, rhs.stat_max(catalog)?);
306-
307-
Some(with_nan_predicate(lhs, rhs, min_max_check, catalog))
308-
}
309-
Operator::Lte => {
310-
// NaN is not captured by the min/max stat, so we must check NaNCount before pruning
311-
let min_max_check = gt(lhs.stat_min(catalog)?, rhs.stat_max(catalog)?);
312-
313-
Some(with_nan_predicate(lhs, rhs, min_max_check, catalog))
314-
}
315-
Operator::And => or_collect(
316-
lhs.stat_falsification(catalog)
317-
.into_iter()
318-
.chain(rhs.stat_falsification(catalog)),
319-
),
320-
Operator::Or => Some(and(
321-
lhs.stat_falsification(catalog)?,
322-
rhs.stat_falsification(catalog)?,
323-
)),
324-
Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => None,
325-
}
326-
}
327-
328215
fn validity(
329216
&self,
330217
operator: &Operator,
@@ -381,8 +268,12 @@ mod tests {
381268
use crate::expr::Expression;
382269
use crate::expr::and_collect;
383270
use crate::expr::col;
271+
use crate::expr::eq;
272+
use crate::expr::gt;
273+
use crate::expr::gt_eq;
384274
use crate::expr::lit;
385275
use crate::expr::lt;
276+
use crate::expr::lt_eq;
386277
use crate::expr::not_eq;
387278
use crate::expr::or;
388279
use crate::expr::or_collect;

vortex-array/src/scalar_fn/fns/dynamic.rs

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use crate::IntoArray;
2020
use crate::arrays::ConstantArray;
2121
use crate::dtype::DType;
2222
use crate::expr::Expression;
23-
use crate::expr::StatsCatalog;
2423
use crate::expr::traversal::NodeExt;
2524
use crate::expr::traversal::NodeVisitor;
2625
use crate::expr::traversal::TraversalOrder;
@@ -120,50 +119,6 @@ impl ScalarFnVTable for DynamicComparison {
120119
.into_array())
121120
}
122121

123-
fn stat_falsification(
124-
&self,
125-
dynamic: &DynamicComparisonExpr,
126-
expr: &Expression,
127-
catalog: &dyn StatsCatalog,
128-
) -> Option<Expression> {
129-
let lhs = expr.child(0);
130-
match dynamic.operator {
131-
CompareOperator::Eq | CompareOperator::NotEq => None,
132-
CompareOperator::Gt => Some(DynamicComparison.new_expr(
133-
DynamicComparisonExpr {
134-
operator: CompareOperator::Lte,
135-
rhs: Arc::clone(&dynamic.rhs),
136-
default: !dynamic.default,
137-
},
138-
vec![lhs.stat_max(catalog)?],
139-
)),
140-
CompareOperator::Gte => Some(DynamicComparison.new_expr(
141-
DynamicComparisonExpr {
142-
operator: CompareOperator::Lt,
143-
rhs: Arc::clone(&dynamic.rhs),
144-
default: !dynamic.default,
145-
},
146-
vec![lhs.stat_max(catalog)?],
147-
)),
148-
CompareOperator::Lt => Some(DynamicComparison.new_expr(
149-
DynamicComparisonExpr {
150-
operator: CompareOperator::Gte,
151-
rhs: Arc::clone(&dynamic.rhs),
152-
default: !dynamic.default,
153-
},
154-
vec![lhs.stat_min(catalog)?],
155-
)),
156-
CompareOperator::Lte => Some(DynamicComparison.new_expr(
157-
DynamicComparisonExpr {
158-
operator: CompareOperator::Gt,
159-
rhs: Arc::clone(&dynamic.rhs),
160-
default: !dynamic.default,
161-
},
162-
vec![lhs.stat_min(catalog)?],
163-
)),
164-
}
165-
}
166-
167122
// Defer to the child
168123
fn is_null_sensitive(&self, _instance: &Self::Options) -> bool {
169124
false

vortex-array/src/scalar_fn/fns/is_not_null.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
use std::fmt::Formatter;
55

6-
use vortex_array::scalar_fn::internal::row_count::RowCount;
76
use vortex_error::VortexResult;
87
use vortex_session::VortexSession;
98
use vortex_session::registry::CachedId;
@@ -15,16 +14,12 @@ use crate::arrays::ConstantArray;
1514
use crate::dtype::DType;
1615
use crate::dtype::Nullability;
1716
use crate::expr::Expression;
18-
use crate::expr::StatsCatalog;
19-
use crate::expr::eq;
20-
use crate::expr::stats::Stat;
2117
use crate::scalar_fn::Arity;
2218
use crate::scalar_fn::ChildName;
2319
use crate::scalar_fn::EmptyOptions;
2420
use crate::scalar_fn::ExecutionArgs;
2521
use crate::scalar_fn::ScalarFnId;
2622
use crate::scalar_fn::ScalarFnVTable;
27-
use crate::scalar_fn::ScalarFnVTableExt;
2823
use crate::validity::Validity;
2924

3025
/// Expression that checks for non-null values.
@@ -100,18 +95,6 @@ impl ScalarFnVTable for IsNotNull {
10095
fn is_fallible(&self, _instance: &Self::Options) -> bool {
10196
false
10297
}
103-
104-
fn stat_falsification(
105-
&self,
106-
_options: &Self::Options,
107-
expr: &Expression,
108-
catalog: &dyn StatsCatalog,
109-
) -> Option<Expression> {
110-
// is_not_null is falsified when ALL values are null, i.e. null_count == row_count.
111-
let child = expr.child(0);
112-
let null_count_expr = child.stat_expression(Stat::NullCount, catalog)?;
113-
Some(eq(null_count_expr, RowCount.new_expr(EmptyOptions, [])))
114-
}
11598
}
11699

117100
#[cfg(test)]

0 commit comments

Comments
 (0)