Esempio n. 1
0
        //void explore(const vector<bool>& isFrequent,
        //    const vector<TextTree>& database,
        //    const int& support,
        //    vector<int>& frequency,
        //    const short level)

        void explore(List <bool> isFrequent,
                     List <TextTree> database,
                     int support,
                     List <int> frequency,
                     Int32 level)
        {
            frequency[currentVertexNumber]++;

            //first, explore the children of the rightmost node
            AutoCreateDictionary <Int32, OccList> potentialChildren = new AutoCreateDictionary <Int32, OccList>();

            HashSet <Int32> buffer = new HashSet <Int32>();

            for (int i = 0; i < occurrence.Count; i++)
            {
                int   myTid      = occurrence[i].Item1;
                Int32 myLocation = occurrence[i].Item2;
                Int32 k          = database[myTid].firstChild[myLocation];
                while (k != -1)
                {
                    if (isFrequent[database[myTid].vLabel[k] - Globals.MIN_VERTEX] == true)
                    {
                        buffer.Add(k);
                    }
                    k = database[myTid].nextSibling[k];
                }

                while ((i + 1) < occurrence.Count && myTid == occurrence[i + 1].Item1)
                {
                    i++;
                    myLocation = occurrence[i].Item2;
                    k          = database[myTid].firstChild[myLocation];
                    while (k != -1)
                    {
                        if (isFrequent[database[myTid].vLabel[k] - Globals.MIN_VERTEX] == true)
                        {
                            buffer.Add(k);
                        }
                        k = database[myTid].nextSibling[k];
                    }
                }

                foreach (Int32 pos2 in buffer)
                {
                    potentialChildren[(Int32)(database[myTid].vLabel[pos2] - Globals.MIN_VERTEX)].insert(myTid, pos2);
                }
                buffer.Clear();
            }

            /*
             * for (pos = potentialChildren.begin(); pos != potentialChildren.end(); ++pos)
             * {
             *  if (pos->second.mySupport >= support)
             *  { //a frequent extension!
             *      currentVertexNumber++;
             *      pos->second.explore(isFrequent, database, support, frequency, level + 1);
             *      currentVertexNumber--;
             *  }
             * }
             */
            foreach (var kvp in potentialChildren)
            {
                if (kvp.Value.mySupport >= support)
                {
                    currentVertexNumber++;
                    kvp.Value.explore(isFrequent, database, support, frequency, (Int32)(level + 1));
                    currentVertexNumber--;
                }
            }

            //second, explore the right siblings of all the ancestors of the rightmost node
            Int32 myLevel = level; //how many backtracks needed to go from the rightmost node to this node on the rightmost path

            while (myLevel != 0)
            {
                potentialChildren.Clear();
                for (int i = 0; i < occurrence.Count; i++)
                {
                    int   myTid      = occurrence[i].Item1;
                    Int32 myLocation = occurrence[i].Item2;
                    //find the location of the current node, the location is derived from the location of the rightmost node
                    for (Int32 m = level; m > myLevel; m--)
                    {
                        myLocation = database[myTid].parent[myLocation];
                    }
                    Int32 k = database[myTid].nextSibling[myLocation];
                    while (k != -1)
                    {
                        if (isFrequent[database[myTid].vLabel[k] - Globals.MIN_VERTEX] == true)
                        {
                            buffer.Add(k);
                        }
                        k = database[myTid].nextSibling[k];
                    }

                    while ((i + 1) < occurrence.Count && myTid == occurrence[i + 1].Item1)
                    {
                        i++;
                        myLocation = occurrence[i].Item2;
                        for (Int32 m = level; m > myLevel; m--)
                        {
                            myLocation = database[myTid].parent[myLocation];
                        }
                        k = database[myTid].nextSibling[myLocation];
                        while (k != -1)
                        {
                            if (isFrequent[database[myTid].vLabel[k] - Globals.MIN_VERTEX] == true)
                            {
                                buffer.Add(k);
                            }
                            k = database[myTid].nextSibling[k];
                        }
                    }


                    //for (pos2 = buffer.begin(); pos2 != buffer.end(); ++pos2)
                    //{
                    //    potentialChildren[database[myTid].vLabel[*pos2] - MIN_VERTEX].insert(myTid, *pos2);
                    //}
                    foreach (Int32 pos2 in buffer)
                    {
                        potentialChildren[(Int32)(database[myTid].vLabel[pos2] - Globals.MIN_VERTEX)].insert(myTid, pos2);
                    }
                    buffer.Clear();
                }

                foreach (var kvp in potentialChildren)
                {
                    if (kvp.Value.mySupport >= support)
                    {
                        //a frequent extension!
                        currentVertexNumber++;
                        kvp.Value.explore(isFrequent, database, support, frequency, myLevel);
                        currentVertexNumber--;
                    }
                }
                myLevel--; //backtrack
            }
        }
