Skip to content

Commit c3ba409

Browse files
committed
Thread scope dtype through stats rewrites
Signed-off-by: Nicholas Gates <nick@nickgates.com>
1 parent ba5064a commit c3ba409

3 files changed

Lines changed: 64 additions & 12 deletions

File tree

vortex-array/public-api.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12918,13 +12918,13 @@ pub fn vortex_array::expr::Expression::children(&self) -> &alloc::sync::Arc<allo
1291812918

1291912919
pub fn vortex_array::expr::Expression::display_tree(&self) -> impl core::fmt::Display
1292012920

12921-
pub fn vortex_array::expr::Expression::falsify(&self, &vortex_session::VortexSession) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
12921+
pub fn vortex_array::expr::Expression::falsify(&self, &vortex_array::dtype::DType, &vortex_session::VortexSession) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
1292212922

1292312923
pub fn vortex_array::expr::Expression::fmt_sql(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
1292412924

1292512925
pub fn vortex_array::expr::Expression::return_dtype(&self, &vortex_array::dtype::DType) -> vortex_error::VortexResult<vortex_array::dtype::DType>
1292612926

12927-
pub fn vortex_array::expr::Expression::satisfy(&self, &vortex_session::VortexSession) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
12927+
pub fn vortex_array::expr::Expression::satisfy(&self, &vortex_array::dtype::DType, &vortex_session::VortexSession) -> vortex_error::VortexResult<core::option::Option<vortex_array::expr::Expression>>
1292812928

1292912929
pub fn vortex_array::expr::Expression::scalar_fn(&self) -> &vortex_array::scalar_fn::ScalarFnRef
1293012930

vortex-array/src/expr/expression.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,18 +138,30 @@ impl Expression {
138138

139139
/// Returns an expression that proves this predicate is definitely false from stats.
140140
///
141+
/// `scope` is the dtype of the row this expression evaluates over.
142+
///
141143
/// If the returned expression evaluates to `true` for a stats scope, this expression is
142144
/// guaranteed to be false for every row in that scope. `false` and `null` are unknown.
143-
pub fn falsify(&self, session: &VortexSession) -> VortexResult<Option<Expression>> {
144-
crate::stats::rewrite::StatsRewriteCtx::new(session).falsify(self)
145+
pub fn falsify(
146+
&self,
147+
scope: &DType,
148+
session: &VortexSession,
149+
) -> VortexResult<Option<Expression>> {
150+
crate::stats::rewrite::StatsRewriteCtx::new(session, scope).falsify(self)
145151
}
146152

147153
/// Returns an expression that proves this predicate is definitely true from stats.
148154
///
155+
/// `scope` is the dtype of the row this expression evaluates over.
156+
///
149157
/// If the returned expression evaluates to `true` for a stats scope, this expression is
150158
/// guaranteed to be true for every row in that scope. `false` and `null` are unknown.
151-
pub fn satisfy(&self, session: &VortexSession) -> VortexResult<Option<Expression>> {
152-
crate::stats::rewrite::StatsRewriteCtx::new(session).satisfy(self)
159+
pub fn satisfy(
160+
&self,
161+
scope: &DType,
162+
session: &VortexSession,
163+
) -> VortexResult<Option<Expression>> {
164+
crate::stats::rewrite::StatsRewriteCtx::new(session, scope).satisfy(self)
153165
}
154166

155167
/// Returns an expression representing the zoned statistic for the given stat, if available.

vortex-array/src/stats/rewrite.rs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ use std::fmt::Debug;
77
use std::sync::Arc;
88

99
use vortex_error::VortexResult;
10+
use vortex_error::vortex_ensure;
1011
use vortex_session::VortexSession;
1112

13+
use crate::dtype::DType;
1214
use crate::expr::Expression;
1315
use crate::expr::or_collect;
1416
use crate::scalar_fn::ScalarFnId;
@@ -54,28 +56,45 @@ pub(crate) trait StatsRewriteRule: Debug + Send + Sync + 'static {
5456
/// Context passed to stats rewrite rules.
5557
pub(crate) struct StatsRewriteCtx<'a> {
5658
session: &'a VortexSession,
59+
scope: &'a DType,
5760
}
5861

5962
impl<'a> StatsRewriteCtx<'a> {
6063
/// Create a rewrite context for `session`.
61-
pub(crate) fn new(session: &'a VortexSession) -> Self {
62-
Self { session }
64+
pub(crate) fn new(session: &'a VortexSession, scope: &'a DType) -> Self {
65+
Self { session, scope }
6366
}
6467

6568
/// Returns the session that owns the rewrite registry.
6669
pub(crate) fn session(&self) -> &'a VortexSession {
6770
self.session
6871
}
6972

73+
/// Return the dtype of `expr` within this rewrite scope.
74+
pub(crate) fn return_dtype(&self, expr: &Expression) -> VortexResult<DType> {
75+
expr.return_dtype(self.scope)
76+
}
77+
7078
/// Rewrite `expr` into a stats-backed falsifier.
7179
pub(crate) fn falsify(&self, expr: &Expression) -> VortexResult<Option<Expression>> {
80+
self.ensure_predicate(expr)?;
7281
rewrite(expr, self, StatsRewriteRule::falsify)
7382
}
7483

7584
/// Rewrite `expr` into a stats-backed satisfier.
7685
pub(crate) fn satisfy(&self, expr: &Expression) -> VortexResult<Option<Expression>> {
86+
self.ensure_predicate(expr)?;
7787
rewrite(expr, self, StatsRewriteRule::satisfy)
7888
}
89+
90+
fn ensure_predicate(&self, expr: &Expression) -> VortexResult<()> {
91+
let dtype = self.return_dtype(expr)?;
92+
vortex_ensure!(
93+
matches!(dtype, DType::Bool(_)),
94+
"Stats rewrites require a boolean predicate, got {dtype}",
95+
);
96+
Ok(())
97+
}
7998
}
8099

81100
fn rewrite(
@@ -112,6 +131,9 @@ mod tests {
112131

113132
use super::StatsRewriteCtx;
114133
use super::StatsRewriteRule;
134+
use crate::dtype::DType;
135+
use crate::dtype::Nullability;
136+
use crate::dtype::PType;
115137
use crate::expr::Expression;
116138
use crate::expr::lit;
117139
use crate::expr::or;
@@ -152,6 +174,7 @@ mod tests {
152174
#[test]
153175
fn combines_multiple_falsifiers_with_or() -> VortexResult<()> {
154176
let session = VortexSession::empty().with::<StatsRewriteSession>();
177+
let dtype = DType::Primitive(PType::I32, Nullability::NonNullable);
155178
session.stats_rewrites().register(StaticLiteralRule {
156179
falsifier: Some(lit(false)),
157180
satisfier: None,
@@ -161,13 +184,17 @@ mod tests {
161184
satisfier: None,
162185
});
163186

164-
assert_eq!(lit(7).falsify(&session)?, Some(or(lit(false), lit(true))));
187+
assert_eq!(
188+
lit(true).falsify(&dtype, &session)?,
189+
Some(or(lit(false), lit(true)))
190+
);
165191
Ok(())
166192
}
167193

168194
#[test]
169195
fn combines_multiple_satisfiers_with_or() -> VortexResult<()> {
170196
let session = VortexSession::empty().with::<StatsRewriteSession>();
197+
let dtype = DType::Primitive(PType::I32, Nullability::NonNullable);
171198
session.stats_rewrites().register(StaticLiteralRule {
172199
falsifier: None,
173200
satisfier: Some(lit(false)),
@@ -177,16 +204,29 @@ mod tests {
177204
satisfier: Some(lit(true)),
178205
});
179206

180-
assert_eq!(lit(7).satisfy(&session)?, Some(or(lit(false), lit(true))));
207+
assert_eq!(
208+
lit(true).satisfy(&dtype, &session)?,
209+
Some(or(lit(false), lit(true)))
210+
);
181211
Ok(())
182212
}
183213

184214
#[test]
185215
fn unregistered_expression_has_no_rewrite() -> VortexResult<()> {
186216
let session = VortexSession::empty().with::<StatsRewriteSession>();
217+
let dtype = DType::Primitive(PType::I32, Nullability::NonNullable);
187218

188-
assert_eq!(lit(7).falsify(&session)?, None);
189-
assert_eq!(lit(7).satisfy(&session)?, None);
219+
assert_eq!(lit(true).falsify(&dtype, &session)?, None);
220+
assert_eq!(lit(true).satisfy(&dtype, &session)?, None);
190221
Ok(())
191222
}
223+
224+
#[test]
225+
fn non_predicate_expression_errors() {
226+
let session = VortexSession::empty().with::<StatsRewriteSession>();
227+
let dtype = DType::Primitive(PType::I32, Nullability::NonNullable);
228+
229+
assert!(lit(7).falsify(&dtype, &session).is_err());
230+
assert!(lit(7).satisfy(&dtype, &session).is_err());
231+
}
192232
}

0 commit comments

Comments
 (0)