/// <summary> /// Проверка и удаление нечастых поддеревьев /// </summary> /// <param name="freqList">Список поддеревьев</param> /// <param name="support">Поддержка</param> /// <param name="depth">Глубина</param> private void PruneAfterConnection(FrequentSubtrees freqList, int support, int depth) { List <Tree> freqSubtreesAtDepth = freqList.GetFrequentsAtDepth(depth + 1); foreach (Tree tree in freqSubtreesAtDepth) { tree.PruneAfterConnection(support, depth); } freqList.RemoveCannotBeExtended(depth + 1); }
/// <summary> /// Оценка частоты каждого поддерева из 1 и 2 узлов /// </summary> private void EvaluateFrequency() { foreach (Tree t1 in OneNodeTrees.Values.Where(t => t.IsFrequent)) { FrequentSubtrees.AddFrequentSubtree(t1); } foreach (Tree t2 in TwoNodeTrees.Values.Where(t => t.IsFrequent)) { FrequentSubtrees.AddFrequentSubtree(t2); } }
/// <summary> /// Формирование поддеревьев из 1 и 2 узлов /// </summary> /// <param name="treeSet">Список кодировок деревьев</param> /// <returns>Максимальная глубина деревьев</returns> protected override int Generate1NodeAnd2NodesTrees(List <TextTreeEncoding> treeSet) { int maxDepth = -1; foreach (TextTreeEncoding tree in treeSet) { Get1NodeAnd2NodesTrees(tree.Root, ref maxDepth); } FrequentSubtrees.SetDepth(maxDepth); EvaluateFrequency(); return(maxDepth); }
/// <summary> /// Соединение 2 поддеревьев /// </summary> /// <param name="t2">Поддерево из 2 узлов</param> /// <param name="tree">Поддерево с корнем в листе первого</param> /// <param name="depth">Глубина</param> private void Connect2Subtrees(Tree t2, Tree tree, int depth) { Debug.Assert(t2.Size == 2); string[] preList = t2.ConnectDfsRepresentation(tree); Tree child = Tree.Create(preList, true, SearchParams.Support); ExtendedSubtrees.AddSubtree(child); int depthC = depth + 1; // Глубина соединения while (--depthC >= 0) { if (!t2.ContainsDepth(depthC)) { continue; } int depthTree = depthC + 1; if (!tree.ContainsDepth(depthTree)) { continue; } foreach (TreeEntries tSet in t2[depthC].GetTreeEntries()) { if (!tree.ContainsTreeAtDepth(depthTree, tSet.TreeId)) { continue; } foreach (RootEntry root in tSet.GetRootEntries()) { foreach (SubtreeEntry t2Entry in root.RightMostList) { if (!tree[depthTree][tSet.TreeId].RootDictionary.ContainsKey(t2Entry.SecondIndex)) { continue; } var newEntry = t2Entry.Connect(tree[depthTree][tSet.TreeId][t2Entry.SecondIndex].FirstEntry); child.AddEntry(newEntry); } } } } if (!child.IsFrequent) { return; } FrequentSubtrees.AddFrequentSubtree(child); child.Father = t2; child.Mother = tree; }
/// <summary> /// Комбинирование 2 поддеревьев /// </summary> /// <param name="xTree">Первое поддерево</param> /// <param name="yTree">Второе поддерево</param> /// <param name="depth">Глубина</param> /// <returns>Новое поддерево, полученное путем комбинирования</returns> private Tree Combine2Subtrees(Tree xTree, Tree yTree, int depth) { string[] dfsList = xTree.CombineDfsRepresentation(yTree); Tree child = Tree.Create(dfsList, false, SearchParams.Support); ExtendedSubtrees.AddSubtree(child); int curDepth = depth + 1; while (--curDepth >= 0) { if (!xTree.ContainsDepth(curDepth) || !yTree.ContainsDepth(curDepth)) { continue; } foreach (TreeEntries tSet in xTree[curDepth].GetTreeEntries()) { if (!yTree.ContainsTreeAtDepth(curDepth, tSet.TreeId)) { continue; } foreach (RootEntry root in tSet.GetRootEntries()) { if (!yTree.ContainsRootIndex(curDepth, tSet.TreeId, root.RootIndex)) { continue; } SubtreeEntry xEntry = xTree.GetEntry(curDepth, tSet.TreeId, root.RootIndex); SubtreeEntry yEntry = yTree.GetFirstEntryAfterSpecifiedIndex(xEntry.Depth, xEntry.TreeId, xEntry.RootIndex, xEntry.RightMostIndex); if (yEntry == null) { continue; } child.AddEntry(xEntry.Combine(yEntry)); } } } if (!child.IsFrequent) { return(null); } FrequentSubtrees.AddFrequentSubtree(child); child.Father = xTree; child.Mother = yTree; return(child); }
/// <summary> /// Соединение поддеревьев на заданной глубине /// </summary> /// <param name="depth">Глубина</param> protected override void Connect(int depth) { List <Tree> connectableTrees = FrequentSubtrees.GetConnectableAtDepth(depth); List <Tree> treesToBeConnected = FrequentSubtrees.GetToBeConnectableAtDepth(depth + 1); foreach (Tree f2 in connectableTrees) { List <Tree> toBeConnected = SelectSubtreesOfSameRoot(f2.SecondSymbol, treesToBeConnected, depth + 1); foreach (Tree t in toBeConnected) { string childDfsStr = f2.ConnectDfsRepresentation(t).ToDfsString(); if (ExtendedSubtrees.AlreadyExtended(childDfsStr)) { continue; } if (!f2.HasNewConnectEntryAtDepth(t, depth)) { continue; } Connect2Subtrees(f2, t, depth); } } PruneAfterConnection(FrequentSubtrees, SearchParams.Support, depth); }
/// <summary> /// Обход с целью комбинирования поддеревьев /// </summary> /// <param name="xTree">Дерево, с которым производится комбинация</param> /// <param name="yIndex">Индекс дерева в списке</param> /// <param name="group">Список деревьев, которые можно комбинировать с xTree</param> /// <param name="depth">Глубина</param> private void Traversal(Tree xTree, int yIndex, IList <Tree> group, int depth) { Tree treeX = xTree; Tree treeY = group[yIndex]; string childDfsStr = treeX.CombineDfsRepresentation(treeY).ToDfsString(); Tree child = null; if (ExtendedSubtrees.AlreadyExtended(childDfsStr)) { child = FrequentSubtrees.GetSubtreeAtDepth(childDfsStr, depth); } else if (treeX.HasNewCombineEntryAtDepth(treeY, depth)) { child = Combine2Subtrees(treeX, treeY, depth); } if (child == null) { return; } for (int i = 0; i < group.Count; i++) { Traversal(child, i, group, depth); } }
/// <summary> /// Комбинирование поддеревьев на заданной глубине /// </summary> /// <param name="depth">Глубина</param> protected override void Combine(int depth) { List <Tree> combinableSubtrees = FrequentSubtrees.GetCombinableAtDepth(depth); StartTraversal(combinableSubtrees, depth); }