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()); }
// 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); }
// 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; }