/******************************************************************************* * Copyright (c) 2012-present Jakub Kováč, Jozef Brandýs, Katarína Kotrlová, * Pavol Lukča, Ladislav Pápay, Viktor Tomkovič, Tatiana Tóthová * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package algvis.ds.suffixtree; import algvis.core.Algorithm; import algvis.core.NodeColor; import algvis.core.StringElem; import algvis.ds.trie.TrieWordNode; import java.util.Vector; public class SuffixTreeInsert extends Algorithm { private final SuffixTree T; private final String s; private TrieWordNode hw; public SuffixTreeInsert(SuffixTree T, String s) { super(T.panel); this.T = T; this.s = s; T.clear(); } void beforeReturn() { removeFromScene(hw); // T.clearExtraColor(); addNote("done"); } @Override public void runAlgorithm() { T.text = s; T.str = new StringElem(T.text, 0, SuffixTree.textpos); setHeader("trieinsert", s.substring(0, s.length() - 1)); if (s.compareTo("$") == 0) { addNote("badword"); } Vector<SuffixTreeNode> ruleOneBuffer = new Vector<SuffixTreeNode>(); T.getRoot().ch = ':'; T.text = s; SuffixTreeNode starting = T.getRoot(); int startingJ = 0; SuffixTreeNode setUpSuffixLinkOnThis = T.getRoot(); final int length = T.text.length(); for (int i = 0; i < length; i++) { addStep("sxbphase", i + 1); T.str.setColor(NodeColor.NORMAL.bgColor, i, i + 1); T.reposition(); pause(); final char ch = T.text.charAt(i); if (ch != '$') { addStep("sxbfirstrule", "" + ch); } else { addStep("sxbfirstrule", "\\$"); } T.reposition(); pause(); // in real implementation this is done in O(1) both time & space final Vector<SuffixTreeNode> newRuleOneBuffer = new Vector<SuffixTreeNode>(); for (final SuffixTreeNode u : ruleOneBuffer) { u.setColor(NodeColor.NORMAL); final SuffixTreeNode w = new SuffixTreeNode(T, ch, u.x, u.y, true); u.addChild(w); w.setColor(NodeColor.CACHED); newRuleOneBuffer.add(w); starting = w; w.setKey(newRuleOneBuffer.size()); } ruleOneBuffer = newRuleOneBuffer; starting.setColor(NodeColor.FOUND); if (ch != '$') { addStep("sxbcontinue", "" + ch); } else { addStep("sxbcontinue", "\\$"); } T.reposition(); pause(); final Vector<SuffixTreeNode> upWalk = new Vector<SuffixTreeNode>(); String cachedUpWalk = ""; setUpSuffixLinkOnThis = T.getRoot(); SuffixTreeNode current = starting; boolean pathEnded = false; while (!pathEnded) { addStep("sxbupwalk"); T.reposition(); pause(); SuffixTreeNode caching = current; if ((caching == starting) && (current != T.getRoot())) { caching = caching.getParent(); } while (caching.isPacked()) { upWalk.add(caching); cachedUpWalk = caching.ch + cachedUpWalk; caching = caching.getParent(); } current.unmark(); starting.setColor(NodeColor.FOUND); current = caching; current.mark(); // if upWalk != null for (final SuffixTreeNode u : upWalk) { u.setColor(NodeColor.INSERT); } current.unmark(); if (!current.isRoot()) { addStep("sxbslink"); T.reposition(); pause(); current = current.getSuffixLink(); } if (current.isRoot()) { cachedUpWalk = T.text.substring(startingJ, i); addStep("sxbfind", cachedUpWalk); T.reposition(); pause(); } current.mark(); for (final SuffixTreeNode u : upWalk) { u.setColor(NodeColor.NORMAL); } starting.setColor(NodeColor.FOUND); if (ch != '$') { addStep("sxbdownwalk", "" + ch); } else { addStep("sxbdownwalk", "\\$"); } hw = new TrieWordNode(T, cachedUpWalk, current.x, current.y, NodeColor.INSERT); addToScene(hw); hw.goNextTo(current); T.reposition(); pause(); final Vector<SuffixTreeNode> downWalk = new Vector<SuffixTreeNode>(); caching = current; while (!cachedUpWalk.equals("")) { if (!caching.isPacked()) { current.unmark(); current = caching; current.mark(); } for (final SuffixTreeNode u : downWalk) { u.setColor(NodeColor.INSERT); } hw.setAndGoNextTo(cachedUpWalk, current); // addStep("sxbdownwalkedge"); // T.reposition(); // pause(); // in real implementation this is O(1) both time and space do { caching = caching .getChildWithCH(cachedUpWalk.charAt(0)); cachedUpWalk = cachedUpWalk.substring(1); downWalk.add(caching); } while (!cachedUpWalk.equals("") && caching.isPacked()); } for (final SuffixTreeNode u : downWalk) { u.setColor(NodeColor.NORMAL); } upWalk.clear(); hw.setAndGoNextTo(cachedUpWalk, current); T.reposition(); current = caching; current.mark(); if (current.getChildWithCH(ch) != null) { // rule 3! pathEnded = true; if (setUpSuffixLinkOnThis != T.getRoot()) { setUpSuffixLinkOnThis.setSuffixLink(current); } addStep("sxbthirdrule"); T.reposition(); pause(); current.unmark(); } else { // rule 2 if (setUpSuffixLinkOnThis != T.getRoot()) { setUpSuffixLinkOnThis.setSuffixLink(current); } if (ch != '$') { addStep("sxbsecondrule", "" + ch); } else { addStep("sxbsecondrule", "\\$"); } T.reposition(); pause(); if (current != T.getRoot()) { setUpSuffixLinkOnThis = current; } else { pathEnded = true; } current.setPacked(false); final SuffixTreeNode u = new SuffixTreeNode(T, ch, current.x, current.y, true); current.addChild(u); u.setParent(current); ruleOneBuffer.add(u); u.setKey(ruleOneBuffer.size()); starting.setColor(NodeColor.CACHED); starting = u; startingJ++; starting.setColor(NodeColor.FOUND); addStep("sxbaftersecondrule", "" + ch); T.reposition(); pause(); current.unmark(); if ((current.getSuffixLink() == null) && (!current.isRoot())) { upWalk.add(current); cachedUpWalk = current.ch + cachedUpWalk; current = current.getParent(); } } removeFromScene(hw); } } /* * After Ukkonen's algorithm we need to mark leaves. */ addStep("sxbexplicit"); T.reposition(); pause(); for (final SuffixTreeNode u : ruleOneBuffer) { u.setPacked(false); u.setColor(NodeColor.NORMAL); } T.reposition(); beforeReturn(); } }