package Presenter.Algorithms; import Model.Line; import Model.Point; import Model.Slab; import Presenter.*; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.Observable; import java.util.concurrent.ThreadLocalRandom; /** * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden. * * @Author: Armin Wolf * @Email: a_wolf28@uni-muenster.de * @Date: 28.05.2017. */ public class TheilSenEstimator extends Observable implements Algorithm { private Presenter presenter; private ArrayList setOfLines; private ArrayList setOfIntersections; private ArrayList intervalIntersections; private ArrayList yCoordinates; private ArrayList xCoordinates; private Slab interval; private Double j; private Integer jA; private Integer jB; private Double r; private Integer n; private Double N; private Integer k; private Double a; private Double b; private Double aVariant; private Double bVariant; private ArrayList sampledIntersections; public TheilSenEstimator(LinkedList setOfLines, LinkedList setOfIntersections, Presenter presenter) { this.presenter = presenter; this.setOfLines = new ArrayList<>(setOfLines); this.setOfIntersections = new ArrayList<>(setOfIntersections); this.intervalIntersections = new ArrayList<>(setOfIntersections); this.n = setOfLines.size(); this.sampledIntersections = new ArrayList<>(); this.yCoordinates = new ArrayList<>(); this.xCoordinates = new ArrayList<>(); this.N = BinomialCoeffizient.run(n, 2); this.k = Integer.valueOf((int) (N * 0.5)); for (Point l : setOfIntersections){ yCoordinates.add(l.getY()); xCoordinates.add(l.getX()); } } /** * */ public void run(){ a = -90000d; b = 90000d; Collections.sort(setOfIntersections); interval = new Slab(a,b); while (true){ if (this.N <= n){ break; } else { r = Double.valueOf(n); this.k = Integer.valueOf((int) (N * 0.5)); System.out.println("#number: "+N); int numberOfIntersections = checkNumberOfIntersectionInInterval(-90000,a, setOfIntersections); j = (r /N) * (k - numberOfIntersections); jA = (int) Math.floor(j - (3 * Math.sqrt(r))); jB = (int) Math.floor(j + (3 * Math.sqrt(r))); do { sampledIntersections = randomSampleOfIntersections(intervalIntersections, r); Collections.sort(sampledIntersections); aVariant = sampledIntersections.get(jA); bVariant = sampledIntersections.get(jB); } while (!checkCondition()); a = aVariant; b = bVariant; interval.setLower(a); interval.setUpper(b); N = Double.valueOf(checkNumberOfIntersectionInInterval(a,b, intervalIntersections)); intervalIntersections = getKleftMostIntersection(a,b); } } } /** * Diese Funktion überprüft ob die Bedingung für das Interval erfüllt ist. Dabei muss der k-te * Schnittpunkt in diesem Interval enthalten sein. des weiteren soll die Anzahl der Schnittpunkte * im Interval kleiner oder gleich dem Term: (11*N)/sqrt(r) sein. * * @return Boolscher Wert ob die Bedingung erfüllt ist */ private Boolean checkCondition(){ Collections.sort(intervalIntersections); Boolean cond1 = (intervalIntersections.get(k-1).getX() >= aVariant) && ( intervalIntersections.get(k-1).getX() < bVariant); Boolean cond2 = (checkNumberOfIntersectionInInterval(aVariant,bVariant, intervalIntersections) <= ((11 * N) / Math.sqrt(r))); return cond1 && cond2; } /** * Diese Funktion gibt eine r Elementige Stichprobe aus der überegebenene Menge an * Schnittpunkten. Diese Stichprobe soll zufällig sein. Es können aus gleiche Werte in der Rückgabe * vertreten sein. * * @param set Menge an Schnittpunkten * @param r Stichprobengröße * @return Stichprobe */ public ArrayList randomSampleOfIntersections(ArrayList set, Double r){ ArrayList sampledLines = new ArrayList<>(); while (sampledLines.size() < r){ Double x = set.get(ThreadLocalRandom.current().nextInt(0, set.size())).getX(); if (!sampledLines.contains(x)) sampledLines.add(x); } return sampledLines; } /** * Berechne wieviele von den Schnittpunkten in dem Interval zwischen a und b * enthalten sind. * * @param a untere Grenze des Intervals * @param b obere Grenze des Intrvals * @return Anzahl der Schnittpunkte im Interval [a,b) */ public int checkNumberOfIntersectionInInterval(double a, double b, ArrayList set){ int counter = 0; for (Point x : set){ if (x.getX() >= a && x.getX() < b){ counter++; } } return counter; } /** * Berechne wieviele von den Schnittpunkten in dem Interval zwischen a und b * enthalten sind. Zusätzlich werden diese Schnittpunkte in einer Liste festgehalten und diese werden * zurückgeliefert. * * @param a untere Grenze des Intervals * @param b obere Grenze des Intrvals * @return Liste der Schnittpunkte die im Interval [a,b) vertreten sind */ public ArrayList getKleftMostIntersection(double a, double b){ ArrayList list = new ArrayList<>(); for (Point x : intervalIntersections){ if (x.getX() >= a && x.getX() < b){ list.add(x); } } return list; } @Override public void getResult() { if (presenter != null) { setChanged(); double m,x; double b,y; Collections.sort(xCoordinates); Collections.sort(yCoordinates); int n = xCoordinates.size(); if (n % 2 == 0){ x = 0.5 * (xCoordinates.get((n/2)-1) + xCoordinates.get((n/2))); y = 0.5 * (yCoordinates.get((n/2)-1) + yCoordinates.get((n/2))); } else { x = xCoordinates.get(((n+1)/2)-1); y = yCoordinates.get(((n+1)/2)-1); } ArrayList resultSt = getKleftMostIntersection(a, this.b); int size = resultSt.size(); if (size % 2 == 0){ m = 0.5 * (resultSt.get((size/2)-1).getX() + resultSt.get((size/2)).getX()); } else { m = resultSt.get(((size+1)/2)-1).getX(); } m *= -1; b = (x * m) + y; String[] result = new String[]{"ts", m+"", b+""}; notifyObservers(result); } } }