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

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


The following commit(s) were added to refs/heads/main by this push:
     new 34967696e feat: add the similar optimization function for bitwise 
negative (#5516)
34967696e is described below

commit 34967696e97f45d7d95fd1a9025a579cd6c00bee
Author: Igor Izvekov <[email protected]>
AuthorDate: Wed Mar 15 15:25:14 2023 +0300

    feat: add the similar optimization function for bitwise negative (#5516)
    
    * feat: add the similar optimization function for bitwise negative
    
    * fix: some feature fixes
    
    * fix: change name from "negative_clause" to "distribute_negation"
    
    * feat: add tests for De Morgan's laws
---
 .../src/simplify_expressions/expr_simplifier.rs    | 41 +++++++++++++++++++---
 .../optimizer/src/simplify_expressions/utils.rs    | 41 +++++++++++++++++++++-
 2 files changed, 76 insertions(+), 6 deletions(-)

diff --git a/datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs 
b/datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs
index 2b015acd7..f70e1fef4 100644
--- a/datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs
+++ b/datafusion/optimizer/src/simplify_expressions/expr_simplifier.rs
@@ -1018,6 +1018,11 @@ impl<'a, S: SimplifyInfo> ExprRewriter for 
Simplifier<'a, S> {
             //
             Expr::Not(inner) => negate_clause(*inner),
 
+            //
+            // Rules for Negative
+            //
+            Expr::Negative(inner) => distribute_negation(*inner),
+
             //
             // Rules for Case
             //
@@ -2139,6 +2144,37 @@ mod tests {
         assert_eq!(simplify(expr), expected);
     }
 
+    #[test]
+    fn test_simplify_by_de_morgan_laws() {
+        // Laws with logical operations
+        // !(c3 AND c4) --> !c3 OR !c4
+        let expr = and(col("c3"), col("c4")).not();
+        let expected = or(col("c3").not(), col("c4").not());
+        assert_eq!(simplify(expr), expected);
+        // !(c3 OR c4) --> !c3 AND !c4
+        let expr = or(col("c3"), col("c4")).not();
+        let expected = and(col("c3").not(), col("c4").not());
+        assert_eq!(simplify(expr), expected);
+        // !(!c3) --> c3
+        let expr = col("c3").not().not();
+        let expected = col("c3");
+        assert_eq!(simplify(expr), expected);
+
+        // Laws with bitwise operations
+        // !(c3 & c4) --> !c3 | !c4
+        let expr = -bitwise_and(col("c3"), col("c4"));
+        let expected = bitwise_or(-col("c3"), -col("c4"));
+        assert_eq!(simplify(expr), expected);
+        // !(c3 | c4) --> !c3 & !c4
+        let expr = -bitwise_or(col("c3"), col("c4"));
+        let expected = bitwise_and(-col("c3"), -col("c4"));
+        assert_eq!(simplify(expr), expected);
+        // !(!c3) --> c3
+        let expr = -(-col("c3"));
+        let expected = col("c3");
+        assert_eq!(simplify(expr), expected);
+    }
+
     #[test]
     fn test_simplify_null_and_false() {
         let expr = and(lit_bool_null(), lit(false));
@@ -2442,11 +2478,6 @@ mod tests {
         )
     }
 
-    #[test]
-    fn simplify_expr_not_not() {
-        assert_eq!(simplify(col("c2").not().not().not()), col("c2").not(),);
-    }
-
     #[test]
     fn simplify_expr_null_comparison() {
         // x = null is always null
diff --git a/datafusion/optimizer/src/simplify_expressions/utils.rs 
b/datafusion/optimizer/src/simplify_expressions/utils.rs
index 352674c3a..8b3f437dc 100644
--- a/datafusion/optimizer/src/simplify_expressions/utils.rs
+++ b/datafusion/optimizer/src/simplify_expressions/utils.rs
@@ -20,7 +20,7 @@
 use datafusion_common::{DataFusionError, Result, ScalarValue};
 use datafusion_expr::{
     expr::{Between, BinaryExpr},
-    expr_fn::{and, concat_ws, or},
+    expr_fn::{and, bitwise_and, bitwise_or, concat_ws, or},
     lit, BuiltinScalarFunction, Expr, Like, Operator,
 };
 
@@ -311,6 +311,45 @@ pub fn negate_clause(expr: Expr) -> Expr {
     }
 }
 
+/// bitwise negate a Negative clause
+/// input is the clause to be bitwise negated.(args for Negative clause)
+/// For BinaryExpr:
+///    ~(A & B) ===> ~A | ~B
+///    ~(A | B) ===> ~A & ~B
+/// For Negative:
+///    ~(~A) ===> A
+/// For others, use Negative clause
+pub fn distribute_negation(expr: Expr) -> Expr {
+    match expr {
+        Expr::BinaryExpr(BinaryExpr { left, op, right }) => {
+            match op {
+                // ~(A & B) ===> ~A | ~B
+                Operator::BitwiseAnd => {
+                    let left = distribute_negation(*left);
+                    let right = distribute_negation(*right);
+
+                    bitwise_or(left, right)
+                }
+                // ~(A | B) ===> ~A & ~B
+                Operator::BitwiseOr => {
+                    let left = distribute_negation(*left);
+                    let right = distribute_negation(*right);
+
+                    bitwise_and(left, right)
+                }
+                // use negative clause
+                _ => Expr::Negative(Box::new(Expr::BinaryExpr(BinaryExpr::new(
+                    left, op, right,
+                )))),
+            }
+        }
+        // ~(~A) ===> A
+        Expr::Negative(expr) => *expr,
+        // use negative clause
+        _ => Expr::Negative(Box::new(expr)),
+    }
+}
+
 /// Simplify the `concat` function by
 /// 1. filtering out all `null` literals
 /// 2. concatenating contiguous literal arguments

Reply via email to