private void Cleaning(SplitTree ST, SplitTree tPrime)
 {
     //different from original algorithm 7, since the structure of T' is marked with visited flags, here we don't reset the flags
     //scan T' twice
     System.Collections.Generic.HashSet<MarkerVertex> A = new System.Collections.Generic.HashSet<MarkerVertex>();
     System.Collections.Generic.HashSet<MarkerVertex> B = new System.Collections.Generic.HashSet<MarkerVertex>();
     for (int i = 0, n = tPrime.vertices.Count; i < n; ++i)
     {
         if (tPrime.vertices[i] is DegenerateNode)
         {
             var deg = tPrime.vertices[i] as DegenerateNode;
             A.Clear();//Here A is P* and B is V \ P*
             B.Clear();
             deg.ForEachMarkerVertex((v) =>
                 {
                     if (v.perfect && v != deg.center)
                         A.Add(v);
                     else
                         B.Add(v);
                     return IterationFlag.Continue;
                 });
             if (A.Count > 1 && B.Count > 1)
             {
                 var newNode = SplitNode(deg, B, A);
                 if (newNode.parent == deg)
                     newNode.rootMarkerVertex.opposite.MarkAsPerfect();
                 else
                     deg.rootMarkerVertex.MarkAsPerfect();
                 ST.vertices.Add(newNode);//In this way, the structure of T' is unchanged as the newly forked node contains P*(u)
             }
         }
     }
     //again we don't need to reset flags
     for (int i = 0, n = tPrime.vertices.Count; i < n; ++i)
     {
         if (tPrime.vertices[i] is DegenerateNode)
         {
             var deg = tPrime.vertices[i] as DegenerateNode;
             A.Clear();//Here A is V \ E* and B is E
             B.Clear();
             deg.ForEachMarkerVertex((v) =>
                 {
                     if ((v.perfect && v == deg.center) || (!v.perfect && !deg.GetOppositeGLTVertex(v).visited))//if v is not P and is not incident to a tree edge in T', it is E*
                         B.Add(v);
                     else
                         A.Add(v);
                     return IterationFlag.Continue;
                 });
             if (A.Count > 1 & B.Count > 1)
             {
                 ST.vertices.Add(SplitNode(deg, A, B));//let V \ E* be preserved in T'
             }
         }
     }
     //and we're done with cl(ST(G)) and T_c.
 }
 public SplitTree SplitDecomposition()
 {
     var ST = new SplitTree();
     var sigma = LexBFS();
     for (int i = 0, n = NodeCount; i < n; ++i)
     {
         VertexInsertion(ST, sigma, i);
         //if (i % 100 == 0 && n > 100)
         //    Console.WriteLine(i);
         //if (i >= 2)
         //    ST.Debug(false);
     }
     return ST;
 }
        private void VertexInsertion(SplitTree ST, List<int> sigma, int idx)
        {
            #region Bootstrapping
            if (ST.vertices.Count == 0)//initialization
            {
                Leaf v = new Leaf
                {
                    id = sigma[idx],
                    parent = null,
                };
                ST.AddLeaf(v);
                ST.root = v;
            }
            else if (ST.vertices.Count == 1)//only the root, thus we cache the second vertex
            {
                Leaf v = new Leaf
                {
                    id = sigma[idx],
                    parent = null,
                };
                ST.AddLeaf(v);
            }
            else if (ST.vertices.Count == 2)//now we're building the first trinity
            {
                Leaf v = new Leaf
                {
                    id = sigma[idx],
                    parent = null
                };
                ST.AddLeaf(v);
                int missingConnection = -1; //test the missing connection between the cached 3 leave
                if (!storage[(ST.vertices[0] as Leaf).id].Contains((ST.vertices[1] as Leaf).id))
                {
                    missingConnection = 0;
                }
                else if (!storage[(ST.vertices[0] as Leaf).id].Contains((ST.vertices[2] as Leaf).id))
                {
                    missingConnection = 1;
                }
                else if (!storage[(ST.vertices[1] as Leaf).id].Contains((ST.vertices[2] as Leaf).id))
                {
                    missingConnection = 2;
                }
                MarkerVertex v1 = new MarkerVertex()
                {
                    opposite = ST.vertices[0]
                };
                MarkerVertex v2 = new MarkerVertex()
                {
                    opposite = ST.vertices[1]
                };
                MarkerVertex v3 = new MarkerVertex()
                {
                    opposite = ST.vertices[2]
                };
                (ST.vertices[0] as Leaf).opposite = v1;
                (ST.vertices[1] as Leaf).opposite = v2;
                (ST.vertices[2] as Leaf).opposite = v3;
                MarkerVertex center = null;
                switch (missingConnection)
                {
                    case 0:
                        center = v3;
                        break;
                    case 1:
                        center = v2;
                        break;
                    case 2:
                        center = v1;
                        break;
                    default: break;
                }
                var deg = new DegenerateNode()
                {
                    parent = ST.vertices[0],
                    Vu = new List<MarkerVertex> { v1, v2, v3 },
                    center = center,
                    rootMarkerVertex = v1
                };
                v1.node = deg;
                ST.vertices[1].parent = ST.vertices[2].parent = deg;
                ST.vertices.Add(deg);
                ST.lastVertex = ST.vertices[2] as Leaf;
            }
            #endregion
            else
            {
                TreeEdge e; Vertex u; SplitTree tPrime;
                var returnType = SplitTree_CaseIdentification(ST, sigma, idx, out e, out u, out tPrime);
                switch (returnType)
                {
                    case CaseIdentification_ResultType.SingleLeaf:
                        //This case is not discussed in paper. However, if there's only a single leaf in neighbor set,
                        //then a unique PE edge can be found.
                        //Applying proposition 4.17, case 6
                        e.u = (u as Leaf).opposite;
                        e.v = u;
                        ST.SplitEdgeToStar(e, sigma[idx]);
                        break;
                    case CaseIdentification_ResultType.TreeEdge://PP or PE
                        {
                            bool unique = true;
                            bool pp;
                            //testing uniqueness, page 24
                            //check whether pp or pe
                            if (!e.u.Perfect())
                            {
                                var tmp = e.u;
                                e.u = e.v;
                                e.v = tmp;
                            }
                            pp = e.v.Perfect();
                            var u_GLT = e.u_GLT;
                            var v_GLT = e.v_GLT;
                            DegenerateNode degNode = null;
                            if (u_GLT is DegenerateNode)
                                degNode = u_GLT as DegenerateNode;
                            if (v_GLT is DegenerateNode)
                                degNode = v_GLT as DegenerateNode;
                            if (degNode != null)//attached to a clique or a star
                            {
                                if ((pp && degNode.isClique) || (!pp/*pe*/ && degNode.isStar && (e.u == degNode.center || degNode.Degree(e.v as MarkerVertex) == 1)))
                                {
                                    unique = false;
                                }
                            }
                            if (unique)
                            {
                                //Proposition 4.17 case 5 or 6

                                if (pp)//PP
                                {
                                    ST.SplitEdgeToClique(e, sigma[idx]);
                                }
                                else//PE
                                {
                                    ST.SplitEdgeToStar(e, sigma[idx]);
                                }
                            }
                            else
                            {
                                //Proposition 4.15, case 1 or 2
                                var deg = u_GLT;
                                if (v_GLT is DegenerateNode)
                                    deg = v_GLT;
                                ST.AttachToDegenerateNode(deg as DegenerateNode, sigma[idx]);
                            }
                        }
                        break;
                    case CaseIdentification_ResultType.HybridNode:
                        if (u is DegenerateNode)
                        {
                            //Proposition 4.16
                            var uDeg = u as DegenerateNode;
                            System.Collections.Generic.HashSet<MarkerVertex> PStar = new System.Collections.Generic.HashSet<MarkerVertex>();
                            System.Collections.Generic.HashSet<MarkerVertex> EStar = new System.Collections.Generic.HashSet<MarkerVertex>();
                            uDeg.ForEachMarkerVertex((v) =>
                                {
                                    if (v.perfect && v != uDeg.center)
                                        PStar.Add(v);
                                    else
                                        EStar.Add(v);
                                    return IterationFlag.Continue;
                                });
                            //before we split, determine the new perfect states for the two new markers to be generated
                            bool pp = false;
                            if (uDeg.isStar && uDeg.center.perfect)
                            {
                                pp = true;//see figure 7. pp==true iff star and center is perfect.
                            }
                            var newNode = SplitNode(uDeg, PStar, EStar);
                            ST.vertices.Add(newNode);
                            //e.u \in PStar ; e.v \in EStar (thus containing the original center, if star)
                            //PStar in uDeg; EStar in newNode
                            if (newNode.parent == uDeg)
                            {
                                e.u = newNode.rootMarkerVertex.opposite;
                                e.v = newNode.rootMarkerVertex;
                            }
                            else
                            {
                                e.u = uDeg.rootMarkerVertex;
                                e.v = uDeg.rootMarkerVertex.opposite;
                            }
                            //assign perfect state values
                            if (pp)
                            {
                                e.u.MarkAsPerfect();
                                e.v.MarkAsPerfect();
                            }
                            else//PE, and PStar part always has an empty state and EStar part has perfect.
                            {
                                e.u.MarkAsEmpty();
                                e.v.MarkAsPerfect();
                            }
                            //check whether pp or pe
                            if (!e.u.Perfect())
                            {
                                var tmp = e.u;
                                e.u = e.v;
                                e.v = tmp;
                            }
                            if (e.v.Perfect())//PP
                            {
                                ST.SplitEdgeToClique(e, sigma[idx]);
                            }
                            else//PE
                            {
                                ST.SplitEdgeToStar(e, sigma[idx]);
                            }
                        }
                        else
                        {
                            //Proposition 4.15, case 3
                            ST.AttachToPrimeNode(u as PrimeNode, sigma[idx]);
                        }
                        break;
                    case CaseIdentification_ResultType.FullyMixedSubTree:
                        //Proposition 4.20
                        Cleaning(ST, tPrime);
                        //ST.Debug(false);
                        var contractionNode = Contraction(ST, tPrime, sigma[idx]);
                        break;
                }
            }
        }
        private PrimeNode Contraction(SplitTree ST, SplitTree tPrime, int xId)
        {
            //during the contraction, the active flags won't be used any more. thus available as temporary delete flags
            //when a deleted node has non-empty parentLink and empty unionFind_parent, it is a degenerate to prime conversion and the parentLink points to the converted prime node.
            //when a deleted node has non-empty unionFind_parent, it is a fake node (only playing a role of child representative)
            ST.ResetActiveFlags();
            List<DegenerateNode> Phase1List = new List<DegenerateNode>();
            List<Node> Phase2List = new List<Node>();
            List<Node> nonLeafChildren = new List<Node>();
            Node phase3 = null;//since phase 3 is recursive, we need only a start point.
            #region Phase 0 Initial sweep
            foreach (var v in tPrime.vertices)
            {
                var d = v as DegenerateNode;
                var n = v as Node;
                if (d != null && d.isStar && d.rootMarkerVertex == d.center)
                    Phase1List.Add(d);
                if (n != null && n.Degree(n.rootMarkerVertex) == 1)
                    Phase2List.Add(n);
                if (n != null)
                    phase3 = n;//in case Phase1List and Phase2List are both empty, at least we have a start point for phase 3
            }
            #endregion
            #region Phase 1 node-joins
            foreach (var star in Phase1List)
            {
                if (star.active)//deleted
                    continue;
                phase3 = star;
                nonLeafChildren.Clear();
                phase3.ForEachChild((v) =>
                    {
                        if (v is Node)
                        {
                            nonLeafChildren.Add(v as Node);
                        }
                        return IterationFlag.Continue;
                    }, subtree: true);
                foreach (var c in nonLeafChildren)
                {
                    phase3 = NodeJoin(ST, phase3, c);
                    //c.parentLink = dummy;
                }
                phase3.visited = true;//add the joint node back into T'
            }
            #endregion
            #region Phase 2 node-joins
            foreach (var node in Phase2List)
            {
                if (node.active)//actually I mean "deleted"
                    continue;
                phase3 = node;
                var p = phase3.parent;
                if (p.visited && p is Node)
                {
                    phase3 = NodeJoin(ST, p as Node, phase3);//make sure phase3 now points to the new parent(which is prime)
                }
            }
            #endregion
            #region Phase 3 node-joins
            Debug.Assert(phase3 != null, "Phase 3 node is null, which means that there's nothing left in the fully-mixed subtree T'");
            while (true)
            {
                while (true)
                {
                    nonLeafChildren.Clear();
                    phase3.ForEachChild((v) =>
                        {
                            if (v is Node)
                            {
                                nonLeafChildren.Add(v as Node);
                            }
                            return IterationFlag.Continue;
                        }, subtree: true);
                    if (nonLeafChildren.Count == 0)
                        break;
                    foreach (var c in nonLeafChildren)
                    {
                        phase3 = NodeJoin(ST, phase3, c);
                    }
                }
                var p = phase3.parent;
                if (p == null || p is Leaf || p.visited == false)
                {
                    break;
                }
                else
                    phase3 = p as Node;
            }
            #endregion
            //rebuild ST from dummy flags. Note that this step is very important before using Find() and parent accessor again, because there might be a node with unionFind_parent == dummyFake, and dummyFake has unionFind_parent == null
            //List<GLTVertex> newSTList = new List<GLTVertex>();
            //foreach (var vertex in ST.vertices)
            //{
            //    if (!vertex.active)
            //        newSTList.Add(vertex);//a normal vertex
            //    else if (vertex.parentLink != null && vertex.unionFind_parent == null)
            //        newSTList.Add(vertex.parentLink);//a converted vertex
            //    //otherwise, either a fake node, or a truely-removed one, we don't add them back to ST any more.
            //    //if (vertex.parentLink != deleteDummy && vertex.unionFind_parent != fakeDummy)//neither deleted nor fake
            //    //    newSTList.Add(vertex);
            //    //else if (vertex.parentLink == deleteDummy && vertex.unionFind_parent != null)//replaced
            //    //    newSTList.Add(vertex.unionFind_parent);
            //    //else if (vertex.unionFind_parent == fakeDummy)
            //    //    vertex.unionFind_parent = vertex;//point the unionFind_parent back
            //}
            //ST.vertices = newSTList;

            HashSet<MarkerVertex> Pset = new HashSet<MarkerVertex>();
            phase3.ForEachMarkerVertex((v) =>
                {
                    if (v.perfect)
                        Pset.Add(v);
                    return IterationFlag.Continue;
                });
            Leaf newLeaf = new Leaf()
            {
                id = xId,
                parent = phase3,
            };
            MarkerVertex newMarker = new MarkerVertex()
            {
                opposite = newLeaf,
            };
            newLeaf.opposite = newMarker;
            (phase3 as PrimeNode).AddMarkerVertex(newMarker, Pset);
            (phase3 as PrimeNode).lastMarkerVertex = newMarker;
            ST.AddLeaf(newLeaf);
            return phase3 as PrimeNode;
        }
        //uPrime is the child of u
        //the result of the join is returned.
        private PrimeNode NodeJoin(SplitTree ST, Node u, Node uPrime)
        {
            MarkerVertex qPrime = uPrime.rootMarkerVertex;
            MarkerVertex q = qPrime.opposite as MarkerVertex;
            PrimeNode ret = null;
            List<GLTVertex> uPrimeChildren = new List<GLTVertex>();

            if (u is DegenerateNode)
            {
                ret = (u as DegenerateNode).ConvertToPrime();
                //u.parentLink = ret;
                //u.unionFind_parent = null;
                u.active = true;
            }
            else
                ret = u as PrimeNode;
            var representative = ret.childSetRepresentative;
            if (uPrime is DegenerateNode && (uPrime as DegenerateNode).isStar && qPrime != (uPrime as DegenerateNode).center)//qPrime has degree 1, not center.
            {
                var center = (uPrime as DegenerateNode).center;
                var centerOpposite = center.GetOppositeGLTVertex();
                //Algorithm 8 says q now represents the center of u', so we have to update the center's opposite..
                if (centerOpposite is Node)
                {
                    (centerOpposite as Node).rootMarkerVertex.opposite = q;
                }
                else
                    (centerOpposite as Leaf).opposite = q;
                uPrimeChildren.Add(centerOpposite);
                //And also copy the center's perfect state, and opposite.
                q.perfect = center.perfect;
                q.opposite = center.opposite;
                (uPrime as DegenerateNode).ForEachMarkerVertex((v) =>
                    {
                        if (v != center && v != qPrime)
                        {
                            ret.AddMarkerVertex(v, new HashSet<MarkerVertex> { q });
                            uPrimeChildren.Add(v.GetOppositeGLTVertex());
                        }
                        return IterationFlag.Continue;
                    });
            }
            else
            {
                List<MarkerVertex> qNeighbor = new List<MarkerVertex>();
                ret.ForEachNeighbor(q, (v) =>
                    {
                        qNeighbor.Add(v);
                        return IterationFlag.Continue;
                    });
                ret.RemoveMarkerVertex(q);
                var qPrimeNeighbor = new System.Collections.Generic.HashSet<MarkerVertex>();
                uPrime.ForEachNeighbor(qPrime, (v) =>
                    {
                        qPrimeNeighbor.Add(v);
                        return IterationFlag.Continue;
                    });
                uPrime.ForEachMarkerVertex((v) =>
                    {
                        if (v != qPrime)
                        {
                            if (qPrimeNeighbor.Contains(v))
                            {
                                HashSet<MarkerVertex> nSet = new HashSet<MarkerVertex>(qNeighbor);
                                uPrime.ForEachNeighbor(v, (w) =>
                                    {
                                        if (w != qPrime)
                                            nSet.Add(w);
                                        return IterationFlag.Continue;
                                    });
                                ret.AddMarkerVertex(v, nSet);
                            }
                            else
                            {
                                HashSet<MarkerVertex> nSet = new HashSet<MarkerVertex>();
                                uPrime.ForEachNeighbor(v, (w) =>
                                    {
                                        if (w != qPrime)
                                            nSet.Add(w);
                                        return IterationFlag.Continue;
                                    });
                                ret.AddMarkerVertex(v, nSet);
                            }
                        }
                        return IterationFlag.Continue;
                    });
                if (uPrime is PrimeNode)
                {
                    uPrimeChildren.Add((uPrime as PrimeNode).childSetRepresentative);
                }
                else
                {
                    uPrime.ForEachChild(v =>
                        {
                            uPrimeChildren.Add(v);
                            return IterationFlag.Continue;
                        }, false);
                }
            }

            //union the children of uPrime

            for (int i = 0, n = uPrimeChildren.Count; i < n; ++i)
            {
                uPrimeChildren[i].parentLink = null;
                uPrimeChildren[i].unionFind_parent = representative;
            }

            //set deletion flag for uPrime, or if it's the child representative, make it a fake node
            uPrime.active = true;
            if (uPrime == representative)
            {
                uPrime.parentLink = ret;//update the parentLink to the new prime node
                //don't touch the unoinFind_parent field. leave it pointing to uPrime itself.
            }
            else//uPrime is not a fake node.
            {
                uPrime.parentLink = ret;
                //uPrime.unionFind_parent = null;
            }
            return ret;
        }
        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
        }
        //XXX this algorithm may terminate when there's still an active vertex.
        private SplitTree SmallestSpanningTree(SplitTree ST, int x)
        {
            SplitTree ret = new SplitTree();//Here we don't need the associated graph, just a tree.
            if (ST.vertices.Count == 0)
                return ret;
            //Compute N(x). Note that the initial set L is also Nx
            //PerfectFlags are reset in Algorithm 5, which calls this one.
            Queue<GLTVertex> L = new Queue<GLTVertex>();
            ST.ResetActiveFlags();
            ST.ResetNeighborFlags();
            var originalNx = storage[x];
            GLTVertex p = null;
            bool rootVisited = false;
            foreach (int n in originalNx)
            {
                Leaf v = null;
                if (ST.LeafMapper.TryGetValue(n, out v))
                {
                    v.active = true;//marking a vertex with active means that it is currently enqueued
                    (v as Leaf).neighbor = true;
                    //set the non-root marker vertices opposite leaves of N(x) to perfect
                    var opposite = (v as Leaf).opposite as MarkerVertex;
                    //if (opposite.node == null)//non-root
                    {
                        opposite.perfect = true;
                    }
                    L.Enqueue(v);
                }
            }
            ST.ResetVisitFlags();
            while (L.Count > 0
                //(!rootVisited && L.Count >= 2) || (rootVisited && L.Count >= 1)
                )
            {
                var u = L.Dequeue();
                u.active = false;
                u.visited = true;
                ret.vertices.Add(u);
                p = u.parent;
                if (p == null)
                    rootVisited = true;
                else if (!p.visited && !p.active)
                {
                    p.active = true;
                    L.Enqueue(p);
                }
            }
            if (ret.vertices.Count == 0)
                return ret;
            //adjust the root
            GLTVertex root = ret.vertices[0];
            while ((p = root.parent) != null && p.visited)
                root = p;
            //do not use numberOfChildren, since not all of the children are included in the subtree
            while (true)
            {
                if (root is Leaf)//if root is a leaf, then definitely it has less than 2 children. proceed to the child if it has one.
                {
                    var opposite = (root as Leaf).opposite;
                    bool rootInNx = (root as Leaf).neighbor;
                    if (opposite == null)
                    {
                        //The current leaf is the only vertex in the GLT.
                        //If it is not in Nx, drop it
                        if (!rootInNx)
                        {
                            root.visited = false;
                            ret.vertices.Remove(root);
                            root = null;
                        }
                        break;
                    }

                    if (rootInNx)
                        break;
                    var marker = opposite as MarkerVertex;
                    Debug.Assert(marker != null, "The opposite of a leaf is something other than MarkerVertex!");
                    //Since we are traversing from parent to children, the opposite marker vertex must be the root marker vertex
                    ret.vertices.Remove(root);
                    root.visited = false;
                    root = marker.node;
                }
                else//root is a node. then we check each of its marker vertex except the root marker, find its opposite and see whether it's included or not
                {
                    int count = 0;
                    GLTVertex child = null;
                    (root as Node).ForEachChild((v) =>
                        {
                            ++count;
                            child = v;
                            return IterationFlag.Continue;
                        }, true);
                    if (count != 1)
                        break;
                    //remember to remove root from ret and uncheck its visited flag before iterating to the child
                    ret.vertices.Remove(root);
                    root.visited = false;
                    root = child;
                }
                //ret.vertices.Remove(root);
                //root = c;
            }
            ret.root = root;

            return ret;
        }