You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by al...@apache.org on 2022/10/12 18:30:26 UTC

[arrow-datafusion] branch master updated: Optimizer now simplifies multiplication when either left or right arg is a literal zero or one and division, modulo when right arg is one (#3782)

This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git


The following commit(s) were added to refs/heads/master by this push:
     new a226587de Optimizer now simplifies multiplication when either left or right arg is a literal zero or one and division, modulo when right arg is one (#3782)
a226587de is described below

commit a226587de5a17f93c175727bca37844ef0bd934a
Author: Roman Nozdrin <dr...@gmail.com>
AuthorDate: Wed Oct 12 21:30:20 2022 +0300

    Optimizer now simplifies multiplication when either left or right arg is a literal zero or one and division, modulo when right arg is one (#3782)
    
    Co-authored-by: Andrew Lamb <an...@nerdnetworks.org>
---
 datafusion/optimizer/src/simplify_expressions.rs | 95 +++++++++++++++++++++++-
 1 file changed, 92 insertions(+), 3 deletions(-)

diff --git a/datafusion/optimizer/src/simplify_expressions.rs b/datafusion/optimizer/src/simplify_expressions.rs
index 23d3edf91..7c203bdfe 100644
--- a/datafusion/optimizer/src/simplify_expressions.rs
+++ b/datafusion/optimizer/src/simplify_expressions.rs
@@ -20,7 +20,7 @@
 use crate::expr_simplifier::{ExprSimplifier, SimplifyContext};
 use crate::{expr_simplifier::SimplifyInfo, OptimizerConfig, OptimizerRule};
 use arrow::array::new_null_array;
-use arrow::datatypes::{DataType, Field, Schema};
+use arrow::datatypes::{DataType, Field, Schema, DECIMAL128_MAX_PRECISION};
 use arrow::error::ArrowError;
 use arrow::record_batch::RecordBatch;
 use datafusion_common::{DFSchema, DataFusionError, Result, ScalarValue};
@@ -34,6 +34,47 @@ use datafusion_expr::{
 };
 use datafusion_physical_expr::{create_physical_expr, execution_props::ExecutionProps};
 
+static POWS_OF_TEN: [i128; 38] = [
+    1,
+    10,
+    100,
+    1000,
+    10000,
+    100000,
+    1000000,
+    10000000,
+    100000000,
+    1000000000,
+    10000000000,
+    100000000000,
+    1000000000000,
+    10000000000000,
+    100000000000000,
+    1000000000000000,
+    10000000000000000,
+    100000000000000000,
+    1000000000000000000,
+    10000000000000000000,
+    100000000000000000000,
+    1000000000000000000000,
+    10000000000000000000000,
+    100000000000000000000000,
+    1000000000000000000000000,
+    10000000000000000000000000,
+    100000000000000000000000000,
+    1000000000000000000000000000,
+    10000000000000000000000000000,
+    100000000000000000000000000000,
+    1000000000000000000000000000000,
+    10000000000000000000000000000000,
+    100000000000000000000000000000000,
+    1000000000000000000000000000000000,
+    10000000000000000000000000000000000,
+    100000000000000000000000000000000000,
+    1000000000000000000000000000000000000,
+    10000000000000000000000000000000000000,
+];
+
 /// Optimizer Pass that simplifies [`LogicalPlan`]s by rewriting
 /// [`Expr`]`s evaluating constants and applying algebraic
 /// simplifications
@@ -73,6 +114,7 @@ fn is_zero(s: &Expr) -> bool {
         | Expr::Literal(ScalarValue::UInt64(Some(0))) => true,
         Expr::Literal(ScalarValue::Float32(Some(v))) if *v == 0. => true,
         Expr::Literal(ScalarValue::Float64(Some(v))) if *v == 0. => true,
+        Expr::Literal(ScalarValue::Decimal128(Some(v), _p, _s)) if *v == 0 => true,
         _ => false,
     }
 }
@@ -89,6 +131,9 @@ fn is_one(s: &Expr) -> bool {
         | Expr::Literal(ScalarValue::UInt64(Some(1))) => true,
         Expr::Literal(ScalarValue::Float32(Some(v))) if *v == 1. => true,
         Expr::Literal(ScalarValue::Float64(Some(v))) if *v == 1. => true,
+        Expr::Literal(ScalarValue::Decimal128(Some(v), _p, _s)) => {
+            *_s < DECIMAL128_MAX_PRECISION && POWS_OF_TEN[*_s as usize] == *v
+        }
         _ => false,
     }
 }
@@ -1031,6 +1076,19 @@ mod tests {
 
         assert_eq!(simplify(expr_a), expected);
         assert_eq!(simplify(expr_b), expected);
+
+        let expr = binary_expr(
+            col("c2"),
+            Operator::Multiply,
+            Expr::Literal(ScalarValue::Decimal128(Some(10000000000), 38, 10)),
+        );
+        assert_eq!(simplify(expr), expected);
+        let expr = binary_expr(
+            Expr::Literal(ScalarValue::Decimal128(Some(10000000000), 31, 10)),
+            Operator::Multiply,
+            col("c2"),
+        );
+        assert_eq!(simplify(expr), expected);
     }
 
     #[test]
@@ -1068,13 +1126,39 @@ mod tests {
             let expr = binary_expr(col("c2_non_null"), Operator::Multiply, lit(0));
             assert_eq!(simplify(expr), lit(0));
         }
+        // A * Decimal128(0) --> 0 if A is not nullable
+        {
+            let expr = binary_expr(
+                col("c2_non_null"),
+                Operator::Multiply,
+                Expr::Literal(ScalarValue::Decimal128(Some(0), 31, 10)),
+            );
+            assert_eq!(
+                simplify(expr),
+                Expr::Literal(ScalarValue::Decimal128(Some(0), 31, 10))
+            );
+            let expr = binary_expr(
+                Expr::Literal(ScalarValue::Decimal128(Some(0), 31, 10)),
+                Operator::Multiply,
+                col("c2_non_null"),
+            );
+            assert_eq!(
+                simplify(expr),
+                Expr::Literal(ScalarValue::Decimal128(Some(0), 31, 10))
+            );
+        }
     }
 
     #[test]
     fn test_simplify_divide_by_one() {
         let expr = binary_expr(col("c2"), Operator::Divide, lit(1));
         let expected = col("c2");
-
+        assert_eq!(simplify(expr), expected);
+        let expr = binary_expr(
+            col("c2"),
+            Operator::Divide,
+            Expr::Literal(ScalarValue::Decimal128(Some(10000000000), 31, 10)),
+        );
         assert_eq!(simplify(expr), expected);
     }
 
@@ -1138,7 +1222,12 @@ mod tests {
     fn test_simplify_modulo_by_one_non_null() {
         let expr = binary_expr(col("c2_non_null"), Operator::Modulo, lit(1));
         let expected = lit(0);
-
+        assert_eq!(simplify(expr), expected);
+        let expr = binary_expr(
+            col("c2_non_null"),
+            Operator::Modulo,
+            Expr::Literal(ScalarValue::Decimal128(Some(10000000000), 31, 10)),
+        );
         assert_eq!(simplify(expr), expected);
     }