Skip to content

Commit

Permalink
Improve simplification by running it twice (#3811)
Browse files Browse the repository at this point in the history
  • Loading branch information
alamb authored Oct 12, 2022
1 parent 7179c54 commit 37fe938
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 8 deletions.
9 changes: 4 additions & 5 deletions datafusion-examples/examples/expr_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,11 @@ fn simplify_demo() -> Result<()> {
col("i") + lit(3)
);

// TODO uncomment when https://github.com/apache/arrow-datafusion/issues/1160 is done
// (i * 0) > 5 --> false (only if null)
// assert_eq!(
// simplifier.simplify((col("i") * lit(0)).gt(lit(5)))?,
// lit(false)
// );
assert_eq!(
simplifier.simplify((col("i") * lit(0)).gt(lit(5)))?,
lit(false)
);

// Logical simplification

Expand Down
44 changes: 41 additions & 3 deletions datafusion/optimizer/src/expr_simplifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,18 @@ impl<S: SimplifyInfo> ExprSimplifier<S> {
/// assert_eq!(expr, b_lt_2);
/// ```
pub fn simplify(&self, expr: Expr) -> Result<Expr> {
let mut rewriter = Simplifier::new(&self.info);
let mut simplifier = Simplifier::new(&self.info);
let mut const_evaluator = ConstEvaluator::try_new(self.info.execution_props())?;

// TODO iterate until no changes are made during rewrite
// (evaluating constants can enable new simplifications and
// simplifications can enable new constant evaluation)
// https://github.com/apache/arrow-datafusion/issues/1160
expr.rewrite(&mut const_evaluator)?.rewrite(&mut rewriter)
expr.rewrite(&mut const_evaluator)?
.rewrite(&mut simplifier)?
// run both passes twice to try an minimize simplifications that we missed
.rewrite(&mut const_evaluator)?
.rewrite(&mut simplifier)
}

/// Apply type coercion to an [`Expr`] so that it can be
Expand Down Expand Up @@ -231,7 +235,7 @@ mod tests {
use super::*;
use arrow::datatypes::{Field, Schema};
use datafusion_common::ToDFSchema;
use datafusion_expr::{col, lit};
use datafusion_expr::{col, lit, when};

#[test]
fn api_basic() {
Expand Down Expand Up @@ -274,4 +278,38 @@ mod tests {
.to_dfschema_ref()
.unwrap()
}

#[test]
fn simplify_and_constant_prop() {
let props = ExecutionProps::new();
let simplifier =
ExprSimplifier::new(SimplifyContext::new(&props).with_schema(test_schema()));

// should be able to simplify to false
// (i * (1 - 2)) > 0
let expr = (col("i") * (lit(1) - lit(1))).gt(lit(0));
let expected = lit(false);
assert_eq!(expected, simplifier.simplify(expr).unwrap());
}

#[test]
fn simplify_and_constant_prop_with_case() {
let props = ExecutionProps::new();
let simplifier =
ExprSimplifier::new(SimplifyContext::new(&props).with_schema(test_schema()));

// CASE
// WHEN i>5 AND false THEN i > 5
// WHEN i<5 AND true THEN i < 5
// ELSE false
// END
//
// Can be simplified to `i < 5`
let expr = when(col("i").gt(lit(5)).and(lit(false)), col("i").gt(lit(5)))
.when(col("i").lt(lit(5)).and(lit(true)), col("i").lt(lit(5)))
.otherwise(lit(false))
.unwrap();
let expected = col("i").lt(lit(5));
assert_eq!(expected, simplifier.simplify(expr).unwrap());
}
}

0 comments on commit 37fe938

Please sign in to comment.