public SearchArgument.Builder startNot()
            {
                ExpressionTree node = new ExpressionTree(ExpressionTree.Operator.NOT);

                currentTree.Peek().getChildren().Add(node);
                currentTree.Push(node);
                return(this);
            }
 /**
  * Convert an expression so that the top level operator is AND with OR
  * operators under it. This routine assumes that all of the NOT operators
  * have been pushed to the leaves via pushdDownNot.
  * @param root the expression
  * @return the normalized expression
  */
 internal static ExpressionTree convertToCNF(ExpressionTree root)
 {
     if (root.getChildren() != null)
     {
         // convert all of the children to CNF
         int size = root.getChildren().Count;
         for (int i = 0; i < size; ++i)
         {
             root.getChildren()[i] = convertToCNF(root.getChildren()[i]);
         }
         if (root.getOperator() == ExpressionTree.Operator.OR)
         {
             // a list of leaves that weren't under AND expressions
             List <ExpressionTree> nonAndList = new List <ExpressionTree>();
             // a list of AND expressions that we need to distribute
             List <ExpressionTree> andList = new List <ExpressionTree>();
             foreach (ExpressionTree child in root.getChildren())
             {
                 if (child.getOperator() == ExpressionTree.Operator.AND)
                 {
                     andList.Add(child);
                 }
                 else if (child.getOperator() == ExpressionTree.Operator.OR)
                 {
                     // pull apart the kids of the OR expression
                     foreach (ExpressionTree grandkid in child.getChildren())
                     {
                         nonAndList.Add(grandkid);
                     }
                 }
                 else
                 {
                     nonAndList.Add(child);
                 }
             }
             if (andList.Count != 0)
             {
                 if (checkCombinationsThreshold(andList))
                 {
                     root = new ExpressionTree(ExpressionTree.Operator.AND);
                     generateAllCombinations(root.getChildren(), andList, nonAndList);
                 }
                 else
                 {
                     root = new ExpressionTree(TruthValue.YES_NO_NULL);
                 }
             }
         }
     }
     return(root);
 }
            /**
             * Push the negations all the way to just before the leaves. Also remove
             * double negatives.
             * @param root the expression to normalize
             * @return the normalized expression, which may share some or all of the
             * nodes of the original expression.
             */
            internal static ExpressionTree pushDownNot(ExpressionTree root)
            {
                if (root.getOperator() == ExpressionTree.Operator.NOT)
                {
                    ExpressionTree child = root.getChildren()[0];
                    switch (child.getOperator())
                    {
                    case ExpressionTree.Operator.NOT:
                        return(pushDownNot(child.getChildren()[0]));

                    case ExpressionTree.Operator.CONSTANT:
                        return(new ExpressionTree(child.getConstant().Value.not()));

                    case ExpressionTree.Operator.AND:
                        root = new ExpressionTree(ExpressionTree.Operator.OR);
                        foreach (ExpressionTree kid in child.getChildren())
                        {
                            root.getChildren().Add(pushDownNot(new
                                                               ExpressionTree(ExpressionTree.Operator.NOT, kid)));
                        }
                        break;

                    case ExpressionTree.Operator.OR:
                        root = new ExpressionTree(ExpressionTree.Operator.AND);
                        foreach (ExpressionTree kid in child.getChildren())
                        {
                            root.getChildren().Add(pushDownNot(new ExpressionTree
                                                                   (ExpressionTree.Operator.NOT, kid)));
                        }
                        break;

                    // for leaf, we don't do anything
                    default:
                        break;
                    }
                }
                else if (root.getChildren() != null)
                {
                    // iterate through children and push down not for each one
                    for (int i = 0; i < root.getChildren().Count; ++i)
                    {
                        root.getChildren()[i] = pushDownNot(root.getChildren()[i]);
                    }
                }
                return(root);
            }
 /**
  * Rewrite expression tree to update the leaves.
  * @param root the root of the tree to fix
  * @param leafReorder a map from old leaf ids to new leaf ids
  * @return the fixed root
  */
 static ExpressionTree rewriteLeaves(ExpressionTree root,
                                     int[] leafReorder)
 {
     if (root.getOperator() == ExpressionTree.Operator.LEAF)
     {
         return(new ExpressionTree(leafReorder[root.getLeaf()]));
     }
     else if (root.getChildren() != null)
     {
         List <ExpressionTree> children = root.getChildren();
         for (int i = 0; i < children.Count; ++i)
         {
             children[i] = rewriteLeaves(children[i], leafReorder);
         }
     }
     return(root);
 }
            public SearchArgument.Builder isNull(string column, PredicateLeaf.Type type)
            {
                ExpressionTree parent = currentTree.Peek();

                if (column == null)
                {
                    parent.getChildren().Add(new ExpressionTree(TruthValue.YES_NO_NULL));
                }
                else
                {
                    PredicateLeaf leaf =
                        new PredicateLeafImpl(PredicateLeaf.Operator.IS_NULL,
                                              type, column, null, null);
                    parent.getChildren().Add(new ExpressionTree(addLeaf(leaf)));
                }
                return(this);
            }
            public SearchArgument.Builder nullSafeEquals(string column, PredicateLeaf.Type type, object literal)
            {
                ExpressionTree parent = currentTree.Peek();

                if (column == null || literal == null)
                {
                    parent.getChildren().Add(new ExpressionTree(TruthValue.YES_NO_NULL));
                }
                else
                {
                    PredicateLeaf leaf =
                        new PredicateLeafImpl(PredicateLeaf.Operator.NULL_SAFE_EQUALS,
                                              type, column, literal, null);
                    parent.getChildren().Add(new ExpressionTree(addLeaf(leaf)));
                }
                return(this);
            }
            public SearchArgument.Builder end()
            {
                ExpressionTree current = currentTree.Pop();

                if (current.getChildren().Count == 0)
                {
                    throw new ArgumentException("Can't create expression " + root +
                                                " with no children.");
                }
                if (current.getOperator() == ExpressionTree.Operator.NOT &&
                    current.getChildren().Count != 1)
                {
                    throw new ArgumentException("Can't create not expression " +
                                                current + " with more than 1 child.");
                }
                return(this);
            }
