Distributing AND over OR in a binary tree (Conjunctive Normal Form)

后端 未结 2 1130
忘了有多久
忘了有多久 2021-01-14 01:08

I\'m trying to convert a binary tree e.g.

OR (Implementation of Operator - a specialisation of TreeNode... see below)
|-A (Implementation of TreeNode... see          


        
相关标签:
2条回答
  • 2021-01-14 01:52

    If AND and OR are the only operators you are using, it shouldn't be hard to tranform your tree to CNF. All you have to do is find structures in the form OR(AND(X,Y), Z) or OR(Z, AND(X,Y)) and use the distribution law.

    private static TreeNode distribute(TreeNode n, TreeNode left, TreeNode right) {
      if (n instanceof Or) {
        if (left instanceof And) {
          // distribute right over left AND
          return new And(new Or(left.getLeft(), right), 
                         new Or(left.getRight(), right));
        } else if (right instanceof And) {
          // distribute left over right AND
          return new And(new Or(right.getLeft(), left), 
                         new Or(right.getRight(), left));
        }
      }
    
      // no change
      return treeNode;
    }
    

    This algorithm must be applied to all nodes of your tree until the tree isn't changed anymore. The order in which you apply the algorithm to the nodes doesn't matter. Intuitively, repetitive application of the algorithm will pull up all AND nodes over OR nodes until the tree is in CNF.

    TreeNode root = ....;
    while (true) {
      TreeNode transformedRoot = reconstruct(root);
      if (root.equals(transformedRoot)) {
        break;
      }
      root = transformedRoot;
    }
    // root is now in CNF
    

    Note: Be aware that the CNF transformation may blow up your tree exponential in size. The shown implementation is quite primitive and doesn't use any enhancements to reduce computation time.

    0 讨论(0)
  • 2021-01-14 01:55

    I recommend you look how the tree is navigated, in your code looks like is a Depth-first search so you will start with the deepest branch (Deepest operator) you have to design your method distribute expecting that order and apply the Distributive Laws for the child nodes in a backtracking way.

    A very general description of what distribute method should do is:

    The flow of what kind of distributive law have to be applied depends on parent's operation type and child nodes. Each child node can be an operator or a value, depending on this combination do the distribution required by the law.

    A pseudo code of what i am trying to tell you is:

    if parent node is OR type
        if child nodes are OPERATOR-VALUE combination
            if OPERATION is AND type
                apply correspondig distribution 
                return the new parent
            else
                apply correspondig distribution 
                return the new parent
        if child node are VALUE-VALUE combination
            return parent
    if parent node is AND type
        if child nodes are OPERATOR-VALUE combination
            if OPERATION is AND type
                apply correspondig distribution 
                return the new parent
            else
                apply correspondig distribution 
                return the new parent
        if child nodes are VALUE-VALUE combination
            return parent;
    

    An implementation example:

    public TreeNode distribute(TreeNode parent,TreeNode leftChild, TreeNode rightChild) {
        if( !(leftChild instanceof Operator) && !(rightChild instanceof Operator) ){
            /*There is nothing to do */
            return parent;
        }
        if( parent.getType() == 'OR'){
            /*
                Apply distributive laws and return the new branch
                for example:        
            */
            if ( (leftChild instanceof operator) &&  !(rightChild instanceof Operator) ){
                TreeNode operatorLeftChild  = leftChild.getLeftChild();
                TreeNode operatorRightChild = leftChild.getRightChild();
                if(leftChild.getType() == 'AND' )
                {
                    /*
                    Applying distributive laws:
                        rightChild OR (operatorLeftChild AND operatorRightChild) 
                            -> (rightChild OR operatorLeftChild) AND (rightChild OR operatorRightChild)
                    */
                    TreeNode newBranch = new Operator("AND");
                    /*new Left child*/
                    TreeNode newLeftChild= new Operator("OR");
                    newLeftChild.setLeftChild(rightChild);
                    newLeftChild.setRightChild(operatorLeftChild);
                    /*new Richt Child */
                    TreeNode newRightChild= new Operator("OR");
                    newRightChild.setLeftChild(rightChild);
                    newRightChild.setRightChild(operatorRightChild);
                    /*Setting the new Branch*/
                    newBranch.setLeftChild(newLeftChild);
                    newBranch.setRightChild(newRightChild);
                    return newBranch;
                }
    
            }
        }
        if( parent.getType() == 'AND'){
            /*
                Else-If and distributive laws stuff
            */
        }
        /*
            You can also implement this part wihtout the else-if code by implementing a true table
            but is more abstract and less human redeable
         */
    }
    

    Note The previous code has not been tested and i am assuming a lot of things i dont know how your tree is implemented may be you will be required to update the parent reference in child nodes.

    0 讨论(0)
提交回复
热议问题