private CellTreeNode SimplifyTreeByMergingNodes(CellTreeNode rootNode)
        {
            if (rootNode is LeafCellTreeNode)
            {
                return(rootNode);
            }
            rootNode = this.RestructureTreeForMerges(rootNode);
            List <CellTreeNode> children = rootNode.Children;

            for (int index = 0; index < children.Count; ++index)
            {
                children[index] = this.SimplifyTreeByMergingNodes(children[index]);
            }
            bool flag1 = CellTreeNode.IsAssociativeOp(rootNode.OpType);
            List <CellTreeNode> cellTreeNodeList = !flag1?CellTreeSimplifier.GroupNonAssociativeLeafChildren(children) : CellTreeSimplifier.GroupLeafChildrenByExtent(children);

            OpCellTreeNode opCellTreeNode = new OpCellTreeNode(this.m_viewgenContext, rootNode.OpType);
            CellTreeNode   node1          = (CellTreeNode)null;
            bool           flag2          = false;

            foreach (CellTreeNode node2 in cellTreeNodeList)
            {
                if (node1 == null)
                {
                    node1 = node2;
                }
                else
                {
                    bool flag3 = false;
                    if (!flag2 && node1.OpType == CellTreeOpType.Leaf && node2.OpType == CellTreeOpType.Leaf)
                    {
                        flag3 = this.TryMergeCellQueries(rootNode.OpType, ref node1, node2);
                    }
                    if (!flag3)
                    {
                        opCellTreeNode.Add(node1);
                        node1 = node2;
                        if (!flag1)
                        {
                            flag2 = true;
                        }
                    }
                }
            }
            opCellTreeNode.Add(node1);
            return(opCellTreeNode.AssociativeFlatten());
        }
Example #2
0
        // effects: Simplifies the tree rooted at rootNode and returns a new
        // tree -- it ensures that the returned tree has at most one node for
        // any particular extent unless the tree has nodes of the same extent
        // embedded two leaves below LASJ or LOJ, e.g., if we have a tree
        // (where Ni indicates a node for extent i - one Ni can be different
        // from anohter Ni:
        // [N0 IJ N1] LASJ N0 --> This will not be simplified
        // canBooleansOverlap indicates whether an original input cell
        // contributes to multiple nodes in this tree, e.g., V1 IJ V2 UNION V2 IJ V3
        private CellTreeNode SimplifyTreeByMergingNodes(CellTreeNode rootNode)
        {
            if (rootNode is LeafCellTreeNode)
            {
                // View already simple!
                return(rootNode);
            }
            Debug.Assert(
                rootNode.OpType == CellTreeOpType.LOJ || rootNode.OpType == CellTreeOpType.IJ ||
                rootNode.OpType == CellTreeOpType.FOJ || rootNode.OpType == CellTreeOpType.Union ||
                rootNode.OpType == CellTreeOpType.LASJ,
                "Only handle these operations");

            // Before we apply any rule, check if we can improve the opportunity to
            // collapse the nodes
            rootNode = RestructureTreeForMerges(rootNode);

            var children = rootNode.Children;

            Debug.Assert(children.Count > 0, "OpCellTreeNode has no children?");

            // Apply recursively
            for (var i = 0; i < children.Count; i++)
            {
                children[i] = SimplifyTreeByMergingNodes(children[i]);
            }

            // Essentially, we have a node with IJ, LOJ, U or FOJ type that
            // has some children. Check if some of the children can be merged
            // with one another using the corresponding TM/SP rule

            // Ops such as IJ, Union and FOJ are associative, i.e., A op (B
            // op C) is the same as (A op B) op C. This is not true for LOJ
            // and LASJ
            var isAssociativeOp = CellTreeNode.IsAssociativeOp(rootNode.OpType);

            if (isAssociativeOp)
            {
                // Group all the leaf cells of an extent together so that we can
                // later simply run through them without running nested loops
                // We do not do this for LOJ/LASJ nodes since LOJ (LASJ) is not commutative
                // (or associative);
                children = GroupLeafChildrenByExtent(children);
            }
            else
            {
                children = GroupNonAssociativeLeafChildren(children);
            }

            // childrenSet keeps track of the children that need to be procesed/partitioned
            var          newNode   = new OpCellTreeNode(m_viewgenContext, rootNode.OpType);
            CellTreeNode lastChild = null;
            var          skipRest  = false;

            foreach (var child in children)
            {
                if (lastChild == null)
                {
                    // First time in the loop. Just set lastChild
                    lastChild = child;
                    continue;
                }

                var mergedOk = false;
                // try to merge lastChild and child
                if (false == skipRest &&
                    lastChild.OpType == CellTreeOpType.Leaf
                    &&
                    child.OpType == CellTreeOpType.Leaf)
                {
                    // Both are cell queries. Can try to merge them
                    // We do not add lastChild since it could merge
                    // further. It will be added in a later loop or outside the loop
                    mergedOk = TryMergeCellQueries(rootNode.OpType, ref lastChild, child);
                }

                if (false == mergedOk)
                {
                    // No merge occurred. Simply add the previous child as it
                    // is (Note lastChild will be added in the next loop or if
                    // the loop finishes, outside the loop
                    newNode.Add(lastChild);
                    lastChild = child;
                    if (false == isAssociativeOp)
                    {
                        // LOJ is not associative:
                        // (P loj PA) loj PO != P loj (PA loj PO). The RHS does not have
                        // Persons who have orders but no addresses
                        skipRest = true;
                    }
                }
            }

            newNode.Add(lastChild);
            var result = newNode.AssociativeFlatten();

            return(result);
        }
