package de.wwwu.awolf.presenter.algorithms.naiv; import de.wwwu.awolf.model.Line; import de.wwwu.awolf.model.Point; import de.wwwu.awolf.model.communication.AlgorithmData; import de.wwwu.awolf.model.communication.Data; import de.wwwu.awolf.model.communication.SubscriberType; import de.wwwu.awolf.presenter.AbstractPresenter; import de.wwwu.awolf.presenter.algorithms.Algorithm; import de.wwwu.awolf.presenter.util.FastElementSelector; import de.wwwu.awolf.presenter.util.Logging; import java.util.*; import java.util.concurrent.Flow; /** * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden. * * @Author: Armin Wolf * @Email: a_wolf28@uni-muenster.de * @Date: 15.09.2017. */ public class NaivRepeatedMedianEstimator implements Algorithm { private static final Algorithm.Type type = Type.NAIV_RM; private List setOfLines; private Map> slopesPerLine; private Map> interceptPerLine; private List xMedians; private List yMedians; private double medianX; private double medianY; private Flow.Subscriber subscriber; private AbstractPresenter presenter; @Override public Line call() { slopesPerLine = new HashMap<>(); interceptPerLine = new HashMap<>(); xMedians = new ArrayList<>(); yMedians = new ArrayList<>(); //init the List for the slopes Logging.logInfo("=== S T A R T - naiv R M ==="); long start; long end; start = System.currentTimeMillis(); for (Line leq : setOfLines) { slopesPerLine.computeIfAbsent(leq.getId(), k -> new ArrayList<>()); interceptPerLine.computeIfAbsent(leq.getId(), k -> new ArrayList<>()); } //calculate all slopes for each line Point ret; for (int i = 0; i < setOfLines.size(); i++) { for (int j = i + 1; j < setOfLines.size(); j++) { ret = calculateLine(setOfLines.get(i), setOfLines.get(j)); slopesPerLine.get(setOfLines.get(i).getId()).add(ret.getX()); interceptPerLine.get(setOfLines.get(i).getId()).add(ret.getY()); } } //berechne mediane Steigung for (String l : slopesPerLine.keySet()) { List list = slopesPerLine.get(l); int size = list.size() / 2; if (size > 0) { double medianX = FastElementSelector.randomizedSelect(list, size); xMedians.add(medianX); } } //berechne medianen y-Achsenabschnitt for (String l : interceptPerLine.keySet()) { List list = interceptPerLine.get(l); int size = list.size() / 2; if (size > 0) { double medianY = FastElementSelector.randomizedSelect(list, size); yMedians.add(medianY); } } medianX = FastElementSelector.randomizedSelect(xMedians, xMedians.size() * 0.5); medianY = FastElementSelector.randomizedSelect(yMedians, yMedians.size() * 0.5); end = System.currentTimeMillis(); Logging.logInfo("=== E N D - naiv R M ==="); Logging.logInfo("Slope: " + getSlope() + ", y-Interception: " + getYInterception()); AlgorithmData data = new AlgorithmData(); data.setAlgorithmType(getType()); data.setType(SubscriberType.ALGORITHM); data.setLineData(new Line(getSlope(), getYInterception())); this.subscriber.onNext(data); return new Line(getSlope(), getYInterception()); } @Override public void setInput(Set lines) { this.setOfLines = new ArrayList<>(lines); } @Override public Type getType() { return type; } @Override public void setPresenter(AbstractPresenter presenter) { this.presenter = presenter; subscribe(presenter); } /** * Berechnet die Geraden zwischen zwei Punkten im dualen Raum. * * @param startPoint Gerade 1 => Startpunkt mit den Koordianten (m,b) * @param endPoint Gerade 2 => Endpunkt mit den Koordianten (m', b') * @return */ private Point calculateLine(Line startPoint, Line endPoint) { double xi; double xj; double yi; double yj; if (endPoint.getM() > startPoint.getM()) { xi = startPoint.getM(); yi = startPoint.getB(); xj = endPoint.getM(); yj = endPoint.getB(); } else { xj = startPoint.getM(); yj = startPoint.getB(); xi = endPoint.getM(); yi = endPoint.getB(); } double m = (yj - yi) / (xj - xi); double b = ((xj * yi) - (xi * yj)) / (xj - xi); return new Point(m, b); } /** * @return Steigung */ public double getSlope() { return medianX * -1; } /** * @return y-Achsenabschnitt */ public double getYInterception() { return medianY * -1; } @Override public void subscribe(Flow.Subscriber subscriber) { this.subscriber = subscriber; } }