Skip to content

Commit 1d3c592

Browse files
authored
Improve simplify_expressions rule (#15735)
* Improve simplify_expressions rule * address comments * address comments
1 parent 76a4c60 commit 1d3c592

File tree

3 files changed

+48
-13
lines changed

3 files changed

+48
-13
lines changed

datafusion/core/tests/expr_api/simplification.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,9 +547,9 @@ fn test_simplify_with_cycle_count(
547547
};
548548
let simplifier = ExprSimplifier::new(info);
549549
let (simplified_expr, count) = simplifier
550-
.simplify_with_cycle_count(input_expr.clone())
550+
.simplify_with_cycle_count_transformed(input_expr.clone())
551551
.expect("successfully evaluated");
552-
552+
let simplified_expr = simplified_expr.data;
553553
assert_eq!(
554554
simplified_expr, expected_expr,
555555
"Mismatch evaluating {input_expr}\n Expected:{expected_expr}\n Got:{simplified_expr}"

datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ impl<S: SimplifyInfo> ExprSimplifier<S> {
188188
/// assert_eq!(expr, b_lt_2);
189189
/// ```
190190
pub fn simplify(&self, expr: Expr) -> Result<Expr> {
191-
Ok(self.simplify_with_cycle_count(expr)?.0)
191+
Ok(self.simplify_with_cycle_count_transformed(expr)?.0.data)
192192
}
193193

194194
/// Like [Self::simplify], simplifies this [`Expr`] as much as possible, evaluating
@@ -198,7 +198,34 @@ impl<S: SimplifyInfo> ExprSimplifier<S> {
198198
///
199199
/// See [Self::simplify] for details and usage examples.
200200
///
201+
#[deprecated(
202+
since = "48.0.0",
203+
note = "Use `simplify_with_cycle_count_transformed` instead"
204+
)]
205+
#[allow(unused_mut)]
201206
pub fn simplify_with_cycle_count(&self, mut expr: Expr) -> Result<(Expr, u32)> {
207+
let (transformed, cycle_count) =
208+
self.simplify_with_cycle_count_transformed(expr)?;
209+
Ok((transformed.data, cycle_count))
210+
}
211+
212+
/// Like [Self::simplify], simplifies this [`Expr`] as much as possible, evaluating
213+
/// constants and applying algebraic simplifications. Additionally returns a `u32`
214+
/// representing the number of simplification cycles performed, which can be useful for testing
215+
/// optimizations.
216+
///
217+
/// # Returns
218+
///
219+
/// A tuple containing:
220+
/// - The simplified expression wrapped in a `Transformed<Expr>` indicating if changes were made
221+
/// - The number of simplification cycles that were performed
222+
///
223+
/// See [Self::simplify] for details and usage examples.
224+
///
225+
pub fn simplify_with_cycle_count_transformed(
226+
&self,
227+
mut expr: Expr,
228+
) -> Result<(Transformed<Expr>, u32)> {
202229
let mut simplifier = Simplifier::new(&self.info);
203230
let mut const_evaluator = ConstEvaluator::try_new(self.info.execution_props())?;
204231
let mut shorten_in_list_simplifier = ShortenInListSimplifier::new();
@@ -212,6 +239,7 @@ impl<S: SimplifyInfo> ExprSimplifier<S> {
212239
// simplifications can enable new constant evaluation
213240
// see `Self::with_max_cycles`
214241
let mut num_cycles = 0;
242+
let mut has_transformed = false;
215243
loop {
216244
let Transformed {
217245
data, transformed, ..
@@ -221,13 +249,18 @@ impl<S: SimplifyInfo> ExprSimplifier<S> {
221249
.transform_data(|expr| expr.rewrite(&mut guarantee_rewriter))?;
222250
expr = data;
223251
num_cycles += 1;
252+
// Track if any transformation occurred
253+
has_transformed = has_transformed || transformed;
224254
if !transformed || num_cycles >= self.max_simplifier_cycles {
225255
break;
226256
}
227257
}
228258
// shorten inlist should be started after other inlist rules are applied
229259
expr = expr.rewrite(&mut shorten_in_list_simplifier).data()?;
230-
Ok((expr, num_cycles))
260+
Ok((
261+
Transformed::new_transformed(expr, has_transformed),
262+
num_cycles,
263+
))
231264
}
232265

233266
/// Apply type coercion to an [`Expr`] so that it can be
@@ -392,15 +425,15 @@ impl<S: SimplifyInfo> ExprSimplifier<S> {
392425
/// let expr = col("a").is_not_null();
393426
///
394427
/// // When using default maximum cycles, 2 cycles will be performed.
395-
/// let (simplified_expr, count) = simplifier.simplify_with_cycle_count(expr.clone()).unwrap();
396-
/// assert_eq!(simplified_expr, lit(true));
428+
/// let (simplified_expr, count) = simplifier.simplify_with_cycle_count_transformed(expr.clone()).unwrap();
429+
/// assert_eq!(simplified_expr.data, lit(true));
397430
/// // 2 cycles were executed, but only 1 was needed
398431
/// assert_eq!(count, 2);
399432
///
400433
/// // Only 1 simplification pass is necessary here, so we can set the maximum cycles to 1.
401-
/// let (simplified_expr, count) = simplifier.with_max_cycles(1).simplify_with_cycle_count(expr.clone()).unwrap();
434+
/// let (simplified_expr, count) = simplifier.with_max_cycles(1).simplify_with_cycle_count_transformed(expr.clone()).unwrap();
402435
/// // Expression has been rewritten to: (c = a AND b = 1)
403-
/// assert_eq!(simplified_expr, lit(true));
436+
/// assert_eq!(simplified_expr.data, lit(true));
404437
/// // Only 1 cycle was executed
405438
/// assert_eq!(count, 1);
406439
///
@@ -3329,7 +3362,8 @@ mod tests {
33293362
let simplifier = ExprSimplifier::new(
33303363
SimplifyContext::new(&execution_props).with_schema(schema),
33313364
);
3332-
simplifier.simplify_with_cycle_count(expr)
3365+
let (expr, count) = simplifier.simplify_with_cycle_count_transformed(expr)?;
3366+
Ok((expr.data, count))
33333367
}
33343368

33353369
fn simplify_with_cycle_count(expr: Expr) -> (Expr, u32) {

datafusion/optimizer/src/simplify_expressions/simplify_exprs.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,11 @@ impl SimplifyExpressions {
123123
let name_preserver = NamePreserver::new(&plan);
124124
let mut rewrite_expr = |expr: Expr| {
125125
let name = name_preserver.save(&expr);
126-
let expr = simplifier.simplify(expr)?;
127-
// TODO it would be nice to have a way to know if the expression was simplified
128-
// or not. For now conservatively return Transformed::yes
129-
Ok(Transformed::yes(name.restore(expr)))
126+
let expr = simplifier.simplify_with_cycle_count_transformed(expr)?.0;
127+
Ok(Transformed::new_transformed(
128+
name.restore(expr.data),
129+
expr.transformed,
130+
))
130131
};
131132

132133
plan.map_expressions(|expr| {

0 commit comments

Comments
 (0)