package pl.edu.mimuw.cloudatlas.agent.modules; import org.apache.commons.math3.distribution.EnumeratedDistribution; import org.apache.commons.math3.util.Pair; import pl.edu.mimuw.cloudatlas.model.PathName; import java.util.*; /** round robin with the same frequency for all levels, round robin with the frequency exponentially decreasing with level, random with the same selection probability for all levels, random with the selection probability decreasing exponentially with level. */ public class GossipGirlStrategies { private int roundRobinSameIt; private ArrayList> roundRobinExpFreqs; private List fullPathComponents; private int fullPathLength; private EnumeratedDistribution expDist; private EnumeratedDistribution uniformDist; public GossipGirlStrategies(PathName fullPath) { fullPathComponents = fullPath.getComponents(); fullPathLength = fullPath.getComponents().size(); initUniformZoneProbabilities(); initExpZoneProbabilities(); roundRobinSameIt = 0; initRoundRobinExpFreqs(); } private void initExpZoneProbabilities() { ArrayList> zoneProbabilities; zoneProbabilities = new ArrayList<>(fullPathLength); for (int i = 0; i < fullPathLength; i++) { Pair probPair = new Pair(fullPathComponents.get(i), Math.exp((double) i+1)); zoneProbabilities.add(probPair); } expDist = new EnumeratedDistribution(zoneProbabilities); } private void initUniformZoneProbabilities() { ArrayList> zoneProbabilities; zoneProbabilities = new ArrayList<>(fullPathLength); Double uniformProb = 1.0/fullPathLength; for (int i = 0; i < fullPathLength; i++) { Pair probPair = new Pair(fullPathComponents.get(i), uniformProb); zoneProbabilities.add(probPair); } uniformDist = new EnumeratedDistribution(zoneProbabilities); } private void initRoundRobinExpFreqs() { roundRobinExpFreqs = new ArrayList<>(); for (String component : fullPathComponents) { roundRobinExpFreqs.add(new Pair(component, 0)); } } public enum ZoneSelectionStrategy { ROUND_ROBIN_SAME_FREQ, ROUND_ROBIN_EXP_FREQ, RANDOM_UNFIORM, RANDOM_DECR_EXP } private String updateRoundRobinExpFreqs() { for (int i = 0; i < roundRobinExpFreqs.size() - 1; i++) { Pair p = roundRobinExpFreqs.get(i); Pair nextP = roundRobinExpFreqs.get(i+1); if (2 * p.getSecond() < nextP.getSecond()) { roundRobinExpFreqs.set(i, new Pair(p.getFirst(), p.getSecond() + 1)); return p.getFirst(); } } Pair rootPath = roundRobinExpFreqs.get(roundRobinExpFreqs.size() - 1); roundRobinExpFreqs.set( roundRobinExpFreqs.size() - 1, new Pair(rootPath.getFirst(), rootPath.getSecond() + 1)); return rootPath.getFirst(); } private String formNewPath(String selectedPath) { String newPath = ""; for (String pathEl : fullPathComponents) { newPath = newPath.concat("/" + pathEl); if (pathEl.equals(selectedPath)) break; } return newPath; } public PathName selectStrategy(ZoneSelectionStrategy selectionStrategy) { String selectedPath = null; switch(selectionStrategy) { case ROUND_ROBIN_SAME_FREQ: selectedPath = fullPathComponents.get(roundRobinSameIt); roundRobinSameIt = (roundRobinSameIt + 1) % fullPathLength; break; case ROUND_ROBIN_EXP_FREQ: selectedPath = updateRoundRobinExpFreqs(); break; case RANDOM_UNFIORM: selectedPath = uniformDist.sample(); break; case RANDOM_DECR_EXP: selectedPath = expDist.sample(); break; default: throw new UnsupportedOperationException("Such strategy doesn't exist"); } return new PathName(formNewPath(selectedPath)); } }