Esempio n. 2
0
        public void Run(IEnumerable <TextTree> trees, TreeCollector treeCollector)
        {
            List <TextTree> database = trees.Where(t => treeCollector.IsTreeInteresting(t)).ToList();


            if (database.Count == 0)
            {
                throw new Exception("No trees are interesting... Check TreeCollector.IsTreeInteresting filter function");
            }

            List <int> frequency = Util.CreateListAndFillWithValue(1000, 0);
            List <int> @checked  = Util.CreateListAndFillWithValue(1000, 0);
            List <int> closed    = Util.CreateListAndFillWithValue(1000, 0);
            List <int> maximal   = Util.CreateListAndFillWithValue(1000, 0);

            PatternTree.currentPatternTree.initialSize();

            foreach (TextTree tree in database)
            {
                Globals.MAX_VERTEX = Math.Max(tree.vLabel.Max(), Globals.MAX_VERTEX);
                Globals.MIN_VERTEX = Math.Min(tree.vLabel.Min(), Globals.MIN_VERTEX);
            }

            /******************************************************************
            *   step2.1: scan the database once, find frequent node labels
            ******************************************************************/
            List <bool> isFrequent = Util.CreateListAndFillWithValue(Globals.MAX_VERTEX - Globals.MIN_VERTEX + 1, false);
            AutoCreateDictionary <Int32, int> count = new AutoCreateDictionary <Int32, int>();

            foreach (var curTree in database)
            {
                if (DoDebug)
                {
                    Debug.WriteLine("Tree");
                    Debug.WriteLine(curTree.OutputToString());
                }

                List <bool> isVisited = Util.CreateListAndFillWithValue(Globals.MAX_VERTEX - Globals.MIN_VERTEX + 1, false);
                for (Int32 j = 0; j < curTree.vNumber; j++)
                {
                    Int32 temp = (Int32)(curTree.vLabel[j] - Globals.MIN_VERTEX);
                    if (!isVisited[temp])
                    {
                        isVisited[temp] = true;
                        if (count.ContainsKey(temp))
                        {
                            count[temp]++;
                        }
                        else
                        {
                            count[temp] = 1;
                        }
                    }
                }
            }
            for (Int32 i = 0; i < isFrequent.Count; i++)
            {
                if (count[i] >= Support)
                {
                    isFrequent[i] = true;
                }
            }

            /******************************************************************
            *   step2.2: scan the database another time, to get occurrenceList for all
            *   frequent nodes
            ******************************************************************/
            AutoCreateDictionary <Int32, OccLongList> occLongList = new AutoCreateDictionary <Int32, OccLongList>();
            List <Int32> dummy = new List <Int32>();

            for (int i = 0; i < database.Count; i++)
            {
                for (Int32 j = 0; j < database[i].vNumber; j++)
                {
                    if (isFrequent[database[i].vLabel[j] - Globals.MIN_VERTEX] == true)
                    {
                        occLongList[(Int32)(database[i].vLabel[j] - Globals.MIN_VERTEX)].Insert(i, dummy, j);
                    }
                }
            }

            /******************************************************************
            *  step2.3: explore each frequent item
            ******************************************************************/

            foreach (var kvp in occLongList)
            {
                if (kvp.Value.mySupport >= Support)
                {
                    PatternTree.currentPatternTree.addRightmost((Int32)(kvp.Key + Globals.MIN_VERTEX), 0);
                    kvp.Value.Explore(isFrequent, database, Support, @checked, closed, maximal, 1, treeCollector);
                    PatternTree.currentPatternTree.deleteRightmost();
                }
            }

            //stop_time = time(0);

            /******************************************************************
            *  step2.4: output the results
            ******************************************************************/
            var sb = new StringBuilder();

            for (Int32 j = 0; j < 1000; j++)
            {
                if (@checked[j] > 0)
                {
                    sb.AppendLine($"number of checked {j} trees: {@checked[j]}");
                }
            }
            sb.AppendLine("\n************************");
            for (Int32 j = 0; j < 1000; j++)
            {
                if (closed[j] > 0)
                {
                    sb.AppendLine($"number of closed {j} trees: {closed[j]}");
                }
            }
            sb.AppendLine("\n************************");
            for (Int32 j = 0; j < 1000; j++)
            {
                if (maximal[j] > 0)
                {
                    sb.AppendLine($"number of maximal {j} trees: {maximal[j]}");
                }
            }

            foreach (var pattern in treeCollector.ClosedTrees.OrderBy(p => p.MatchLocations.Count()))
            {
                //Debug.WriteLine($"Tree with support {pattern.MatchLocations.Count()}\n{TreeUtil.StringRepresentation(pattern.Pattern)}");
                //Debug.WriteLine(string.Join("\n", pattern.MatchLocations.Select(treeId => "    " + treeId)));
            }

            Debug.WriteLine(sb.ToString());
            // Console.WriteLine(sb.ToString());
        }
