public CaseIdentification_ResultType SplitTree_CaseIdentification(SplitTree ST, List<int> sigma, int idx, out TreeEdge e, out Vertex u, out SplitTree tree) { //nodeOrder is the inverse permutation of sigma //Here idx is the index of x. e = new TreeEdge(); u = null; #region Line 1 MarkerVertex.ResetPerfectFlags();//new N(x) will be generated. All old perfect flags outdated. tree = SmallestSpanningTree(ST, sigma[idx]);//N(x) is implied in neighbor flag of each vertex #endregion //remember tree is rooted in tree.root,and it perhaps has a valid parent! //Also, check visited flag when traversing, as only those with visited flag true are included in subtree. #region Line 2 int nodeCount = 0; Queue<Node> processingQueue = new Queue<Node>(); Action<Node> testAllLeave = (n) => { bool? allLeave = null; (n as Node).ForEachChild((v) => { if (!(v is Leaf)) { allLeave = false; return IterationFlag.Break; } allLeave = true; return IterationFlag.Continue; }, subtree: false);//TODO XXX here subtree should be true, according to Algorithm 5 if (!(allLeave == null || !allLeave.Value))//has all leave processingQueue.Enqueue(n); }; foreach (var n in tree.vertices) if (n is Node) { ++nodeCount; testAllLeave(n as Node); } if (nodeCount > 1)//since there're not only 1 node, a node with all leaf children will certainly not be root { while (processingQueue.Count != 0) { var node = processingQueue.Dequeue(); //cast the spell of Remark 5.5 List<MarkerVertex> P, M, E; node.ComputeStates(out P, out M, out E, exclude: node.rootMarkerVertex); //since node has all leaf children, when we exclude the rootMarkerVertex, the time complexity is bound to |Children| //also, M should be empty. Thus case 2 automatically satisfied. <- XXX not really, cannot assert here //Debug.Assert(M.Count == 0, "A node with all leaf children has a mixed marker vertex!!"); var Pset = new System.Collections.Generic.HashSet<MarkerVertex>(P); var inCount = 0; var neighborCount = 0; node.ForEachNeighbor(node.rootMarkerVertex, (q) => { ++neighborCount; if (Pset.Contains(q)) ++inCount; return IterationFlag.Continue; }); //P == N_Gu(q) iff P.Count == inCount == neighborCount if (P.Count == inCount && inCount == neighborCount && M.Count == 0)//now we say that rootMarkerVertex'es opposite vertex is perfect { //(node.rootMarkerVertex.opposite as GLTVertex). node.rootMarkerVertex.opposite.MarkAsPerfect(); tree.RemoveSubTree(node); if (node.parent is Node) testAllLeave(node.parent as Node); } } } #endregion #region Line 3 u = tree.root; bool unique = true; Debug.Assert(u != null, "the root of subtree is null, after removing pendant perfect subtrees"); while (true) { Node child = null; if (u is Leaf) { child = (u as Leaf).opposite.node; if (child == null || !child.visited)//now the leaf root u is the unique vertex in T' { //this case is not discussed in paper... Thanks Emeric, problem solved. return CaseIdentification_ResultType.SingleLeaf; } } else { (u as Node).ForEachChild((v) => { if (v is Node) { if (child == null) { unique = true; child = v as Node; } else { unique = false; return IterationFlag.Break; } } return IterationFlag.Continue; }, subtree: true); } //here unique indicates whether u has a unique node child if (unique == false) break;//there are at least two non-leaf children of the current root; break out and return the subtree, now. else if (child == null)//u contains no non-leaf child { //now we can say u is the unique node in T' break; } else// the unique child node is located { if (u is Leaf) { //the root is a leaf, which indicates that root \in N(x), thus perfect. (u as Leaf).visited = false; tree.vertices.Remove(u as Leaf); u = child;//prune it directly. } else { List<MarkerVertex> P, M, E; (u as Node).ComputeStates(out P, out M, out E, exclude: child.rootMarkerVertex.opposite as MarkerVertex, excludeRootMarkerVertex: false); bool perfect = false; if (M.Count == 0)//condition 2 is satisfied { var Pset = new System.Collections.Generic.HashSet<MarkerVertex>(P); var inCount = 0; var neighborCount = 0; (u as Node).ForEachNeighbor(child.rootMarkerVertex.opposite as MarkerVertex, (q) => { ++neighborCount; if (Pset.Contains(q)) ++inCount; return IterationFlag.Continue; }); //P == N_Gu(q) iff P.Count == inCount == neighborCount if (P.Count == inCount && inCount == neighborCount)//now we say that child's rootMarkerVertex is perfect { child.rootMarkerVertex.MarkAsPerfect(); perfect = true; } } if (perfect) { tree.RemoveSubTree(u as Node, exclude: child); u = child; } else { //the tree edge uv is fully mixed. thus the subtree T' is fully mixed. unique = false; break; } } } tree.root = u as GLTVertex;//let the tree root follow u after each iteration of the processing loop } #endregion #region Line 4 if (!unique) return CaseIdentification_ResultType.FullyMixedSubTree; else { #region if (u is DegenerateNode) if (u is DegenerateNode) { #region Lemma 5.6 var uDeg = u as DegenerateNode; MarkerVertex q = null; List<MarkerVertex> P, M, E; //Note, we computed P(u), thus if q exists, its perfect flag is available (uDeg).ComputeStates(out P, out M, out E); //Debug.Assert(M.Count == 0, "Algorithm 5 Line 4, lemma 5.6 requires P(u) == NE(u)!"); if (M.Count == 0) { if (P.Count == 1 && uDeg.isStar && uDeg.center == P[0])//case 3 { uDeg.ForEachMarkerVertex((v) => { if (v != uDeg.center) { q = v; return IterationFlag.Break; } return IterationFlag.Continue; }); } else if (P.Count == 2 && uDeg.isStar && P.Contains(uDeg.center))//case 4 { if (uDeg.center == P[0]) q = P[1]; else q = P[0]; } else { int count = P.Count + E.Count;//faster than the commented line below //uDeg.ForEachMarkerVertex((v) => { ++count; return IterationFlag.Continue; }); if (count == P.Count)//case 1 { if (uDeg.isClique) q = P[0]; else q = uDeg.center; } else if (P.Count == count - 1 && (uDeg.isClique || E[0] == uDeg.center))//case 2 { //E[0]: V(u) \ P(u) q = E[0]; } } } #endregion if (q != null) { e.u = q; e.v = q.opposite; q.opposite.MarkAsPerfect(); return CaseIdentification_ResultType.TreeEdge; } else { return CaseIdentification_ResultType.HybridNode; } } #endregion #region else: prime node else//prime node { var uPrime = u as PrimeNode; MarkerVertex q = uPrime.lastMarkerVertex;//last leaf vertex in \sigma[G(u)] MarkerVertex qPrime = (u as PrimeNode).universalMarkerVetex;//the universal marker (if any) //Again cast the spell of Remark 5.5 List<MarkerVertex> P, M, E; //Note, here we didn't exclude anything. Which means that, if a PP/PE edge is returned, perfect flags will be available. uPrime.ComputeStates(out P, out M, out E); //first, for q if (M.Count == 0 || (M.Count == 1 && M[0] == q))//condition 2 { var Pset = new System.Collections.Generic.HashSet<MarkerVertex>(P); var inCount = 0; var neighborCount = 0; uPrime.ForEachNeighbor(q, (r) => { ++neighborCount; if (Pset.Contains(r)) ++inCount; return IterationFlag.Continue; }); //P == N_Gu(q) iff P.Count == inCount == neighborCount, or P.Count == inCount+1 == neighborCount+1 and q in P if ((P.Count == inCount && inCount == neighborCount) || (P.Count == inCount + 1 && P.Count == neighborCount + 1 && Pset.Contains(q))) { e.u = q; e.v = q.opposite; q.opposite.MarkAsPerfect(); return CaseIdentification_ResultType.TreeEdge; } } //then for q' if (qPrime != null) { if (M.Count == 0 || (M.Count == 1 && M[0] == qPrime))//condition 2 { var Pset = new System.Collections.Generic.HashSet<MarkerVertex>(P); var inCount = 0; var neighborCount = 0; uPrime.ForEachNeighbor(qPrime, (r) => { ++neighborCount; if (Pset.Contains(r)) ++inCount; return IterationFlag.Continue; }); //P == N_Gu(q) iff P.Count == inCount == neighborCount, or P.Count == inCount+1 == neighborCount+1 and q in P if ((P.Count == inCount && inCount == neighborCount) || (P.Count == inCount + 1 && P.Count == neighborCount + 1 && Pset.Contains(qPrime))) { e.u = qPrime; e.v = qPrime.opposite; qPrime.opposite.MarkAsPerfect(); return CaseIdentification_ResultType.TreeEdge; } } } //else, just return u return CaseIdentification_ResultType.HybridNode; } #endregion } #endregion }
//Proposition 4.17 internal void SplitEdgeToStar(TreeEdge e, int xId) { //Assume e is P-E GLTVertex oParent = e.u.GetGLTVertex(); GLTVertex oChild = e.v.GetGLTVertex(); bool uIsParent = true; //test and swap if (oChild.parent != oParent) { var tmp = oParent; oParent = oChild; oChild = tmp; uIsParent = false; } ////Fixing multiple-star forking problem //var oChildDeg = oChild as DegenerateNode; //if (oChildDeg != null && oChildDeg.isStar && oChildDeg.center == oChildDeg.rootMarkerVertex) //{ // //note that if child's center is not root, we cannot merge. // AttachToDegenerateNode(oChildDeg, xId); // return; //} MarkerVertex v1 = new MarkerVertex(); MarkerVertex v2 = new MarkerVertex(); MarkerVertex v3 = new MarkerVertex(); //center is E (e.v) => v2 var deg = new DegenerateNode() { active = false, center = v2, parent = oParent, rootMarkerVertex = uIsParent ? v1 : v2, visited = false, Vu = new List<MarkerVertex> { v1, v2, v3 } }; if (uIsParent) v1.node = deg; else v2.node = deg; deg.parent = oParent; if (oParent is PrimeNode == false) { oChild.parent = deg; } else { //(oParent as PrimeNode).ForEachChild(c => // { // if (c.unionFind_parent == oChild) // Console.WriteLine("!!!"); // return IterationFlag.Continue; // }, false); //oChild.parent = deg; var newChild = oChild.Clone();//since oChild is potentially pointed by others' unionFind_parent, we have to clone. if (newChild is Leaf) { LeafMapper[(newChild as Leaf).id] = newChild as Leaf; //a new leaf is cloned. thus e.u / e.v is cloned. check and update. if (e.u is Leaf) e.u = newChild; else e.v = newChild; } newChild.parent = deg; } //linking e.u & e.v to v1 & v2 if (e.u is MarkerVertex) (e.u as MarkerVertex).opposite = v1; else (e.u as Leaf).opposite = v1; if (e.v is MarkerVertex) (e.v as MarkerVertex).opposite = v2; else (e.v as Leaf).opposite = v2; v1.opposite = e.u; v2.opposite = e.v; Leaf x = new Leaf { id = xId, opposite = v3, }; v3.opposite = x; x.parent = deg; //vertices.Add(deg); AddLeaf(x); }