1 //---------------------------------------------------------------------
2 // <copyright file="Simplifier.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 //---------------------------------------------------------------------
11 using System.Collections.Generic;
13 using System.Diagnostics;
15 namespace System.Data.Common.Utils.Boolean
17 // Simplifier visitor for Boolean expressions. Performs the following
18 // simplifications bottom-up:
19 // - Eliminate True and False (A Or False iff. A, A And True iff. A)
20 // - Resolve tautology (A Or !A iff. True, True Or A iff. True) and
21 // contradiction (A And !A iff. False, False And A iff. False)
22 // - Flatten nested negations (!!A iff. A)
23 // - Evaluate bound literals (!True iff. False, etc.)
24 // - Flatten unary/empty And/Or expressions
25 internal class Simplifier<T_Identifier> : BasicVisitor<T_Identifier>
27 internal static readonly Simplifier<T_Identifier> Instance = new Simplifier<T_Identifier>();
29 protected Simplifier()
33 internal override BoolExpr<T_Identifier> VisitNot(NotExpr<T_Identifier> expression)
35 BoolExpr<T_Identifier> child = expression.Child.Accept(this);
36 switch (child.ExprType)
39 return ((NotExpr<T_Identifier>)child).Child;
40 case ExprType.True: return FalseExpr<T_Identifier>.Value;
41 case ExprType.False: return TrueExpr<T_Identifier>.Value;
42 default: return base.VisitNot(expression);
46 internal override BoolExpr<T_Identifier> VisitAnd(AndExpr<T_Identifier> expression)
48 return SimplifyTree(expression);
51 internal override BoolExpr<T_Identifier> VisitOr(OrExpr<T_Identifier> expression)
53 return SimplifyTree(expression);
56 private BoolExpr<T_Identifier> SimplifyTree(TreeExpr<T_Identifier> tree)
58 bool isAnd = ExprType.And == tree.ExprType;
59 Debug.Assert(isAnd || ExprType.Or == tree.ExprType);
61 // Get list of simplified children, flattening nested And/Or expressions
62 List<BoolExpr<T_Identifier>> simplifiedChildren = new List<BoolExpr<T_Identifier>>(tree.Children.Count);
63 foreach (BoolExpr<T_Identifier> child in tree.Children)
65 BoolExpr<T_Identifier> simplifiedChild = child.Accept(this);
66 // And(And(A, B), C) iff. And(A, B, C)
67 // Or(Or(A, B), C) iff. Or(A, B, C)
68 if (simplifiedChild.ExprType == tree.ExprType)
70 simplifiedChildren.AddRange(((TreeExpr<T_Identifier>)simplifiedChild).Children);
74 simplifiedChildren.Add(simplifiedChild);
78 // Track negated children separately to identify tautologies and contradictions
79 Dictionary<BoolExpr<T_Identifier>, bool> negatedChildren = new Dictionary<BoolExpr<T_Identifier>, bool>(tree.Children.Count);
80 List<BoolExpr<T_Identifier>> otherChildren = new List<BoolExpr<T_Identifier>>(tree.Children.Count);
81 foreach (BoolExpr<T_Identifier> simplifiedChild in simplifiedChildren)
83 switch (simplifiedChild.ExprType)
86 negatedChildren[((NotExpr<T_Identifier>)simplifiedChild).Child] = true;
89 // False And A --> False
90 if (isAnd) { return FalseExpr<T_Identifier>.Value; }
91 // False || A --> A (omit False from child collections)
95 if (!isAnd) { return TrueExpr<T_Identifier>.Value; }
96 // True And A --> A (omit True from child collections)
99 otherChildren.Add(simplifiedChild);
103 List<BoolExpr<T_Identifier>> children = new List<BoolExpr<T_Identifier>>();
104 foreach (BoolExpr<T_Identifier> child in otherChildren)
106 if (negatedChildren.ContainsKey(child))
108 // A && !A --> False, A || !A --> True
109 if (isAnd) { return FalseExpr<T_Identifier>.Value; }
110 else { return TrueExpr<T_Identifier>.Value; }
114 foreach (BoolExpr<T_Identifier> child in negatedChildren.Keys)
116 children.Add(child.MakeNegated());
118 if (0 == children.Count)
121 if (isAnd) { return TrueExpr<T_Identifier>.Value; }
123 else { return FalseExpr<T_Identifier>.Value; }
125 else if (1 == children.Count)
127 // Or(A) iff. A, And(A) iff. A
132 // Construct simplified And/Or expression
133 TreeExpr<T_Identifier> result;
134 if (isAnd) { result = new AndExpr<T_Identifier>(children); }
135 else { result = new OrExpr<T_Identifier>(children); }