Esempio n. 8
0
 public ExpressionTree(ExpressionTree other)
 {
     this.@operator = other.@operator;
     if (other.children == null)
     {
         this.children = null;
     }
     else
     {
         this.children = new List<ExpressionTree>();
         foreach (ExpressionTree child in other.children)
         {
             children.Add(new ExpressionTree(child));
         }
     }
     this.leaf = other.leaf;
     this.constant = other.constant;
 }
 public ExpressionTree(ExpressionTree other)
 {
     this.@operator = other.@operator;
     if (other.children == null)
     {
         this.children = null;
     }
     else
     {
         this.children = new List <ExpressionTree>();
         foreach (ExpressionTree child in other.children)
         {
             children.Add(new ExpressionTree(child));
         }
     }
     this.leaf     = other.leaf;
     this.constant = other.constant;
 }
 /**
  * Recursively explore the tree to find the leaves that are still reachable
  * after optimizations.
  * @param tree the node to check next
  * @param next the next available leaf id
  * @param leafReorder
  * @return the next available leaf id
  */
 static int compactLeaves(ExpressionTree tree, int next, int[] leafReorder)
 {
     if (tree.getOperator() == ExpressionTree.Operator.LEAF)
     {
         int oldLeaf = tree.getLeaf();
         if (leafReorder[oldLeaf] == -1)
         {
             leafReorder[oldLeaf] = next++;
         }
     }
     else if (tree.getChildren() != null)
     {
         foreach (ExpressionTree child in tree.getChildren())
         {
             next = compactLeaves(child, next, leafReorder);
         }
     }
     return(next);
 }
 /**
  * Converts multi-level ands and ors into single level ones.
  * @param root the expression to flatten
  * @return the flattened expression, which will always be root with
  *   potentially modified children.
  */
 internal static ExpressionTree flatten(ExpressionTree root)
 {
     if (root.getChildren() != null)
     {
         // iterate through the index, so that if we add more children,
         // they don't get re-visited
         for (int i = 0; i < root.getChildren().Count; ++i)
         {
             ExpressionTree child = flatten(root.getChildren()[i]);
             // do we need to flatten?
             if (child.getOperator() == root.getOperator() &&
                 child.getOperator() != ExpressionTree.Operator.NOT)
             {
                 bool first = true;
                 foreach (ExpressionTree grandkid in child.getChildren())
                 {
                     // for the first grandkid replace the original parent
                     if (first)
                     {
                         first = false;
                         root.getChildren()[i] = grandkid;
                     }
                     else
                     {
                         root.getChildren().Insert(++i, grandkid);
                     }
                 }
             }
             else
             {
                 root.getChildren()[i] = child;
             }
         }
         // if we have a singleton AND or OR, just return the child
         if ((root.getOperator() == ExpressionTree.Operator.OR ||
              root.getOperator() == ExpressionTree.Operator.AND) &&
             root.getChildren().Count == 1)
         {
             return(root.getChildren()[0]);
         }
     }
     return(root);
 }
            public SearchArgument.Builder between(string column, PredicateLeaf.Type type, object lower, object upper)
            {
                ExpressionTree parent = currentTree.Peek();

                if (column == null || lower == null || upper == null)
                {
                    parent.getChildren().Add(new ExpressionTree(TruthValue.YES_NO_NULL));
                }
                else
                {
                    List <object> argList = new List <object>();
                    argList.Add(lower);
                    argList.Add(upper);
                    PredicateLeaf leaf =
                        new PredicateLeafImpl(PredicateLeaf.Operator.BETWEEN,
                                              type, column, null, argList);
                    parent.getChildren().Add(new ExpressionTree(addLeaf(leaf)));
                }
                return(this);
            }
            /**
             * Generate all combinations of items on the andList. For each item on the
             * andList, it generates all combinations of one child from each and
             * expression. Thus, (and a b) (and c d) will be expanded to: (or a c)
             * (or a d) (or b c) (or b d). If there are items on the nonAndList, they
             * are added to each or expression.
             * @param result a list to put the results onto
             * @param andList a list of and expressions
             * @param nonAndList a list of non-and expressions
             */
            private static void generateAllCombinations(List <ExpressionTree> result,
                                                        List <ExpressionTree> andList,
                                                        List <ExpressionTree> nonAndList
                                                        )
            {
                List <ExpressionTree> kids = andList[0].getChildren();

                if (result.Count == 0)
                {
                    foreach (ExpressionTree kid in kids)
                    {
                        ExpressionTree or = new ExpressionTree(ExpressionTree.Operator.OR);
                        result.Add(or);
                        foreach (ExpressionTree node in nonAndList)
                        {
                            or.getChildren().Add(new ExpressionTree(node));
                        }
                        or.getChildren().Add(kid);
                    }
                }
                else
                {
                    List <ExpressionTree> work = new List <ExpressionTree>(result);
                    result.Clear();
                    foreach (ExpressionTree kid in kids)
                    {
                        foreach (ExpressionTree or in work)
                        {
                            ExpressionTree copy = new ExpressionTree(or);
                            copy.getChildren().Add(kid);
                            result.Add(copy);
                        }
                    }
                }
                if (andList.Count > 1)
                {
                    generateAllCombinations(result, andList.subList(1, andList.Count),
                                            nonAndList);
                }
            }
            /**
             * Remove MAYBE values from the expression. If they are in an AND operator,
             * they are dropped. If they are in an OR operator, they kill their parent.
             * This assumes that pushDownNot has already been called.
             * @param expr The expression to clean up
             * @return The cleaned up expression
             */
            internal static ExpressionTree foldMaybe(ExpressionTree expr)
            {
                if (expr.getChildren() != null)
                {
                    for (int i = 0; i < expr.getChildren().Count; ++i)
                    {
                        ExpressionTree child = foldMaybe(expr.getChildren()[i]);
                        if (child.getConstant() == TruthValue.YES_NO_NULL)
                        {
                            switch (expr.getOperator())
                            {
                            case ExpressionTree.Operator.AND:
                                expr.getChildren().RemoveAt(i);
                                i -= 1;
                                break;

                            case ExpressionTree.Operator.OR:
                                // a maybe will kill the or condition
                                return(child);

                            default:
                                throw new InvalidOperationException("Got a maybe as child of " +
                                                                    expr);
                            }
                        }
                        else
                        {
                            expr.getChildren()[i] = child;
                        }
                    }
                    if (expr.getChildren().Count == 0)
                    {
                        return(new ExpressionTree(TruthValue.YES_NO_NULL));
                    }
                }
                return(expr);
            }
            public SearchArgument build()
            {
                if (currentTree.Count != 1)
                {
                    throw new ArgumentException("Failed to end " +
                                                currentTree.Count + " operations.");
                }
                ExpressionTree optimized = pushDownNot(root);

                optimized = foldMaybe(optimized);
                optimized = flatten(optimized);
                optimized = convertToCNF(optimized);
                optimized = flatten(optimized);
                int[] leafReorder = new int[leaves.Count];
                Arrays.fill(leafReorder, -1);
                int newLeafCount = compactLeaves(optimized, 0, leafReorder);

                optimized = rewriteLeaves(optimized, leafReorder);
                List <PredicateLeaf> leafList = new List <PredicateLeaf>(newLeafCount);

                // expand list to correct size
                for (int i = 0; i < newLeafCount; ++i)
                {
                    leafList.Add(null);
                }
                // build the new list
                foreach (KeyValuePair <PredicateLeaf, int> elem in leaves)
                {
                    int newLoc = leafReorder[elem.Value];
                    if (newLoc != -1)
                    {
                        leafList[newLoc] = elem.Key;
                    }
                }
                return(new SearchArgumentImpl(optimized, leafList));
            }
 /**
  * Recursively explore the tree to find the leaves that are still reachable
  * after optimizations.
  * @param tree the node to check next
  * @param next the next available leaf id
  * @param leafReorder
  * @return the next available leaf id
  */
 static int compactLeaves(ExpressionTree tree, int next, int[] leafReorder)
 {
     if (tree.getOperator() == ExpressionTree.Operator.LEAF)
     {
         int oldLeaf = tree.getLeaf();
         if (leafReorder[oldLeaf] == -1)
         {
             leafReorder[oldLeaf] = next++;
         }
     }
     else if (tree.getChildren() != null)
     {
         foreach (ExpressionTree child in tree.getChildren())
         {
             next = compactLeaves(child, next, leafReorder);
         }
     }
     return next;
 }
 /**
  * Push the negations all the way to just before the leaves. Also remove
  * double negatives.
  * @param root the expression to normalize
  * @return the normalized expression, which may share some or all of the
  * nodes of the original expression.
  */
 internal static ExpressionTree pushDownNot(ExpressionTree root)
 {
     if (root.getOperator() == ExpressionTree.Operator.NOT)
     {
         ExpressionTree child = root.getChildren()[0];
         switch (child.getOperator())
         {
             case ExpressionTree.Operator.NOT:
                 return pushDownNot(child.getChildren()[0]);
             case ExpressionTree.Operator.CONSTANT:
                 return new ExpressionTree(child.getConstant().Value.not());
             case ExpressionTree.Operator.AND:
                 root = new ExpressionTree(ExpressionTree.Operator.OR);
                 foreach (ExpressionTree kid in child.getChildren())
                 {
                     root.getChildren().Add(pushDownNot(new
                         ExpressionTree(ExpressionTree.Operator.NOT, kid)));
                 }
                 break;
             case ExpressionTree.Operator.OR:
                 root = new ExpressionTree(ExpressionTree.Operator.AND);
                 foreach (ExpressionTree kid in child.getChildren())
                 {
                     root.getChildren().Add(pushDownNot(new ExpressionTree
                         (ExpressionTree.Operator.NOT, kid)));
                 }
                 break;
             // for leaf, we don't do anything
             default:
                 break;
         }
     }
     else if (root.getChildren() != null)
     {
         // iterate through children and push down not for each one
         for (int i = 0; i < root.getChildren().Count; ++i)
         {
             root.getChildren()[i] = pushDownNot(root.getChildren()[i]);
         }
     }
     return root;
 }
 // Used by kyro
 SearchArgumentImpl()
 {
     leaves = null;
     expression = null;
 }
 /**
  * Remove MAYBE values from the expression. If they are in an AND operator,
  * they are dropped. If they are in an OR operator, they kill their parent.
  * This assumes that pushDownNot has already been called.
  * @param expr The expression to clean up
  * @return The cleaned up expression
  */
 internal static ExpressionTree foldMaybe(ExpressionTree expr)
 {
     if (expr.getChildren() != null)
     {
         for (int i = 0; i < expr.getChildren().Count; ++i)
         {
             ExpressionTree child = foldMaybe(expr.getChildren()[i]);
             if (child.getConstant() == TruthValue.YES_NO_NULL)
             {
                 switch (expr.getOperator())
                 {
                     case ExpressionTree.Operator.AND:
                         expr.getChildren().RemoveAt(i);
                         i -= 1;
                         break;
                     case ExpressionTree.Operator.OR:
                         // a maybe will kill the or condition
                         return child;
                     default:
                         throw new InvalidOperationException("Got a maybe as child of " +
                             expr);
                 }
             }
             else
             {
                 expr.getChildren()[i] = child;
             }
         }
         if (expr.getChildren().Count == 0)
         {
             return new ExpressionTree(TruthValue.YES_NO_NULL);
         }
     }
     return expr;
 }
 SearchArgumentImpl(ExpressionTree expression, List<PredicateLeaf> leaves)
 {
     this.expression = expression;
     this.leaves = leaves;
 }
 /**
  * Converts multi-level ands and ors into single level ones.
  * @param root the expression to flatten
  * @return the flattened expression, which will always be root with
  *   potentially modified children.
  */
 internal static ExpressionTree flatten(ExpressionTree root)
 {
     if (root.getChildren() != null)
     {
         // iterate through the index, so that if we add more children,
         // they don't get re-visited
         for (int i = 0; i < root.getChildren().Count; ++i)
         {
             ExpressionTree child = flatten(root.getChildren()[i]);
             // do we need to flatten?
             if (child.getOperator() == root.getOperator() &&
                 child.getOperator() != ExpressionTree.Operator.NOT)
             {
                 bool first = true;
                 foreach (ExpressionTree grandkid in child.getChildren())
                 {
                     // for the first grandkid replace the original parent
                     if (first)
                     {
                         first = false;
                         root.getChildren()[i] = grandkid;
                     }
                     else
                     {
                         root.getChildren().Insert(++i, grandkid);
                     }
                 }
             }
             else
             {
                 root.getChildren()[i] = child;
             }
         }
         // if we have a singleton AND or OR, just return the child
         if ((root.getOperator() == ExpressionTree.Operator.OR ||
             root.getOperator() == ExpressionTree.Operator.AND) &&
             root.getChildren().Count == 1)
         {
             return root.getChildren()[0];
         }
     }
     return root;
 }
 /**
  * Convert an expression so that the top level operator is AND with OR
  * operators under it. This routine assumes that all of the NOT operators
  * have been pushed to the leaves via pushdDownNot.
  * @param root the expression
  * @return the normalized expression
  */
 internal static ExpressionTree convertToCNF(ExpressionTree root)
 {
     if (root.getChildren() != null)
     {
         // convert all of the children to CNF
         int size = root.getChildren().Count;
         for (int i = 0; i < size; ++i)
         {
             root.getChildren()[i] = convertToCNF(root.getChildren()[i]);
         }
         if (root.getOperator() == ExpressionTree.Operator.OR)
         {
             // a list of leaves that weren't under AND expressions
             List<ExpressionTree> nonAndList = new List<ExpressionTree>();
             // a list of AND expressions that we need to distribute
             List<ExpressionTree> andList = new List<ExpressionTree>();
             foreach (ExpressionTree child in root.getChildren())
             {
                 if (child.getOperator() == ExpressionTree.Operator.AND)
                 {
                     andList.Add(child);
                 }
                 else if (child.getOperator() == ExpressionTree.Operator.OR)
                 {
                     // pull apart the kids of the OR expression
                     foreach (ExpressionTree grandkid in child.getChildren())
                     {
                         nonAndList.Add(grandkid);
                     }
                 }
                 else
                 {
                     nonAndList.Add(child);
                 }
             }
             if (andList.Count != 0)
             {
                 if (checkCombinationsThreshold(andList))
                 {
                     root = new ExpressionTree(ExpressionTree.Operator.AND);
                     generateAllCombinations(root.getChildren(), andList, nonAndList);
                 }
                 else
                 {
                     root = new ExpressionTree(TruthValue.YES_NO_NULL);
                 }
             }
         }
     }
     return root;
 }
 public SearchArgument.Builder startOr()
 {
     ExpressionTree node = new ExpressionTree(ExpressionTree.Operator.OR);
     currentTree.Peek().getChildren().Add(node);
     currentTree.Push(node);
     return this;
 }
 private ExpressionTree not(ExpressionTree arg)
 {
     return new ExpressionTree(ExpressionTree.Operator.NOT, arg);
 }
 private static void assertNoSharedNodes(ExpressionTree tree, HashSet<ExpressionTree> seen)
 {
     if (seen.Contains(tree) &&
         tree.getOperator() != ExpressionTree.Operator.LEAF)
     {
         Assert.True(false, "repeated node in expression " + tree);
     }
     seen.Add(tree);
     if (tree.getChildren() != null)
     {
         foreach (ExpressionTree child in tree.getChildren())
         {
             assertNoSharedNodes(child, seen);
         }
     }
 }
 // Used by kyro
 SearchArgumentImpl()
 {
     leaves     = null;
     expression = null;
 }
 /**
  * Generate all combinations of items on the andList. For each item on the
  * andList, it generates all combinations of one child from each and
  * expression. Thus, (and a b) (and c d) will be expanded to: (or a c)
  * (or a d) (or b c) (or b d). If there are items on the nonAndList, they
  * are added to each or expression.
  * @param result a list to put the results onto
  * @param andList a list of and expressions
  * @param nonAndList a list of non-and expressions
  */
 private static void generateAllCombinations(List<ExpressionTree> result,
                                             List<ExpressionTree> andList,
                                             List<ExpressionTree> nonAndList
 )
 {
     List<ExpressionTree> kids = andList[0].getChildren();
     if (result.Count == 0)
     {
         foreach (ExpressionTree kid in kids)
         {
             ExpressionTree or = new ExpressionTree(ExpressionTree.Operator.OR);
             result.Add(or);
             foreach (ExpressionTree node in nonAndList)
             {
                 or.getChildren().Add(new ExpressionTree(node));
             }
             or.getChildren().Add(kid);
         }
     }
     else
     {
         List<ExpressionTree> work = new List<ExpressionTree>(result);
         result.Clear();
         foreach (ExpressionTree kid in kids)
         {
             foreach (ExpressionTree or in work)
             {
                 ExpressionTree copy = new ExpressionTree(or);
                 copy.getChildren().Add(kid);
                 result.Add(copy);
             }
         }
     }
     if (andList.Count > 1)
     {
         generateAllCombinations(result, andList.subList(1, andList.Count),
             nonAndList);
     }
 }
 /**
  * Rewrite expression tree to update the leaves.
  * @param root the root of the tree to fix
  * @param leafReorder a map from old leaf ids to new leaf ids
  * @return the fixed root
  */
 static ExpressionTree rewriteLeaves(ExpressionTree root,
                                     int[] leafReorder)
 {
     if (root.getOperator() == ExpressionTree.Operator.LEAF)
     {
         return new ExpressionTree(leafReorder[root.getLeaf()]);
     }
     else if (root.getChildren() != null)
     {
         List<ExpressionTree> children = root.getChildren();
         for (int i = 0; i < children.Count; ++i)
         {
             children[i] = rewriteLeaves(children[i], leafReorder);
         }
     }
     return root;
 }
 SearchArgumentImpl(ExpressionTree expression, List <PredicateLeaf> leaves)
 {
     this.expression = expression;
     this.leaves     = leaves;
 }