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