package edu.usc.enl.dynamicmeasurement.algorithms.tasks.hhh.flow.singleswitch; import edu.usc.enl.dynamicmeasurement.algorithms.tasks.hhh.NeedInitHHHAlgorithm; import edu.usc.enl.dynamicmeasurement.algorithms.tasks.hhh.flow.FlowHHHAlgorithm; import edu.usc.enl.dynamicmeasurement.algorithms.tasks.multitask.singleswitch.SingleSwitchTask; import edu.usc.enl.dynamicmeasurement.model.WildcardPattern; import edu.usc.enl.dynamicmeasurement.util.Util; import org.w3c.dom.Element; import java.util.*; /** * Created with IntelliJ IDEA. * User: Masoud * Date: 1/22/13 * Time: 11:23 AM <br/> * The single switch implementation of divide & merge algorithm. * It picks the node with maximum weight to divide and picks two sibling nodes to merge */ public class SingleSwitch extends FlowHHHAlgorithm implements NeedInitHHHAlgorithm, SingleSwitchTask.SingleSwitchTaskImplementation { protected TreeMap<WildcardPattern, WildcardPattern> monitors; protected Set<WildcardPattern> siblings; protected int capacity; private double lastHHHAvgRatio = 0; private FalseHHHFinder falseHHHFinder; private double lastAccuracy = 0; public SingleSwitch(Element element) { super(element); int capacity = Util.getNetwork().getFirstMonitorPoints().getCapacity(); setCapacityShare(capacity); monitors = new TreeMap<>(WildcardPattern.WILDCARDNUM_COMPARATOR); initMonitors(capacity, this, taskWildcardPattern); // find siblings in monitors initSiblings(); falseHHHFinder = new FalseHHHFinder(false, wildcardNum); } @Override public void setCapacityShare(int c) { this.capacity = c; } @Override public double estimateAccuracy() { return lastAccuracy; // return -lastHHHAvgRatio; // return 1.0 / (5 * (lastHHHAvgRatio - 1)); //1 - Math.exp(-4 * sum); } @Override public int getUsedResourceShare() { return monitors.size(); } public Collection<WildcardPattern> getMonitors() { return monitors.keySet(); } @Override public Collection<WildcardPattern> findHHH() { Collection<WildcardPattern> hhh = super.findHHH(); double sum = 0; for (WildcardPattern wildcardPattern : hhh) { sum += wildcardPattern.getWeight(); } sum /= hhh.size() * threshold; lastHHHAvgRatio = sum; double accuracy = falseHHHFinder.findFalseHHHs2(hhh, monitors.keySet(), threshold); if (hhh.size() == 0) { lastAccuracy = 1; } else { // double falseHHHs = falseHHHFinder.getLastFalseHHHs().size(); // double trueHHHs = hhh.size() - falseHHHs; // lastAccuracy = (trueHHHs + falseHHHs * trueHHHs / hhh.size()) / hhh.size(); lastAccuracy = accuracy / hhh.size(); // System.out.println(lastAccuracy); } return hhh; } @Override public void update() { //create the treeset TreeSet<WildcardPattern> weights = new TreeSet<>(WildcardPattern.WEIGHT_COMPARATOR); weights.addAll(monitors.keySet()); update(weights); } private void initSiblings() { //assumes monitors is already sorted siblings = new TreeSet<WildcardPattern>();//capacity, 1 WildcardPattern last = null; for (WildcardPattern monitor : monitors.keySet()) { if (last == null) { last = monitor; } else { if (last.isSibling(monitor)) { siblings.add(last); siblings.add(monitor); } last = monitor; } } } public void update(final TreeSet<WildcardPattern> weights) { // printMonitors(); boolean canUpdate = true; int step = 0; while (weights.size() > 0 && canUpdate) { canUpdate = updateStep(weights); displayHook(null, step++); } // System.out.println("////////////////////"); // printMonitors(); } protected boolean updateStep(TreeSet<WildcardPattern> weights) { if (monitors.size() < capacity) { WildcardPattern divideCandidate = findDivideCandidate(weights); if (divideCandidate == null) { return false; } commitDivide(weights, divideCandidate); return true; } if (monitors.size() > capacity) { MinSiblingsFinder minSiblingsFinder = new MinSiblingsFinder(weights, Double.MAX_VALUE).invoke(); WildcardPattern toMerge1 = minSiblingsFinder.getToMerge1(); WildcardPattern toMerge2 = minSiblingsFinder.getToMerge2(); if (toMerge1 == null) { return false; } commitMerge(weights, toMerge1, toMerge2); return true; } if (monitors.size() == capacity) { WildcardPattern maxEntry = findDivideCandidate(weights); if (maxEntry == null) { return false; } MinSiblingsFinder minSiblingsFinder = new MinSiblingsFinder(weights, maxEntry.getWeight()).invoke(); WildcardPattern foundNode1 = minSiblingsFinder.getToMerge1(); WildcardPattern foundNode2 = minSiblingsFinder.getToMerge2(); if (foundNode1 == null) { return false; } commitDivide(weights, maxEntry); commitMerge(weights, foundNode1, foundNode2); return true; } return false; } protected WildcardPattern findDivideCandidate(TreeSet<WildcardPattern> weights) { WildcardPattern maxEntry = null; while (weights.size() > 0) { WildcardPattern maxEntry2 = weights.pollFirst(); if (maxEntry2.canGoDown()) { maxEntry = maxEntry2; break; } } return maxEntry; } protected void commitMerge(TreeSet<WildcardPattern> weights, WildcardPattern toMerge1, WildcardPattern toMerge2) { weights.remove(toMerge1); weights.remove(toMerge2); siblings.remove(toMerge1); siblings.remove(toMerge2); //update monitors monitors.remove(toMerge1); monitors.remove(toMerge2); //go up WildcardPattern minsParent = toMerge1.goUp(); //update weights minsParent.setWeight(toMerge1.getWeight() + toMerge2.getWeight()); weights.add(minsParent); //update siblings WildcardPattern newSibling = minsParent.getSibling(); WildcardPattern sibling = monitors.get(newSibling); if (sibling != null) { //newSibling.setWeight(weight); siblings.add(sibling); siblings.add(minsParent); } monitors.put(minsParent, minsParent); } protected void commitDivide(TreeSet<WildcardPattern> weights, WildcardPattern divideCandidate) { double maxWeight = divideCandidate.getWeight(); if (siblings.contains(divideCandidate)) { //remove old sibling siblings.remove(divideCandidate);//siblings is a set don't mess with hash function siblings.remove(divideCandidate.getSibling()); } monitors.remove(divideCandidate); WildcardPattern divideChild1 = null; WildcardPattern divideChild2 = null; try { divideChild1 = divideCandidate.clone().goDown(false); divideChild2 = divideCandidate.goDown(true); } catch (WildcardPattern.InvalidWildCardValue invalidWildCardValue) { invalidWildCardValue.printStackTrace(); } divideChild1.setWeight(maxWeight / 2); divideChild2.setWeight(maxWeight / 2); weights.add(divideChild1); weights.add(divideChild2); siblings.add(divideChild1); siblings.add(divideChild2); monitors.put(divideChild1, divideChild1); monitors.put(divideChild2, divideChild2); } protected void dfsBreak(WildcardPattern node, int maxLevel, int currentLevel) throws WildcardPattern.InvalidWildCardValue { WildcardPattern lClone = node.clone(); lClone.goDown(false); node.goDown(true); if (currentLevel < maxLevel) { dfsBreak(lClone, maxLevel, currentLevel + 1); dfsBreak(node, maxLevel, currentLevel + 1); } else { monitors.put(lClone, lClone); monitors.put(node, node); } } @Override public void addMonitor(WildcardPattern wildcardPattern) { monitors.put(wildcardPattern, wildcardPattern); } @Override public WildcardPattern pollAMonitor() { return monitors.pollLastEntry().getKey(); } protected class MinSiblingsFinder { protected final TreeSet<WildcardPattern> weights; protected WildcardPattern toMerge1; protected WildcardPattern toMerge2; protected double benefit; public MinSiblingsFinder(TreeSet<WildcardPattern> weights, double benefit) { this.weights = weights; this.benefit = benefit; } public WildcardPattern getToMerge1() { return toMerge1; } public WildcardPattern getToMerge2() { return toMerge2; } public MinSiblingsFinder invoke() { //find min node that has sibling toMerge1 = null; toMerge2 = null; { Map<WildcardPattern, WildcardPattern> seenSiblings = new HashMap<>(); double minSiblingWeight = -1; for (WildcardPattern minCandidate : weights.descendingSet()) {//TODO: can be optimized by tracking the last min if (minCandidate.getWeight() >= benefit || (minSiblingWeight >= 0 && (minCandidate.getWeight() > minSiblingWeight))) { break;//no chance to see a better sibling pair } if (siblings.contains(minCandidate)) { WildcardPattern sibling = monitors.get(minCandidate.getSibling()); double siblingWeight = sibling.getWeight() + minCandidate.getWeight(); if (seenSiblings.containsKey(sibling) && siblingWeight < benefit) {//then check benefit //found it! but the sum may not be min if (minSiblingWeight < 0 || minSiblingWeight > siblingWeight) { toMerge1 = minCandidate; toMerge2 = sibling; minSiblingWeight = siblingWeight; } } else { seenSiblings.put(minCandidate, minCandidate); //wait for the larger candidate } } } } return this; } } }