package de.ugoe.cs.eventbench.models; import java.util.LinkedList; import java.util.List; import java.util.Random; import de.ugoe.cs.eventbench.data.Event; import de.ugoe.cs.eventbench.data.ReplayableEvent; /** *

* This class provides functions to create flattened first-order Markov models * from {@link HighOrderMarkovModel}s and {@link PredictionByPartialMatch} * models through state splitting. *

*

* If possible, the normal high-order markov model should be used, as the Events * may be broken by the flattener, as, e.g., the information * {@link ReplayableEvent}s contain is not preserved. *

* * @author Steffen Herbold * @version 1.0 */ public class ModelFlattener { private static final String EVENT_SEPARATOR = "-=-"; Trie> firstOrderTrie; /** *

* Takes a {@link HighOrderMarkovModel} and returns a * {@link FirstOrderMarkovModel} that conserves the high-order memory * through state splitting. *

* * @param model * model that is flattened * @return flattened first-order Markov model */ public FirstOrderMarkovModel flattenHighOrderMarkovModel( HighOrderMarkovModel model) { int markovOrder = model.trieOrder - 1; FirstOrderMarkovModel firstOrderModel = new FirstOrderMarkovModel( new Random()); firstOrderModel.trieOrder = 2; if (markovOrder == 1) { firstOrderModel.trie = new Trie>(model.trie); firstOrderModel.trieOrder = 2; } else { firstOrderTrie = new Trie>(); TrieNode> rootNode = model.trie.find(null); generateFirstOrderTrie(rootNode, new LinkedList(), markovOrder); firstOrderTrie.updateKnownSymbols(); firstOrderModel.trie = firstOrderTrie; } return firstOrderModel; } /** *

* This method is not available yet and always return null! *

*

* Takes a {@link PredictionByPartialMatch} model and returns a * {@link FirstOrderMarkovModel} that conserves the high-order memory * through state splitting. *

* * @param model * model that is flattened * @return flattened first-order Markov model */ public FirstOrderMarkovModel flattenPredictionByPartialMatch( PredictionByPartialMatch model) { // TODO implement method return null; } /** *

* Converts all nodes of the given depth into first-order node through * state-splitting. For each node at the given depth a new node is created * and appropriate transitions will be added. *

*

* This method traverses through the tree recursively. If the recursion * reaches the desired depth in the tree, node are added. *

* * @param currentNode * node whose sub-trie is currently traversed * @param parentIDs * ID strings of the ancestors of the currentNode * @param depth * depth to go - NOT the current depth. */ private void generateFirstOrderTrie(TrieNode> currentNode, List parentIDs, int depth) { for (TrieNode> child : currentNode.getChildren()) { String currentId = child.getSymbol().getStandardId(); if (depth > 1) { List childParentIDs = new LinkedList(parentIDs); childParentIDs.add(currentId); generateFirstOrderTrie(child, childParentIDs, depth - 1); } else { StringBuilder firstOrderID = new StringBuilder(); for (String parentID : parentIDs) { firstOrderID.append(parentID + EVENT_SEPARATOR); } firstOrderID.append(currentId); TrieNode> firstOrderNode = firstOrderTrie .getChildCreate(new Event(firstOrderID .toString())); firstOrderNode.setCount(child.getCount()); for (TrieNode> transitionChild : child.getChildren()) { StringBuilder transitionID = new StringBuilder(); for (String parentID : parentIDs.subList(1, parentIDs.size())) { transitionID.append(parentID + EVENT_SEPARATOR); } transitionID.append(currentId + EVENT_SEPARATOR); transitionID.append(transitionChild.getSymbol() .getStandardId()); TrieNode> firstOrderTransitionChild = firstOrderNode .getChildCreate(new Event(transitionID .toString())); firstOrderTransitionChild.setCount(transitionChild .getCount()); } } } } }