package edu.usc.enl.dynamicmeasurement.algorithms.tasks.changedetection.groundtruth;
import edu.usc.enl.dynamicmeasurement.algorithms.tasks.changedetection.ChangeDetectionAlgorithm;
import edu.usc.enl.dynamicmeasurement.algorithms.tasks.multitask.singleswitch.SingleSwitchTask;
import edu.usc.enl.dynamicmeasurement.model.WildcardPattern;
import org.w3c.dom.Element;
import java.util.*;
/**
* Created with IntelliJ IDEA.
* User: masoud
* Date: 1/10/14
* Time: 2:56 PM <br/>
* The groundtruth implementation for finding big changes.
* It keeps track of the changes of the most exact IPs after ignoring WildcardNum bits.
* <p>
* <p>An item may have no traffic for many epochs.
* Their record will be removed after NO_TRAFFIC_REMOVE epochs to save memory.
* The item that has no record is assumed to have 0 traffic.</p>
* <p>
* <p>This class does not respect allocated resources and always estimate its accuracy to be 1.
* This class is not a TCAM-based algorithm so it cannot be used in real experiments.</p>
*/
public class ChangeDetectionGroundTruth extends ChangeDetectionAlgorithm implements SingleSwitchTask.SingleSwitchTaskImplementation {
public static final int NO_TRAFFIC_REMOVE = 5;
private Map<Long, GroundTruthNodeHistory> IPHistory = new HashMap<>();
private int step = 0;
public ChangeDetectionGroundTruth(Element element) {
super(element);
}
@Override
public void match(long item, double diff) {
item >>>= wildcardNum; //ignore bits
GroundTruthNodeHistory nodeHistory = IPHistory.get(item);
if (nodeHistory == null) {
nodeHistory = new GroundTruthNodeHistory();
IPHistory.put(item, nodeHistory);
}
nodeHistory.size += diff;
}
/**
* Go through all IP histories gathered and report those with large traffic changes
*
* @param step
* @return
*/
@Override
public Collection<WildcardPattern> findBigChanges(int step) {
Collection<WildcardPattern> output = new ArrayList<>();
for (Iterator<Map.Entry<Long, GroundTruthNodeHistory>> iterator = IPHistory.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<Long, GroundTruthNodeHistory> entry = iterator.next();
GroundTruthNodeHistory history = entry.getValue();
double size = history.size;
if (size == 0) {
history.noTrafficEpochs++;
if (history.noTrafficEpochs > NO_TRAFFIC_REMOVE) {
iterator.remove();
continue;
}
} else {
history.noTrafficEpochs = 0;
}
try {
Double mean = history.getMean();
Long item = entry.getKey();
if (Math.abs(mean - history.size) >= threshold) {
output.add(new WildcardPattern(item, wildcardNum, size - mean));
// System.out.println(this.step + "," + new WildcardPattern(item, 0, size).toStringNoWeight() + "," + size + "," + mean);
}
} catch (NotEnoughDataException e) {
}
history.update();
}
this.step++;
return output;
}
@Override
public void setCapacityShare(int resource) {
}
@Override
public double estimateAccuracy() {
return 1;
}
@Override
public int getUsedResourceShare() {
return 0;
}
@Override
public void reset() {
super.reset();
for (GroundTruthNodeHistory history : IPHistory.values()) {
history.size = 0;
}
}
/**
* keeps track of the history of an item
*/
private class GroundTruthNodeHistory {
private int noTrafficEpochs = 0;
private double ewmaMean;
private double size;
public void update() {
ewmaMean = ewmaMean * ewmaAlpha + size * (1 - ewmaAlpha);
}
public Double getMean() throws NotEnoughDataException {
return ewmaMean;
}
}
}