Esempio n. 3
0
        public void Explore(List <bool> isFrequent,
                            List <TextTree> database,
                            int support,
                            List <int> @checked,
                            List <int> closed,
                            List <int> maximal,
                            int depth,
                            TreeCollector treeCollector)
        {
            //for debug
            //Debug.WriteLine($"depth {depth} support of current pattern tree is: {mySupport}");

            /*
             * if (Main.DoDebug && PatternTree.currentPatternTree.NumberOfNodesContainingSubstring("Azure") >= 2)
             * {
             *  Debug.WriteLine($"depth {depth} support of current pattern tree is: {mySupport}");
             *  Debug.WriteLine(PatternTree.currentPatternTree.OutputToString());
             *  Debug.WriteLine(GetOccurrenceLongString());
             *
             *  foreach (var id in occurrenceLong.Select(kvp => kvp.Item1).Distinct())
             *  {
             *      Debug.WriteLine($"  {database[id].tid}");
             *
             *  }
             * }
             */


            Int32 tempV = PatternTree.currentPatternTree.vNumber;

            @checked[tempV]++; //update the number of checked trees

            List <bool> rightPath = Util.CreateListAndFillWithValue(tempV, false);
            Int32       temp      = (Int32)(tempV - 1);

            while (temp != -1)
            {
                rightPath[temp] = true;
                temp            = PatternTree.currentPatternTree.parent[temp];
            }

            HashSet <Tuple <Int32, Int32> > occurrenceMatch = new HashSet <Tuple <Int32, Int32> >(); //(short,short) = (position,label)
            //HashSet<Tuple<short, short>>::iterator pos2;

            //step 1, do the occurrence match check
            int currentIndex; //current index of the occurrenceLong
            int myTid;
            int myLocation;

            //step 1.1, construct the base for occurrenceMatch
            //look at the root (0-th vertex) of the pattern tree
            currentIndex = 0;
            myTid        = occurrenceLong[currentIndex].Item1;
            myLocation   = occurrenceLong[currentIndex].Item2[0];
            if (myLocation != 0)
            { //the rooted of the pattern tree is not the root of the transaction
                occurrenceMatch.Add(Tuple.Create((Int32)0, database[myTid].vLabel[database[myTid].parent[myLocation]]));
            }

            //step 1.2, construct the base for occurrenceMatch
            //look at the "left","below", and "right" of all other nodes (not below the rightmost node)
            for (Int32 i = 1; i < tempV; i++)
            {
                myLocation = occurrenceLong[currentIndex].Item2[i];
                Int32 j;

                //record left occurrences
                if (PatternTree.currentPatternTree.previousSibling[i] == -1) //I have no left sibling
                {
                    j = database[myTid].firstChild[database[myTid].parent[myLocation]];
                }
                else
                {
                    j = occurrenceLong[currentIndex].Item2[PatternTree.currentPatternTree.previousSibling[i]];
                    j = database[myTid].nextSibling[j];
                }

                while (j != myLocation)
                {
                    occurrenceMatch.Add(Tuple.Create(i, database[myTid].vLabel[j]));
                    j = database[myTid].nextSibling[j];
                }

                //record below occurrences
                if (PatternTree.currentPatternTree.firstChild[i] == -1 && i != (tempV - 1))
                {
                    //I have no children
                    //and I am not the rightmost node
                    j = database[myTid].firstChild[myLocation];
                    while (j != -1)
                    {
                        occurrenceMatch.Add(Tuple.Create((Int32)(i + tempV), database[myTid].vLabel[j]));
                        j = database[myTid].nextSibling[j];
                    }
                }

                //record right occurrences
                if (PatternTree.currentPatternTree.nextSibling[i] == -1 && !rightPath[i])
                {
                    //I have no right sibling
                    //and I am not on the rightmost path
                    j = database[myTid].nextSibling[myLocation];
                    while (j != -1)
                    {
                        occurrenceMatch.Add(Tuple.Create((Int32)(i + 2 * tempV), database[myTid].vLabel[j]));
                        j = database[myTid].nextSibling[j];
                    }
                }
            }

            //step 1.3, check the occurrence match
            currentIndex++;

            while (occurrenceMatch.Count != 0 && currentIndex < occurrenceLong.Count)
            {
                myTid = occurrenceLong[currentIndex].Item1;
                var  pos2        = occurrenceMatch.GetEnumerator();
                bool pos2HasNext = pos2.MoveNext();

                var toRemoveFromOccurrenceMatch = new HashSet <Tuple <Int32, Int32> >();
                while (pos2HasNext)
                {
                    Int32 j;

                    if (pos2.Current.Item1 == 0)
                    { //root occurrence
                        myLocation = occurrenceLong[currentIndex].Item2[pos2.Current.Item1];
                        bool isFound = false;

                        if (pos2.Current.Item2 == database[myTid].vLabel[database[myTid].parent[myLocation]])
                        {
                            isFound = true;
                        }

                        if (!isFound)
                        {
                            //occurrenceMatch.Remove(pos2.Current);
                            toRemoveFromOccurrenceMatch.Add(pos2.Current);
                            pos2HasNext = pos2.MoveNext();
                        }
                        else
                        {
                            pos2HasNext = pos2.MoveNext();
                        }
                    }
                    else if (pos2.Current.Item1 < tempV)
                    { //a left occurrence
                        myLocation = occurrenceLong[currentIndex].Item2[pos2.Current.Item1];
                        bool isFound = false;

                        if (PatternTree.currentPatternTree.previousSibling[pos2.Current.Item1] == -1) //I have no left sibling
                        {
                            j = database[myTid].firstChild[database[myTid].parent[myLocation]];
                        }
                        else
                        {
                            j = occurrenceLong[currentIndex].Item2[PatternTree.currentPatternTree.previousSibling[pos2.Current.Item1]];
                            j = database[myTid].nextSibling[j];
                        }

                        while (j != myLocation)
                        {
                            if (database[myTid].vLabel[j] == pos2.Current.Item2)
                            { //found it!
                                isFound = true;
                                break;
                            }
                            j = database[myTid].nextSibling[j];
                        }

                        if (!isFound)
                        {
                            //occurrenceMatch.Remove(pos2.Current);
                            toRemoveFromOccurrenceMatch.Add(pos2.Current);
                            pos2HasNext = pos2.MoveNext();
                        }
                        else
                        {
                            pos2HasNext = pos2.MoveNext();
                        }
                    }
                    else if (tempV < pos2.Current.Item1 && pos2.Current.Item1 < 2 * tempV)
                    { //a below occurrence
                        myLocation = occurrenceLong[currentIndex].Item2[pos2.Current.Item1 - tempV];
                        bool isFound = false;

                        j = database[myTid].firstChild[myLocation];
                        while (j != -1)
                        {
                            if (database[myTid].vLabel[j] == pos2.Current.Item2)
                            { //found it!
                                isFound = true;
                                break;
                            }
                            j = database[myTid].nextSibling[j];
                        }

                        if (!isFound)
                        {
                            //occurrenceMatch.Remove(pos2.Current);
                            toRemoveFromOccurrenceMatch.Add(pos2.Current);
                            pos2HasNext = pos2.MoveNext();
                        }
                        else
                        {
                            pos2HasNext = pos2.MoveNext();
                        }
                    }
                    else
                    { //a right occurrence
                        myLocation = occurrenceLong[currentIndex].Item2[pos2.Current.Item1 - 2 * tempV];
                        bool isFound = false;

                        j = database[myTid].nextSibling[myLocation];
                        while (j != -1)
                        {
                            if (database[myTid].vLabel[j] == pos2.Current.Item2)
                            { //found it!
                                isFound = true;
                                break;
                            }
                            j = database[myTid].nextSibling[j];
                        }

                        if (!isFound)
                        {
                            //occurrenceMatch.Remove(pos2.Current);
                            toRemoveFromOccurrenceMatch.Add(pos2.Current);
                            pos2HasNext = pos2.MoveNext();
                        }
                        else
                        {
                            pos2HasNext = pos2.MoveNext();
                        }
                    }
                }

                foreach (var match in toRemoveFromOccurrenceMatch)
                {
                    occurrenceMatch.Remove(match);
                }
                currentIndex++;
            }

            //step 1.4 prune, if there is occurrence match
            if (occurrenceMatch.Count != 0)
            {
                return;
            }

            //step 2, do transaction match checking
            bool isClosed  = true; //innocent until proven guilty
            bool isMaximal = true;
            HashSet <Tuple <Int32, Int32> > transactionMatch = new HashSet <Tuple <Int32, Int32> >();

            currentIndex = 0;
            int startIndex = 0; //the lower bound of a range
            int stopIndex  = 0; //the upper bound of a range

            myTid = occurrenceLong[0].Item1;
            while ((stopIndex + 1) < occurrenceLong.Count &&
                   myTid == occurrenceLong[stopIndex + 1].Item1)
            {
                stopIndex++;
            }

            for (currentIndex = startIndex; currentIndex <= stopIndex; currentIndex++)
            {
                myLocation = occurrenceLong[currentIndex].Item2[0];

                //step 2.1, construct the base for transactionMatch
                //look at the root (0-th vertex) of the pattern tree
                if (myLocation != 0)
                { //the rooted of the pattern tree is not the root of the transaction
                    transactionMatch.Add(Tuple.Create((Int32)0, database[myTid].vLabel[database[myTid].parent[myLocation]]));
                }

                //step 2.2, construct the base for transactionMatch
                //look at the "left", "below", and "right" of all other nodes (not below the rightmost node)
                for (Int32 i = 1; i < tempV; i++)
                {
                    myLocation = occurrenceLong[currentIndex].Item2[i];
                    Int32 j;

                    //record left occurrences
                    if (PatternTree.currentPatternTree.previousSibling[i] == -1) //I have no left sibling
                    {
                        j = database[myTid].firstChild[database[myTid].parent[myLocation]];
                    }
                    else
                    {
                        j = occurrenceLong[currentIndex].Item2[PatternTree.currentPatternTree.previousSibling[i]];
                        j = database[myTid].nextSibling[j];
                    }
                    while (j != myLocation)
                    {
                        transactionMatch.Add(Tuple.Create(i, database[myTid].vLabel[j]));
                        j = database[myTid].nextSibling[j];
                    }

                    //record below occurrences
                    if (PatternTree.currentPatternTree.firstChild[i] == -1 && i != (tempV - 1))
                    {
                        //I have no children
                        //and I am not the rightmost node
                        j = database[myTid].firstChild[myLocation];
                        while (j != -1)
                        {
                            transactionMatch.Add(Tuple.Create((Int32)(i + tempV), database[myTid].vLabel[j]));
                            j = database[myTid].nextSibling[j];
                        }
                    }

                    //record right occurrences
                    if (PatternTree.currentPatternTree.nextSibling[i] == -1 && !rightPath[i])
                    {
                        //I have no right sibling
                        //and I am not on the rightmost path
                        j = database[myTid].nextSibling[myLocation];
                        while (j != -1)
                        {
                            occurrenceMatch.Add(Tuple.Create((Int32)(i + 2 * tempV), database[myTid].vLabel[j]));
                            j = database[myTid].nextSibling[j];
                        }
                    }
                }
            }

            //step 2.3, check the transaction match
            startIndex = stopIndex + 1;
            while (transactionMatch.Count != 0 && startIndex < occurrenceLong.Count)
            {
                stopIndex = startIndex;
                myTid     = occurrenceLong[startIndex].Item1;

                while ((stopIndex + 1) < occurrenceLong.Count &&
                       myTid == occurrenceLong[stopIndex + 1].Item1)
                {
                    stopIndex++;
                }

                // pos2 = transactionMatch.begin();
                var pos2        = transactionMatch.GetEnumerator();
                var pos2HasNext = pos2.MoveNext();

                var toRemoveFromTransactionMatch = new HashSet <Tuple <Int32, Int32> >();
                while (pos2HasNext)
                {
                    Int32 j;

                    if (pos2.Current.Item1 == 0)
                    { //root occurrence
                        bool isFound = false;
                        currentIndex = startIndex;

                        while (!isFound && currentIndex <= stopIndex)
                        {
                            myLocation = occurrenceLong[currentIndex].Item2[pos2.Current.Item1];

                            if (pos2.Current.Item2 == database[myTid].vLabel[database[myTid].parent[myLocation]])
                            {
                                isFound = true;
                            }

                            currentIndex++;
                        }

                        if (!isFound)
                        {
                            //transactionMatch.erase(pos2++);
                            //transactionMatch.Remove(pos2.Current);
                            toRemoveFromTransactionMatch.Add(pos2.Current);
                            pos2HasNext = pos2.MoveNext();
                        }
                        else
                        {
                            pos2HasNext = pos2.MoveNext();
                        }
                    }
                    else if (pos2.Current.Item1 < tempV)
                    { //a left occurrence
                        bool isFound = false;
                        currentIndex = startIndex;

                        while (!isFound && currentIndex <= stopIndex)
                        {
                            myLocation = occurrenceLong[currentIndex].Item2[pos2.Current.Item1];
                            if (PatternTree.currentPatternTree.previousSibling[pos2.Current.Item1] == -1) //I have no left sibling
                            {
                                j = database[myTid].firstChild[database[myTid].parent[myLocation]];
                            }
                            else
                            {
                                j = occurrenceLong[currentIndex].Item2[PatternTree.currentPatternTree.previousSibling[pos2.Current.Item1]];
                                j = database[myTid].nextSibling[j];
                            }

                            while (j != myLocation)
                            {
                                if (database[myTid].vLabel[j] == pos2.Current.Item2)
                                { //found it!
                                    isFound = true;
                                    break;
                                }
                                j = database[myTid].nextSibling[j];
                            }
                            currentIndex++;
                        }

                        if (!isFound)
                        {
                            //transactionMatch.erase(pos2++);
                            //transactionMatch.Remove(pos2.Current);
                            toRemoveFromTransactionMatch.Add(pos2.Current);
                            pos2HasNext = pos2.MoveNext();
                        }
                        else
                        {
                            pos2HasNext = pos2.MoveNext();
                        }
                    }
                    else if (tempV < pos2.Current.Item1 && pos2.Current.Item1 < 2 * tempV)
                    { //a below occurrence
                        bool isFound = false;
                        currentIndex = startIndex;

                        while (!isFound && currentIndex <= stopIndex)
                        {
                            myLocation = occurrenceLong[currentIndex].Item2[pos2.Current.Item1 - tempV];

                            j = database[myTid].firstChild[myLocation];
                            while (j != -1)
                            {
                                if (database[myTid].vLabel[j] == pos2.Current.Item2)
                                { //found it!
                                    isFound = true;
                                    break;
                                }
                                j = database[myTid].nextSibling[j];
                            }
                            currentIndex++;
                        }

                        if (!isFound)
                        {
                            //transactionMatch.erase(pos2++);
                            //
                            //transactionMatch.Remove(pos2.Current);
                            toRemoveFromTransactionMatch.Add(pos2.Current);
                            pos2HasNext = pos2.MoveNext();
                        }
                        else
                        {
                            pos2HasNext = pos2.MoveNext();
                        }
                    }
                    else
                    { //a right occurrence
                        bool isFound = false;
                        currentIndex = startIndex;

                        while (!isFound && currentIndex <= stopIndex)
                        {
                            myLocation = occurrenceLong[currentIndex].Item2[pos2.Current.Item1 - 2 * tempV];

                            j = database[myTid].nextSibling[myLocation];
                            while (j != -1)
                            {
                                if (database[myTid].vLabel[j] == pos2.Current.Item2)
                                { //found it!
                                    isFound = true;
                                    break;
                                }
                                j = database[myTid].nextSibling[j];
                            }
                        }
                    }
                }

                foreach (var transaction in toRemoveFromTransactionMatch)
                {
                    transactionMatch.Remove(transaction);
                }

                startIndex = stopIndex + 1;
            }

            //step 2.4 not closed or maximal, if there is transaction match
            if (transactionMatch.Count != 0)
            {
                isClosed  = false;
                isMaximal = false;
            }

            //step 3, explore all the right expansions
            bool isRightOccurrenceMatch = false;

            //step 3.1, explore the children of the rightmost node
            AutoCreateDictionary <Int32, OccList> potentialChildren = new AutoCreateDictionary <Int32, OccList>();

            for (int i = 0; i < occurrenceLong.Count; i++)
            {
                myTid      = occurrenceLong[i].Item1;
                myLocation = occurrenceLong[i].Item2[tempV - 1];
                Int32 k = database[myTid].firstChild[myLocation];
                //here, redundancy must be recorded also.
                while (k != -1)
                {
                    if (isFrequent[database[myTid].vLabel[k] - Globals.MIN_VERTEX] == true)
                    {
                        potentialChildren[(Int32)(database[myTid].vLabel[k] - Globals.MIN_VERTEX)].insert(myTid, k, i);
                    }
                    k = database[myTid].nextSibling[k];
                }
            }

            //for (pos = potentialChildren.begin(); pos != potentialChildren.end(); ++pos )
            foreach (var pos in potentialChildren)
            {
                if (pos.Value.mySupport >= support)
                { //a frequent extension!
                    if (pos.Value.mySupport == mySupport)
                    {
                        isClosed = false;
                    }
                    isMaximal = false;
                    PatternTree.currentPatternTree.addRightmost((Int32)(pos.Key + Globals.MIN_VERTEX), PatternTree.currentPatternTree.vNumber);
                    OccLongList newLongList = new OccLongList();
                    if (newLongList.CombineList(this, pos.Value))
                    {
                        isRightOccurrenceMatch = true;
                        isClosed  = false;
                        isMaximal = false;
                    }
                    //Debug.WriteLine($"depth {depth} calling explore in 3.1");
                    newLongList.Explore(isFrequent, database, support, @checked, closed, maximal, depth + 1, treeCollector);
                    //Debug.WriteLine($"depth {depth} returning from explore in 3.1");
                    PatternTree.currentPatternTree.deleteRightmost();
                }
            }

            //step 3.2, explore the right siblings of all the ancestors of the rightmost node
            Int32 tempNode = (Int32)(PatternTree.currentPatternTree.vNumber - 1);

            while (tempNode != 0 && !isRightOccurrenceMatch)
            {
                potentialChildren.Clear();
                for (int i = 0; i < occurrenceLong.Count; i++)
                {
                    myTid      = occurrenceLong[i].Item1;
                    myLocation = occurrenceLong[i].Item2[tempNode];
                    Int32 k = database[myTid].nextSibling[myLocation];
                    while (k != -1)
                    {
                        if (isFrequent[database[myTid].vLabel[k] - Globals.MIN_VERTEX] == true)
                        {
                            potentialChildren[(Int32)(database[myTid].vLabel[k] - Globals.MIN_VERTEX)].insert(myTid, k, i);
                            //Debug.WriteLine($"depth {depth} adding potential child: tid: {myTid} k: {k} i: {i}");
                        }
                        k = database[myTid].nextSibling[k];
                    }
                }

                foreach (var kvp in potentialChildren)
                {
                    //Debug.WriteLine($"depth {depth} in 3.2 looking at potential child {kvp.Key} with label {PatternTree.currentPatternTree.vLabel[kvp.Key]}");
                    if (kvp.Value.mySupport >= support)
                    { //a frequent extension!
                        if (kvp.Value.mySupport == mySupport)
                        {
                            isClosed = false;
                        }
                        isMaximal = false;
                        PatternTree.currentPatternTree.addRightmost((Int32)(kvp.Key + Globals.MIN_VERTEX), tempNode);
                        OccLongList newLongList = new OccLongList();
                        if (newLongList.CombineList(this, kvp.Value))
                        {
                            isRightOccurrenceMatch = true;
                            isClosed  = false;
                            isMaximal = false;
                        }
                        //Debug.WriteLine($"depth {depth} calling explore in 3.2");
                        newLongList.Explore(isFrequent, database, support, @checked, closed, maximal, depth + 1, treeCollector);
                        //Debug.WriteLine($"depth {depth} returning from explore in 3.2");
                        PatternTree.currentPatternTree.deleteRightmost();
                    }
                }
                tempNode = PatternTree.currentPatternTree.parent[tempNode];
            }

            //step 4, the worst case, need to check left blanket to see if maximal
            Dictionary <Tuple <Int32, Int32>, Tuple <int, int> > potentialBlanket = new Dictionary <Tuple <Int32, Int32>, Tuple <int, int> >();
            //(short,short) = (position,label)
            //(int, int) = (lastTid,count)

            Tuple <int, int> pos3;

            currentIndex = 0;
            while (isMaximal && currentIndex < occurrenceLong.Count)
            {
                myTid = occurrenceLong[currentIndex].Item1;

                //step 4.1, look at the root (0-th vertex) of the pattern tree
                myLocation = occurrenceLong[currentIndex].Item2[0];
                if (myLocation != 0)
                { //the rooted of the pattern tree is not the root of the transaction
                  //pos3 = potentialBlanket.find(Tuple.Create(0,database[myTid].vLabel[database[myTid].parent[myLocation]]));

                    var key = Tuple.Create((Int32)0, database[myTid].vLabel[database[myTid].parent[myLocation]]);
                    if (potentialBlanket.TryGetValue(key, out pos3))
                    {
                        if (pos3.Item1 != myTid)
                        {
                            //pos3.Item1 = myTid;
                            //pos3.Item2++;
                            pos3 = Tuple.Create(myTid, pos3.Item2 + 1);
                            potentialBlanket[key] = pos3;
                            if (pos3.Item2 >= support)
                            {
                                isMaximal = false;
                            }
                        }
                    }
                    else
                    {
                        potentialBlanket.Add(key, Tuple.Create(myTid, 1));
                    }
                }

                //step 4.2, look at the "left", "below", and "right" of all other nodes (not below the rightmost node)
                for (Int32 i = 1; i < tempV && isMaximal; i++)
                {
                    myLocation = occurrenceLong[currentIndex].Item2[i];
                    Int32 j;

                    //record left occurrences
                    if (PatternTree.currentPatternTree.previousSibling[i] == -1) //I have no left sibling
                    {
                        j = database[myTid].firstChild[database[myTid].parent[myLocation]];
                    }
                    else
                    {
                        j = occurrenceLong[currentIndex].Item2[PatternTree.currentPatternTree.previousSibling[i]];
                        j = database[myTid].nextSibling[j];
                    }
                    while (j != myLocation)
                    {
                        var key = Tuple.Create(i, database[myTid].vLabel[j]);

                        if (potentialBlanket.TryGetValue(key, out pos3))
                        {
                            if (pos3.Item1 != myTid)
                            {
                                //pos3.Item1 = myTid;
                                //pos3.Item2++;
                                pos3 = Tuple.Create(myTid, pos3.Item2 + 1);
                                potentialBlanket[key] = pos3;
                                if (pos3.Item2 >= support)
                                {
                                    isMaximal = false;
                                }
                            }
                        }
                        else
                        {
                            potentialBlanket.Add(key, Tuple.Create(myTid, 1));
                        }

                        j = database[myTid].nextSibling[j];
                    }

                    //record below occurrences
                    if (isMaximal && (PatternTree.currentPatternTree.firstChild[i] == -1 && i != (tempV - 1)))
                    {
                        //I have no children and I am not the rightmost node
                        j = database[myTid].firstChild[myLocation];
                        while (j != -1)
                        {
                            var key = Tuple.Create((Int32)(i + tempV), database[myTid].vLabel[j]);
                            if (potentialBlanket.TryGetValue(key, out pos3))
                            {
                                if (pos3.Item1 != myTid)
                                {
                                    pos3 = Tuple.Create(myTid, pos3.Item2 + 1);
                                    if (pos3.Item2 >= support)
                                    {
                                        isMaximal = false;
                                    }
                                }
                            }
                            else
                            {
                                potentialBlanket.Add(key, Tuple.Create(myTid, 1));
                            }
                            j = database[myTid].nextSibling[j];
                        }
                    }

                    //record right occurrence
                    if (isMaximal && (PatternTree.currentPatternTree.nextSibling[i] == -1 && !rightPath[i]))
                    {
                        //I have no right sibling and I am not on the right path
                        j = database[myTid].nextSibling[myLocation];
                        while (j != -1)
                        {
                            var key = Tuple.Create((Int32)(i + 2 * tempV), database[myTid].vLabel[j]);

                            if (potentialBlanket.TryGetValue(key, out pos3))
                            {
                                if (pos3.Item1 != myTid)
                                {
                                    pos3 = Tuple.Create(myTid, pos3.Item2 + 1);
                                    if (pos3.Item2 >= support)
                                    {
                                        isMaximal = false;
                                    }
                                }
                            }
                            else
                            {
                                potentialBlanket.Add(key, Tuple.Create(myTid, 1));
                            }
                            j = database[myTid].nextSibling[j];
                        }
                    }
                }

                if (!isMaximal)
                {
                    break;
                }
                currentIndex++;
            }

            if (isClosed && treeCollector.IsTreeInteresting(PatternTree.currentPatternTree))
            {
                closed[tempV]++;

                var treeIDs = occurrenceLong.Select(kvp => database[kvp.Item1].tid).Distinct();

                treeCollector.AddClosedTree(PatternTree.currentPatternTree, mySupport, treeIDs);
                //Debug.WriteLine($"closed with support {mySupport}:  ");
                //Debug.WriteLine(PatternTree.currentPatternTree.OutputToString());
            }
            if (isMaximal && treeCollector.IsTreeInteresting(PatternTree.currentPatternTree))
            {
                maximal[tempV]++;

                var treeIDs = occurrenceLong.Select(kvp => database[kvp.Item1].tid).Distinct();

                treeCollector.AddMaximalTree(PatternTree.currentPatternTree, mySupport, treeIDs);
                //Debug.WriteLine($"closed with support {mySupport}:  ");
                //Debug.WriteLine(PatternTree.currentPatternTree.OutputToString());
            }
        }