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