Example #3
0
        // effects: Restructure tree so that it is better positioned for merges
        private CellTreeNode RestructureTreeForMerges(CellTreeNode rootNode)
        {
            var children = rootNode.Children;

            if (CellTreeNode.IsAssociativeOp(rootNode.OpType) == false ||
                children.Count <= 1)
            {
                return(rootNode);
            }

            // If this node's operator is associative and each child's
            // operator is also associative, check if there is a common set
            // of leaf nodes across all grandchildren

            var commonGrandChildren = GetCommonGrandChildren(children);

            if (commonGrandChildren == null)
            {
                return(rootNode);
            }

            var commonChildOpType = children[0].OpType;

            //  We do have the structure that we are looking for
            // (common op2 gc2) op1 (common op2 gc3) op1 (common op2 gc4) becomes
            // common op2 (gc2 op1 gc3 op1 gc4)
            // e.g., (A IJ B IJ X IJ Y) UNION (A IJ B IJ Y IJ Z) UNION (A IJ B IJ R IJ S)
            // becomes A IJ B IJ ((X IJ Y) UNION (Y IJ Z) UNION (R IJ S))

            // From each child in children, get the nodes other than commonGrandChildren - these are gc2, gc3, ...
            // Each gc2 must be connected by op2 as before, i.e., ABC + ACD = A(BC + CD)

            // All children must be OpCellTreeNodes!
            var newChildren = new List <OpCellTreeNode>(children.Count);

            foreach (OpCellTreeNode child in children)
            {
                // Remove all children in child that belong to commonGrandChildren
                // All grandChildren must be leaf nodes at this point
                var newGrandChildren = new List <LeafCellTreeNode>(child.Children.Count);
                foreach (LeafCellTreeNode grandChild in child.Children)
                {
                    if (commonGrandChildren.Contains(grandChild) == false)
                    {
                        newGrandChildren.Add(grandChild);
                    }
                }
                // In the above example, child.OpType is IJ
                Debug.Assert(child.OpType == commonChildOpType);
                var newChild = new OpCellTreeNode(
                    m_viewgenContext, child.OpType,
                    Helpers.AsSuperTypeList <LeafCellTreeNode, CellTreeNode>(newGrandChildren));
                newChildren.Add(newChild);
            }
            // Connect gc2 op1 gc3 op1 gc4 - op1 is UNION in this
            // ((X IJ Y) UNION (Y IJ Z) UNION (R IJ S))
            // rootNode.Type is UNION
            CellTreeNode remainingNodes = new OpCellTreeNode(
                m_viewgenContext, rootNode.OpType,
                Helpers.AsSuperTypeList <OpCellTreeNode, CellTreeNode>(newChildren));
            // Take the common grandchildren and connect via commonChildType
            // i.e., A IJ B
            CellTreeNode commonNodes = new OpCellTreeNode(
                m_viewgenContext, commonChildOpType,
                Helpers.AsSuperTypeList <LeafCellTreeNode, CellTreeNode>(commonGrandChildren));

            // Connect both by commonChildType
            CellTreeNode result = new OpCellTreeNode(
                m_viewgenContext, commonChildOpType,
                new[] { commonNodes, remainingNodes });

            result = result.AssociativeFlatten();
            return(result);
        }
        // effects: Simplifies the tree rooted at rootNode and returns a new
        // tree -- it ensures that the returned tree has at most one node for
        // any particular extent unless the tree has nodes of the same extent
        // embedded two leaves below LASJ or LOJ, e.g., if we have a tree
        // (where Ni indicates a node for extent i - one Ni can be different
        // from anohter Ni: 
        // [N0 IJ N1] LASJ N0 --> This will not be simplified
        // canBooleansOverlap indicates whether an original input cell
        // contributes to multiple nodes in this tree, e.g., V1 IJ V2 UNION V2 IJ V3
        private CellTreeNode SimplifyTreeByMergingNodes(CellTreeNode rootNode)
        {

            if (rootNode is LeafCellTreeNode)
            { // View already simple!
                return rootNode;
            }
            Debug.Assert(rootNode.OpType == CellTreeOpType.LOJ || rootNode.OpType == CellTreeOpType.IJ ||
                         rootNode.OpType == CellTreeOpType.FOJ || rootNode.OpType == CellTreeOpType.Union ||
                         rootNode.OpType == CellTreeOpType.LASJ,
                         "Only handle these operations");

            // Before we apply any rule, check if we can improve the opportunity to
            // collapse the nodes
            rootNode = RestructureTreeForMerges(rootNode);

            List<CellTreeNode> children = rootNode.Children;
            Debug.Assert(children.Count > 0, "OpCellTreeNode has no children?");

            // Apply recursively
            for (int i = 0; i < children.Count; i++)
            {
                children[i] = SimplifyTreeByMergingNodes(children[i]);
            }

            // Essentially, we have a node with IJ, LOJ, U or FOJ type that
            // has some children. Check if some of the children can be merged
            // with one another using the corresponding TM/SP rule

            // Ops such as IJ, Union and FOJ are associative, i.e., A op (B
            // op C) is the same as (A op B) op C. This is not true for LOJ
            // and LASJ
            bool isAssociativeOp = CellTreeNode.IsAssociativeOp(rootNode.OpType);
            if (isAssociativeOp)
            {
                // Group all the leaf cells of an extent together so that we can
                // later simply run through them without running nested loops
                // We do not do this for LOJ/LASJ nodes since LOJ (LASJ) is not commutative
                // (or associative);
                children = GroupLeafChildrenByExtent(children);
            }
            else
            {
                children = GroupNonAssociativeLeafChildren(children);
            }

            // childrenSet keeps track of the children that need to be procesed/partitioned
            OpCellTreeNode newNode = new OpCellTreeNode(m_viewgenContext, rootNode.OpType);
            CellTreeNode lastChild = null;
            bool skipRest = false;
            foreach (CellTreeNode child in children)
            {
                if (lastChild == null)
                {
                    // First time in the loop. Just set lastChild
                    lastChild = child;
                    continue;
                }

                bool mergedOk = false;
                // try to merge lastChild and child
                if (false == skipRest && lastChild.OpType == CellTreeOpType.Leaf &&
                    child.OpType == CellTreeOpType.Leaf)
                {
                    // Both are cell queries. Can try to merge them
                    // We do not add lastChild since it could merge
                    // further. It will be added in a later loop or outside the loop
                    mergedOk = TryMergeCellQueries(rootNode.OpType, ref lastChild, child);
                }

                if (false == mergedOk)
                {
                    // No merge occurred. Simply add the previous child as it
                    // is (Note lastChild will be added in the next loop or if
                    // the loop finishes, outside the loop
                    newNode.Add(lastChild);
                    lastChild = child;
                    if (false == isAssociativeOp)
                    {
                        // LOJ is not associative:
                        // (P loj PA) loj PO != P loj (PA loj PO). The RHS does not have
                        // Persons who have orders but no addresses
                        skipRest = true;
                    }
                }
            }

            newNode.Add(lastChild);
            CellTreeNode result = newNode.AssociativeFlatten();
            return result;
        }
        // effects: Restructure tree so that it is better positioned for merges
        private CellTreeNode RestructureTreeForMerges(CellTreeNode rootNode)
        {
            List<CellTreeNode> children = rootNode.Children;
            if (CellTreeNode.IsAssociativeOp(rootNode.OpType) == false || children.Count <= 1)
            {
                return rootNode;
            }

            // If this node's operator is associative and each child's
            // operator is also associative, check if there is a common set
            // of leaf nodes across all grandchildren

            Set<LeafCellTreeNode> commonGrandChildren = GetCommonGrandChildren(children);
            if (commonGrandChildren == null)
            {
                return rootNode;
            }

            CellTreeOpType commonChildOpType = children[0].OpType;

            //  We do have the structure that we are looking for
            // (common op2 gc2) op1 (common op2 gc3) op1 (common op2 gc4) becomes
            // common op2 (gc2 op1 gc3 op1 gc4)
            // e.g., (A IJ B IJ X IJ Y) UNION (A IJ B IJ Y IJ Z) UNION (A IJ B IJ R IJ S)
            // becomes A IJ B IJ ((X IJ Y) UNION (Y IJ Z) UNION (R IJ S))

            // From each child in children, get the nodes other than commonGrandChildren - these are gc2, gc3, ...
            // Each gc2 must be connected by op2 as before, i.e., ABC + ACD = A(BC + CD)

            // All children must be OpCellTreeNodes!
            List<OpCellTreeNode> newChildren = new List<OpCellTreeNode>(children.Count);
            foreach (OpCellTreeNode child in children)
            {
                // Remove all children in child that belong to commonGrandChildren
                // All grandChildren must be leaf nodes at this point
                List<LeafCellTreeNode> newGrandChildren = new List<LeafCellTreeNode>(child.Children.Count);
                foreach (LeafCellTreeNode grandChild in child.Children)
                {
                    if (commonGrandChildren.Contains(grandChild) == false)
                    {
                        newGrandChildren.Add(grandChild);
                    }
                }
                // In the above example, child.OpType is IJ
                Debug.Assert(child.OpType == commonChildOpType);
                OpCellTreeNode newChild = new OpCellTreeNode(m_viewgenContext, child.OpType,
                                                             Helpers.AsSuperTypeList<LeafCellTreeNode, CellTreeNode>(newGrandChildren));
                newChildren.Add(newChild);
            }
            // Connect gc2 op1 gc3 op1 gc4 - op1 is UNION in this
            // ((X IJ Y) UNION (Y IJ Z) UNION (R IJ S))
            // rootNode.Type is UNION
            CellTreeNode remainingNodes = new OpCellTreeNode(m_viewgenContext, rootNode.OpType,
                                                             Helpers.AsSuperTypeList<OpCellTreeNode, CellTreeNode>(newChildren));
            // Take the common grandchildren and connect via commonChildType
            // i.e., A IJ B
            CellTreeNode commonNodes = new OpCellTreeNode(m_viewgenContext, commonChildOpType,
                                                            Helpers.AsSuperTypeList<LeafCellTreeNode, CellTreeNode>(commonGrandChildren));

            // Connect both by commonChildType
            CellTreeNode result = new OpCellTreeNode(m_viewgenContext, commonChildOpType,
                                                     new CellTreeNode[] { commonNodes, remainingNodes });

            result = result.AssociativeFlatten();
            return result;
        }