Pareto.java

92 lines | 3.627 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;
  private Metrics bestMetrics;

  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(0D);
    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() {
    if (this.bestMetrics == null) this.bestMetrics = getBestMetrics(Configuration.getPreferences().get(0), Configuration.getPreferences().get(1));
    return this.bestMetrics;
  }

  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();
  }

}