Pareto.java

90 lines | 3.781 kB Blame History Raw Download
package br.ufrgs.inf.prosoft.tfcache;

import br.ufrgs.inf.prosoft.tfcache.configuration.Configuration;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Pareto {

    private final Map<Double, Metrics> savedTimeHasMetrics;

    public Pareto() {
        savedTimeHasMetrics = new ConcurrentHashMap<>();
    }

    public Pareto(List<Metrics> metrics) {
        this();
        metrics.forEach(this::addIfPareto);
    }

    public static void removeDominatedMetrics(Collection<Metrics> allMetrics) {
        Map<Double, List<Metrics>> groupBySavedTime = allMetrics.stream().collect(Collectors.groupingBy(Metrics::getSavedTime));
        groupBySavedTime.remove(0L);
        groupBySavedTime.forEach((savedTime, metrics) -> {
            double minIdleTime = metrics.stream().mapToDouble(Metrics::getIdleTime).min().orElse(0);
            metrics.removeIf(metric -> metric.getIdleTime() > minIdleTime);
        });

        List<Metrics> localMaxima = groupBySavedTime.values().stream()
                .map(Collection::stream)
                .reduce(Stream::concat)
                .orElse(Stream.empty())
                .collect(Collectors.toList());

        allMetrics.removeIf(metrics -> !localMaxima.contains(metrics));
    }

    public synchronized void addIfPareto(Metrics metrics) {
        if (metrics.getSavedTime() == 0) {
            return;
        }
        savedTimeHasMetrics.merge(metrics.getSavedTime(), metrics, (existing, incoming) -> existing.getIdleTime() < incoming.getIdleTime() ? existing : incoming);
    }

    public Collection<Metrics> values() {
        return savedTimeHasMetrics.values();
    }

    public Set<Long> getTtls() {
        return values().stream().map(Metrics::getTtl).collect(Collectors.toSet());
    }

    public Stream<Metrics> getNormalised() {
        double minSavedTime = values().stream().mapToDouble(Metrics::getSavedTime).min().orElseThrow();
        double maxSavedTime = values().stream().mapToDouble(Metrics::getSavedTime).max().orElseThrow();
        double distanceSavedTime = maxSavedTime - minSavedTime;
        double minIdleTime = values().stream().mapToDouble(Metrics::getIdleTime).min().orElseThrow();
        double maxIdleTime = values().stream().mapToDouble(Metrics::getIdleTime).max().orElseThrow();
        double distanceIdleTime = maxIdleTime - minIdleTime;

        return values().stream().map(it -> {
            double normalisedSavedTime = (it.getSavedTime() - minSavedTime) / distanceSavedTime;
            double normalisedIdleTime = (it.getIdleTime() - minIdleTime) / distanceIdleTime;
            return it.getNormalised(normalisedSavedTime, normalisedIdleTime);
        });
    }

    public Metrics getBestMetrics() {
        return getBestMetrics(Configuration.getPreferences().get(0), Configuration.getPreferences().get(1));
    }

    private Metrics getBestMetrics(double percentageObjectiveSavedTime, double percentageObjectiveIdleTime) {
        if (percentageObjectiveSavedTime < 0 || percentageObjectiveSavedTime > 1) {
            throw new RuntimeException("invalid objective saved time");
        }
        if (percentageObjectiveIdleTime < 0 || percentageObjectiveIdleTime > 1) {
            throw new RuntimeException("invalid objective idle time");
        }
        if (savedTimeHasMetrics.isEmpty()) {
            return new Metrics();
        }
        double minIdleTime = values().stream().mapToDouble(Metrics::getIdleTime).min().orElseThrow() * percentageObjectiveIdleTime;
        double maxSavedTime = values().stream().mapToDouble(Metrics::getSavedTime).max().orElseThrow() * percentageObjectiveSavedTime;
        return values().stream().min(Comparator.comparingDouble(it -> it.calculateEuclideanDistance(maxSavedTime, minIdleTime))).orElseThrow();
    }

}