/* * Copyright (c) 2005-2010 KOM – Multimedia Communications Lab * * This file is part of PeerfactSim.KOM. * * PeerfactSim.KOM 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 * any later version. * * PeerfactSim.KOM 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 PeerfactSim.KOM. If not, see . * */ package de.tud.kom.p2psim.impl.vehicular.caching.decision; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import de.tudarmstadt.maki.simonstrator.api.Time; import de.tudarmstadt.maki.simonstrator.api.component.sensor.environment.data.TemporalDependencyMatrix; import de.tudarmstadt.maki.simonstrator.api.component.sensor.environment.data.VectoralProperty; import de.tudarmstadt.maki.simonstrator.api.component.sensor.environment.data.measurement.MeasurementDistributionTypeContainer; import de.tudarmstadt.maki.simonstrator.api.component.vehicular.caching.decision.CacheDecisionStrategy; import de.tudarmstadt.maki.simonstrator.api.component.vehicular.information.AvailableInformationAttributes; import de.tudarmstadt.maki.simonstrator.api.component.vehicular.information.PointInformation; import de.tudarmstadt.maki.simonstrator.api.component.vehicular.information.RoadInformation; import de.tudarmstadt.maki.simonstrator.api.component.vehicular.roadnetwork.RoadNetworkEdge; public class TTLbasedVectoralCacheDecisionStrategy implements CacheDecisionStrategy { private static final long SCALING = Time.SECOND; private static final double ACCURACY_FACTOR = 100000; private static final double MIN_STEP = 0.00001; private double accuracy = 1; private double costWrongKeep = 1; private double costWrongChange = 1; private Object _lastDecision = null; public TTLbasedVectoralCacheDecisionStrategy(Map pParams) { for (Entry param : pParams.entrySet()) { switch (param.getKey()) { case "ACCURACY": accuracy = Double.valueOf(param.getValue()); break; case "COST_RATIO": double ratio = Double.valueOf(param.getValue()); costWrongChange = 2 / (ratio + 1); costWrongKeep = 2 - costWrongChange; break; default: break; } } } public double getCostWrongChange() { return costWrongChange; } public double getCostWrongKeep() { return costWrongKeep; } @Override public T decideOnCorrectInformation( List pSimilarPointInformation) { if (pSimilarPointInformation.size() == 1) { T decision = pSimilarPointInformation.get(0); _lastDecision = decision.getValue(); return decision; } else if (pSimilarPointInformation.size() == 0) { return null; } Collections.sort(pSimilarPointInformation, new Comparator() { @Override public int compare(T pArg0, T pArg1) { return Long.compare(pArg0.getDetectionDate(), pArg1.getDetectionDate()); } }); long minTimestamp = Long.MAX_VALUE; long maxTimestamp = 0; Object value = pSimilarPointInformation.get(0).getValue(); if (value instanceof VectoralProperty) { value = ((VectoralProperty) value).getMostProbableIndex(); } boolean differentValue = false; List possibleValues = new ArrayList<>(); for (T t : pSimilarPointInformation) { if (!t.hasAttribute(AvailableInformationAttributes.TTL)) { throw new AssertionError("Unable to perform TTL-based majority voting witout TTL"); } long timestamp = t.getDetectionDate(); if (timestamp < minTimestamp) { minTimestamp = timestamp; } if (timestamp > maxTimestamp) { maxTimestamp = timestamp; } Object currentValue = t.getValue(); if (currentValue instanceof VectoralProperty) { VectoralProperty currentProperty = (VectoralProperty) currentValue; currentValue = currentProperty.getMostProbableIndex(); if (!value.equals(currentValue)) { differentValue = true; } for (int i = 0; i < currentProperty.getValueProbabilities().length; i++) { if (!possibleValues.contains(i)) { possibleValues.add(i); } } } } if (differentValue) { long difference = maxTimestamp - minTimestamp; if (difference == 0) { return pSimilarPointInformation.get(pSimilarPointInformation.size() - 1); } double rate = difference / ((double) (pSimilarPointInformation.size() - 1) * SCALING); long ttl = getTTL(pSimilarPointInformation.get(0)); double numberOfMessages = ttl / rate + 1; VectoralProperty currentProperty = null; List bValues = new ArrayList<>(); double b; for (Integer possibleValue : possibleValues) { double temp = determineB((VectoralProperty) pSimilarPointInformation.get(0).getValue(), ((RoadInformation)pSimilarPointInformation.get(0)).getEdge(), possibleValue, getChangeRate(pSimilarPointInformation.get(0), rate), rate, 1 - accuracy, numberOfMessages, costWrongKeep, costWrongChange); if (!Double.isNaN(temp)) { bValues.add(temp); } } Collections.sort(bValues); if (bValues.size() > 0) { if (bValues.size() % 2 == 0) { b = (bValues.get(bValues.size() / 2) + bValues.get(bValues.size() / 2 - 1)) / 2.0; } else { b = bValues.get(bValues.size() / 2); } } else { b = Double.NEGATIVE_INFINITY; } int count = 0; for (T t : pSimilarPointInformation) { RoadInformation roadInformation = ((RoadInformation) t); VectoralProperty property = (VectoralProperty) roadInformation.getValue(); double impact = calculateImpact(1 - accuracy, numberOfMessages, (((t.getDetectionDate() - maxTimestamp) / SCALING + ttl) / (double)ttl) * numberOfMessages, b) / (accuracy); TemporalDependencyMatrix dependencyMatrix = property.getDependencyMatrix(); dependencyMatrix = modifyDependencyMatrix(dependencyMatrix.age((maxTimestamp - property.getDetectionDate()) / SCALING), impact); VectoralProperty agedProperty = property.age(1, dependencyMatrix); if (currentProperty != null) { currentProperty = currentProperty.combine(agedProperty); } else { currentProperty = agedProperty; } } if (Double.isNaN(currentProperty.getValueProbabilities()[0])) { return pSimilarPointInformation.get(pSimilarPointInformation.size() - 1); } RoadInformation roadInformation = new RoadInformation(currentProperty); copyAttributes((RoadInformation) pSimilarPointInformation.get(0), roadInformation); _lastDecision = roadInformation.getValue(); return (T) roadInformation; } else { maxTimestamp = -1; T maxFitting = null; for (T t : pSimilarPointInformation) { long timestamp = (long) t.getAttribute(AvailableInformationAttributes.TTL); if (timestamp > maxTimestamp) { maxTimestamp = timestamp; maxFitting = t; } } _lastDecision = maxFitting.getValue(); return maxFitting; } } /** * @param pT * @return */ private double getAccuracy(T pT) { // if (pT instanceof RoadInformation) { // RoadInformation roadInformation = ((RoadInformation) pT); // VectoralProperty property = (VectoralProperty) roadInformation.getValue(); // double accuracy = property.getProbabilityForIndex(property.getMostProbableIndex()); // return accuracy; // } return this.accuracy; } private double getChangeRate(T pT, double pRate) { // if (pT instanceof RoadInformation) { // RoadInformation roadInformation = ((RoadInformation) pT); // VectoralProperty property = (VectoralProperty) roadInformation.getValue(); // // TemporalDependencyMatrix dependencyMatrix = property.getDependencyMatrix(); // return 1 - Math.pow(1 - dependencyMatrix.getChangeProbability(0), pRate * (SCALING / Time.SECOND)); // } return getChangeProbability((long) (getTTL(pT) / pRate)); } public long getTTL( T pT) { return (long)pT.getAttribute(AvailableInformationAttributes.TTL) / SCALING; } /** * @param pT * @param pRoadInformation */ private void copyAttributes(RoadInformation pSrc, RoadInformation pDest) { for (AvailableInformationAttributes attribute : pSrc.getAvailableAttributes()) { pDest.setAttribute(attribute, pSrc.getAttribute(attribute)); } } private TemporalDependencyMatrix modifyDependencyMatrix( TemporalDependencyMatrix pDependencyMatrix, double pImpact) { TemporalDependencyMatrix result = pDependencyMatrix.clone(); double[][] dependencies = result.getDependencies(); for (int i = 0; i < dependencies.length; i++) { double finalPercentages = 1.0 / dependencies[i].length; for (int j = 0; j < dependencies[i].length; j++) { dependencies[i][j] = finalPercentages + (pDependencyMatrix.getDependencies()[i][j] - finalPercentages) * pImpact; } } return result; } public double calculateImpact(double errorProbability, double pNumberOfMessages, double pMessageNumber, double b) { double age = pNumberOfMessages - pMessageNumber; if (errorProbability == 0) { if (pMessageNumber == pNumberOfMessages) { return 1; } else { return 0; } } else if (errorProbability == 1) { return 1; } else if (errorProbability == 0.5 || b == 0) { return (1 - errorProbability) / pNumberOfMessages * age + errorProbability; } else if (b == Double.NEGATIVE_INFINITY) { if (pMessageNumber == pNumberOfMessages) { return 1; } else { return 0; } } return (1 - errorProbability) * (Math.exp(b * age) - Math.exp(b * pNumberOfMessages)) / (1 - Math.exp(b * pNumberOfMessages)); } public double getChangeProbability(long ttl) { return 1 - Math.pow(0.5, 1 / (double) ttl); } public int getOptimalMessageAmountForSwitch(double changeProbability, double errorProbability, double costSlow, double costFast) { return (int) Math.round(Math.log(-changeProbability / Math.log(errorProbability) * costSlow / costFast) / Math.log(errorProbability)); } public double determineB(VectoralProperty pTemplate, RoadNetworkEdge pRoadNetworkEdge, int pPossibleValue, double change, double rate, double errorProbability, double pNumberOfMessages, double costSlow, double costFast) { if (errorProbability == 0 || errorProbability == 1 || errorProbability == 0.5) { return Double.NaN; } if (_lastDecision != null) { if (pPossibleValue == ((VectoralProperty)_lastDecision).getMostProbableIndex()) { return Double.NaN; } } else { if (pPossibleValue == pTemplate.getDefaultIndex()) { return Double.NaN; } } double b; double p_c = change; int optimalAmount = getOptimalMessageAmountForSwitch(p_c, errorProbability, costSlow, costFast); if ((int)pNumberOfMessages <= optimalAmount) { return Double.POSITIVE_INFINITY; } if (optimalAmount == 1) { return Double.NEGATIVE_INFINITY; } boolean first = true; double step = 10; if (errorProbability < 0.5) { b = -1 * step; } else { b = 1 * step; } do { VectoralProperty valueAfterN = calculateMostProbable(pTemplate, pRoadNetworkEdge, pPossibleValue, optimalAmount, rate, errorProbability, pNumberOfMessages, b); double probableValueAfterN = Double.NaN; if (valueAfterN != null) { probableValueAfterN = valueAfterN.getMostProbableIndex(); } VectoralProperty valueBeforeN = calculateMostProbable(pTemplate, pRoadNetworkEdge, pPossibleValue, optimalAmount - 1, rate, errorProbability, pNumberOfMessages, b); double probableValueBeforeN = Double.NaN; if (valueBeforeN != null) { probableValueBeforeN = valueBeforeN.getMostProbableIndex(); } if (probableValueAfterN == pPossibleValue && probableValueAfterN != probableValueBeforeN) { return b; } if (!Double.isNaN(probableValueBeforeN) && !Double.isNaN(probableValueBeforeN) && step >= MIN_STEP) { if (probableValueAfterN != pPossibleValue) { if (b < 0) { b -= step; if (!first) { step *= 0.5; } } else { b -= step; step *= 0.5; first = false; } } else if (probableValueAfterN == pPossibleValue && probableValueAfterN == probableValueBeforeN) { if (b > 0) { b += step; if (!first) { step *= 0.5; } } else { b += step; step *= 0.5; first = false; } } else { return Double.NaN; } } else { return Double.NaN; } } while (true); } public VectoralProperty calculateMostProbable(VectoralProperty pTemplate, RoadNetworkEdge pRoadNetworkEdge, int pNewValue, int optimalMessageAmount, double rate, double errorProbability, double pNumberOfMessages, double b) { VectoralProperty currentProperty = null; for (int a = optimalMessageAmount + 1; a <= pNumberOfMessages; a++) { VectoralProperty jamProperty = pTemplate.clone(); if (_lastDecision != null) { jamProperty.set(((VectoralProperty)_lastDecision).getMostProbableIndex(), accuracy, MeasurementDistributionTypeContainer.getDistribution(pTemplate.getClass())); } else { jamProperty.set(pTemplate.getDefaultIndex(), accuracy, MeasurementDistributionTypeContainer.getDistribution(pTemplate.getClass())); } TemporalDependencyMatrix temporalDependencyMatrix = jamProperty.getDependencyMatrix(); temporalDependencyMatrix = temporalDependencyMatrix.age((long) (a * rate)); double impact = calculateImpact(errorProbability, pNumberOfMessages, pNumberOfMessages - a, b); if (Double.isNaN(impact)) { return null; } temporalDependencyMatrix = modifyDependencyMatrix(temporalDependencyMatrix, impact); jamProperty = (VectoralProperty) jamProperty.age(1, temporalDependencyMatrix); if (currentProperty != null) { currentProperty = (VectoralProperty) currentProperty.combine(jamProperty); } else { currentProperty = jamProperty; } } for (int a = 0; a <= optimalMessageAmount; a++) { VectoralProperty jamProperty = pTemplate.clone(); jamProperty.setGaussianWithAccuracy(pNewValue, accuracy); TemporalDependencyMatrix temporalDependencyMatrix = jamProperty.getDependencyMatrix(); temporalDependencyMatrix = temporalDependencyMatrix.age((long) (a * rate)); double impact = calculateImpact(errorProbability, pNumberOfMessages, pNumberOfMessages - a, b); if (Double.isNaN(impact)) { return null; } temporalDependencyMatrix = modifyDependencyMatrix(temporalDependencyMatrix, impact); jamProperty = (VectoralProperty) jamProperty.age(1, temporalDependencyMatrix); if (currentProperty != null) { currentProperty = (VectoralProperty) currentProperty.combine(jamProperty); } else { currentProperty = jamProperty; } } return currentProperty; } }